Neden bu iki kez (1927'de) ├ž─▒kartmak garip bir sonu├ž veriyor?


Al─▒nan cevaba git


A┼ča─č─▒daki program─▒ ├žal─▒┼čt─▒r─▒rsam, bu, 1 saniye aral─▒klarla iki saniye dizgesini ayr─▒┼čt─▒r─▒r ve bunlar─▒ kar┼č─▒la┼čt─▒r─▒r:

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

Çıktı:

353

Neden oldu─ču ld4-ld3 de─čil 1 (─▒ zamanlarda bir saniyelik farktan bekledi─činiz gibi), ancak 353 ?

Tarihleri ÔÇőÔÇő1 saniye sonra tekrarlarsam:

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

O ld4-ld3 zaman olacak 1 .


Java versiyonu:

 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
 

6565









Cevap say─▒s─▒n─▒ say: 10






31 Aral─▒k'ta ┼×anghay'da bir saat dilimi de─či┼čikli─či.

┼×angay'daki 1927 detaylar─▒ i├žin bu sayfaya bak─▒n─▒z . Temel olarak, 1927'nin sonundaki gece yar─▒s─▒nda, saatler 5 dakika 52 saniye geri d├Ând├╝. ├ľyleyse "1927-12-31 23:54:08" asl─▒nda iki kez oldu ve Java, yerel tarih / saat i├žin m├╝mk├╝n olan en ge├ž an─▒ olarak ayr─▒┼čt─▒r─▒yor gibi g├Âr├╝n├╝yor - bu y├╝zden fark.

Zaman dilimlerinin ├žo─ču zaman garip ve harika d├╝nyas─▒nda bir ba┼čka b├Âl├╝m.

EDIT: Basmay─▒ kes! Tarih de─či┼čiklikleri ...

Orijinal soru, TZDB'nin 2013a versiyonuyla yeniden in┼ča edildi─činde art─▒k ayn─▒ davran─▒┼č─▒ g├Âstermeyecektir . 2013a'da sonu├ž, 238.08 yerine 23:54:03 ge├ži┼č s├╝resiyle 358 saniye olacakt─▒r.

Bunu fark ettim ├ž├╝nk├╝ Noda Time'da b├Âyle sorular toplad─▒m, birim testleri ┼čeklinde ... Test ┼čimdi de─či┼čti, ama sadece g├Âsterime gidiyor - ge├žmi┼č veriler bile g├╝venli de─čil.

EDIT: Tarih tekrar de─či┼čti ...

TZDB 2014f, de─či┼čim zaman─▒ 1900-12-31 ta┼č─▒nd─▒ ve (aras─▒ndaki zaman y├╝zden ┼čimdi sadece 343 saniye de─či┼čikli─čidir t ve t+1 344 saniyedir, ne demek istedi─čimi g├Âr├╝rseniz).

EDIT: 1900ÔÇÖdeki bir ge├ži┼čle ilgili bir soruyu yan─▒tlamak i├žin ... Java zaman dilimi uygulamas─▒ t├╝m zaman dilimlerini 1900 UTCÔÇÖnin ba┼člang─▒c─▒ndan ├Ânceki herhangi bir an i├žin standart zamanlar─▒nda oldu─ču gibi ele al─▒yor gibi g├Âr├╝n├╝yor :

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

Yukar─▒daki kod Windows makinemde ├ž─▒kt─▒ vermiyor. Bu nedenle, 1900'├╝n ba┼č─▒nda standart olan─▒ d─▒┼č─▒nda herhangi bir zaman dilimi olan herhangi bir saat dilimi, ge├ži┼č olarak say─▒lacakt─▒r. TZDB'nin kendisinin bundan daha eskilere dayanan baz─▒ verileri var ve ÔÇťsabitÔÇŁ standart zaman fikrine dayanm─▒yor ( getRawOffset ge├žerli bir kavram oldu─ču varsay─▒l─▒r), bu nedenle di─čer k├╝t├╝phanelerin bu yapay ge├ži┼či tan─▒tmas─▒na gerek kalmad─▒.


10531







Yerel bir s├╝reksizlikle kar┼č─▒la┼čt─▒n─▒z :

Yerel standart saat, 1 Ocak 1928, 00:00:00 pazar─▒na gelmek ├╝zereyken saatler, saat 0:05:52 saatlerinden 31 Aral─▒k Cumartesi 1927, 23:54:08 yerel standart saatine kadar geri d├Ând├╝.

Bu ├Âzellikle garip de─čil ve siyasi veya idari eylemler nedeniyle zaman dilimleri de─či┼čtirildi─či veya de─či┼čtirildi─či i├žin bir anda veya ba┼čka bir yerde hemen hemen her yerde oldu.


1553







Bu tuhafl─▒─č─▒n ahlaki:

  • UTC'de tarih ve saatleri m├╝mk├╝n olan her yerde kullan─▒n.
  • UTC'de bir tarih veya saat g├Âr├╝nt├╝leyemiyorsan─▒z, her zaman saat dilimini belirtin.
  • UTC'de bir giri┼č tarihi / saati gerektiremiyorsan─▒z, a├ž─▒k├ža belirtilmi┼č bir zaman dilimi gerektirir.

634







Zaman─▒ artt─▒r─▒rken, tekrar UTC'ye d├Ân├╝┼čt├╝rmeli ve sonra eklemelisiniz veya ├ž─▒karmal─▒s─▒n─▒z. Yerel saati yaln─▒zca ekran i├žin kullan─▒n.

Bu ┼čekilde, saatlerin veya dakikalar─▒n iki kez oldu─ču herhangi bir periyotta y├╝r├╝yebilirsiniz.

UTC'ye d├Ân├╝┼čt├╝rd├╝yseniz, her saniye ekleyin ve g├Âr├╝nt├╝lemek i├žin yerel saate d├Ân├╝┼čt├╝r├╝n. Sen 23:54:08 ├╝zerinden gidece─čini LMT'de - 11:59:59 pm LMT ve ard─▒ndan 11:54:08 CST - 11:59:59 CST.


351







Her tarihi d├Ân├╝┼čt├╝rmek yerine, a┼ča─č─▒daki kodu kullan─▒rs─▒n─▒z.

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

Ve sonucu g├Ârmek:

 1
 

296







Bunu s├Âyledi─čim i├žin ├╝zg├╝n├╝m, ancak zaman─▒n s├╝reksizli─či

JDK 6 iki y─▒l ├Ânce ve JDK 7'de daha yeni 25 .

├ľ─črenilecek ders: UTC d─▒┼č─▒ zamanlardan ka├ž─▒n─▒n, belki g├Âr├╝nt├╝leme hari├ž, her ne pahas─▒na olursa olsun.


216







Ba┼čkalar─▒ taraf─▒ndan a├ž─▒kland─▒─č─▒ gibi, orada bir zaman kesintisi var. Orada iki olas─▒ zaman dilimi uzakl─▒klar i├žindir 1927-12-31 23:54:08 de Asia/Shanghai , ama sadece bir i├žin ofset 1927-12-31 23:54:07 . Bu nedenle, hangi ofsetin kullan─▒ld─▒─č─▒na ba─čl─▒ olarak, bir saniye fark ya da 5 dakika 53 saniye fark vard─▒r.

Al─▒┼č─▒lm─▒┼č oldu─čumuz bir saatlik yaz saati tasarruflar─▒ yerine (yaz saati) al─▒┼čk─▒n oldu─čumuz bu hafif kayma, sorunu biraz gizliyor.

Saat dilimi veritaban─▒n─▒n 2013a g├╝ncellemesinin bu s├╝reksizli─či birka├ž saniye ├Ânce de─či┼čtirdi─čini, ancak etkinin hala g├Âzlemlenebilir olaca─č─▒n─▒ unutmay─▒n.

java.time Java 8'deki yeni paket, bunu daha net g├Ârerek kullan─▒m─▒na izin verdi ve i┼člemek i├žin ara├žlar sa─člad─▒. Verilen:

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

Sonra durationAtEarlierOffset bir saniye, durationAtLaterOffset be┼č dakika ve 53 saniye.

Ayr─▒ca, bu iki ofset ayn─▒d─▒r:

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

Ancak bu ikisi farkl─▒:

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

// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();
 

Bununla 1927-12-31 23:59:59 birlikte 1928-01-01 00:00:00 , ayn─▒ problemi kar┼č─▒la┼čt─▒rarak g├Ârebilirsiniz , ancak bu durumda, daha uzun sapmay─▒ ├╝reten ├Ânceki mahsup, ve iki olas─▒ kaymas─▒ olan ├Ânceki tarihtir.

Buna yakla┼čman─▒n ba┼čka bir yolu, bir ge├ži┼č olup olmad─▒─č─▒n─▒ kontrol etmektir. Bunu b├Âyle yapabiliriz:

 // Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);

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

Ge├ži┼čin ├╝st ├╝ste binme olup olmad─▒─č─▒n─▒ kontrol edebilirsiniz - bu durumda bu tarih / saat i├žin birden fazla ge├žerli kayma varsa - veya bir bo┼čluk - bu durumda bu tarih / saat bu b├Âlge kimli─či i├žin ge├žerli de─čildir - isOverlap() ve isGap() y├Ântemlerini kullanarak zot4 .

Umar─▒m bu, Java 8 yayg─▒n olarak kullan─▒labilir hale geldi─činde veya JSR 310 deste─čini kullanan Java 7 kullananlar i├žin bu t├╝r sorunlar─▒ ├ž├Âzmelerine yard─▒mc─▒ olur.


190







IMHO, Java'daki yayg─▒n, ├Ârt├╝l├╝ yerelle┼čtirme, en b├╝y├╝k tasar─▒m hatas─▒d─▒r. Kullan─▒c─▒ aray├╝zleri i├žin tasarlanabilir, ancak a├ž─▒k├žas─▒, programc─▒lar─▒n tam olarak hedef kitlesi olmad─▒─č─▒ i├žin yerel olarak temelde g├Ârmezden gelebilece─činiz baz─▒ IDE'ler d─▒┼č─▒nda bug├╝n kullan─▒c─▒ aray├╝zleri i├žin Java'y─▒ ger├žekten kullananlar. Bunu (├Âzellikle Linux sunucular─▒nda) a┼ča─č─▒dakileri yaparak d├╝zeltebilirsiniz:

  • ihracat LC_ALL = C TZ = UTC
  • sistem saatinizi UTC'ye ayarlay─▒n
  • Kesinlikle gerekli olmad─▒k├ža asla yerel uygulamalar kullanmay─▒n (├Ârne─čin sadece g├Âsterim i├žin).

To Java Community Process ├╝yeleri Ben tavsiye:

  • yerelle┼čtirilmi┼č y├Ântemleri varsay─▒lan de─čil, kullan─▒c─▒n─▒n a├ž─▒k├ža yerelle┼čtirme istemesini gerektirir.
  • UTF-8 / UTC'yi FIXED varsay─▒lan─▒ olarak kullan─▒n, ├ž├╝nk├╝ bug├╝n yaln─▒zca varsay─▒land─▒r. B├Âyle bir i┼č par├žac─▒─č─▒ ├╝retmek istemeniz d─▒┼č─▒nda, ba┼čka bir ┼čey yapmak i├žin hi├žbir sebep yoktur.

Yani, hadi, genel statik de─či┼čkenler bir OO kar┼č─▒t─▒ model de─čil mi? Ba┼čka hi├žbir ┼čey, baz─▒ ilkel ortam de─či┼čkenleri taraf─▒ndan verilen yayg─▒n varsay─▒lanlar de─čildir.


157







Di─čerlerinin de dedi─či gibi, 1927'de ba┼čkalar─▒n─▒n da s├Âyledi─či gibi ┼×angay'da bir zaman de─či┼čikli─či.

Temel olarak, 23:54:07 ┼×angay'da, yerel standart zaman, bir s├╝re sonra ertesi g├╝ne d├Ând├╝ 00:00:00 . Ancak daha sonra 23:54:08 yerel standart zamana geri d├Ând├╝ . ─░┼čte bu y├╝zden fark 343 saniye, 1 saniye de─čil.

Bu ayn─▒ zamanda ABD gibi di─čer yerlerle de kar─▒┼čabilir. ABD'de Yaz Saati Uygulamas─▒ var. Yaz Saati Uygulamas─▒ ba┼člad─▒─č─▒nda, zaman 1 saat ileri gider. Fakat bir s├╝re sonra Yaz Saati uygulamas─▒ sona erdi─činde standart saat dilimine 1 saat geri gider. Bu y├╝zden bazen ABD'deki zamanlar─▒ kar┼č─▒la┼čt─▒r─▒rken fark yakla┼č─▒k 3600 1 saniye de─čil saniyedir.

UTC olmayan zaman─▒n, ekranda oldu─ču gibi kullan─▒lmas─▒ gerekmedik├že, zaman─▒n de─či┼čmedi─či yerlerde UTC kullanmak daha iyidir.


10







 import java.util.TimeZone;

public class Demo {
    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);
            }
        }
    }
}
 

-2