Si j'exécute le programme suivant, qui analyse deux chaînes de date faisant référence à des intervalles de 1 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);
}
La sortie est:
353
Pourquoi ld4-ld3
pas 1
(comme je m'attendais à la différence d'une seconde dans le temps), mais 353
?
Si je change les dates en fois 1 seconde plus tard:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Ce ld4-ld3
sera le cas 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
Réponses:
C'est un changement de fuseau horaire le 31 décembre à Shanghai.
Voir cette page pour les détails de 1927 à Shanghai. Fondamentalement, à minuit fin 1927, les horloges sont remontées 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'ait analysé comme l' instant le plus tard possible pour cette date / heure locale - d'où la différence.
Juste un autre épisode dans le monde souvent étrange et merveilleux des fuseaux horaires.
EDIT: Arrêtez d'appuyer! L'histoire change ...
La question d'origine ne démontrerait plus le même comportement si elle était reconstruite avec la version 2013a de TZDB . 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 collecte des questions comme celle-ci dans Noda Time, sous la forme de tests unitaires ... Le test a maintenant été modifié, mais cela ne fait que montrer - même les données historiques ne sont pas sûres.
EDIT: L' histoire a encore changé ...
Dans TZDB 2014f, l'heure du changement est passée au 1900-12-31, et il ne s'agit désormais que d'un changement de 343 secondes (donc le temps entre
t
ett+1
est de 344 secondes, si vous voyez ce que je veux dire).EDIT: Pour répondre à une question concernant une transition à 1900 ... il semble que l'implémentation du fuseau horaire Java traite tous les fuseaux horaires comme étant simplement à leur heure standard pour tout instant avant le début de 1900 UTC:
Le code ci-dessus ne produit aucune sortie sur ma machine Windows. Ainsi, tout fuseau horaire qui a un décalage autre que son standard au début de 1900 comptera cela comme une transition. TZDB lui-même a des données remontant plus tôt que cela, et ne s'appuie sur aucune idée d'un temps standard "fixe" (ce qui
getRawOffset
suppose être un concept valide), de sorte que les autres bibliothèques n'ont pas besoin d'introduire cette transition artificielle.la source
Vous avez rencontré une discontinuité d'heure locale :
Ce n'est pas particulièrement étrange et cela s'est produit à peu près partout à un moment ou à un autre, car les fuseaux horaires ont été changés ou modifiés en raison d'actions politiques ou administratives.
la source
La morale de cette étrangeté est:
la source
Lors de l'incrémentation du temps, vous devez reconvertir en UTC, puis ajouter ou soustraire. Utilisez l'heure locale uniquement pour l'affichage.
De cette façon, vous pourrez parcourir toutes les périodes où les heures ou les minutes se produisent deux fois.
Si vous avez converti en UTC, ajoutez chaque seconde et convertissez en heure locale pour l'affichage. Vous passeriez par 23 h 54 min 08 s LMT - 23 h 59 min 59 s LMT puis 23 h 54 min 08 s CST - 23 h 59 min 59 s CST.
la source
Au lieu de convertir chaque date, vous pouvez utiliser le code suivant:
Et puis voyez que le résultat est:
la source
1
, car nous avons différents paramètres régionaux.Je suis désolé de le dire, mais la discontinuité temporelle a un peu bougé
JDK 6 il y a deux ans, et dans JDK 7 tout récemment dans la mise à jour 25 .
Leçon à tirer: évitez à tout prix les heures non UTC, sauf peut-être pour l'affichage.
la source
Comme expliqué par d'autres, il y a là une discontinuité temporelle. Il existe deux décalages de fuseau horaire possibles pour
1927-12-31 23:54:08
àAsia/Shanghai
, mais un seul décalage pour1927-12-31 23:54:07
. Ainsi, selon le décalage utilisé, il y a soit une différence d'une seconde, soit une différence de 5 minutes et 53 secondes.Ce léger décalage des décalages, au lieu de l'heure d'été habituelle (heure d'été) à laquelle nous sommes habitués, obscurcit un peu le problème.
Notez que la mise à jour 2013a de la base de données de fuseau horaire a déplacé cette discontinuité quelques secondes plus tôt, mais l'effet serait toujours observable.
Le nouveau
java.time
package sur Java 8 permet de voir cela plus clairement et fournit des outils pour le gérer. Donné:Il y
durationAtEarlierOffset
aura ensuite une seconde, tandis quedurationAtLaterOffset
sera de cinq minutes et 53 secondes.De plus, ces deux décalages sont identiques:
Mais ces deux sont différents:
Vous pouvez voir le même problème par rapport
1927-12-31 23:59:59
à1928-01-01 00:00:00
, cependant, dans ce cas, c'est le décalage antérieur qui produit la divergence la plus longue, et c'est la date antérieure qui a deux décalages possibles.Une autre façon d'aborder cela est de vérifier s'il y a une transition en cours. Nous pouvons le faire comme ceci:
Vous pouvez vérifier si la transition est un chevauchement où il y a plus d'un décalage valide pour cette date / heure ou un écart où cette date / heure n'est pas valide pour cet identifiant de zone - en utilisant les méthodes
isOverlap()
et .isGap()
zot4
J'espère que cela aidera les gens à gérer ce type de problème une fois que Java 8 sera largement disponible, ou à ceux qui utilisent Java 7 qui adoptent le backport JSR 310.
la source
1900-12-31 23:54:16
et1900-12-31 23:54:17
, mais cela ne fonctionne pas sur le site que vous avez partagé, ils utilisent donc une version Java différente de la mienne.À mon humble avis, la localisation implicite omniprésente dans Java est sa plus grande faille de conception. Il peut être destiné aux interfaces utilisateur, mais franchement, qui utilise vraiment Java pour les interfaces utilisateur aujourd'hui, à l'exception de certains IDE où vous pouvez essentiellement ignorer la localisation car les programmeurs ne sont pas exactement le public cible pour cela. Vous pouvez le corriger (en particulier sur les serveurs Linux) en:
Aux membres du Java Community Process , je recommande:
Je veux dire, allez, les variables statiques globales ne sont-elles pas un modèle anti-OO? Rien d'autre n'est ces défauts omniprésents donnés par certaines variables d'environnement rudimentaires .......
la source
Comme d'autres l'ont dit, c'est un changement d'heure en 1927 à Shanghai.
Lorsqu'il était
23:54:07
à Shanghai, l'heure locale, mais après 5 minutes et 52 secondes, il est passé au lendemain à00:00:00
, puis l'heure locale a changé23:54:08
. C'est pourquoi la différence entre les deux temps est de 343 secondes et non d'une seconde, comme vous vous en doutez.Le temps peut également gâcher dans d'autres endroits comme les États-Unis. Les États-Unis ont l'heure d'été. Lorsque l'heure d'été commence, l'heure avance d'une heure. Mais après un certain temps, l'heure d'été se termine et revient en arrière d'une heure au fuseau horaire standard. Ainsi, parfois, lorsque l'on compare les heures aux États-Unis, la différence est d'environ
3600
secondes, pas 1 seconde.Mais il y a quelque chose de différent dans ces deux changements de temps. Ce dernier change continuellement et le premier n'était qu'un changement. Il n'a pas changé ou changé à nouveau du même montant.
Il est préférable d'utiliser UTC où l'heure ne change pas, sauf si nécessaire pour utiliser l'heure non UTC comme dans l'affichage.
la source