Convertir fecha / hora para la zona horaria dada – java

Quiero convertir esta marca de tiempo GMT a GMT + 13:

2011-10-06 03:35:05 

He intentado unas 100 combinaciones diferentes de DateFormat, TimeZone, Date, GregorianCalendar etc. para intentar hacer esta MUY tarea básica.

Este código hace lo que quiero para la HORA ACTUAL:

 Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT")); DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z"); formatter.setTimeZone(TimeZone.getTimeZone("GMT+13")); String newZealandTime = formatter.format(calendar.getTime()); 

Pero lo que quiero es establecer el tiempo en lugar de usar la hora actual.

Encontré que cada vez que trato de establecer el tiempo de esta manera:

 calendar.setTime(new Date(1317816735000L)); 

se usa el TimeZone de la máquina local. ¿Porqué es eso? Sé que cuando “new Date ()” devuelve UTC + 0 vez, entonces ¿por qué cuando configura el tiempo en milisegundos, ya no asume que el tiempo está en UTC?

Es posible:

  1. Establecer la hora en un objeto (Calendario / Fecha / Marca de tiempo)
  2. (Posiblemente) Establezca la Zona horaria de la marca de tiempo inicial (calendar.setTimeZone (…))
  3. Formatee la marca de tiempo con una nueva TimeZone (formatter.setTimeZone (…)))
  4. Devuelve una cadena con un nuevo huso horario. (formatter.format (calendar.getTime ()))

Gracias de antemano por cualquier ayuda: D

Comprender cómo funciona el tiempo de la computadora es muy importante. Dicho esto, acepto que si se crea una API para ayudarlo a procesar el tiempo de la computadora, como el tiempo real, entonces debería funcionar de tal manera que le permita tratarlo como en tiempo real. En su mayor parte, este es el caso, pero hay algunos descuidos importantes que requieren atención.

De todos modos estoy divagando !! Si tiene su compensación UTC (mejor para trabajar en UTC que en las compensaciones GMT), puede calcular el tiempo en milisegundos y agregarlo a su marca de tiempo. Tenga en cuenta que una marca de tiempo SQL puede variar de una marca de tiempo de Java, ya que la forma en que se calcula el tiempo transcurrido desde la época no siempre es el mismo: depende de las tecnologías de base de datos y también de los sistemas operativos.

Te aconsejaría que utilizaras System.currentTimeMillis () como marcas de tiempo, ya que pueden procesarse de forma más constante en Java sin preocuparte por convertir SQL Timestamps en java Date objects, etc.

Para calcular su compensación, puede intentar algo como esto:

 Long gmtTime =1317951113613L; // 2.32pm NZDT Long timezoneAlteredTime = 0L; if (offset != 0L) { int multiplier = (offset*60)*(60*1000); timezoneAlteredTime = gmtTime + multiplier; } else { timezoneAlteredTime = gmtTime; } Calendar calendar = new GregorianCalendar(); calendar.setTimeInMillis(timezoneAlteredTime); DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z"); formatter.setCalendar(calendar); formatter.setTimeZone(TimeZone.getTimeZone(timeZone)); String newZealandTime = formatter.format(calendar.getTime()); 

¡Espero que esto sea útil!

Para mí, la forma más sencilla de hacerlo es:

 Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //Here you say to java the initial timezone. This is the secret sdf.setTimeZone(TimeZone.getTimeZone("UTC")); //Will print in UTC System.out.println(sdf.format(calendar.getTime())); //Here you set to your timezone sdf.setTimeZone(TimeZone.getDefault()); //Will print on your default Timezone System.out.println(sdf.format(calendar.getTime())); 

Como siempre, recomiendo leer este artículo sobre la fecha y la hora en Java para que lo comprenda.

La idea básica es que “bajo el capó” todo se hace en milisegundos UTC desde la época. Esto significa que es más fácil si opera sin utilizar zonas horarias en absoluto, con la excepción del formato de cadena para el usuario.

