2010-05-20 14 views
11

Ricevo un datetime da un servizio web SOAP senza informazioni su timzone. Quindi, il deserializzatore dell'Asse assume UTC. Tuttavia, il datetime è davvero all'ora di Sydney. Ho risolto il problema sottraendo l'offset fuso orario:Modifica del fuso orario senza modificare il tempo in Java

Calendar trade_date = trade.getTradeDateTime(); 
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney"); 
long millis = trade_date.getTimeInMillis() - est_tz.getRawOffset(); 
trade_date.setTimeZone(est_tz); 
trade_date.setTimeInMillis(millis); 

Tuttavia, non sono sicuro se questa soluzione prende anche l'ora legale in considerazione. Penso che dovrebbe, perché tutte le operazioni sono in ora UTC. Qualche esperienza con la manipolazione del tempo in Java? Migliori idee su come risolvere questo problema?

+1

ho sempre, sempre, e manipola solo la data (in qualsiasi lingua) utilizzando l'unica unità corretta. Quell'unità è il secondo (o millisecondo). Ci sono minuti con 59 o 61 secondi e ci sono giorni con 23 o 25 ore. Ci sono ore con 60 * 60 +/- 1 secondi, ecc. Tutte le mie date sono memorizzate come (milli) secondi dall'epoca. Ecco come sono nel DB, è così che vengono ordinati. L'unica volta in cui eseguo un fuso orario/aaaa-mm-gg qualunque sia la conversione quando deve essere visualizzata all'utente (o quando si utilizzano API interrotte che non comprendono che una data è espressiva in secondi). – SyntaxT3rr0r

+0

@WizardOfOdds. Questo è il consiglio del suono, ma OP ha chiaramente pubblicato che riceve il timestamp da un servizio web (eventualmente di terze parti) e ha usato una libreria di terze parti per elaborare quella richiesta. Chiaramente ci sono alcune cose fuori dal suo controllo diretto, e la conversione da fuso orario a fuso orario non è sicuramente diretta con java.util.Calendar. –

+0

Grazie per i vostri commenti. Sto generando gli stub del servizio Web dal file WSDL utilizzando Axis. Sto utilizzando le classi generate per connettersi a un servizio web di terze parti. In realtà, dovrebbero trasmettere i campi datetime con le informazioni sul fuso orario o in UTC, che è ciò che si aspetta Axis. Ma non è la mia scelta. –

risposta

-1

Ho deciso di reparse la stringa datetime ricevuta con il fuso orario corretto impostato. Questo l'ora legale deve anche considerare:

public class DateTest { 

    private static SimpleDateFormat soapdatetime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     TimeZone oztz = TimeZone.getTimeZone("Australia/Sydney"); 
     TimeZone gmtz = TimeZone.getTimeZone("GMT"); 
     Calendar datetime = Calendar.getInstance(gmtz); 

     soapdatetime.setTimeZone(gmtz); 
     String soap_datetime = soapdatetime.format(datetime.getTime()); 
     System.out.println(soap_datetime); 

     soapdatetime.setTimeZone(oztz); 
     datetime.setTimeZone(oztz); 
     try { 
      datetime.setTime(
        soapdatetime.parse(soap_datetime) 
      ); 
     } catch (ParseException e) { 
      e.printStackTrace(); 
     } 

     soapdatetime.setTimeZone(gmtz); 
     soap_datetime = soapdatetime.format(datetime.getTime()); 
     System.out.println(soap_datetime); 
    } 
} 
16

Peccato per il pazzo che deve fare le date in Java.

Quello che hai fatto quasi certamente andrà storto durante le transizioni di risparmio di luce del giorno. Il modo migliore per farlo è probabilmente creare un nuovo oggetto Calendar, impostarne il fuso orario e quindi impostare tutti i campi singolarmente, quindi anno, mese, giorno, ora, minuto, secondo, ottenendo i valori dall'oggetto Date .

Edit:
Per mantenere l'tutti felici, probabilmente si dovrebbe fare questo:

Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
Calendar sydneyTime = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney"); 
utcTime.setTime(trade_date); 
for (int i = 0; i < Calendar.FIELD_COUNT; i++) { 
    sydneyTime.set(i, utcTime.get(i)); 
} 

Poi si prevede di non utilizzare tutti i metodi deprecati.

+0

-1: per suggerire l'uso di metodi obsoleti della classe java.util.Date –

+0

probabilmente: 'newCalendar.set (oldCalendar.get (Calender.YEAR), oldCalendar.get (Calendar.MONTH), ..., oldCalendar.get (Calendar.SECOND)); ' – wds

