2011-05-14 20 views
9

Sé cómo convertir la hora local a hora UTC y viceversa. Pero estoy muy confundido acerca del manejo del horario de verano (DST) mientras hago esto.Convertir hora local a hora UTC o viceversa teniendo en cuenta el horario de verano

¿Alguien puede responder a las siguientes preguntas:
1. ¿Java maneja internamente el horario de verano al convertir entre zonas horarias?
2. ¿Qué cosas debo hacer al convertir zonas horarias?
3. ¿Algún artículo bueno que explique sobre esto más claramente?

Gracias de antemano.

+0

para convertir entre zonas horarias, es necesario especificar qué zona horaria que tiene y la zona horaria que desea convertir. La fecha usa UTC, por lo que el método getDate() será UTC. La zona horaria con horario de verano manejará el horario de verano. –

+0

Estoy usando el objeto Calendario. Además, mi pregunta es ¿tengo que manejar todo lo relacionado con el horario de verano mientras hago la conversión? – Newbie

Respuesta

15

¿Estás seguro de que sabes cómo convertir las fechas a UTC y viceversa? ¿Correctamente?
Tengo miedo, lo dudo.

  1. Sí.
  2. No necesita convertir, solo necesita asignar TimeZone correcto.
  3. ¿Para qué necesitas un artículo? OK, estoy trabajando en esto, pero por ahora déjame poner una respuesta aquí.

Lo primero es lo primero. Su programa debe almacenar la Fecha (o el Calendario) en UTC TimeZone internamente. Bueno, de hecho en GMT, porque no hay segundos intercalares en Java, pero esa es otra historia.
El único lugar donde debe necesitar "conversión" es cuando va a mostrar la hora para el usuario. Eso se refiere al envío de mensajes de correo electrónico también. En ambos casos, necesita formato para obtener su representación textual. Para que utilizaría DateFormat y asignar zona horaria correcta:

// that's for desktop application 
    // for web application one needs to detect Locale 
    Locale locale = Locale.getDefault(); 
    // again, this one works for desktop application 
    // for web application it is more complicated 
    TimeZone currentTimeZone = TimeZone.getDefault(); 
    // in fact I could skip this line and get just DateTime instance, 
    // but I wanted to show how to do that correctly for 
    // any time zone and locale 
    DateFormat formatter = DateFormat.getDateTimeInstance(
      DateFormat.DEFAULT, 
      DateFormat.DEFAULT, 
      locale); 
    formatter.setTimeZone(currentTimeZone); 

    // Dates "conversion" 
    Date currentDate = new Date(); 
    long sixMonths = 180L * 24 * 3600 * 1000; 
    Date inSixMonths = new Date(currentDate.getTime() + sixMonths); 

    System.out.println(formatter.format(currentDate)); 
    System.out.println(formatter.format(inSixMonths)); 
    // for me it prints 
    // 2011-05-14 16:11:29 
    // 2011-11-10 15:11:29 

    // now for "UTC" 
    formatter.setTimeZone(TimeZone.getTimeZone("UTC")); 
    System.out.println(formatter.format(currentDate)); 
    System.out.println(formatter.format(inSixMonths)); 
    // 2011-05-14 14:13:50 
    // 2011-11-10 14:13:50 

Como se puede ver, Java se preocupa por el manejo de DST. Por supuesto, puede manejarlo manualmente, solo lea TimeZone related JavaDoc.

+0

"En seis meses" debería ser "en alrededor de seis meses", pero en realidad no importa. La parte de la hora es lo que importa. –

7

Aquí está la mejor solución que he encontrado. Lo estoy copiando aquí, pero la solución vino del http://biese.wordpress.com/2014/02/28/the-easy-way-to-convert-local-time-to-utc-time/.

package com.test.timezone; 

import java.util.TimeZone; 

public final class Utility { 
    public static final TimeZone utcTZ = TimeZone.getTimeZone("UTC"); 