Por lo tanto, me saltaría la mayoría de los pasos que ha sugerido.

  1. Establezca la hora en un objeto (Fecha, Calendario, etc.).
  2. Establezca la zona horaria en un objeto formateador.
  3. Devuelve una cadena del formateador.

Alternativamente, puede usar el tiempo Joda . He oído que es una API de fecha mucho más intuitiva.

tl; dr

Si se le da una entrada de 1317816735000L

 Instant.ofEpochMilli( 1_317_816_735_000L ) // Represent a moment in UTC using a count of milliseconds since the epoch reference of 1970-01-01T00:00Z. .atZone( ZoneId.of( "Pacific/Auckland" ) ) // Adjust from UTC into the wall-clock time used by the people of a certain region (a time zone). Returns a `ZonedDateTime` object. .format( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ) .withLocale( new Locale( "en" , "NZ" ) ) // Locale specifies the human language and cultural norms used in localization. ) // Returns a `String` object that represents the value of our `ZonedDateTime` object's value. 

Si se le da entrada de 2011-10-06 03:35:05

 LocalDateTime.parse( // Parse input string lacking any indicator of time zone or offset-from-UTC using the `LocalDateTime` class. "2011-10-06 03:35:05" .replace( " " , "T" ) // Comply with ISO 8601 standard by replacing SPACE in the middle with a `T`. ) // Returns a `LocalDateTime` object. .atZone( // Adjust from UTC into the wall-clock time used by the people of a certain region (a time zone). Returns a `ZonedDateTime` object. ZoneId.of( "Pacific/Auckland" ) // Always specify a time zone by `Continent/Region` name. Never use 3-4 pseudo-time-zones such as `PST`, `CST`, or `IST`. ) // Returns a `ZonedDateTime` object. 

java.time

La Pregunta y la mayoría de las respuestas usan clases heredadas de fecha y hora obsoletas de las primeras versiones de Java. Estas viejas clases han demostrado ser problemáticas y confusas. Evítales. En su lugar, use las clases java.time.

ISO 8601

Su cadena de entrada está casi en el formato estándar ISO 8601 . Simplemente reemplace el ESPACIO en el medio con una T

 String input = "2011-10-06 03:35:05".replace( " " , "T" ) ; // Comply with ISO 8601 standard format by replacing the SPACE with a `T`. 

Las clases java.time usan estos formatos estándar de forma predeterminada al analizar / generar cadenas. Entonces no es necesario especificar un patrón de formateo.

LocalDateTime

Ahora LocalDateTime como LocalDateTime porque la entrada carece de información sobre offset-from-UTC o zona horaria. Un LocalDateTime no tiene ningún concepto de desplazamiento ni zona horaria, por lo que no representa un momento real en la línea de tiempo.

 LocalDateTime ldt = LocalDateTime.parse( input ); 

ZoneOffset

Pareces estar diciendo que, desde el contexto empresarial, sabes que la intención de esta cadena es representar un momento 13 horas antes de UTC. Entonces instanciamos un ZoneOffset .

 ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe. 

OffsetDateTime

Aplicarlo para obtener un objeto OffsetDateTime . Esto se convierte en un momento real en la línea de tiempo.

 OffsetDateTime odt = ldt.atOffset( offset); 

ZoneId

Pero luego mencionas Nueva Zelanda. Entonces tenías un huso horario específico en mente. Una zona horaria es un desplazamiento desde UTC más un conjunto de reglas para manejar anomalías como el horario de verano (DST). Por lo tanto, podemos especificar un ZoneId a un ZonedDateTime lugar de un mero desplazamiento.

Especifique un nombre de zona horaria adecuado . Nunca utilice la abreviatura de 3-4 letras, como EST o IST ya que no son zonas horarias verdaderas, no están estandarizadas y ni siquiera son únicas (!). Por ejemplo, Pacific/Auckland .

 ZoneId z = ZoneId.of( "Pacific/Auckland" ); 

ZonedDateTime

Aplicar el ZoneId .

 ZonedDateTime zdt = ldt.atZone( z ); 

Puede ajustar fácilmente en otra zona para el mismo momento en la línea de tiempo.

 ZoneId zParis = ZoneId.of( "Europe/Paris" ); ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis ); // Same moment in time, but seen through lens of Paris wall-clock time. 

