Kodėl šių dviejų kartų atėmimas (1927 m.) Duoda keistą rezultatą?

Jei vykdau šią programą, kuri analizuoja dvi datos eilutes, nurodydama vieną kartą per 1 sekundę ir palygina jas:

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

Išeiti:

353

Kodėl ld4-ld3 ne 1 (kaip ld4-ld3 dėl laiko skirtumo per vieną sekundę), bet 353 ?

Jei pakeisiu datas 1 sekundę vėliau:

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

Tada ld4-ld3 bus 1 .


„Java“ versija:

27 июля '11 в 11:15 2011-07-27 11:15 Freewind yra nustatytas liepos 27 d . 11 val. 11:15 2011-07-27 11:15
@ 8 atsakymai

Tai yra laiko juostos pokytis gruodžio 31 d. Šanchajuje.

Daugiau informacijos apie 1927 m. Šanchajuje. Iš esmės, vidurnaktį 1927 m. Pabaigoje, laikrodis sugrįžo į 5 minutes ir 52 sekundes. Taigi, „1927-12-31 23:54:08“ iš tikrųjų įvyko du kartus, ir atrodo, kad „Java“ ją analizuoja kaip galimą momentą šiai vietinei datai / laikui - taigi ir skirtumas.

Tik dar vienas epizodas dažnai keistame ir nuostabiame laiko juostų pasaulyje.

Redaguoti: sustabdyti paspauskite! Istorija keičiasi ...

Pradinis klausimas nebebus rodomas lygiai taip pat, jei jis bus atstatytas su TZDB 2013a versija. 2013 m. Rezultatas bus 358 sekundės, o perėjimo laikas yra 23:54:03 vietoj 23:54:08.

Tai pastebėjau tik todėl, kad surinko panašius klausimus „Noda Time“ vienetų testų forma ... Dabar testas pasikeitė, tačiau tiesiog rodo, kad net istoriniai duomenys nėra saugūs.

Redaguoti: istorija vėl pasikeitė ...

TZDB 2014f pakeitimo laikas perkeltas į 1900-12-31, o dabar jis yra tik 343 sekundės (taigi laikas tarp t ir t+1 yra 344 sekundės, jei suprantate tai, ką turiu galvoje).

EDIT: Norėdami atsakyti į klausimą apie perėjimą 1900 m. ... atrodo, kad Java laiko juostos diegimas apdoroja visas laiko zonas kaip paprastas standartiniu laiku bet kuriuo metu iki 1900 m. UTC pradžios:

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

Minėtas kodas neperduodamas į „Windows“ kompiuterį. Taigi 1900 m. Pradžioje bet kuri laiko juosta, kurioje yra kitoks nei standartas, bus laikomas pereinamuoju laikotarpiu. TZDB pats turi tam tikrus duomenis, kurie grąžinami anksčiau, ir nesiremia jokia „fiksuoto“ standartinio laiko idėja (kurią getRawOffset laiko galiojančia koncepcija), todėl kitos bibliotekos neturėtų patekti į šį dirbtinį perėjimą.

10143
27 июля '11 в 11:31 2011-07-27 11:31 atsakymą pateikė Jonas Skeetas liepos 27 d. 11 val. 11:31 2011-07-27 11:31

Jūs susiduriate su vietos laiko spraga :

Kai vietinis standartinis laikas pasiekė sekmadienį, 1928 m. Sausio 1 d., 00:00:00 val., Valandos buvo atšauktos 0:05:52 val. Iki šeštadienio, 1927 m. Gruodžio 31 d., 23:54:08 vietoj įprastinio vietinio laiko

border=0

Tai nėra ypatingai keista ir atsitiko visur vienu metu ar kitaip, kai dėl politinių ar administracinių veiksmų buvo pakeisti arba pakeisti laiko intervalai.

1516
27 июля '11 в 11:38 2011-07-27 11:38 atsakymą pateikė Michael Borgwardt, liepos 27 d. 11, 11:38 2011-07-27 11:38

Šio keistumo moralė yra:

  • Jei įmanoma, naudokite datas ir laikus UTC.
  • Jei negalite rodyti datos ar laiko UTC, visada nurodykite laiko juostą.
  • Jei negalite įvesti įrašo datos / laiko UTC, jums reikia aiškiai nurodytos laiko juostos.
607
28 июля '11 в 14:50 2011-07-28 14:50 atsakymas pateikiamas Raedwaldui liepos 28 d., 11 val. 14:50 2011-07-28 14:50

Jei padidinsite laiką, turite grįžti į UTC ir tada pridėti arba atimti. Naudokite tik vietinį laiką rodymui.

Taigi, galite eiti per visus laikotarpius, kai valandos ar minutės įvyksta du kartus.

Jei konvertuojate į UTC, pridėkite kiekvieną sekundę ir konvertuokite į vietos laiką. Jūs praeisite per 11:54:08. LMT - 11:59:59 val LMT ir tada 11:54:08. CST - 11:59:59 p. CST.

336
30 июля '11 в 19:55 2011-07-30 19:55 atsakymas pateikiamas PatrickO liepos 30 d., 11 val., 19:55, 2011-07-30 19:55

Vietoj to, kad būtų konvertuojama kiekviena data, naudosite šį kodą.

 long difference = (sDt4.getTime() - sDt3.getTime()) / 1000; System.out.println(difference); 

Ir pamatyti rezultatą:

 1 
283
16 мая '12 в 8:31 2012-05-16 08:31 atsakymą pateikė Rajshri gegužės 16, 12 d. 8:31 val. 2012-05-16 08:31

