Come impostare il fuso orario di un java.util.Date?

Ho analizzato un java.util.Date da una String ma sta impostando il fuso orario locale come fuso orario dell’object date .

Il fuso orario non è specificato nella String da cui viene analizzata la data. Voglio impostare un fuso orario specifico dell’object date .

Come lo posso fare?

Usa DateFormat. Per esempio,

 SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); isoFormat.setTimeZone(TimeZone.getTimeZone("UTC")); Date date = isoFormat.parse("2010-05-23T09:01:02"); 

Tieni presente che gli oggetti java.util.Date non contengono informazioni sul fuso orario da soli: non puoi impostare il fuso orario su un object Date . L’unica cosa che contiene un object Date è un numero di millisecondi dall’epoca “- 1 gennaio 1970, 00:00:00 UTC.

Come mostra ZZ Coder, si imposta il fuso orario sull’object DateFormat , per indicare in quale fuso orario si desidera visualizzare la data e l’ora.

tl; dr

… analizzato … da una stringa … il fuso orario non è specificato … Voglio impostare un fuso orario specifico

 LocalDateTime.parse( "2018-01-23T01:23:45.123456789" ) // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`. .atZone( ZoneId.of( "Africa/Tunis" ) ) // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object. 

Nessun fuso orario in juDate

Come indicato nelle altre risposte corrette, un java.util.Date non ha un fuso orario . Rappresenta UTC / GMT (nessun fuso orario). Molto confuso perché il suo metodo toString applica il fuso orario predefinito della JVM quando genera una rappresentazione String.

Evitare juDate

Per questo e molti altri motivi, dovresti evitare di usare java.util.Date e .Calendar e java.text.SimpleDateFormat. Sono notoriamente fastidiosi.

Utilizzare invece il pacchetto java.time in bundle con Java 8 . Queste nuove classi sono ispirate a Joda-Time , definito da JSR 310 e ampliato dal progetto ThreeTen-Extra . Per Java 6 e 7, utilizzare il progetto back-port, ThreeTen-Backport . Per Android, l’adattamento di quella back-port, ThreeTenABP . Vedi Oracle Tutorial .

java.time

Le classi java.time possono rappresentare un momento sulla timeline in tre modi:

  • UTC ( Instant )
  • Con un offset ( OffsetDateTime con ZoneOffset )
  • Con un fuso orario ( ZonedDateTime con ZoneId )

Instant

In java.time , il building block di base è Instant , un momento sulla time line in UTC. Usa oggetti Instant per gran parte della tua logica aziendale.

 Instant instant = Instant.now(); 

OffsetDateTime

Applicare un offset da UTC per adattarsi all’ora dell’orologio a muro di alcune località.

Applicare un ZoneOffset per ottenere un OffsetDateTime .

 ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" ); OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset ); 

ZonedDateTime

È meglio applicare un fuso orario , un offset più le regole per la gestione delle anomalie come l’ ora legale (DST) .

Applica un ZoneId ad Instant per ottenere un ZonedDateTime . Specificare sempre un nome di fuso orario appropriato . Non usare mai 3-4 abbreviazioni come EST o IST che non sono né uniche né standardizzate.

 ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId ); 

LocalDateTime

Se la stringa di input mancava di un indicatore di offset o di zona, analizzare come LocalDateTime .

Se si è certi del fuso orario desiderato, assegnare un ZoneId per produrre un ZonedDateTime . Vedere l’esempio di codice sopra nella sezione tl; dr in alto.

Stringhe formattate

Chiamare il metodo toString su una di queste tre classi per generare una stringa che rappresenta il valore di data e ora nel formato ISO 8601 standard . La class ZonedDateTime estende il formato standard aggiungendo il nome del fuso orario tra parentesi.

 String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00 String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris] 

Per altri formati usa la class DateTimeFormatter . Generalmente è meglio lasciare che questa class generi formati localizzati usando la lingua umana e le norme culturali previste dall’utente. Oppure puoi specificare un particolare formato.


Joda-Time

Mentre Joda-Time è ancora triggersmente mantenuto, i suoi creatori ci hanno detto di migrare a java.time non appena è conveniente. Lascio questa sezione intatta come riferimento, ma suggerisco invece di utilizzare la sezione java.time alto.