Cuenta desde época

Recomiendo enfáticamente que no se manejen los valores de fecha y hora como un recuento de epoch, como milisegundos desde el inicio de 1970 UTC. Pero si es necesario, crea un Instant desde tal número.

 Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L ); 

Luego, asigne una zona horaria como se ve arriba, si lo desea, para alejarse de UTC.

 ZoneId z = ZoneId.of( "Pacific/Auckland" ); ZonedDateTime zdt = instant.atZone( z ); 

Su valor de 1_317_816_735_000L es:

  • 2011-10-05T12:12:15Z (mié, 05 de octubre de 2011, 12:12:15 GMT)
  • 2011-10-06T01:12:15+13:00[Pacific/Auckland] (jueves 06 de octubre de 2011 a las 01:12:15 en Auckland, Nueva Zelanda).

Generar cadenas

Para generar una cadena en formato estándar ISO 8601 , simplemente llame a toString . Tenga en cuenta que ZonedDateTime sabiamente extiende el formato estándar al agregar el nombre de la zona horaria entre corchetes.

 String output = zdt.toString(); 

Para otros formatos, busque Stack Overflow para la clase DateTimeFormatter . Ya cubierto muchas veces.

Especifique un FormatStyle y una FormatStyle Locale .

 Locale l = new Locale( "en" , "NZ" ); DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l ); String output = zdt.format( f ); 

Acerca de java.time

El marco java.time está integrado en Java 8 y posterior. Estas clases suplantan a las problemáticas antiguas clases heredadas de fecha y hora como java.util.Date , Calendar y SimpleDateFormat .

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Puede intercambiar objetos java.time directamente con su base de datos. Use un controlador JDBC que cumpla con JDBC 4.2 o posterior. Sin necesidad de cadenas, sin necesidad de clases java.sql.* .

¿Dónde obtener las clases de java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características y correcciones menores.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
  • Androide
    • Versiones posteriores de las implementaciones del paquete de Android de las clases java.time.
    • Para Android anterior (<26), el proyecto ThreeTenABP adapta ThreeTen-Backport (mencionado anteriormente). Consulte Cómo utilizar ThreeTenABP ….

El proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí, como Interval , YearWeek , YearQuarter y más .

Echa un vistazo y no creo que haya una zona horaria en Java que sea GMT + 13. Así que creo que debes usar:

 Calendar calendar = Calendar.getInstance(); //OR Calendar.getInstance(TimeZone.getTimeZone("GMT")); calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)+13); Date d = calendar.getTime(); 

(Si hay, entonces cambie “GMT” a esa zona horaria y elimine la 2da línea de código)

O

 SimpleDateFormat df = new SimpleDateFormat(); df.setTimeZone(TimeZone.getTimeZone("GMT+13")); System.out.println(df.format(c.getTime())); 

Si desea establecer una hora / fecha específica, también puede usar:

  calendar.set(Calendar.DATE, 15); calendar.set(Calendar.MONTH, 3); calendar.set(Calendar.YEAR, 2011); calendar.set(Calendar.HOUR_OF_DAY, 13); calendar.set(Calendar.MINUTE, 45); calendar.set(Calendar.SECOND, 00); 

