Como definir o fuso horário de um java.util.Date?

Eu analisei um java.util.Date de uma String mas está definindo o fuso horário local como o fuso horário do object de date .

O fuso horário não é especificado na String da qual a Date é analisada. Eu quero definir um fuso horário específico do object de date .

Como eu posso fazer isso?

Use DateFormat. Por exemplo,

 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"); 

Esteja ciente de que os objects java.util.Date não contêm informações de fuso horário sozinhos – você não pode definir o fuso horário em um object Date . A única coisa que um object Date contém é um número de milissegundos desde o “epoch” – 1 de janeiro de 1970, 00:00:00 UTC.

Como mostra o ZZ Coder, você define o fuso horário no object DateFormat , para informar em qual fuso horário deseja exibir a data e a hora.

Você também pode definir o fuso horário no nível da 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); 

saída:

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

tl; dr

… Analisado… a partir de um fuso horário… o fuso horário não está especificado… Quero definir um fuso horário específico

 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. 

Nenhum fuso horário no juDate

Como as outras respostas corretas afirmaram, um java.util.Date não possui fuso horário . Representa UTC / GMT (sem deslocamento de fuso horário). Muito confuso porque seu método toString aplica o fuso horário padrão da JVM ao gerar uma representação de String.

Evite juDate

Por essa e muitas outras razões, você deve evitar usar o java.util.Date & .Calendar & java.text.SimpleDateFormat embutido. Eles são notoriamente problemáticos.

Em vez disso, use o pacote java.time empacotado com o Java 8 . Essas novas classs são inspiradas no Joda-Time , definidas pela JSR 310 e ampliadas pelo projeto ThreeTen-Extra . Para Java 6 e 7, use o projeto back-port, ThreeTen-Backport . Para o Android, a adaptação desse back-port, o ThreeTenABP . Veja o Oracle Tutorial .

java.time

As classs java.time podem representar um momento na linha do tempo de três maneiras:

  • UTC ( Instant )
  • Com um deslocamento ( OffsetDateTime com ZoneOffset )
  • Com um fuso horário ( ZonedDateTime com ZoneId )

Instant

Em java.time , o bloco de construção básico é Instant , um momento na linha do tempo no UTC. Use objects Instant para grande parte de sua lógica de negócios.

 Instant instant = Instant.now(); 

OffsetDateTime

Aplique um deslocamento de UTC para ajustar a hora do relógio de parede de alguma localidade.

Aplique um ZoneOffset para obter um OffsetDateTime .

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

ZonedDateTime

Melhor é aplicar um fuso horário , um deslocamento mais as regras para lidar com anomalias como o horário de verão (DST) .

Aplique um ZoneId a um Instant para obter um ZonedDateTime . Sempre especifique um nome de fuso horário adequado . Nunca use 3-4 abreviações como EST ou IST que não sejam exclusivas nem padronizadas.

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

LocalDateTime

Se a cadeia de input não tiver nenhum indicador de deslocamento ou zona, analise como LocalDateTime .

Se você tiver certeza do fuso horário pretendido, atribua um ZoneId para produzir um ZonedDateTime . Veja o exemplo de código acima na seção dr no topo.

Cordas Formatadas

Chame o método toString em qualquer uma dessas três classs para gerar uma String representando o valor de data e hora no formato padrão ISO 8601 . A class ZonedDateTime estende o formato padrão anexando o nome do fuso horário entre colchetes.

 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] 

Para outros formatos, use a class DateTimeFormatter . Geralmente é melhor deixar essa class gerar formatos localizados usando a linguagem humana e as normas culturais esperadas pelo usuário. Ou você pode especificar um formato específico.


Joda-Time

Embora o Joda-Time ainda seja mantido ativamente, seus fabricantes nos disseram para migrar para o java.time assim que for conveniente. Deixo esta seção intacta como referência, mas sugiro usar a seção java.time acima.

No Joda-Time , um object de data e hora ( DateTime ) realmente conhece seu fuso horário atribuído. Isso significa um deslocamento do UTC e as regras e o histórico do horário de verão (DST) desse fuso horário e outras anomalias desse tipo.

 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 ); 

Chame o método toString para gerar uma String no formato ISO 8601 .

 String output = dateTimeIndia.toString(); 

O Joda-Time também oferece resources avançados para gerar todos os tipos de outros formatos de String.

Se necessário, você pode converter do Joda-Time DateTime para um java.util.Date.

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

Pesquise StackOverflow para “joda date” para encontrar muitos mais exemplos, alguns bastante detalhados.


Na verdade, há um fuso horário incorporado em um java.util.Date, usado para algumas funções internas (veja os comentários sobre esta resposta). Mas esse fuso horário interno não é exposto como uma propriedade e não pode ser definido. Esse fuso horário interno não é aquele usado pelo método toString para gerar uma representação de string do valor de data e hora; em vez disso, o fuso horário padrão atual da JVM é aplicado on-the-fly. Então, como taquigrafia, costumamos dizer “juDate não tem fuso horário”. Confuso? Sim. Mais uma razão para evitar essas velhas classs cansadas.

java.util.Calendar é a maneira usual de lidar com fusos horários usando apenas classs JDK. O Apache Commons tem algumas outras alternativas / utilitários que podem ser úteis. Editar a nota de Spong me lembrou que eu ouvi coisas realmente boas sobre Joda-Time (embora eu não tenha usado eu mesmo).

Se você deve trabalhar apenas com classs JDK padrão, você pode usar isto:

 /** * 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; } 

O crédito vai para este post .

Se alguém precisar disso, se você precisar converter um fuso horário XMLGregorianCalendar em seu fuso horário atual de UTC, tudo o que você precisa fazer é definir o fuso horário como 0 , em seguida, chamar toGregorianCalendar() – ele permanecerá no mesmo fuso horário, mas a Date sabe como convertê-lo para o seu, para que você possa obter os dados de 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()); 

Resultado:

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

Converta a Data em String e faça isso com 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);