2010-04-09 7 views
15

J'ai un horodatage de millisecondes-depuis-date-heure que je voudrais convertir en horodatage de millisecondes-depuis-UTC-epoch. D'un rapide coup d'œil à travers les documents, il ressemble à quelque chose comme ça fonctionnerait:Conversion de l'horodatage local en horodatage UTC en Java

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

Y at-il une meilleure façon de le faire?

Répondre

6

Utilisez un Calendar pour connaître le décalage de l'heure locale, puis ajoutez-le à l'horodatage de l'heure locale.

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

Cela ne tient pas compte du DST du tout. –

+0

@Quartz - ça n'a pas à le faire, puisque nous avons affaire à des deltas de l'époque. Avez-vous un exemple (zone et timeSinceLocalEpoch) où cela échoue? – leedm777

2

Non, cela ne fonctionnera certainement pas - il ne tient pas compte de l'heure d'été. Vous ne pouvez pas simplement utiliser getOffset(oldTime) non plus, comme la DST peut avoir changé entre les deux ...

Vous pouvez utiliser getOffset(oldTime) pour obtenir une estimation initiale à l'horodatage, puis vérifiez getOffset(utcTime) pour voir si elles sont les mêmes ou ne pas. Cela devient amusant, fondamentalement.

Joda Timedevrait soutenir cela en utilisant DateTimeZone.getOffsetFromLocal mais c'est slightly broken (OMI) autour des transitions DST.

Tout cela dépend vraiment de ce que vous entendez par "millisecondes depuis l'époque locale". Si vous vraiment signifie écoulé millisecondes depuis 1970 local, vous pouvez simplement trouver le décalage à cette date, et l'appliquer malgré tout. Typiquement (IME) une valeur "locale" de millis ne signifie pas tout à fait cela - cela signifie "le nombre de millis pour arriver à une date et une heure particulières (par exemple le 9 avril 2010, 18h06) en UTC, mais en ce qui concerne un fuseau horaire différent ". En d'autres termes, il peut représenter des combinaisons date/heure ambiguës ou impossibles basées sur des transitions DST.

+0

Mais je pense que vous pouvez utiliser 'getOffset (0L)' Tout ce qui importe est la différence de temps à l'époque, au début de l'époque - et j'espère que la transition de l'heure d'été n'a pas eu lieu le 1er janvier. –

9

Malheureusement, cela semble être la meilleure façon de le faire:

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

(Je sais que cela est plusieurs mois date de publication passé, mais il est un problème qui est très utile pour résoudre lorsque travaille avec des messages texte sur Android réponse de dave est erroné)

3

Utilisation de l'heure Joda ce serait comme ceci:..

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

dt.getMillis(); 

ÉDITÉE: Désolé, c'est la version correcte:

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

dt.getMillis(); 
3

En fait, Chris Lercher mettre le doigt dessus, mais il ne fait dans un bref commentaire, donc je voulais développer sur elle.

Imaginez deux chronomètres; l'un est quelque part où UTC est l'heure locale le 1er janvier 1970, et l'autre chronomètre est local dans votre région (disons que c'est à New York, 5 heures après l'UTC). À UTC minuit, le 1er janvier 1970, le chronomètre UTC est démarré. 5 heures plus tard, votre chronomètre local est démarré. Ces deux temps de chronométrage diffèrent d'un certain montant, déterminé uniquement par la différence entre l'heure UTC et l'heure locale à locale minuit le 1er janvier 1970. Toutes les manigances de l'heure d'été, depuis lors, n'ont aucune incidence sur la différence entre ces chronomètres. Donc, toutes les corrections DST pour votre présent fois ou pour les fois où vous êtes convertir, sont hors de propos.Tout ce dont vous avez besoin est de savoir combien de temps plus tard votre chronomètre local a commencé le 1er janvier 1970.

Comme Chris l'a souligné, cela est juste: getOffset (0L), donc:

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

... devrait fonctionner correctement. Cependant ....

Pour vraiment aider saisir cela, notez ceci: « 0L » dans getOffset() est le nombre de millisecondes depuis l'époque UTC (qui est la seule époque réelle). Donc, votre variable offset va avoir le nombre de secondes de décalage à minuit UTC (c'est-à-dire, quand il était, disons, 19:00 le 31/12/1969 à New York). Si votre heure locale est passée de/à l'heure d'été dans ces dernières heures avant local minuit, alors getOffset (0L) ne serait pas correct. Vous devez savoir quel était votre statut en matière d'heure d'été au local à minuit, pas à minuit UTC. Je serais surpris si c'était le cas, n'importe où (c.-à-d., N'importe quel fuseau horaire qui a changé de/à DST entre leur minuit local et UTC minuit du 1er janvier 1970). Cependant, juste pour le plaisir, un hack pas cher pour aider à se prémunir contre ce serait de vérifier si le décalage changé dans les heures:

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

Ici, localMidnightOffset sera ce que le décalage horaire était à un moment -offset millisecondes après UTC minuit en 1970. Si aucun changement d'heure d'été n'a eu lieu, alors localMidnightOffset sera égal à l'offset, et vous avez terminé. Si un changement DST a se produit, alors vous pourriez avoir à chasser autour ... probablement continuer à faire un

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

jusqu'à ce qu'il cesse de changer ... et espérons que vous ne soyez pas pris dans une boucle sans fin. Je suis curieux de voir si quelqu'un a une solution convergente garantie. Kinda vous fait souhaiter que le monde soit plat, hein?

+0

meilleure réponse que j'ai vu sur SO pendant un certain temps – 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); 

Cela a fonctionné pour moi de convertir en UTC.

0

Peut être que cela peut vous aider j'ai essayé de cette façon. S'il vous plaît commentez-moi s'il y a une meilleure et optimiser la façon de convertir l'heure locale en horodatage UTC.

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

Appel: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; 
     } 

Voici le résultat: (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 
Questions connexes