La solución es bastante simple (Java pura y simple):

 System.out.println(" NZ Local Time: 2011-10-06 03:35:05"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime localNZ = LocalDateTime.parse("2011-10-06 03:35:05",formatter); ZonedDateTime zonedNZ = ZonedDateTime.of(localNZ,ZoneId.of("+13:00")); LocalDateTime localUTC = zonedNZ.withZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime(); System.out.println("UTC Local Time: "+localUTC.format(formatter)); 

SALIDA ES:

  NZ Local Time: 2011-10-06 03:35:05 UTC Local Time: 2011-10-05 14:35:05 

Joda-Time

Las clases de java.util.Date/Calendar son un desastre y deben evitarse.

Actualización: el proyecto Joda-Time está en modo de mantenimiento. El equipo aconseja la migración a las clases java.time.

Aquí está su respuesta usando la biblioteca Joda-Time 2.3. Muy fácil.

Como se indica en el código de ejemplo, le sugiero que use zonas horarias con nombre siempre que sea posible para que su progtwigción pueda manejar el horario de verano (DST) y otras anomalías.

Si hubiera colocado una T en el medio de la cadena en lugar de un espacio, podría omitir las dos primeras líneas de código, tratando con un formateador para analizar la cadena. El constructor de DateTime puede tomar una cadena en formato ISO 8601 .

 // © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so. // import org.joda.time.*; // import org.joda.time.format.*; // Parse string as a date-time in UTC (no time zone offset). DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat.forPattern( "yyyy-MM-dd' 'HH:mm:ss" ); DateTime dateTimeInUTC = formatter.withZoneUTC().parseDateTime( "2011-10-06 03:35:05" ); // Adjust for 13 hour offset from UTC/GMT. DateTimeZone offsetThirteen = DateTimeZone.forOffsetHours( 13 ); DateTime thirteenDateTime = dateTimeInUTC.toDateTime( offsetThirteen ); // Hard-coded offsets should be avoided. Better to use a desired time zone for handling Daylight Saving Time (DST) and other anomalies. // Time Zone list… http://joda-time.sourceforge.net/timezones.html DateTimeZone timeZoneTongatapu = DateTimeZone.forID( "Pacific/Tongatapu" ); DateTime tongatapuDateTime = dateTimeInUTC.toDateTime( timeZoneTongatapu ); 

Volcar esos valores …

 System.out.println( "dateTimeInUTC: " + dateTimeInUTC ); System.out.println( "thirteenDateTime: " + thirteenDateTime ); System.out.println( "tongatapuDateTime: " + tongatapuDateTime ); 

Cuando se ejecuta …

 dateTimeInUTC: 2011-10-06T03:35:05.000Z thirteenDateTime: 2011-10-06T16:35:05.000+13:00 tongatapuDateTime: 2011-10-06T16:35:05.000+13:00 

He intentado este código

 try{ SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss Z"); Date datetime = new Date(); System.out.println("date "+sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println("GMT "+ sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("GMT+13")); System.out.println("GMT+13 "+ sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); System.out.println("utc "+sdf.format(datetime)); Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT")); DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z"); formatter.setTimeZone(TimeZone.getTimeZone("GMT+13")); String newZealandTime = formatter.format(calendar.getTime()); System.out.println("using calendar "+newZealandTime); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } 

y obteniendo este resultado

 date 06-10-2011 10:40:05 +0530 GMT 06-10-2011 05:10:05 +0000 // here getting 5:10:05 GMT+13 06-10-2011 06:10:05 +1300 // here getting 6:10:05 utc 06-10-2011 05:10:05 +0000 using calendar 06 Oct 2011 18:10:05 GMT+13:00 

Podemos manejar esto usando el valor de compensación

  public static long convertDateTimeZone(long lngDate, String fromTimeZone, String toTimeZone){ TimeZone toTZ = TimeZone.getTimeZone(toTimeZone); Calendar toCal = Calendar.getInstance(toTZ); TimeZone fromTZ = TimeZone.getTimeZone(fromTimeZone); Calendar fromCal = Calendar.getInstance(fromTZ); fromCal.setTimeInMillis(lngDate); toCal.setTimeInMillis(fromCal.getTimeInMillis() + toTZ.getOffset(fromCal.getTimeInMillis()) - TimeZone.getDefault().getOffset(fromCal.getTimeInMillis())); return toCal.getTimeInMillis(); } 

Fragmento de código de prueba:

  System.out.println(new Date().getTime()) System.out.println(convertDateTimeZone(new Date().getTime(), TimeZone .getDefault().getID(), "EST")); 

Salida: 1387353270742 1387335270742