+1

@Alexander Pogrebnyak: Ho aggiornato la risposta in modo che gli utenti non siano portati al lato oscuro ;-) –

3

Tuttavia, non sono sicuro se questa soluzione prende anche l'ora legale in conto. Penso che dovrebbe, perché tutte le operazioni sono in ora UTC.

Sì, è necessario tenere in considerazione l'ora legale, poiché influenza lo scostamento su UTC.

Qualche esperienza con la manipolazione del tempo in Java? Migliori idee su come risolvere questo problema?

Joda-Time è un'API migliore. Forse il seguente frammento potrebbe essere di aiuto:

DateTimeZone zone; // TODO : get zone 
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone); 

tipi JodaTime sono immutabili, che è anche un vantaggio.

+0

Grazie per il collegamento a JodaTime. Tuttavia, non introdurrò una nuova libreria di terze parti per quel progetto. Ma considererò JodaTime la nex volta. –

+0

Joda-Time vale la pena di aggiungere una libreria di terze parti. Ben indossato e provato. Le classi java.util.Date e Calendar sono notoriamente fastidiose. –

2

faccio di solito in questo modo

Calendar trade_date_utc = trade.getTradeDateTime(); 
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney"); 
Calendar trade_date = Calendar.GetInstance(est_tz); 
trade_date.setTimeInMillis(millis); 
4

voglio ringraziare la persona per la risposta in 6. Questo è stato un grande inizio per me e un approccio non ho prendere in considerazione. Ci sono alcuni passaggi aggiuntivi necessari per portarlo a livello di codice di produzione. In particolare, osserva i passaggi richiesti per DST_OFFSET e ZONE_OFFSET. Voglio condividere la soluzione che ho trovato.

Questo prende il tempo dall'oggetto di input Calendar, lo copia nel tempo di uscita, imposta il nuovo fuso orario sull'output. Viene utilizzato quando si prende letteralmente il tempo dal database e si imposta il fuso orario senza cambiare l'ora.

public static Calendar setNewTimeZoneCopyOldTime(Calendar inputTime, 
     TimeZone timeZone) { 
    if((inputTime == null) || (timeZone == null)) { return(null); } 

    Calendar outputTime = Calendar.getInstance(timeZone); 
    for(int i = 0; i < Calendar.FIELD_COUNT; i++) { 
     if((i != Calendar.ZONE_OFFSET) && (i != Calendar.DST_OFFSET)) { 
      outputTime.set(i, inputTime.get(i)); 
     } 
    } 

    return((Calendar) outputTime.clone()); 
} 
0

Stai ottenendo una stringa di stile ISO 8601 da quel servizio Web incasinato? Se è così, la libreria Joda-Time 2.3 lo rende molto facile.

Se si ottiene una stringa ISO 8601 senza offset del fuso orario, si passa un oggetto del fuso orario al costruttore DateTime.

DateTimeZone timeZone = DateTimeZone.forID("Australia/Sydney"); 
String input = "2014-01-02T03:00:00"; // Note the lack of time zone offset at end. 
DateTime dateTime = new DateTime(input, timeZone); 

Dump per consolarla ...

System.out.println("dateTime: " + dateTime); 

Quando eseguito ...

dateTime: 2014-01-02T03:00:00.000+11:00 
0
@Test 
public void tzTest() { 
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z"); 
    TimeZone tz1 = TimeZone.getTimeZone("Europe/Moscow"); 
    Calendar cal1 = Calendar.getInstance(tz1); 
    long l1 = cal1.getTimeInMillis(); 
    df.setTimeZone(tz1); 
    System.out.println(df.format(cal1.getTime())); 
    System.out.println(l1); 
    TimeZone tz2 = TimeZone.getTimeZone("Africa/Douala"); 
    Calendar cal2 = Calendar.getInstance(tz2); 
    long l2 = l1 + tz1.getRawOffset() - tz2.getRawOffset(); 
    cal2.setTimeInMillis(l2); 
    df.setTimeZone(tz2); 
    System.out.println(df.format(cal2.getTime())); 
    System.out.println(l2); 
    assertNotEquals(l2, l1); 
} 


Esecuzione CalendarTest
2016/06/30 19: 09: 16,522 +0300
2016/06/30 19: 09: 16,522 +0100
test eseguiti: 1, Guasti: 0, Errori: 0, saltati: 0, il tempo trascorso: 0.137 sec

Problemi correlati