2010-04-09 46 views
15

Tengo una marca de tiempo de milisegundos-local-época que me gustaría convertir en una marca de tiempo milisegundos-desde-UTC-época. De un vistazo rápido a través de los documentos que se parece a algo como esto funcionaría:Convirtiendo la marca de tiempo local a la marca de tiempo UTC en Java

int offset = TimeZone.getDefault().getRawOffset(); 
long newTime = oldTime - offset; 

¿Hay una mejor manera de hacer esto?

Respuesta

6

Utilice Calendar para ver cuál era el desplazamiento en la Epoca local, luego agréguelo a la marca de tiempo de la época local.

public static long getLocalToUtcDelta() { 
    Calendar local = Calendar.getInstance(); 
    local.clear(); 
    local.set(1970, Calendar.JANUARY, 1, 0, 0, 0); 
    return local.getTimeInMillis(); 
} 

public static long converLocalTimeToUtcTime(long timeSinceLocalEpoch) { 
    return timeSinceLocalEpoch + getLocalToUtcDelta(); 
} 
+2

Esto no cuenta para DST en absoluto. –

+0

@Quartz - no tiene porque, ya que estamos lidiando con deltas de la Época. ¿Tiene un ejemplo (zone and timeSinceLocalEpoch) donde esto falla? – leedm777

2

No, eso definitivamente no funcionará, no tiene en cuenta el horario de verano. No se puede simplemente usar getOffset(oldTime) o bien, como el horario de verano puede haber cambiado entre los dos ...

Usted podría utilizar getOffset(oldTime) para obtener una estimación inicial de la marca de tiempo, a continuación, comprobar getOffset(utcTime) para ver si son los mismos o no. Se pone divertido, básicamente.

Joda Time debería apoyar esta usando DateTimeZone.getOffsetFromLocal pero eso es slightly broken (OMI) en torno a las transiciones de horario de verano.

Todo esto realmente depende de lo que quiere decir con "milisegundos desde época local". Si realmente significa milisegundos transcurridos desde 1970 local, puede averiguar el desplazamiento en esa fecha y aplicarlo independientemente. Típicamente (IME), un valor de millis "local" no significa exactamente eso, significa "el número de milis para llegar a una fecha y hora en particular (por ejemplo, 9 de abril de 2010, 18:06 p.m.) en UTC, pero con respecto a una zona horaria diferente ". En otras palabras, puede representar combinaciones de fecha/hora ambiguas o imposibles basadas en las transiciones DST.

+0

Pero creo que se podría usar 'getOffset (0L)' Lo único que importa es la diferencia horaria en ese momento, al comienzo de la época, y espero que esa transición DST no haya ocurrido el 1 de enero. –

9

Lamentablemente, esto parece ser la mejor manera de hacer esto:

public static Date convertLocalTimestamp(long millis) 
{ 
    TimeZone tz = TimeZone.getDefault(); 
    Calendar c = Calendar.getInstance(tz); 
    long localMillis = millis; 
    int offset, time; 

    c.set(1970, Calendar.JANUARY, 1, 0, 0, 0); 

    // Add milliseconds 
    while (localMillis > Integer.MAX_VALUE) 
    { 
     c.add(Calendar.MILLISECOND, Integer.MAX_VALUE); 
     localMillis -= Integer.MAX_VALUE; 
    } 
    c.add(Calendar.MILLISECOND, (int)localMillis); 

    // Stupidly, the Calendar will give us the wrong result if we use getTime() directly. 
    // Instead, we calculate the offset and do the math ourselves. 
    time = c.get(Calendar.MILLISECOND); 
    time += c.get(Calendar.SECOND) * 1000; 
    time += c.get(Calendar.MINUTE) * 60 * 1000; 
    time += c.get(Calendar.HOUR_OF_DAY) * 60 * 60 * 1000; 
    offset = tz.getOffset(c.get(Calendar.ERA), c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.DAY_OF_WEEK), time); 

    return new Date(millis - offset); 
} 

(sé que esto es de varios meses fecha pasada, pero es un problema que es muy útil para resolver cuando trabajando con los mensajes de texto en Android respuesta de Dave es incorrecta)

3

Usando Joda Time sería así:..