Podemos obtener la marca de tiempo UTC / GMT a partir de la fecha especificada.

 /** * Get the time stamp in GMT/UTC by passing the valid time (dd-MM-yyyy HH:mm:ss) */ public static long getGMTTimeStampFromDate(String datetime) { long timeStamp = 0; Date localTime = new Date(); String format = "dd-MM-yyyy HH:mm:ss"; SimpleDateFormat sdfLocalFormat = new SimpleDateFormat(format); sdfLocalFormat.setTimeZone(TimeZone.getDefault()); try { localTime = (Date) sdfLocalFormat.parse(datetime); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.getDefault()); TimeZone tz = cal.getTimeZone(); cal.setTime(localTime); timeStamp = (localTime.getTime()/1000); Log.d("GMT TimeStamp: ", " Date TimegmtTime: " + datetime + ", GMT TimeStamp : " + localTime.getTime()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return timeStamp; } 

Devolverá la hora UTC en función de la fecha aprobada.

  • Podemos hacer el retroceso como la marca de tiempo UTC a la fecha y hora actuales (viceversa)

      public static String getLocalTimeFromGMT(long gmtTimeStamp) { try{ Calendar calendar = Calendar.getInstance(); TimeZone tz = TimeZone.getDefault(); calendar.setTimeInMillis(gmtTimeStamp * 1000); // calendar.add(Calendar.MILLISECOND, tz.getOffset(calendar.getTimeInMillis())); SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); Date currenTimeZone = (Date) calendar.getTime(); return sdf.format(currenTimeZone); }catch (Exception e) { } return ""; } 

Espero que esto ayude a otros. ¡¡Gracias!!

Una forma rápida es:

 String dateText ="Thu, 02 Jul 2015 21:51:46"; long hours = -5; // time difference between places DateTimeFormatter formatter = DateTimeFormatter.ofPattern(E, dd MMM yyyy HH:mm:ss, Locale.ENGLISH); LocalDateTime date = LocalDateTime.parse(dateText, formatter); date = date.with(date.plusHours(hours)); System.out.println("NEW DATE: "+date); 

Salida

NUEVA FECHA: 2015-07-02T16: 51: 46

 public Timestamp convertLocalTimeToServerDatetime(String dt,String timezone){ String clientDnT = dt ;// "2017-06-01 07:20:00"; try{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse(clientDnT); TimeZone tz = TimeZone.getTimeZone(timezone.trim()); // get time zone of user sdf.setTimeZone(tz); // Convert to servertime zone SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); TimeZone tzInAmerica = TimeZone.getDefault(); sdf1.setTimeZone(tzInAmerica); // assign date to date String serverDate = sdf1.format(date); // Convert to servertime zone to Timestamp Date date2 = sdf.parse(serverDate); Timestamp tsm = new Timestamp(date2.getTime()); return tsm; } catch(Exception e){ System.err.println(e); } return null; } 

De alguna manera fácil. Una cosa importante para recordar es que Date no mantiene la zona horaria, su único número de long millis , como se trata aquí.

 /** * Converts source in GMT+0 to timezone specified by server * * @throws IllegalStateException if server timezone wasnt set */ public static Date convertGmt(Date source) { if (timeZoneServer == null) { throw new IllegalStateException("Server timezone wasnt set"); } long rawOffset = timeZoneServer.getRawOffset(); Date dest = new Date(source.getTime() + rawOffset); return dest; } /** * Converts source in device timezone format to GMT */ public static Date convertToGmt(Date source) { int rawOffset = TimeZone.getDefault().getRawOffset(); Date dest = new Date(source.getTime() - rawOffset); return dest; } 

TimezoneServer es algo así como TimeZone timeZoneServer = TimeZone.getTimeZone("GMT+1")

Su enfoque funciona sin ninguna modificación.

 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); // Timestamp for 2011-10-06 03:35:05 GMT calendar.setTime(new Date(1317872105000L)); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); formatter.setTimeZone(TimeZone.getTimeZone("GMT+13")); // Prints 2011-10-06 16:35:05 GMT+13:00 System.out.println(formatter.format(calendar.getTime()));