¿Cómo configurar el huso horario de un java.util.Date?

He analizado un java.util.Date desde una String pero está configurando la zona horaria local como la zona horaria del objeto de date .

La zona horaria no se especifica en la String partir de la cual se analiza la fecha. Quiero establecer un huso horario específico del objeto de date .

¿Cómo puedo hacer eso?

Use DateFormat. Por ejemplo,

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

Tenga en cuenta que los objetos java.util.Date no contienen ninguna información de zona horaria por sí solos: no puede establecer la zona horaria en un objeto Date . Lo único que contiene un objeto Date es un número de milisegundos desde la “época” – 1 de enero de 1970, 00:00:00 UTC.

Como muestra ZZ Coder, estableces la zona horaria en el objeto DateFormat , para decirle en qué zona horaria quieres que se muestre la fecha y la hora.

tl; dr

… analizado … de un String … zona horaria no especificada … Quiero establecer un huso horario 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. 

Sin zona horaria en juDate

Como se indicó en las otras respuestas correctas, un java.util.Date no tiene zona horaria . Representa UTC / GMT (sin compensación de zona horaria). Muy confuso porque su método toString aplica el huso horario predeterminado de la JVM al generar una representación de Cadena.

Evita juDate

Por esta y muchas otras razones, debe evitar usar el built-in java.util.Date & .Calendar & java.text.SimpleDateFormat. Son notoriamente problemáticos.

En su lugar, use el paquete java.time incluido con Java 8 . Estas nuevas clases están inspiradas en Joda-Time , definidas por JSR 310 , y ampliadas por el proyecto ThreeTen-Extra . Para Java 6 y 7, use el proyecto back-port, ThreeTen-Backport . Para Android, la adaptación de ese puerto de respaldo , ThreeTenABP . Vea el Tutorial de Oracle .

java.time

Las clases de java.time pueden representar un momento en la línea de tiempo de tres maneras:

  • UTC ( Instant )
  • Con un desplazamiento ( OffsetDateTime con ZoneOffset )
  • Con un huso horario ( ZonedDateTime con ZoneId )

Instant

En java.time , el bloque de construcción básico es Instant , un momento en la línea de tiempo en UTC. Use objetos Instant para gran parte de su lógica comercial.

 Instant instant = Instant.now(); 

OffsetDateTime

Aplique un desplazamiento desde UTC para ajustarlo a la hora del reloj de pared de una localidad.

Aplique un ZoneOffset para obtener un OffsetDateTime .

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

ZonedDateTime

Mejor es aplicar un huso horario , un desplazamiento más las reglas para manejar anomalías como el horario de verano (DST) .

Aplique un ZoneId a un Instant para obtener un ZonedDateTime . Siempre especifique un nombre de zona horaria adecuada . Nunca use 3-4 abreviaturas como EST o IST que no son ni únicas ni estandarizadas.

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

LocalDateTime

Si la cadena de entrada carecía de cualquier indicador de desplazamiento o zona, se analiza como LocalDateTime .

Si está seguro de la zona horaria prevista, asigne un ZoneId para producir un ZonedDateTime . Vea el ejemplo de código arriba en la sección tl; dr en la parte superior.

Cuerdas formateadas

Llame al método toString en cualquiera de estas tres clases para generar una cadena que represente el valor de fecha y hora en el formato estándar ISO 8601 . La clase ZonedDateTime amplía el formato estándar al agregar el nombre de la zona horaria entre corchetes.

 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 otros formatos use la clase DateTimeFormatter . Por lo general, es mejor permitir que esa clase genere formatos localizados utilizando el lenguaje humano esperado del usuario y las normas culturales. O puede especificar un formato particular.


Joda-Time

Si bien Joda-Time todavía se mantiene activamente, sus creadores nos han dicho que migremos a java.time tan pronto como sea conveniente. Dejo esta sección intacta como referencia, pero sugiero utilizar la sección java.time anterior.

En Joda-Time , un objeto de fecha y hora ( DateTime ) realmente conoce su zona horaria asignada. Eso significa una compensación de UTC y las reglas y el historial del horario de verano (DST) de esa zona horaria y otras anomalías similares.

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

Llame al método toString para generar un String en formato ISO 8601 .

 String output = dateTimeIndia.toString(); 

Joda-Time también ofrece amplias capacidades para generar todo tipo de otros formatos de cadena.

Si es necesario, puede convertir Joda-Time DateTime a java.util.Date.

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

Busque StackOverflow para “joda date” para encontrar muchos más ejemplos, algunos bastante detallados.


En realidad, hay una zona horaria incrustada en java.util.Date, que se usa para algunas funciones internas (ver comentarios en esta respuesta). Pero esta zona horaria interna no está expuesta como una propiedad, y no se puede establecer. Esta zona horaria interna no es la utilizada por el método toString para generar una representación de cadena del valor de fecha y hora; en su lugar, la zona horaria predeterminada actual de la JVM se aplica sobre la marcha. Entonces, como taquigrafía, a menudo decimos “juDate no tiene zona horaria”. ¿Confuso? Sí. Otra razón para evitar estas viejas clases cansadas.

También puede establecer la zona horaria en el nivel de 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); 

salida:

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

java.util.Calendar es la forma habitual de gestionar zonas horarias utilizando solo clases JDK. Apache Commons tiene algunas otras alternativas / utilidades que pueden ser útiles. Editar la nota de Spong me recordó que he escuchado cosas realmente buenas sobre Joda-Time (aunque yo no las he usado).

Si debe trabajar solo con clases estándar de JDK, puede usar esto:

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

El crédito va a esta publicación .

Si alguna vez alguien necesita esto, si necesita convertir una XMLGregorianCalendar horaria XMLGregorianCalendar a su zona horaria actual desde UTC, todo lo que necesita hacer es establecer la zona horaria en 0 , luego llamar a toGregorianCalendar() – se mantendrá la misma zona horaria, pero la Date sabe cómo convertirlo al suyo, para que pueda obtener los datos desde allí.

 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 

Convierta la fecha en cadena y hágalo 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);