Când dezvoltați unele programe, este posibil să nu vă gândiți la fusurile orare la început. Dacă nu locuiți într-o țară care are de-a face cu mai multe fusuri orare, cum ar fi Statele Unite sau Rusia.

Am întâlnit recent o problemă care implică fusuri orare. Au existat câteva teste unitare care făceau afirmații cu privire la datele care obișnuiau să lucreze la biroul meu din Franța, dar care nu lucrau în Maroc pentru noii membri ai echipei noastre.

Cum sa gestionati fusurile orare si sa va sincronizati software ul
Iată testul unitar care funcționează în Franța, dar nu și în Maroc

‌Aceasta a fost o oportunitate pentru mine de a învăța cum să gestionez corect datele și orele pentru software-ul internațional. În acest articol, voi introduce probleme cu fusul orar și voi împărtăși câteva reguli de urmat.

Introducere rapidă a fusurilor orare

Deoarece pământul este un fel de sferă, soarele răsare în Japonia în timp ce apune în America. Dacă toată lumea a folosit timpul global, să spunem 09:00 ar fi răsăritul soarelui în Japonia, dar pentru americani ar fi apusul soarelui. Nu prea la îndemână.

Pentru a vă asigura că timpul este coordonat cu soarele pentru toată lumea, este necesar să treceți de la ora globală în funcție de locația dvs. Ca urmare, globul se împarte în fusuri orare și fiecare primește un decalaj. Acest decalaj este un număr de minute pentru a adăuga la ora globală pentru a obține ora fusului orar. Poate fi fie pozitiv, fie negativ.

1611504069 662 Cum sa gestionati fusurile orare si sa va sincronizati software ul
Fusele orare mondiale standard – Ilustrație de Hellerick din Wikimedia Commons

Se numește timpul global UTC, reprezintă termenul universal coordonat. S-ar putea să fi auzit și despre GMT care este un fus orar fără niciun decalaj.

De exemplu, când este 10:50 la UTC, este și el 03:50 în San Francisco cu o -0700 compensare și 18:50 la Beijing cu o +0800 decalaj. Cu toate acestea, schimbarea nu este doar în ore întregi: compensarea Nepalului este +0545. O puteți verifica pe Wikipedia.

În plus față de această compensare, care vine cu fusul orar, unele țări schimbă și ceasurile de două ori pe an. Ora de vară sau ora de vară adaugă o oră la fusul orar decalat înainte de vară. Apoi, ceasul este resetat la ora fusului orar iarna. Scopul este de a face ziua mai lungă.

Cel mai comun mod de a afla un fus orar este folosind Baza de date IANA Time Zone. Veți ajunge cu un șir precum Europe/Paris urmând tiparul Zonei / Orașului. În plus, Microsoft își menține propriile sale Baza de date Microsoft Time Zone utilizat pe sistemele sale de operare. Dar asta poate cauza probleme atunci când rulați aplicații multiplataforma .NET Core.

IANA este în continuare cel mai bun scop. Baza de date Microsoft nu este actualizată des, conține mai puțin istoric, nume de fus orar destul de curioase (de exemplu: Romantic Standard Time) și este predispus la erori. De exemplu, încercați să nu vă amestecați Arab , Arabic și Arabian Standard Time. Pentru mai multe detalii despre fiecare bază de date și diferențele lor, consultați acest articol.

Un ultim lucru: există o mulțime de moduri de a scrie o întâlnire. Din fericire, Specificație ISO 8601 stabilește o regulă comună pentru formatarea datei.

November 11, 2018 at 12:51:43 AM (in a time zone at UTC+00:00)
2018-11-05T12:51:43Z <- Z stands for UTC

November 11, 2018 at 12:51:43 AM (in a time zone at UTC +07:30)
2018-11-05T12:51:43+0730

Modul în care computerele gestionează datele

Calculatoarele sunt capabile să efectueze operațiuni numai folosind numere. Aceasta înseamnă că 2020-08-01 +1 nu este egal cu 2020-08-02 și nu poate fi manipulat.

Pentru a lucra mai ușor cu datele, putem reprezenta datele ca numere. Acesta este ce marcaje de timp sunt toate despre. Este numărul de milisecunde scurs de la o dată predefinită (sau epocă) până la data specificată.

Super, hai să alegem o epocă atunci! De fapt, epoca comună a fost deja stabilită și valoarea ei este 1 ianuarie 1970 (miezul nopții UTC).

1611504069 291 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Pentru a vă asigura că ați înțeles, rulați fragmentul anterior în browser. Ce? Nu ai obținut același rezultat?

Ok, am înșelat puțin pentru a obține acest rezultat … Ar trebui să obțin Thu Jan 01 1970 01:00 GMT+0100 deoarece fusul orar al computerului meu este setat la Europa / Paris.

