Jeśli uruchomię następujący program, który analizuje dwa ciągi dat odnoszące się do odstępów co 1 sekundę i porównuje je:
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);
}
Dane wyjściowe to:
353
Dlaczego ld4-ld3
nie jest 1
(jak bym się spodziewał po jednosekundowej różnicy czasów), ale 353
?
Jeśli zmienię daty na czasy 1 sekundę później:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Wtedy ld4-ld3
będzie 1
.
Wersja 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
Odpowiedzi:
To zmiana strefy czasowej 31 grudnia w Szanghaju.
Zobacz tę stronę, aby poznać szczegóły 1927 roku w Szanghaju. Zasadniczo o północy pod koniec 1927 r. Zegary cofnęły się o 5 minut i 52 sekund. Tak więc „1927-12-31 23:54:08” faktycznie wydarzyło się dwa razy i wygląda na to, że Java analizuje go jako późniejszy możliwy moment dla tej lokalnej daty / godziny - stąd różnica.
Kolejny odcinek w często dziwnym i cudownym świecie stref czasowych.
EDYCJA: Przestań naciskać! Historia się zmienia ...
Pierwotne pytanie nie wykazywałoby już takiego samego zachowania, gdyby zostało przebudowane z wersją TZDB 2013a . W 2013a wynik wynosiłby 358 sekund, a czas przejścia to 23:54:03 zamiast 23:54:08.
Zauważyłem to tylko dlatego, że zbieram takie pytania w Czasie Nody, w formie testów jednostkowych ... Test został teraz zmieniony, ale po prostu pokazuje - nawet dane historyczne nie są bezpieczne.
EDYCJA: Historia znów się zmieniła ...
W TZDB 2014f czas zmiany przesunął się do 1900-12-31, a teraz jest to zaledwie 343 sekundowa zmiana (więc czas pomiędzy
t
it+1
wynosi 344 sekundy, jeśli rozumiesz, co mam na myśli).EDYCJA: Aby odpowiedzieć na pytanie związane z przejściem o 1900 ... wygląda na to, że implementacja strefy czasowej Java traktuje wszystkie strefy czasowe po prostu w swoim standardowym czasie dla dowolnej chwili przed rozpoczęciem 1900 UTC:
Powyższy kod nie generuje danych wyjściowych na moim komputerze z systemem Windows. Tak więc każda strefa czasowa, która ma dowolne przesunięcie inne niż standardowe na początku 1900 r., Będzie to traktować jako przejście. Sam TZDB ma pewne wcześniejsze dane i nie opiera się na żadnej idei „ustalonego” standardowego czasu (który
getRawOffset
zakłada, że jest to poprawna koncepcja), więc inne biblioteki nie muszą wprowadzać tego sztucznego przejścia.źródło
Wystąpiła nieciągłość czasu lokalnego :
Nie jest to szczególnie dziwne i zdarzyło się prawie wszędzie w tym samym czasie, ponieważ strefy czasowe zostały zmienione lub zmienione z powodu działań politycznych lub administracyjnych.
źródło
Morał tej dziwności jest następujący:
źródło
Przy zwiększaniu czasu powróć do UTC, a następnie dodaj lub odejmij. Użyj czasu lokalnego tylko do wyświetlenia.
W ten sposób będziesz mógł przejść przez wszystkie okresy, w których godziny lub minuty występują dwa razy.
Jeśli dokonałeś konwersji na UTC, dodaj każdą sekundę i przekonwertuj na czas lokalny do wyświetlenia. Przechodziłbyś przez 11:54:08 pm LMT - 11:59:59 pm LMT, a następnie 23:54:08 CST - 23:59:59 CST.
źródło
Zamiast konwertować każdą datę, możesz użyć następującego kodu:
A potem przekonaj się, że wynikiem jest:
źródło
1
, ponieważ mamy różne lokalizacje.Przykro mi to mówić, ale nieciągłość czasu trochę się zmieniła
JDK 6 dwa lata temu, aw JDK 7 niedawno w aktualizacji 25 .
Lekcja do nauczenia się: za wszelką cenę unikaj czasów poza UTC, z wyjątkiem może wyświetlania.
źródło
Jak wyjaśniają inni, istnieje nieciągłość czasowa. Istnieją dwa możliwe przesunięcia strefy czasowej dla
1927-12-31 23:54:08
oAsia/Shanghai
, ale tylko jedno przesunięcie dla1927-12-31 23:54:07
. Tak więc, w zależności od zastosowanego przesunięcia, występuje różnica jednej sekundy lub różnica 5 minut i 53 sekund.Ta niewielka zmiana przesunięć, zamiast zwykłej jednogodzinnej oszczędności światła dziennego (czasu letniego), do której jesteśmy przyzwyczajeni, nieco zaciemnia problem.
Należy zauważyć, że aktualizacja bazy danych strefy czasowej 2013a przesunęła tę nieciągłość kilka sekund wcześniej, ale efekt byłby nadal widoczny.
Nowy
java.time
pakiet w Javie 8 pozwala lepiej to zobaczyć i zapewnia narzędzia do obsługi. Dany:Następnie
durationAtEarlierOffset
będzie jedną sekundę, natomiastdurationAtLaterOffset
będzie pięć minut i 53 sekund.Te dwa przesunięcia są takie same:
Ale te dwa są różne:
Możesz zobaczyć ten sam problem w porównaniu
1927-12-31 23:59:59
z tym1928-01-01 00:00:00
, jednak w tym przypadku to wcześniejsze przesunięcie powoduje dłuższe rozbieżności i wcześniejsza data ma dwa możliwe przesunięcia.Innym sposobem podejścia do tego jest sprawdzenie, czy zachodzi przejście. Możemy to zrobić w następujący sposób:
Możesz sprawdzić, czy przejście jest pokrywające się, gdy istnieje więcej niż jedno prawidłowe przesunięcie dla tej daty / godziny, czy przerwa, w której ta data / czas nie jest ważna dla tego identyfikatora strefy - przy użyciu metod
isOverlap()
i .isGap()
zot4
Mam nadzieję, że pomoże to ludziom poradzić sobie z tego rodzaju problemami, gdy Java 8 stanie się powszechnie dostępna, lub osobom używającym Java 7, które przyjmą backport JSR 310.
źródło
1900-12-31 23:54:16
a1900-12-31 23:54:17
, ale to nie działa na stronie masz wspólnego, więc są one przy użyciu innej wersji Java niż I.IMHO wszechobecna, domyślna lokalizacja w Javie jest jej największą pojedynczą wadą projektową. Może być przeznaczony dla interfejsów użytkownika, ale szczerze mówiąc, kto tak naprawdę używa Java dla interfejsów użytkownika, z wyjątkiem niektórych IDE, w których można w zasadzie zignorować lokalizację, ponieważ programiści nie są dokładnie docelowymi odbiorcami. Możesz to naprawić (szczególnie na serwerach Linux):
Do Java Community Process członków Polecam:
Chodzi mi o to, czy globalne zmienne statyczne nie są wzorcem anty-OO? Nic więcej nie jest wszechobecnymi wartościami domyślnymi podanymi przez niektóre podstawowe zmienne środowiskowe .......
źródło
Jak powiedzieli inni, to zmiana czasu w 1927 r. W Szanghaju.
Kiedy był
23:54:07
w Szanghaju, czas lokalny standardowy, ale po 5 minutach i 52 sekundach zmienił się na następny dzień o godzinie00:00:00
, a potem czas lokalny standardowy zmienił się z powrotem na23:54:08
. Dlatego różnica między tymi dwoma czasami wynosi 343 sekundy, a nie 1 sekundę, jak można się spodziewać.Czas może również popsuć się w innych miejscach, takich jak USA. USA mają czas letni. Kiedy zaczyna się czas letni, czas przesuwa się o 1 godzinę do przodu. Ale po pewnym czasie kończy się czas letni i wraca o 1 godzinę wstecz do standardowej strefy czasowej. Czasami więc przy porównywaniu czasów w USA różnica wynosi około
3600
sekund, a nie 1 sekundy.Ale w tych dwóch zmianach czasu jest coś innego. Ten drugi zmienia się ciągle, a ten pierwszy był tylko zmianą. Nie zmieniło się ani nie zmieniło o tę samą kwotę.
Lepiej jest używać UTC, gdy czas się nie zmienia, chyba że jest to konieczne, aby użyć czasu innego niż UTC, jak na wyświetlaczu.
źródło