Bu iki dəfə (1927-ci ildə) çıxarma nə üçün çox təəccüblü bir nəticə verir?

Hər iki saniyə bir dəfə istinadən və onları müqayisə edən iki datanı təhlil edən aşağıdakı proqramı çalıştırırsam:

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

Nəticə:

353

Niyə ld4-ld3 1 (bir saniyədə bir fərqi gözlədiyim kimi) deyil, 353 ?

Tarixləri bir neçə saniyə sonra dəyişsəm:

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

Sonra ld4-ld3 1 olacaq.


Java versiyası:

27 июля '11 в 11:15 2011-07-27 11:15 Freewind , 27 iyul ' 11' də saat 11:15 'də təyin olunur 2011-07-27 11:15
@ 8 cavab

Bu, 31 dekabrda Şanxayda bir saat diliminin dəyişməsi.

Ətraflı məlumat üçün 1927-ci ildə Şanxayda ətraflı məlumat üçün bu səhifəyə baxın. Əsasən gecə yarısı 1927-ci ilin sonunda saat 5 dəqiqə və 52 saniyə döndü. Beləliklə, "1927-12-31 23:54:08" əslində iki dəfə baş verdi və göründüyü kimi, Java bu yerli tarix / vaxt üçün daha sonra mümkün bir an kimi təhlil edir - buna görə fərq.

Zaman zonalarının tez-tez qəribə və gözəl dünyasında bir epizod.

EDIT: Tıklamayı dayandırın! Tarix dəyişdirin ...

TZDB-nin 2013a versiyası ilə bərpa olunarsa, orijinal sual artıq tam eyni davranışı göstərməyəcəkdir. 2013-cü ildə nəticə 23:54:08 yerinə 23:54:03 keçid dövrü ilə 358 saniyə olacaq.

Mən bunu yalnız gördüm, çünki Noda Time'da bu tip sualları vahid testlər şəklində toplayıram ... Test artıq dəyişmişdir, ancaq sadəcə tarixi məlumatların təhlükəsiz olmadığını göstərir.

EDIT: Hikayə yenidən dəyişdi ...

TZDB 2014f ildə dəyişmə vaxtı 1900-12-31-ə keçdi və indi yalnız 343 saniyə ( tt+1 arasındakı müddət 344 saniyədir ki, mən orta olduğumu görürsünüz).

EDIT: 1900-cü ildə keçid haqqında suallara cavab vermək üçün ... Java vaxt zonasının tətbiq olunması bütün vaxt zonalarının sadəcə 1900-cü ilin əvvəlində hər hansı bir zaman nöqtəsi üçün standart olaraq qəbul edildiyi görünür:

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

Yuxarıda göstərilən kod mənim kompüterimdə Windows deyil. Beləliklə, 1900-cü ilin əvvəlində standartından fərqli olan hər hansı bir zaman zonası bu keçid hesab edir. TZDB özünün əvvəlcədən qayıtdığı bəzi məlumatlara malikdir və "sabit" standart vaxtın (yəni getRawOffset etibarlı bir konsepsiya olduğu anlamına gəlir) heç bir fikrə istinad etmir, buna görə də digər kitabxanalara bu süni keçidə ehtiyac yoxdur.

9853
27 июля '11 в 11:31 2011-07-27 11:31 Cavab Jon Skeet tərəfindən 27 iyul '11 11:31 'də verildi 2011-07-27 11:31

Yerli vaxt boşluğu ilə qarşılaşırsınız:

Yerli standart vaxt 1 yanvar 1928-ci il saat 00: 00-a çatdıqdan saat saat 01: 30-a qədər şənbə, 31 dekabr 1927-ci il, saat 23: 54-a qədər adi yerli vaxt

border=0

Bu xüsusilə qəribə deyil və hər zaman bir yerdə və ya baş verən zaman, siyasi və ya inzibati tədbirlər nəticəsində vaxt aralıqları dəyişdirildikdə və ya dəyişdirildikdə.

1481
27 июля '11 в 11:38 2011-07-27 11:38 cavab Michael Borgwardt tərəfindən verilir 27 iyul '11 11:38 2011-07-27 11:38

Bu qəribənin əxlaqı:

  • Mümkün olan zaman UTC və tarixləri istifadə edin.
  • UTC-də tarixi və saatı göstərə bilmirsinizsə, həmişə vaxt zonasını müəyyənləşdirin.
  • UTC-in tarixini / tarixini daxil edə bilmirsinizsə, açıq-aşkar müəyyən bir saat diliminə ehtiyacınız var.
590
28 июля '11 в 14:50 2011-07-28 14:50 Cavab Raedwald'a 28 İyul, '11 'də 14:50' də verildi 2011-07-28 14:50

Vaxtını artırırsanız, UTC-ə qayıtmalı və sonra əlavə və ya çıxartmalısınız. Yerli vaxtdan yalnız ekran üçün istifadə edin.

Beləliklə, saat və ya dəqiqə iki dəfə baş verdiyi zaman hər hansı bir dövrdən keçə bilərsiniz.

UTC-ə çevrildiyində, hər ikinci əlavə edin və ekran üçün yerli vaxtınıza çevirin. 11:54:08 ilə keçəcəksiniz. LMT - 11:59:59 pm LMT və sonra 11:54:08. CST - 11:59:59 s. CST.