De fapt, acest moment cu o marcă de timp zero este miezul nopții în Greenwich, dar și 05:45 în Mumbai și chiar 1969-12-31T16:30 în San Francisco când considerați că fusul orar al acestora este compensat.

Regula # 1: Marcajele de timp sunt doar pentru salvare, nu pentru afișare. Este luat în considerare pe UTC, deoarece nu include niciun offset sau fus orar.

Nu ați obținut data „corectă” înainte, deoarece JavaScript utilizează fusul orar local pentru a vă arăta data / ora cea mai exactă.

Acum, încercați următorul fragment. Sunt sigur că veți obține același rezultat ca și mine:

1611504069 307 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Da, marcajul de timp zero este 1970-01-01T00:00:00 la UTC pentru toată lumea de pe glob. Totuși, nu este adevărat dacă alegeți un alt fus orar.

În concluzie, toString afișează data folosind fusul orar local în timp ce toUTCString se bazează pe UTC. De asemenea, nu vă lăsați păcăliți toISOString care este la fel ca toUTCString dar redă formatul ISO 8601 (numele său ar trebui să fie toUTCISOString).

Recomand comanda datei pentru a converti un al doilea timestamp (nu milisecunde) într-un șir lizibil. Utilizarea acestei comenzi cu opțiunea UTC vă asigură că nu ține cont de fusul orar al computerului / browserului.

# Linux
$ date -d @1586159897 -u 
Mon Apr  6 07:58:17 UTC 2020

# For Osx users
$ date -r 1586159897 -u 

Să reparăm testul nostru unitar

Problema pe care am întâlnit-o cu fusurile orare a fost în testele mele unitare. Ia-ți timp să-l citești și să înțelegi ce ar trebui să afirme:

1611504070 644 Cum sa gestionati fusurile orare si sa va sincronizati software ul

În acest test, scopul este de a verifica acest lucru setHours setează orele și minutele datei la zero (miezul nopții). Mai întâi aleg un timestamp aleatoriu care nu este la miezul nopții. Apoi comparați rezultatul cu marcajul de timp pentru aceeași zi la miezul nopții.

De fapt, funcționează – dar numai dacă este compensat fusul orar +0200 (inclusiv DST) în acest moment. De exemplu, nu funcționează pentru Africa / Casablanca ( +0100 inclusiv DST). Să vedem cum sunt tipărite acele timestampuri:

1611504070 555 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Gata, data UTC pentru ambele rezultate nu este aceeași. De asemenea, înseamnă că și marcajele de timp rezultate nu sunt aceleași.

După cum puteți vedea, compensarea pentru Paris este +0200 și +0100 pentru Casablanca. Dar ambele se afișează la miezul nopții cu toString. Aceasta înseamnă că setHours funcția folosește fusul orar al computerului pentru a efectua operația. Și toString afișează data folosind fusul orar.

Aceasta nu este singura problemă cu acest test: ce se întâmplă dacă executați acest test în San Francisco? Corect, ziua ar fi 2020-07-31 pentru ambele date din cauza -0700 decalaj.

Cea mai sigură modalitate de a face acest test de încredere și de a lucra în întreaga lume este să folosiți o dată în fusul orar local. Nu veți mai folosi marcaje de timp pentru a seta datele inițiale.

1611504070 299 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Putem îmbunătăți regula anterioară despre marcajele de timp:

Regula # 2: datele șirurilor sunt potrivite pentru afișare utilizând fusul orar și calculele utilizatorului. Nu sunt pe UTC, dar în general includ un offset.

Păstrați-l la data din partea serverului

Regula despre marcajele de timp se aplică în continuare pe partea serverului. Cu toate acestea, a doua regulă despre utilizarea datelor șir nu poate fi utilizată.

Într-adevăr, în unele cazuri cu tehnologii precum PHP, Java și Rails, paginile sunt redate pe partea serverului (SSR). Aceasta înseamnă că tot HTML este generat de server și nu are nicio idee despre fusul orar al clientului. Gândiți-vă la server – nu este altceva decât un computer de pe glob. De asemenea, are propriul fus orar, dar nu este neapărat același cu fusul orar al clientului.

Regula # 3: Serverele ar putea fie să cunoască fusul orar al clientului, fie să trimită o dată pe UTC. Fusul orar al serverului nu contează.

Noul Java 8 Data / Ora este considerat unul dintre cele mai ușor de înțeles și mai clare API-uri care vă ajută să faceți față datei. Nu voi explica cum funcționează aici, dar să trecem în revistă câteva puncte interesante.

LocalDateTime, OffsetDateTime și ZonedDateTime sunt cele 3 clase furnizate pentru a calcula și afișa data și ora. Nu mai Date sau DateTime care se amestecă afișând data locală și data UTC.