    public static long toLocalTime(long time, TimeZone to) { 
     return convertTime(time, utcTZ, to); 
    } 

    public static long toUTC(long time, TimeZone from) { 
     return convertTime(time, from, utcTZ); 
    } 

    public static long convertTime(long time, TimeZone from, TimeZone to) { 
     return time + getTimeZoneOffset(time, from, to); 
    } 

    private static long getTimeZoneOffset(long time, TimeZone from, TimeZone to) { 
     int fromOffset = from.getOffset(time); 
     int toOffset = to.getOffset(time); 
     int diff = 0; 

     if (fromOffset >= 0){ 
      if (toOffset > 0){ 
       toOffset = -1*toOffset; 
      } else { 
       toOffset = Math.abs(toOffset); 
      } 
      diff = (fromOffset+toOffset)*-1; 
     } else { 
      if (toOffset <= 0){ 
       toOffset = -1*Math.abs(toOffset); 
      } 
      diff = (Math.abs(fromOffset)+toOffset); 
     } 
     return diff; 
    } 
} 

package com.test.timezone; 

import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.GregorianCalendar; 
import java.util.TimeZone; 

public class TestTimezone { 

    public static void main(String[] args) { 
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd HH:mm:ss zzzz"); 
     Calendar date1 = new GregorianCalendar(2014,0,15,10,0,0); 
     System.out.println(sdf.format(date1.getTime())+"\n"); 
     long utcTimeStamp = Utility.toUTC(date1.getTimeInMillis(), date1.getTimeZone()); 
     Calendar utcCal = Calendar.getInstance(); 
     utcCal.setTimeInMillis(utcTimeStamp); 
     System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date2 = new GregorianCalendar(2014,2,15,10,0,0); 
     System.out.println(sdf.format(date2.getTime())+"\n"); 
     utcTimeStamp = Utility.toUTC(date2.getTimeInMillis(), date2.getTimeZone()); 
     utcCal.setTimeInMillis(utcTimeStamp); 
     System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date3 = new GregorianCalendar(2014,11,25,9,0,0); 
     System.out.println(sdf.format(date3.getTime())+"\n"); 
     long uTime = Utility.toUTC(date3.getTimeInMillis(), date3.getTimeZone()); 
     System.out.println("utcTimeStamp: "+uTime+"\n"); 
     long lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST")); 
     Calendar locCal = Calendar.getInstance(); 
     locCal.setTimeInMillis(lTime); 
     System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date4 = new GregorianCalendar(2014,6,4,9,0,0); 
     System.out.println(sdf.format(date4.getTime())+"\n"); 
     uTime = Utility.toUTC(date4.getTimeInMillis(), date4.getTimeZone()); 
     System.out.println("utcTimeStamp: "+uTime+"\n"); 
     lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST")); 
     locCal = Calendar.getInstance(); 
     locCal.setTimeInMillis(lTime); 
     System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n"); 
    } 
} 
+0

Esta es una mala práctica ya que está convirtiendo la base de tiempos (Unix Epoch) que conduce al tiempo de almacenamiento en un asunto localizado. La fecha realmente maneja estas "conversiones" de hecho representaciones para usted. Si usa el método que describe y usa la hora como una fecha como en = nueva Fecha (hora), el objeto Fecha supone que la hora es GMT y el objeto se instancia erróneamente. El único uso válido de estas funciones es convertir el tiempo desde y hacia sistemas externos que no operan en las marcas de tiempo GMT y, por lo tanto, no cumplen con la convención de marcas de tiempo de UNIX. –

4

El código de respuesta de Tale puede simplificarse:

public final class Utility { 
    public static long toLocalTime(long time, TimeZone to) { 
     return time + to.getOffset(time); 
    } 

    public static long toUTC(long time, TimeZone from) { 
     return time - from.getOffset(time); 
    } 
} 
Cuestiones relacionadas