324
30 июля '11 в 19:55 2011-07-30 19:55 Cavab PatrickO 30 iyul, 19 saat 19: 55-da verilib

Hər bir tarixi dəyişdirmək əvəzinə aşağıdakı kodu istifadə edirsiniz.

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

Və nəticəyə baxın:

 1 
269
16 мая '12 в 8:31 2012-05-16 08:31 Cavab Rajshri tərəfindən verilir 16, '12 at 8:31 pm 2012-05-16 08:31

Bunu demək üçün üzüldüm, ancaq vaxt boşluğu bir az taşındı

JDK 6, iki il əvvəl, və JDK 7-yeniləmə 25 .

Öyrənmək üçün dərslər: Bütövlükdə, istisna olmaqla, bütün xərclərdə UTC olmadan vaxtdan qaçın.

192
18 февр. Cavab 18 fevralda 1050755 tərəfindən verilir. 2014-02-18 01:44 '14 da 1:44 2014-02-18 01:44

Başqalarının izah etdiyi kimi, bir vaxt boşluğu var. 1927-12-31 23:54:08 Asia/Shanghai üçün iki mümkün zaman çizelgesi 1927-12-31 23:54:08 var, lakin yalnız 1927-12-31 23:54:07 üçün ofset 1927-12-31 23:54:07 . Beləliklə, hansı ofsetin istifadəsindən asılı olaraq, bir saniyənin bir fərqi və ya 5 dəqiqə və 53 saniyə fərq var.

Köçürmədə bu kiçik dəyişiklik, adət etdiyimiz bir saatlıq gündəlik qənaət (yaz saatı) əvəzinə, biz alışdığımız bu problemi bir az qarışdırır.

2013 saatı verilənlər bazasının yeniləşdirilməsi bu boşluğu bir neçə saniyə əvvəl köçürüb, lakin təsir hələ də müşahidə oluna bilər.

Java 8-də yeni java.time paketi onu daha dəqiq istifadə etməyə və onun emal üçün alət təmin etməyə imkan verir. Verilənlər:

 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 saniyə olacaq və durationAtLaterOffset beş dəqiqə və 53 saniyə olacaq.

Bundan əlavə, bu iki ofset eynidır:

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

Amma bu iki fərqlidir:

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

Eyni problemi 1927-12-31 23:59:59 ilə müqayisə edərək 1927-12-31 23:59:59 1928-01-01 00:00:00 ilə müqayisə oluna bilər, baxmayaraq ki, bu halda daha uzun bir fərqlilikə gətirib çıxaran daha əvvəlki 1928-01-01 00:00:00 və daha əvvəl iki ehtimala malik olan bir tarix.

Buna yanaşmanın başqa bir yolu keçidin baş verdiyini yoxlamaqdır. Bunu aşağıdakı kimi edə bilərik:

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

Bu keçidin bir üst-üstə düşməyini yoxlaya bilərsiniz - bu halda bu tarix / vaxt və ya bir yer üçün birdən çox icazə verilən ofset mövcuddur - bu halda bu tarix / vaxt bu bölgə identifikatoru üçün etibarsızdır - isOverlap()isGap() zot4 .

Ümidvaram ki, bu, Java 8-nin geniş yayımlanacağı kimi və ya JSR 310 backport istifadə edən Java 7 istifadəçilərə tezliklə bu problemlə mübarizə aparmağa kömək edəcəkdir.

171
03 янв. Cavab Daniel C. Sobral Jan 03 tərəfindən verildi 2014-01-03 17:43 '14 at 17:43 2014-01-03 17:43

IMHO-nun ümumi, örtülü lokalizasiyası ən böyük dizayn qüsurlarından biridir. Proqram istifadəçiləri hədəf auditoriya olmadığı üçün, istifadəçi interfeysləri üçün nəzərdə tutulub, lakin həqiqətən bu gün istifadəçi interfeysləri üçün Java istifadə edən, həqiqətən, lokalizasiyaya baxmayaraq, bəzi IDE istisna olmaqla, istifadə etmək olar. Bunu (xüsusilə Linux serverlərində) düzəldə bilərsiniz:

  • ixrac LC_ALL = C TZ = UTC
  • sistem saatını UTC -ə təyin edin
  • Qətiliklə zəruri hallarda lokallaşdırılmış tətbiqləri istifadə etməyin (yəni, yalnız göstərmək üçün)

Java cəmiyyətinin üzvləri olaraq mən məsləhət görürəm:

  • lokallaşdırılmış metodları standart deyil, ancaq istifadəçinin lokalizasiyanı tələb etməsini tələb edir.
  • UTF-8 / UTC-ni default FIXED dəyəri olaraq istifadə edin, çünki bu gün yalnız standartdır. Belə axınları yaratmaq istəmədikcə başqa bir şey etmək üçün heç bir səbəb yoxdur.

Yəni anti-OO modelinin qlobal statik dəyişənləri deyilmi? Başqa bir şey başqa elementar mühit dəyişənləri tərəfindən verilən ümumi bir default deyil .......

142
26 нояб. Cavab 26 noyabr tarixində istifadəçi tərəfindən verildi . 2014-11-26 18:58 '14 'da 18:58 2014-11-26 18:58

bağlı digər suallar və ya sual