In Joda-Time , un object data-ora ( DateTime ) conosce davvero il suo fuso orario assegnato. Ciò significa un offset da UTC e le regole e la cronologia dell’ora legale (DST) di quel fuso orario e altre anomalie simili.

 String input = "2014-01-02T03:04:05"; DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" ); DateTime dateTimeIndia = new DateTime( input, timeZone ); DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC ); 

Chiamare il metodo toString per generare una stringa nel formato ISO 8601 .

 String output = dateTimeIndia.toString(); 

Joda-Time offre anche funzionalità avanzate per la generazione di tutti i tipi di altri formati String.

Se necessario, è ansible convertire da Joda-Time DateTime a un java.util.Date.

 Java.util.Date date = dateTimeIndia.toDate(); 

Cerca StackOverflow per “data joda” per trovare molti altri esempi, alcuni abbastanza dettagliati.


In realtà esiste un fuso orario incorporato in un java.util.Date, utilizzato per alcune funzioni interne (vedere i commenti su questa risposta). Ma questo fuso orario interno non è esposto come proprietà e non può essere impostato. Questo fuso orario interno non è quello utilizzato dal metodo toString per generare una rappresentazione stringa del valore data-ora; invece, il fuso orario predefinito attuale della JVM viene applicato al volo. Quindi, come abbreviazione, spesso diciamo che “juDate non ha un fuso orario”. Confondere? Sì. Ancora un altro motivo per evitare queste vecchie classi stanche.

Puoi anche impostare il fuso orario a livello JVM

 Date date1 = new Date(); System.out.println(date1); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // or pass in a command line arg: -Duser.timezone="UTC" Date date2 = new Date(); System.out.println(date2); 

produzione:

 Thu Sep 05 10:11:12 EDT 2013 Thu Sep 05 14:11:12 UTC 2013 

java.util.Calendar è il solito modo di gestire i fusi orari usando solo classi JDK. Apache Commons ha alcune alternative / utilità che possono essere utili. Modifica la nota di Spong mi ha ricordato che ho sentito cose davvero buone su Joda-Time (anche se non l’ho usato da solo).

Se devi lavorare solo con classi JDK standard puoi usare questo:

 /** * Converts the given date from the fromTimeZone to the * toTimeZone. Since java.util.Date has does not really store time zome * information, this actually converts the date to the date that it would be in the * other time zone. * @param date * @param fromTimeZone * @param toTimeZone * @return */ public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone) { long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone); long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone); return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset)); } /** * Calculates the offset of the timeZone from UTC, factoring in any * additional offset due to the time zone being in daylight savings time as of * the given date. * @param date * @param timeZone * @return */ private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone) { long timeZoneDSTOffset = 0; if(timeZone.inDaylightTime(date)) { timeZoneDSTOffset = timeZone.getDSTSavings(); } return timeZone.getRawOffset() + timeZoneDSTOffset; } 

Il merito va a questo post .

Se qualcuno dovesse averne bisogno, se hai bisogno di convertire un fuso orario XMLGregorianCalendar fuso orario corrente da UTC, allora tutto ciò che devi fare è impostare il fuso orario su 0 , quindi chiamare toGregorianCalendar() – rimarrà lo stesso fuso orario, ma la Date sa come convertirlo al tuo, così puoi ottenere i dati da lì.

 XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance() .newXMLGregorianCalendar( ((GregorianCalendar)GregorianCalendar.getInstance()); xmlStartTime.setTimezone(0); GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar(); Date startDate = startCalendar.getTime(); XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance() .newXMLGregorianCalendar(startCalendar); xmlStartTime.setHour(startDate.getHours()); xmlStartTime.setDay(startDate.getDate()); xmlStartTime.setMinute(startDate.getMinutes()); xmlStartTime.setMonth(startDate.getMonth()+1); xmlStartTime.setTimezone(-startDate.getTimezoneOffset()); xmlStartTime.setSecond(startDate.getSeconds()); xmlStartTime.setYear(startDate.getYear() + 1900); System.out.println(xmlStartTime.toString()); 

Risultato:

 2015-08-26T12:02:27.183Z 2015-08-26T14:02:27.183+02:00 

Converti la data in stringa e fallo con SimpleDateFormat.

  SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset)); String dateStr = readFormat.format(date); SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Date date = writeFormat.parse(dateStr);