7365 votes

Pourquoi la soustraction de ces deux temps (en 1927) donne-t-elle un résultat étrange ?

Si j'exécute le programme suivant, qui analyse deux chaînes de dates faisant référence à des moments séparés d'une seconde et les compare :

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    String str3 = "1927-12-31 23:54:07";  
    String str4 = "1927-12-31 23:54:08";  
    Date sDt3 = sf.parse(str3);  
    Date sDt4 = sf.parse(str4);  
    long ld3 = sDt3.getTime() /1000;  
    long ld4 = sDt4.getTime() /1000;
    System.out.println(ld4-ld3);
}

Le résultat est le suivant :

353

Pourquoi la ld4-ld3 no 1 (comme je m'y attendais compte tenu de la différence d'une seconde entre les temps), mais 353 ?

Si je change les dates en heures 1 seconde plus tard :

String str3 = "1927-12-31 23:54:08";  
String str4 = "1927-12-31 23:54:09";  

Dans ce cas ld4-ld3 sera 1 .


Version Java :

java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)

Timezone(`TimeZone.getDefault()`):

sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]

Locale(Locale.getDefault()): zh_CN

28 votes

Il peut s'agir d'un problème local.

112 votes

La vraie réponse est de toujours, toujours utiliser les secondes depuis l'époque pour l'enregistrement, comme l'époque Unix, avec une représentation entière de 64 bits (signée, si vous voulez autoriser les tampons avant l'époque). Tout système de temps réel a un comportement non linéaire et non monotone, comme les heures bissextiles ou l'heure d'été.

15 votes

Une excellente vidéo sur ce genre de choses : youtube.com/watch?v=-5wpm-gesOY

11628voto

Jon Skeet Points 692016

Il y a un changement de fuseau horaire le 31 décembre à Shanghai.

Voir cette page pour plus de détails sur l'année 1927 à Shanghai. En fait, à minuit, à la fin de l'année 1927, les horloges ont reculé de 5 minutes et 52 secondes. Donc "1927-12-31 23:54:08" s'est en fait produit deux fois, et il semble que Java l'interprète comme la balise plus tard instant possible pour cette date/heure locale - d'où la différence.

Un épisode de plus dans le monde souvent étrange et merveilleux des fuseaux horaires.

Si elle est reconstruite avec la version 2013a de TZDB La question initiale n'aurait plus tout à fait le même comportement. En 2013a, le résultat serait de 358 secondes, avec un temps de transition de 23:54:03 au lieu de 23:54:08.

Je ne l'ai remarqué que parce que je recueille des questions de ce type dans Noda Time, sous la forme de tests unitaires ... Le test a été modifié, mais cela montre bien que même les données historiques ne sont pas sûres.

Dans TZDB 2014f l'heure du changement a été déplacée à 1900-12-31, et il ne s'agit plus que d'un changement de 343 secondes (donc le temps entre le t y t+1 est de 344 secondes, si vous voyez ce que je veux dire).


Pour répondre à une question concernant une transition à 1900... il semble que l'implémentation du fuseau horaire de Java traite todos Les fuseaux horaires sont considérés comme étant simplement dans leur heure standard pour tout instant avant le début de 1900 UTC :

import java.util.TimeZone;

public class Test {
    public static void main(String[] args) throws Exception {
        long startOf1900Utc = -2208988800000L;
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
                System.out.println(id);
            }
        }
    }
}

Le code ci-dessus ne produit aucun résultat sur ma machine Windows. Ainsi, tout fuseau horaire ayant un décalage autre que son décalage standard au début de l'année 1900 sera considéré comme une transition. La base de données TZDB elle-même contient des données antérieures à cette date et ne repose pas sur l'idée d'une heure standard "fixe" (ce qui est le cas de la base de données TZDB). getRawOffset (ce qui semble être un concept valide), de sorte que les autres bibliothèques n'ont pas besoin d'introduire cette transition artificielle.

1711voto

Michael Borgwardt Points 181658

Vous avez rencontré un discontinuité du temps local :

Lorsque l'heure locale s'apprêtait à passer au dimanche 1er janvier 1928, les horloges ont été mises à l'heure de 00:00:00, 00:00:00, les horloges ont été reculées de 0:05:52 heures jusqu'au samedi 31. décembre 1927, 23:54:08 heure locale au lieu de

Cette situation n'est pas particulièrement étrange et s'est produite un peu partout à un moment ou à un autre, lorsque les fuseaux horaires ont été modifiés ou changés à la suite d'actions politiques ou administratives.

6 votes

Cela se produit deux fois par an dans tous les pays qui observent l'heure d'été.

0 votes

Celui-ci n'est pas DST, je pense. Il n'y a que 10 minutes de recul, et une seule fois. En même temps, les changements liés à l'heure d'été peuvent se produire deux fois par an... ou 4 fois par an (à cause du Ramadan). ou même une fois par an dans certaines configurations. Il n'y a pas de règle en la matière :)

732voto

Raedwald Points 8862

La morale de cette étrangeté est la suivante :

  • Utilisez les dates et heures en UTC dans la mesure du possible.
  • Si vous ne pouvez pas afficher une date ou une heure en UTC, indiquez toujours le fuseau horaire.
  • Si vous ne pouvez pas exiger une date/heure d'entrée en UTC, exigez un fuseau horaire explicitement indiqué.

6 votes

Aucun de ces points n'affecterait ce résultat - il relève directement du troisième point - et, de plus, il s'agit d'une période antérieure de plusieurs décennies à la définition de l'UTC, qui ne peut donc pas être exprimée de manière significative en UTC.

4 votes

Bien que votre commentaire soit techniquement correct (le meilleur type de correction !), le temps moyen de Greenwich existe depuis bien longtemps avant l'invention de l'acronyme UTC.

403voto

PatrickO Points 1341

Lorsque vous augmentez le temps, vous devez le convertir en UTC, puis l'ajouter ou le soustraire. N'utilisez l'heure locale que pour l'affichage.

Vous pourrez ainsi traverser les périodes où les heures ou les minutes se répètent deux fois.

Si vous avez converti en UTC, ajoutez chaque seconde et convertissez en heure locale pour l'affichage. Vous passeriez ainsi à 11:54:08 p.m. LMT - 11:59:59 p.m. LMT et ensuite 11:54:08 p.m. CST - 11:59:59 p.m. CST.

207voto

Jacob Points 17521

J'ai exécuté votre code, le résultat est le suivant :

-1325466353
-1325466352
1

Et.. :

-1325466352
-1325466351
1

sur :

$ java -version
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.7) (fedora-52.1.9.7.fc14-i386)
OpenJDK Client VM (build 19.0-b09, mixed mode)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X