DateTime dt = new DateTime(year, month, day, hour, minute, 0, 0, DateTimeZone.forID("local"); 

dt.getMillis(); 

Editado: Lo sentimos, esta es la versión correcta:

DateTime dt = new DateTime(timestamp, DateTimeZone.forID("local"); 

dt.getMillis(); 
3

En realidad, Chris Lercher dio en el clavo en la cabeza, pero él sólo lo hizo en un breve comentario, así que quería expandir en él.

Imagine dos cronómetros; uno está en algún lugar donde UTC es la hora local el 1 de enero de 1970, y el otro cronómetro es local para su área (digamos que está en Nueva York, 5 horas después de UTC). En UTC medianoche, el 1 de enero de 1970, se inicia el cronómetro UTC. 5 horas después, se inicia su cronómetro local. Esos dos tiempos de cronómetro difieren en cierta cantidad, determinado solo por cuál fue la diferencia entre UTC de su hora local en medianoche local el 1 de enero de 1970. Cualquier travesura que ahorre luz del día, desde entonces, no tiene relación con la diferencia entre esos cronómetros. Por lo tanto, cualquier corrección DST para su presente tiempo o para las veces que está convirtiendo, son irrelevantes.Todo lo que necesita es cuánto más tarde comenzó su cronómetro local el 1 de enero de 1970.

Como Chris señaló, esto es sólo: getOffset (0L), por lo que:

int offset = TimeZone.getDefault().getOffset(0L); 
long newTime = oldTime - offset; 

... debería funcionar bien. Sin embargo ....

Para ayudar realmente a comprender esto, tenga en cuenta lo siguiente: que "0L" en getOffset() son los milisegundos desde el tiempo UTC (que es la única verdadera época). Por lo tanto, su variable de compensación tendrá el número de segundos de compensación a la medianoche UTC (es decir, cuando fue, por ejemplo, 19:00 el 31/12/1969 en Nueva York). Si su hora local cambia a/de horario de verano en las últimas horas antes de local medianoche, getOffset (0L) no sería correcto. Debe saber cuál fue su estado de ahorro de luz diurna al local medianoche, no la medianoche de UTC.

Me sorprendería que este fuera el caso, en cualquier lugar (es decir, cualquier zona horaria que cambiara a/desde el horario de verano entre su medianoche local y la medianoche UTC del 1 de enero de 1970). Sin embargo, sólo por diversión, un truco barato para ayudar a protegerse contra esto sería para comprobar si el desplazamiento cambiado en esas horas:

// Offset at UTC midnight 
int offset = TimeZone.getDefault().getOffset(0L); 
long newTime = oldTime - offset; 
// Offset at Local midnight 
int localMidnightOffset = TimeZone.getDefault().getOffset(-offset); 

Aquí, localMidnightOffset será lo que el desplazamiento de zona horaria era a la vez -offset milisegundos después UTC medianoche en 1970. Si no se produjo ningún cambio en el horario de verano, entonces localMidnightOffset igualará el desplazamiento y listo. Si algún cambio DST hizo produce, entonces es posible que tenga que buscar alrededor ... probablemente lo siga haciendo un

localMidnightOffset = TimeZone.getDefault().getOffset(-localMidnightOffset) 

hasta que se detenga el cambio ... y espero que no queden atrapados en un bucle sin fin. Tengo curiosidad por ver si alguien tiene una solución convergente garantizada.

Un poco te hace desear que el mundo fuera plano, ¿eh?

+0

mejor respuesta que he visto en SO por un tiempo – paz

0
static final long localTimeZoneoffset = TimeZone.getDefault().getOffset(0L); 
static final long dstOffset = TimeZone.getDefault().getDSTSavings(); 

long offsetOftime = TimeZone.getDefault().getOffset(time.getTime()); 
long timeinmilli = 0L; 
if(offsetOftime != localTimeZoneoffset) 
    timeinmilli = time.getTime()+localTimeZoneoffset+dstOffset; 
else 
    timeinmilli = time.getTime()+localTimeZoneoffset; 
return new Timestamp(timeinmilli); 

Esto me funcionó para convertir a UTC.

0

Puede ser que esto te ayude a intentarlo de esta manera. Coménteme si hay alguna forma mejor y optimice para convertir la hora local a la marca de tiempo UTC.

String mDate= "Jul 21,2016 1:23 PM"; 
String mDateFormat =""MMM d,yyyy h:mm a"; 

Llamar:getConvertedTimeToUTC(mDate,mDateFormat);

 public String getConvertedTimeToUTC(String ourDate, String mDateFormat) { 
      try { 
       SimpleDateFormat fmt = new SimpleDateFormat(mDateFormat); 
       fmt.setTimeZone(TimeZone.getTimeZone("UTC")); 
       Date value = fmt.parse(ourDate); 
       if (value != null) 
        return String.valueOf(value.getTime()/1000); 
       else 
        return null; 
      } catch (Exception e) { 
       ourDate = "00-00-0000 00:00"; 
      } 
      return ourDate; 
     } 

aquí está el resultado: (Ref : check conversion)

Result 1469107380 
GMT: Thu, 21 Jul 2016 13:23:00 GMT 
Your time zone: Thursday 21 July 2016 06:53:00 PM IST GMT+5:30 
Cuestiones relacionadas