Atsiprašau, bet laiko spraga šiek tiek pasikeitė.

JDK 6 prieš dvejus metus, o JDK 7 neseniai buvo atnaujinta 25 .

Pamoka mokytis: Venkite laiko, išskyrus UTC, bet kokia kaina, išskyrus demonstraciją.

201
18 февр. atsakymą pateikė vartotojo1050755 vasario 18 d. 2014-02-18 01:44 '14 ne 1:44 2014-02-18 01:44

Kaip kiti paaiškina, yra laiko spraga. 1927-12-31 23:54:08 Asia/Shanghai yra du galimi laiko 1927-12-31 23:54:07 poslinkiai, bet tik vienas kompensavimas 1927-12-31 23:54:07 . Taigi, priklausomai nuo to, kuris nuokrypis yra naudojamas, yra arba vienos sekundės skirtumas, arba skirtumas tarp 5 minučių ir 53 sekundžių.

Šis nedidelis poslinkio poslinkis vietoj įprastų vienos valandos dienos sutaupymų (vasaros), su kuriuo mes esame įpratę, šiek tiek užgožia problemą.

Atkreipkite dėmesį, kad atnaujinus 2013 m. Laiko juostų duomenų bazę, ši spraga atsirado prieš kelias sekundes, tačiau poveikis bus pastebimas.

Naujasis „Java 8“ paketas „Java“ leidžia jums jį naudoti aiškiau ir suteikti įrankius jos apdorojimui. Atsižvelgiant į:

 DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder(); dtfb.append(DateTimeFormatter.ISO_LOCAL_DATE); dtfb.appendLiteral(' '); dtfb.append(DateTimeFormatter.ISO_LOCAL_TIME); DateTimeFormatter dtf = dtfb.toFormatter(); ZoneId shanghai = ZoneId.of("Asia/Shanghai"); String str3 = "1927-12-31 23:54:07"; String str4 = "1927-12-31 23:54:08"; ZonedDateTime zdt3 = LocalDateTime.parse(str3, dtf).atZone(shanghai); ZonedDateTime zdt4 = LocalDateTime.parse(str4, dtf).atZone(shanghai); Duration durationAtEarlierOffset = Duration.between(zdt3.withEarlierOffsetAtOverlap(), zdt4.withEarlierOffsetAtOverlap()); Duration durationAtLaterOffset = Duration.between(zdt3.withLaterOffsetAtOverlap(), zdt4.withLaterOffsetAtOverlap()); 

Tada durationAtEarlierOffset bus viena sekundė, o durationAtLaterOffset bus penkios minutės ir 53 sekundės.

Be to, šie du nuokrypiai yra tokie patys:

 // Both have offsets +08:05:52 ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset(); ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset(); 

Tačiau šie du skirtingi:

 // +08:05:52 ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset(); // +08:00 ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset(); 

Tą pačią problemą galite matyti lyginant 1927-12-31 23:59:59 nuo 1928-01-01 00:00:00 , nors šiuo atveju tai yra ankstesnis kompensavimas, kuris veda į ilgesnį skirtumą, ir tai yra anksčiau data, kuri turi dvi galimas kompensacijas.

Kitas būdas tai pasiekti yra patikrinti, ar vyksta perėjimas. Tai galime padaryti taip:

 // Null ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime); // An overlap transition ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime); 

Galite patikrinti, ar perėjimas yra persidengimas - šiuo atveju yra daugiau nei vienas leistinas šios datos / laiko arba erdvės poslinkis - šiuo atveju ši data / laikas yra negaliojantis šiam zonos identifikatoriui - naudojant „ isOverlap() ir „ isGap() zot4 .

Tikiuosi, kad tai padės žmonėms susidoroti su šia problema, kai „Java 8“ bus plačiai prieinama, arba tiems, kurie naudoja „Java 7“, kurie naudojasi „JSR 310“.

179
03 янв. Atsakymą pateikė Daniel C. Sobral Jan 03 2014-01-03 17:43 '14, 17:43, 2014-01-03 17:43

„IMHO“ bendras, netiesioginis „Java“ lokalizavimas yra vienas didžiausių dizaino trūkumų. Jis gali būti suprojektuotas vartotojo sąsajoms, tačiau sąžiningai, kas šiandien naudoja „Java“ vartotojo sąsajoms, išskyrus kai kuriuos IDE, kuriuose dažniausiai galite ignoruoti lokalizaciją, nes programuotojai nėra tikslinė auditorija. Galite tai pataisyti (ypač „Linux“ serveriuose):

  • eksportas LC_ALL = C TZ = UTC
  • nustatykite sistemos laikrodį į UTC
  • niekada nenaudokite lokalizuotų diegimų, jei tai yra absoliučiai būtina (t. y. tik rodyti)

Kaip „Java“ bendruomenės nariai, rekomenduoju:

  • lokalizuoti metodai nėra standartiniai, bet reikalauja, kad vartotojas aiškiai paprašytų lokalizavimo.
  • naudokite UTF-8 / UTC kaip numatytąjį FIXED reikšmę, nes ji yra tik numatytasis šiandien. Nėra jokios priežasties nieko daryti, nebent norite sukurti tokius srautus.

Aš turiu galvoje, ar ne pasauliniai statiniai OO modelio kintamieji? Niekas kitas nėra įprastas numatytasis elementas, kurį pateikia kai kurie elementarūs aplinkos kintamieji .......

148
26 нояб. Atsakymą pateikė vartotojo1050755 lapkritis 26. 2014-11-26 18:58 '14, 18:58, 2014-11-26 18:58

Kiti klausimai apie „ arba Užduoti klausimą