Conversión de zona horaria

Necesito convertir de una zona horaria a otra zona horaria en mi proyecto.

Puedo convertir de mi zona horaria actual a otra, pero no de una zona horaria diferente a otra.

Por ejemplo, estoy en India y puedo convertir de India a EE. UU. Utilizando Date d=new Date(); y asignarlo a un objeto de calendario y establecer la zona horaria.

Sin embargo, no puedo hacer esto desde diferentes zonas horarias a otra zona horaria. Por ejemplo, estoy en India, pero estoy teniendo problemas para convertir zonas horarias de los EE. UU. Al Reino Unido.

tl; dr

 ZonedDateTime.now( ZoneId.of( "Pacific/Auckland" ) // Current moment in a particular time zone. .withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ) // Same moment adjusted into another time zone. 

Detalles

La clase java.util.Date no tiene zona horaria asignada , pero su implementación toString aplica de manera confusa la zona horaria predeterminada actual de la JVM.

Evita java.util.Date y .Calendar

Esta es una de las muchas razones para evitar las notoriamente problemáticas clases java.util.Date, .Calendar y SimpleDateFormat incluidas con Java. Evítales. En su lugar, use cualquiera de estos

  • El paquete java.time integrado en Java 8 e inspirado en Joda-Time.
  • Joda-Time

java.time

Java 8 y posterior tiene incorporado el paquete java.time . Este paquete fue inspirado por Joda-Time . Si bien comparten algunas similitudes y nombres de clase, son diferentes; cada uno tiene características que el otro no tiene. Una diferencia notable es que java.time evita constructores, en su lugar utiliza métodos de instanciación estáticos. Ambos marcos están dirigidos por el mismo hombre, Stephen Colbourne .

Gran parte de la funcionalidad de java.time ha sido retransmitida a Java 6 y 7 en el proyecto ThreeTen-Backport . Adaptado a Android en el proyecto ThreeTenABP .

En el caso de esta pregunta, funcionan de la misma manera. Especifique una zona horaria y llame a un método now para obtener el momento actual, luego cree una nueva instancia basada en la instancia inmutable anterior para ajustar la zona horaria.

Tenga en cuenta las dos clases de zona horaria diferentes. Una es una zona horaria con nombre que incluye todas las reglas para el horario de verano y otras anomalías más una compensación de UTC, mientras que el otro es solo el desplazamiento.

 ZoneId zoneMontréal = ZoneId.of("America/Montreal"); ZonedDateTime nowMontréal = ZonedDateTime.now ( zoneMontréal ); ZoneId zoneTokyo = ZoneId.of("Asia/Tokyo"); ZonedDateTime nowTokyo = nowMontréal.withZoneSameInstant( zoneTokyo ); ZonedDateTime nowUtc = nowMontréal.withZoneSameInstant( ZoneOffset.UTC ); 

Joda-Time

A continuación, aparece un código de ejemplo en Joda-Time 2.3. Busque StackOveflow para obtener muchos más ejemplos y mucha discusión.

 DateTimeZone timeZoneLondon = DateTimeZone.forID( "Europe/London" ); DateTimeZone timeZoneKolkata = DateTimeZone.forID( "Asia/Kolkata" ); DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" ); DateTime nowLondon = DateTime.now( timeZoneLondon ); // Assign a time zone rather than rely on implicit default time zone. DateTime nowKolkata = nowLondon.withZone( timeZoneKolkata ); DateTime nowNewYork = nowLondon.withZone( timeZoneNewYork ); DateTime nowUtc = nowLondon.withZone( DateTimeZone.UTC ); // Built-in constant for UTC. 

Tenemos cuatro representaciones del mismo momento en la línea de tiempo del Universo.


En realidad, la clase java.util.Date tiene una zona horaria enterrada dentro de su código fuente . Pero la clase ignora ese huso horario para la mayoría de los propósitos prácticos. Entonces, como taquigrafía, a menudo se dice que juDate no tiene zona horaria asignada. ¿Confuso? Sí. Evite el desastre que es juDate e ir con Joda-Time y / o java.time.

Algunos ejemplos

Convertir tiempo entre zona horaria

Convertir tiempos entre zonas horarias

 import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; public class TimeZoneExample { public static void main(String[] args) { // Create a calendar object and set it time based on the local // time zone Calendar localTime = Calendar.getInstance(); localTime.set(Calendar.HOUR, 17); localTime.set(Calendar.MINUTE, 15); localTime.set(Calendar.SECOND, 20); int hour = localTime.get(Calendar.HOUR); int minute = localTime.get(Calendar.MINUTE); int second = localTime.get(Calendar.SECOND); // Print the local time System.out.printf("Local time : %02d:%02d:%02d\n", hour, minute, second); // Create a calendar object for representing a Germany time zone. Then we // wet the time of the calendar with the value of the local time Calendar germanyTime = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin")); germanyTime.setTimeInMillis(localTime.getTimeInMillis()); hour = germanyTime.get(Calendar.HOUR); minute = germanyTime.get(Calendar.MINUTE); second = germanyTime.get(Calendar.SECOND); // Print the local time in Germany time zone System.out.printf("Germany time: %02d:%02d:%02d\n", hour, minute, second); } } 
  Date date = new Date(); String formatPattern = ....; SimpleDateFormat sdf = new SimpleDateFormat(formatPattern); TimeZone T1; TimeZone T2; // set the Calendar of sdf to timezone T1 sdf.setTimeZone(T1); System.out.println(sdf.format(date)); // set the Calendar of sdf to timezone T2 sdf.setTimeZone(T2); System.out.println(sdf.format(date)); // Use the 'calOfT2' instance-methods to get specific info // about the time-of-day for date 'date' in timezone T2. Calendar calOfT2 = sdf.getCalendar(); 

La zona horaria “predeterminada” se puede evitar por completo simplemente configurando la zona horaria de forma adecuada para el objeto Calendar . Sin embargo, le sugiero personalmente que utilice Joda Time como una API muy superior para operaciones de fecha y hora en Java. Entre otras cosas, la conversión de zona horaria es muy simple en Joda.

No está claro cómo es tu código actual y por qué solo puedes convertir a través del huso horario predeterminado, pero en Joda Time solo especificas el huso horario explícitamente cuando creas (digamos) un objeto DateTime , y luego utilizas con withZone(DateTimeZone zone) .

Si pudieras decirnos más acerca de cómo obtienes los datos de entrada, podríamos dar un ejemplo más completo.

Puede usar el siguiente fragmento de código

 String dateString = "14 Jul 2014 00:11:04 CEST"; date = formatter.parse(dateString); System.out.println(formatter.format(date)); // Set the formatter to use a different timezone - Indochina Time formatter.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok")); System.out.println("ICT time : "+formatter.format(date)); 

Si no quiere usar Joda, esta es una forma determinista usando las bibliotecas integradas.

Primero, le recomiendo que fuerce su JVM a una zona horaria predeterminada. Esto soluciona los problemas que puede encontrar al mover su JVM de una máquina a otra que están configuradas en diferentes zonas horarias, pero sus datos de origen siempre son una zona horaria particular. Por ejemplo, supongamos que sus datos son siempre zona horaria PDT / PST, pero se ejecuta en un cuadro que está configurado en zona horaria UTC.

El siguiente fragmento de código establece la zona horaria predeterminada en mi JVM:

  //You can either pass the JVM a parameter that //enforces a TZ: java -Duser.timezone=UTC or you can do it //progtwigtically like this TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); TimeZone.setDefault(tz); 

Ahora digamos que su fecha de origen viene como PDT / PST, pero necesita convertirla a UTC. Estos son los pasos:

  DateFormat dateFormatUtc = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dateFormatUtc.setTimeZone(TimeZone.getTimeZone("UTC")); String dateStrInPDT = "2016-05-19 10:00:00"; Date dateInPDT = dateFormat.parse(dateStrInPDT); String dateInUtc = dateFormatUtc.format(dateInPDT); System.out.println("Date In UTC is " + dateInUtc); 

La salida sería:

 Date In UTC is 2016-05-19 17:00:00 

puedes hacer esto para obtener la hora actual en otra zona horaria

 Calendar japanCal = new GregorianCalendar(TimeZone.getTimeZone("Japan")); japanCal.setTimeInMillis(local.getTimeInMillis()); 

Depende de lo que realmente quiere decir con “conversión”.

PUEDE ser tan simple como configurar el huso horario en el FORMATTER, y no borrar el calendario en absoluto.

 Calendar cal = Calendar.getInstance(); TimeZone tzUTC = TimeZone.getTimeZone( "UTC" ); TimeZone tzPST = TimeZone.getTimeZone( "PST8PDT" ); DateFormat dtfmt = new SimpleDateFormat( "EEE, yyyy-MM-dd KK:mm az" ); dtfmt.setTimeZone( tzUTC ); System.out.println( "UTC: " + dtfmt.format( cal.getTime() )); dtfmt.setTimeZone( tzPST ); System.out.println( "PST: " + dtfmt.format( cal.getTime() )); 

Esta no es la respuesta, pero podría ayudar a alguien que intenta generar fechas con la misma zona horaria y aplicar el desplazamiento de otra zona horaria. Es útil cuando su servidor de aplicaciones se ejecuta en una zona horaria y su base de datos en otra.

 public static Date toGreekTimezone (Date date) { ZoneId greek = ZoneId.of(EUROPE_ATHENS); ZonedDateTime greekDate = ZonedDateTime.ofInstant(date.toInstant(), greek); ZoneId def = ZoneId.systemDefault(); ZonedDateTime defDate = greekDate.withZoneSameLocal(def); return Date.from(defDate.toInstant()); } 

Puede usar el java.time.ZoneDateTime#ofInstant() :

 import java.time.*; public class TimeZonesConversion { static ZonedDateTime convert(ZonedDateTime time, ZoneId newTimeZone) { return ZonedDateTime.ofInstant( time.toInstant(), newTimeZone); }; public static void main(String... args) { ZonedDateTime mstTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("-07")); ZonedDateTime localTime = convert(mstTime, Clock.systemDefaultZone().getZone()); System.out.println("MST(" + mstTime + ") = " + localTime); } } 
 public static void convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone) { long milliseconds = date.getTime(); milliseconds += (fromTimeZone.getRawOffset() * -1); if (fromTimeZone.inDaylightTime(date)) { milliseconds += (fromTimeZone.getDSTSavings() * -1); } milliseconds += toTimeZone.getRawOffset(); if (toTimeZone.inDaylightTime(date)) { milliseconds += toTimeZone.getDSTSavings(); } date.setTime(milliseconds); }