Următoarele exemple sunt extrase din acest articol minunat (scris de Jonas Konrad) care descrie Java 8 Date / Time API cu o grămadă de exemple. Apropo, multe mulțumiri lui, mi-a permis să-i citez bucățile de cod!

Să ne uităm la diferențele dintre cele 3 clase:

1611504070 650 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Există o diferență mică, dar importantă între OffsetDateTime și ZonedDateTime, ai observat-o?

După cum spune numele său, OffsetDateTime este conștient doar de un decalaj între data locală și UTC. Aceasta înseamnă că gestionează DST diferit față de o dată atașată la un fus orar.

1611504070 127 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Exemplul cu un fus orar pare să fie comportamentul corect. De fapt, ambele sunt corecte, deoarece adăugarea unei zile poate însemna:

  • Adăugați o zi și păstrați aceeași oră (se ocupă de ora de vară cu ZonedDateTime)
  • Adăugați 24 de ore la data curentă (cu OffsetDateTime).

Vă amintiți regula # 1 despre marcajele de timp? Pentru salvare, ar trebui să utilizați doar o marcă de timp UTC. API-ul Java oferă un fișier Instant class, care este un timestamp pe care îl puteți obține din oricare dintre cele trei clase utilizate pentru afișarea datei.

1611504070 35 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Gânduri finale

În acest articol, ați aflat că marcajele de timp sunt pentru salvare (regula # 1) și datele șirului sunt pentru afișare (regula # 2). Ai observat că numărul de secunde de la epocă este un număr destul de mare?

De aceea după Problema Unix Millennium Bug (Y2K) vine Problema Y2K38 care reprezintă anul 2038. La 2038-01-19T03:14:07Z marcajul de timp (în secunde) va atinge maximul pentru numerele întregi semnate pe 32 de biți 2,147,483,647 . Apoi se va transforma într-un număr negativ după ce a adăugat încă o secundă.

Cum sa gestionati fusurile orare si sa va sincronizati software ul
Acest semn indică ianuarie 1900 în loc de ianuarie 2000 – Imagine din Wikipedia Commons

‌Pe forumuri, oamenii spun că nu le pasă, deoarece software-ul lor nu va fi folosit timp de 20 de ani fără a fi rescris. Ei bine, ar putea fi adevărat, dar să ne gândim în continuare la câteva soluții (cu MySQL):

  • Actualizați TIMESTAMP tastați la numere întregi semnate pe 64 de biți
  • Salvați datele UTC în DATETIME coloane în loc de TIMESTAMP

Ambele soluții au avantajele și dezavantajele lor. Primul pare un hack care raportează problema mai târziu. Cu toate acestea, rezolvă problema pentru foarte, foarte mult timp. Software-ul dvs. va fi învechit și nu va mai fi utilizat atunci când problema apare din nou.

A doua soluție funcționează pentru o perioadă de timp aproape infinită (până la 9999-12-31T23:59:59Z).

Folosind TIMESTAMP este recomandat pentru jurnale, în timp ce DATETIME este mai bun pentru alte nevoi. Nu uitați că un timestamp nu poate stoca o dată anterioară 1970-01-01T00:00:00Z și nu după 2038-01-19T03:14:07Z. Aceasta înseamnă că ar trebui să utilizați DATETIME pentru a salva date departe în trecut și în viitor.

În plus, în MySQL TIMESTAMPS sunt stocate la UTC, dar afișate conform unui fus orar specificat (și convertite la UTC înainte de salvare). Acest mecanism este util atunci când trebuie să obțineți o dată locală și nu există DATETIME.

Un ultim cuvânt despre moment.js, o bibliotecă populară pentru a se ocupa de date. Am experimentat mai întâi o problemă și am vrut să vă avertizez despre aceasta:

1611504070 855 Cum sa gestionati fusurile orare si sa va sincronizati software ul

Ambii console.logva ieși 2020-08-02 00:00. Dacă sunteți obișnuiți cu programarea funcțională, vă așteptați hours și minutes să returneze un nou obiect de moment pentru că sunt funcții pure. Nu este cazul – modifică data de intrare și o returnează pentru o înlănțuire ușoară.

Mulțumesc că ai citit până la capăt. Sper că această experiență a mea ți-a fost utilă. Apropo, nu sunt foarte încrezător în alegerea dintre TIMESTAMP și DATETIME, așa că nu ezitați să ne împărtășiți experiența!

Dacă ați găsit util acest articol, vă rugăm să îl împărtășiți pe rețelele de socializare pentru a-i ajuta pe ceilalți să-l găsească și pentru a vă arăta sprijinul! ?

Nu uitați să verificați pagina autorului pentru articole viitoare ?