Extindeți TMS WEB Core cu JS Libraries cu Andrew: Luxon
Motivația.
Dezvoltatorii Delphi de lungă durată sunt probabil să fie destul de familiarizați cu TDateTime și cu diferitele sale avantaje și deficiențe. Și chiar dacă ești relativ nou în Delphi și nu ai avut prea multă oportunitate de a interacționa cu TDateTime, nu există prea multe lucruri care să te împiedice și, în general, nu este probabil să atragă prea multă atenție de la sine . Acesta este un lucru bun, desigur. Când aveți de-a face cu JavaScript, totuși, frumosul și confortabilul TDateTime este înlocuit cu un format de dată JavaScript destul de sinistru, care nu este niciunul dintre aceste lucruri. Sigur, este destul de ușor să începeți cu o dată JavaScript, dar este într-adevăr o fiară complet diferită. Deplasarea între cele două poate fi o provocare și chiar și doar încercarea de a face cea mai mică parte de formatare poate fi uneori mult mai multe probleme decât ar putea părea posibil. Deci, în această postare, vom trece peste o grămadă de astfel de lucruri. Scoateți totul dintr-o singură lovitură, smulgeți aparatul, ca să spunem așa, ca să putem trece cu sinceritate și încredere la alte subiecte, dar să avem asta în buzunarul din spate atunci când avem nevoie. Și crede-mă, vom avea nevoie de el!
Epocă epică.
Grozav, un alt motiv pentru a detesta Excel. De parcă nu erau deja destui! Detaliile reale din jurul acestui lucru nu vor conta atât de mult, cu excepția cazului în care, desigur, se întâmplă să lucrați cu o mulțime de date în acea perioadă (sau mai devreme), unde aceasta ar putea fi o problemă. Și nici pentru cealaltă direcție nu trebuie să ne îngrijorăm prea mult. Ca o dublă, data maximă care poate fi reprezentată cu TDateTime este cel puțin 9999-12-31. De fapt, poate reprezenta date după aceea, dar lucrurile devin un pic zgomotoase când anul este mai mare de patru cifre.
Unix (și Linux) stochează aceste informații ca numere întregi, numărul de secunde de la 1970-01-01 00:00:00. Folosind numere întregi semnate pe 32 de biți, aceasta înseamnă că valoarea maximă care poate fi stocată se va depăși în 2038. În mod curios, data minimă este în 1901. Din fericire, se pare că sistemele pe 64 de biți le-au actualizat cu înțelepciune pentru a folosi numere întregi pe 64 de biți, deci asta nu ar trebui să fie o problemă. Sunt sigur că până în 2038 veți fi greu să găsiți un prăjitor de pâine fără un procesor pe 64 de biți. În JavaScript, se adoptă o abordare similară, dar este numărul de milisecunde din 1970-01-01 00:00:00 și cred că a folosit întotdeauna numere întregi pe 64 de biți (sau, mai degrabă, ceva aproximativ echivalent), așa că nimic să-ți faci griji acolo. De remarcat, totuși, este faptul că JavaScript presupune ca valoarea să fie în mod specific numărul de milisecunde începând cu 1970-01-01 00:00:00 UTC. Ultimele trei litere vor deveni importante mai târziu.
Utilizarea de bază a Delphi.
Utilizarea TDateTime în Delphi nu este deosebit de dificilă și probabil că este ceva cu care ești deja familiarizat, așa că nu vom petrece prea mult timp cu asta. Din fericire, toate acestea funcționează bine și în TMS WEB Core. Iată o grămadă de exemple ale modurilor în care folosesc cel mai des TDateTime. Acestea sunt tipurile de lucruri pe care vom dori să le putem face și în JavaScript. Și în timp ce unele dintre acestea ar putea părea o grămadă mare de dureri de cap, în practică, acesta nu este cazul. Majoritatea datepicker-urilor de timp sunt folosite pentru a alege datele reale dintr-un calendar sau sunt folosite alte elemente ale interfeței de utilizare, pentru a face ca o mare parte din aceasta să nu fie o problemă. Și, de obicei, nu le-ați folosi pe toate acestea în același timp!
... utilizări ... System.DateUtils, ... procedura TForm1.WebButton2Click(Expeditor: TObject); procedura TestTDateTime(aDateTime: TDateTime); ÎNCEPE console.log('TDateTime Value: '+FloatToStrF(ADateTime,ffNumber,5,3)); console.log('TDateTime = 0.0: '+DateTimeToStr(0.0)); console.log('Format DateTime preferat: ' +FormatDateTime('aaaa-mm-zz hh:nn:ss', aDateTime)); console.log('Al doilea format DateTime preferat: ' +FormatDateTime('aaaa-mmm-zz hh:nn:ss', aDateTime)); console.log('Al treilea format DateTime preferat: ' +FormatDateTime('aaaa-mmm-zz (zz) hh:nn:ss', aDateTime)); console.log('Short DateTime Format: ' +FormatDateTime('ddddd t', aDateTime)); console.log('Long DateTime Format: '+FormatDateTime('ddddd tt', aDateTime)); console.log('Short Date Format Settings: ' +FormatSettings.ShortDateFormat); console.log('Setări de format de dată lungă: ' +FormatSettings.LongDateFormat); console.log('Separator de date: ' +FormatSettings.DateSeparator); console.log('Short Time Format Settings: ' +FormatSettings.ShortTimeFormat); console.log('Setări de format pe termen lung: ' +FormatSettings.LongTimeFormat); console.log('Separator de timp: ' +FormatSettings.TimeSeparator); console.log('Prima zi a lunii: ' +FormatDateTime('aaaa-mmm-zz', StartOfTheMonth(ADateTime))); console.log('Ultima zi a lunii: ' +FormatDateTime('aaaa-mmm-zz', EndOfTheMonth(ADateTime))); console.log('Prima zi a lunii anterioare: ' +FormatDateTime('aaaa-mmm-zz', StartOfTheMonth(IncMonth(ADateTime,-1)))); console.log('Ultima zi a lunii anterioare: ' +FormatDateTime('aaaa-mmm-zz', EndOfTheMonth(IncMonth(ADateTime,-1)))); console.log('Prima zi a lunii următoare: ' +FormatDateTime('aaaa-mmm-zz', StartOfTheMonth(IncMonth(ADateTime,+1)))); console.log('Ultima zi a lunii următoare: ' +FormatDateTime('aaaa-mmm-zz', EndOfTheMonth(IncMonth(ADateTime,+1)))); console.log('Ziua anului: ' +IntToStr(DayOfTheYear(aDateTime))); console.log('Ziua săptămânii: ' +FormatDateTime('dddd', ADateTime)); // Săptămâna începe luni console.log('Numărul ISO al zilei săptămânii: ' +IntToStr(DayoftheWeek(ADateTime))); console.log('Numărul săptămânii ISO: ' +IntToStr(WeekOfTheYear(aDateTime))); console.log('ISO Prima zi a săptămânii: ' +FormatDateTime('aaaa-mmm-zz (zz)', StartOfTheWeek(aDateTime))); console.log('ISO Ultima zi a săptămânii: ' +FormatDateTime('aaaa-mmm-zz (ddd)', EndOfTheWeek(aDateTime))); console.log('ISO Prima zi a săptămânii precedente: ' +FormatDateTime('aaaa-mmm-zz (zz)', StartOfTheWeek(aDateTime-7))); console.log('Ultima zi ISO a săptămânii anterioare: ' +FormatDateTime('aaaa-mmm-zz (zz)', EndOfTheWeek(aDateTime-7))); console.log('ISO Prima zi a săptămânii viitoare: ' +FormatDateTime('aaaa-mmm-zz (zz)', StartOfTheWeek(aDateTime+7))); console.log('ISO Ultima zi a săptămânii viitoare: ' +FormatDateTime('aaaa-mmm-zz (zz)', EndOfTheWeek(aDateTime+7))); // Săptămâna începe duminică console.log('Numărul zilei săptămânii non-ISO: ' +IntToStr(DayofWeek(ADateTime))); // Dacă duminica, folosiți luni în schimb pentru că WeekOfTheYear nu știe despre săptămânile de duminică console.log('Numărul săptămânii non-ISO: ' +IntToStr(WeekOfTheYear(aDateTime+Trunc(DayOftheWeek(ADateTime)/7)))); console.log('Prima zi a săptămânii non-ISO: ' +FormatDateTime('aaaa-mmm-zz (zz)',aDateTime + 1 - DayOfWeek(aDateTime))); console.log('non-ISO Ultima zi a săptămânii: ' +FormatDateTime('aaaa-mmm-zz (zz)',aDateTime + 7 - DayOfWeek(aDateTime))); console.log('non-ISO Prima zi a săptămânii precedente: ' +FormatDateTime('aaaa-mmm-zz (zzj)',aDateTime - 6 - DayOfWeek(aDateTime))); console.log('Ultima zi non-ISO a săptămânii precedente: ' +FormatDateTime('aaaa-mmm-zz (zz)',aDateTime - DayOfWeek(aDateTime))); console.log('non-ISO Prima zi a săptămânii viitoare: ' +FormatDateTime('aaaa-mmm-zz (zzj)',aDateTime + 8 - DayOfWeek(aDateTime))); console.log('non-ISO Ultima zi a săptămânii viitoare: ' +FormatDateTime('aaaa-mmm-zz (zzj)',aDateTime +14 - DayOfWeek(aDateTime))); console.log('Se calculează durata unei zile: ' +IntToStr(DaysBetween(Today,EncodeDate(1971,05,25)))); console.log('Calculul unei durate de timp: ' +IntToStr(MillisecondsBetween(Now,Now-1))+'ms'); Sfârşit; ÎNCEPE TestTDateTime(EncodeDateTime(2021, 12, 26, 12, 13, 14, 0)); // O duminică TestTDateTime(EncodeDateTime(2022, 1, 2, 12, 13, 14, 0)); // Tot o duminică TestTDateTime(EncodeDateTime(2022, 1, 9, 12, 13, 14, 0)); // Da, încă o duminică Sfârşit;
Adunarea rezultatelor celor trei date și punerea lor într-un tabel ne aduce următoarele. Facem aici o distincție între săptămânile care încep luni (standardul ISO) și săptămânile care încep duminică (de obicei, Canada și SUA, dar și altele). Vom aborda acest lucru în doar un moment, dar principalul lucru de reținut este că acest lucru se schimbă acolo unde cade duminica în ceea ce privește numărul real al săptămânii. Dacă nu folosiți numere de săptămână, aceasta nu este o problemă. Dacă o faci, aceasta este, ei bine, aceasta nu este deloc o problemă.
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
|
Valoarea TDateTime |
44.556,509 |
44.563,509 |
44.570,509 |
TDateTime = 0,0 |
1899-12-30 |
1899-12-30 |
1899-12-30 |
Formatul DateTime preferat |
26-12-2021 12:13:14 |
2022-01-02 12:13:14 |
2022-01-09 12:13:14 |
Al doilea format de date și oră preferat |
26-Dec-2021 12:13:14 |
2022-ian-02 12:13:14 |
09-ian-2022 12:13:14 |
Al treilea format preferat de date și oră |
26-dec-2021 (duminică) 12:13:14 |
02-ian-2022 (duminică) 12:13:14 |
09-ian-2022 (duminică) 12:13:14 |
Format scurt DateTime |
26-12-2021 12:13 |
2022-01-02 12:13 |
2022-01-09 12:13 |
Long DateTime Format |
26-12-2021 12:13:14 |
2022-01-02 12:13:14 |
2022-01-09 12:13:14 |
Setări de format de dată scurtă |
aaaa-mm-zz |
aaaa-mm-zz |
aaaa-mm-zz |
Setări de format de dată lungă |
zz, aaaa-mm-zz |
zz, aaaa-mm-zz |
zz, aaaa-mm-zz |
Setări separator de date |
– |
– |
– |
Setări de format de scurtă durată |
hh:nn |
hh:nn |
hh:nn |
Setări de format de lungă durată |
hh:nn:ss |
hh:nn:ss |
hh:nn:ss |
Setări Separator de timp |
: |
: |
: |
Prima zi a lunii |
2021-dec-01 |
01-ian-2022 |
01-ian-2022 |
Ultima zi a lunii |
2021-dec-31 |
31-ian-2022 |
31-ian-2022 |
Prima zi a lunii anterioare |
2021-Nov-01 |
2021-dec-01 |
2021-dec-01 |
Ultima zi a lunii anterioare |
2021-Nov-30 |
2021-dec-31 |
2021-dec-31 |
Prima zi a lunii viitoare |
01-ian-2022 |
01-feb-2022 |
01-feb-2022 |
Ultima zi a lunii viitoare |
31-ian-2022 |
28-feb-2022 |
28-feb-2022 |
Ziua Anului |
360 |
2 |
9 |
Zi a săptămânii |
duminică |
duminică |
duminică |
Numărul ISO al zilei săptămânii |
7 |
7 |
7 |
Numărul săptămânii ISO |
51 |
52 |
1 |
ISO prima zi a săptămânii |
20-dec-2021 (luni) |
27-dec-2021 (luni) |
03-ian-2022 (luni) |
ISO Ultima zi a săptămânii |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
ISO prima zi a săptămânii precedente |
13-dec-2021 (luni) |
20-dec-2021 (luni) |
27-dec-2021 (luni) |
ISO Ultima zi a săptămânii precedente |
19-dec-2021 (duminică) |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
ISO prima zi a săptămânii viitoare |
27-dec-2021 (luni) |
03-ian-2022 (luni) |
10-ian-2022 (luni) |
ISO Ultima zi a săptămânii viitoare |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
16-ian-2022 (duminică) |
Numărul zilei săptămânii non-ISO |
1 |
1 |
1 |
Numărul săptămânii non-ISO |
52 |
1 |
2 |
prima zi a acestei săptămâni non-ISO |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
non-ISO Ultima zi a acestei săptămâni |
01-ian-2022 (sâmbătă) |
08-ian-2022 (sâmbătă) |
15-ian-2022 (sâmbătă) |
non-ISO prima zi a săptămânii precedente |
19-dec-2021 (duminică) |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
non-ISO Ultima zi a săptămânii precedente |
01-ian-2022 (sâmbătă) |
01-ian-2022 (sâmbătă) |
08-ian-2022 (sâmbătă) |
non-ISO prima zi a săptămânii viitoare |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
16-ian-2022 (duminică) |
non-ISO Ultima zi a săptămânii viitoare |
08-ian-2022 (sâmbătă) |
15-ian-2022 (sâmbătă) |
22-ian-2022 (sâmbătă) |
Calcularea duratei unei zile |
18626 |
18626 |
18626 |
non-ISO Ultima zi a săptămânii viitoare |
86400000ms |
86400000ms |
86400000 ms |
Există, desigur, mult mai multe funcții disponibile, iar preferatele tale pot fi foarte bine diferite de ale mele, desigur. Dar chiar și din această listă de bază de apeluri de funcții, apar destul de multe subiecte de interes pe care probabil ar trebui să le acoperim înainte de a continua. Dar o declinare generală aici. Există diverse convenții utilizate în întreaga lume când vine vorba de utilizarea și afișarea datelor și orelor. Ceea ce este obișnuit acolo unde locuiesc, poate foarte bine să fie diferit în altă parte a lumii. Și oamenii au opinii, uneori păreri foarte puternice, inclusiv eu. Și nu mă pot gândi la nimic din partea de sus a minții despre care doi dezvoltatori din diferite regiuni ale lumii ar putea să nu fie de acord mai puternic decât ceva legat de formatele de date. Principalul punct general pe care încerc să îl subliniez aici este că există opțiuni și, în calitate de dezvoltatori TMS WEB Core (sau orice dezvoltatori, într-adevăr), avem o mulțime de instrumente la dispoziție pentru a face din acest tip de lucru o plăcere pentru utilizatorii noștri. sau clienți, indiferent care ar fi convențiile lor preferate, mai degrabă decât o pedeapsă. Deci iată!
- Indiferent de platforma de dezvoltare sau limbajul de programare, se consideră, în general, o bună practică să folosești întotdeauna funcțiile disponibile oferite de mediul tău atunci când ai de-a face cu valorile datetime. În parte, acest lucru este pentru a vă salva de durerile de cap care vin odată cu nevoia de a vă gândi la anii bisecți sau la câte zile sunt într-o lună. Acest lucru funcționează și cu presupunerea că system_function(a_valid_date) -> another_valid_date. Numeroase erori se pot strecura atunci când începi să te joci cu lucruri. Totuși, acest lucru nu este întotdeauna ușor și cu cât te îndepărtezi de „convenție”, cu atât este mai probabil să întâmpinați probleme. Chiar și în exemplele mele de mai sus, există mai multe lăutari decât mi-aș dori cu acele calcule pentru prima/ultima zi a săptămânii. Din fericire, încă nu am întâlnit pe nimeni care să fi argumentat împotriva săptămânilor care au șapte zile, așa că este destul de sigur. Unul dintre puținele cazuri în care nu există numeroase opinii.
- Apropo de asta, ISO8601 pare la început a fi un standard strict în multe privințe, dar la o inspecție mai atentă, nu este deloc atât de strict. Cu excepția, în mod curios, pentru începutul săptămânii, despre care afirmă fără echivoc că este luni. Cu toate acestea, în partea mea de lume (Canada), sincer nu-mi amintesc să fi văzut vreodată un calendar tipărit care nu avea duminica în stânga și sâmbăta în dreapta. Ceea ce înseamnă, indirect, că săptămâna începe duminică. Și oriunde am lucrat și toți cei cu care am lucrat, probabil că ar avea aceeași părere. Cu toate acestea, într-o altă locație, poate într-o altă țară sau continent, se poate întâmpla exact opusul. Și deși nu am întâlnit niciodată această situație personal, am citit că în unele locuri prima zi a săptămânii poate fi sâmbătă. Mai precis, unele grupuri etnice (indiferent de locația fizică) pot prefera acest lucru. Asa de…. ??! Aceasta poate fi o problemă reală. Delphi în sine are chiar diferite variații ale funcțiilor sale. Un set de variații oferă posibilitatea de a trece valorile TDateTime în loc de părțile constitutive (funcțiile “the”). O altă variație se referă la faptul că duminica = 1 sau luni = 1. Tricky, tricky. Indiferent de situația cu care te confrunți, trebuie să fii atent și să fii sigur că folosești aceleași funcții (și convenții) în mod consecvent, chiar dacă doar pentru propria ta minte.
- În mod similar, numerele săptămânii pot fi uneori un motiv de confuzie. Cu un număr mare de ani în urmă, îmi amintesc că am vizitat un birou la începutul lunii ianuarie, când angajații verificau cele mai recente produse agricole de la doi vânzători separati de agricultură de peste miliarde de dolari, ambii din aceeași țară din nordul Europei care se mândrește mai degrabă cu priceperea sa agricolă. . Swag-ul în acest caz includea calendare de perete foarte mari, care arată întregul an dintr-o privire. Cu părți egale de groază și umor, s-a dovedit că calendarele de la diferiți vânzători nu aveau aceleași numere de săptămână alocate. Cred că, colectiv, ca planetă, am ajuns de atunci să fim de acord că Săptămâna #1 este considerată prima săptămână care are o zi de joi. ISO8601 prevalează. Deși aceasta este mai mult o realizare „recentă” la care au ajuns oamenii și nu este neapărat implementată în același mod peste tot. Totuși, cu asta mergem aici. În mod convenabil, acest lucru nu este într-adevăr în conflict cu punctul meu (2) de mai sus. Va trebui doar să ne certăm despre săptămâna în care se încadrează duminica.
- TDateTime are precizie în milisecunde, dacă sunteți interesat de acel nivel de detaliu. Cu toate acestea, unele sisteme (baze de date, de exemplu) pot avea mai multă precizie. Marcajele de timp DB2 înregistrează microsecunde (șase cifre în loc de trei), la fel ca și altele. Deci, acesta este ceva de care trebuie să fiți atenți când mutați datele, mai ales dacă comparați datele în căutarea potrivirilor exacte. Și mai ales când baza de date în sine generează marcaje temporale, pe care le vom trata mai detaliat în curând. Uneori, acest lucru se întâmplă și în culise. Acesta este motivul pentru care, dacă utilizați componente convenționale Delphi DB pentru a accesa o bază de date, marcajele de timp sunt trunchiate după secunde. Pentru a vă asigura că componentele și baza de date folosesc întotdeauna aceeași precizie.
- Un exemplu de ISO8601 care poate fi mai puțin rigid este că datele pot fi exprimate fie ca AAAA-LL-ZZ sau AAAAMMZZ – ceea ce se referă la îmbunătățit vs. de bază. Nimic ca un standard bun pentru a nu lua parte! Așadar, atunci când se pretinde că ceva este compatibil cu ISO8601, trebuie să nu ai prea multă încredere doar în asta, deoarece poate însemna lucruri diferite pentru diferiți oameni. Și da, mă uit la tine, TXDataWebDataset.SetJSONData. Sau FireDAC, la fel de vinovat, presupun! Ca și în orice altceva, astfel de lucruri trebuie testate și trebuie să fii atent nu numai la variațiile de formate, ci și la faptul că atunci când lucrurile funcționează, nu cauzează alte probleme în aval. O parte a unei serii de apeluri de funcții poate tolera cu bucurie mici variații într-un format, în timp ce alta va fi oprită la rece.
- Utilizatorii au preferințe. Clienții au preferințe. Dezvoltatorii au preferințe. Rareori acestea sunt aliniate. Și, uneori, factorul decisiv nu este legat de standarde sau codare sau de oricare dintre aceste preferințe, ci mai degrabă de temutele „reguli de afaceri” când cineva a decis, probabil cu decenii în urmă, că „Asta este calea” pentru acea organizație. Din acest motiv, am luat obiceiul de a oferi o opțiune de configurare generală în proiectele mele, în care diferite perioade (săptămâni, luni, ani fiscali, trimestre, sezoane, perioade de salarizare, vacanțe statistice etc.) pot fi arbitrar. definit și apoi implementat în mod consecvent în cadrul unei organizații, cel puțin în limitele proiectelor mele. Cel puțin atunci când o încurcă (ceea ce și ei fac în mod constant , aproape în fiecare an!), este încurcată în mod constant pentru toată lumea. Nu sunteți sigur dacă acesta a fost un beneficiu net sau nu? Ideea este, totuși, că, cu puțin (OK, MULT) noroc, utilizatorii tăi sau clienții tăi vor fi în concordanță intern cu acest gen de lucruri, cel puțin în cadrul propriei organizații.
- Apoi există conceptul de „internaționalizare”. Să-i spunem așa deocamdată, oricum. Uneori se numește „localizare”. Deloc confuz. Ideea că, oriunde te-ai afla în lume, regiunea ta (de obicei țara ta) are câteva idei general agreate despre care ar trebui să fie formatul datei, care ar trebui să fie prima zi a săptămânii, cum se numesc zilele de săptămâna și lunile anului sunt (cu variații pentru limbile oficiale din regiune), nume mai scurte echivalente pentru zilele săptămânii și lunile anului, cum ar trebui exprimate datele „medie” și „lungi” și așa mai departe . Adesea, veți vedea setări software în aplicații în care puteți selecta o altă regiune, dacă se întâmplă să găsiți că setările implicite preferate ale propriei regiuni nu sunt pe placul dvs. Bănuiesc că Danemarca este probabil o selecție regională mai populară decât ar fi altfel, tocmai din acest motiv. O școală de gândire (foarte bună!) este că, în calitate de dezvoltator, ar trebui să utilizați acest sistem exclusiv, oferind valori implicite bune tuturor utilizatorilor la nivel global, cu opțiunea ca aceștia să folosească setări diferite dacă doresc. Nobil chiar, poate. Dar poate deplasat.
- Și, în sfârșit, complet contrar cu (7) de mai sus, este că utilizatorii dintr-o anumită regiune ar putea să nu dorească să folosească setările implicite pentru regiunea lor sau pentru orice regiune. Chiar dacă se întâmplă să trăiască în Danemarca! Și acest sistem cu siguranță nu este lipsit de defecte proprii. De exemplu, folosesc în mod regulat un sistem desktop Fedora cu FireFox, Thunderbird (BetterBird, de fapt) și Google Chrome. Se pare că toți (un fel de) se bazează pe locația Fedora pentru a-și face treaba. Fedora însăși face o treabă foarte slabă în ceea ce privește oferirea de orice fel de flexibilitate. Și astfel totul în aval de acolo se înrăutățește progresiv. Chiar și Chrome și Firefox s-ar putea să nu fie de acord cu anumite opțiuni care utilizează același sistem, ceea ce poate fi enervant uneori.
Deci, pentru a fi clar, există standarde precum ISO8601 care oferă îndrumări solide cu privire la multe lucruri, dar există și excepții de rutină de care trebuie să fii conștient și adesea reguli care intră în joc care nu au nicio bază în realitate. Vestea bună este că instrumentele aflate la îndemână sunt capabile să se ocupe cu ușurință de aproape orice, atâta timp cât cineva poate găsi o definiție clară. Și ține-te de el. Nu atât de comun pe cât ai putea crede!
procedura TForm1.WebFormCreate(Expeditor: TObject); ÎNCEPE asm var fp1 = flatpickr('#WebEdit1', { appendTo: WebHTMLDiv1, inline: adevărat, WeekNumbers: adevărat, local: { firstDayOfWeek:0, // Duminică } }); var fp2 = flatpickr('#WebEdit2', { appendTo: WebHTMLDiv2, inline: adevărat, WeekNumbers: adevărat, local: { firstDayOfWeek:1, // luni } }); Sfârşit; Sfârşit;
Fusuri orare, UTC, Ora locală și Compensații.
Acest subiect este puțin mai simplu și în același timp puțin mai complex. Partea mai simplă, crezi sau nu, este că toată lumea este de acord (mai mult sau mai puțin, ha!) cu privire la care sunt fusurile orare și unde sunt limitele fizice, când au loc schimbările de timp și așa mai departe. Și chiar dacă limitele sunt uneori vagi, utilizatorul probabil știe în ce fus orar se află și sistemul său (browser, sistem de operare etc.) are probabil ceva în el care ne va ajuta să identificăm fusul orar fără niciun fel de ambiguitate. În general, vă setați fusul orar (sau, mai probabil, doar confirmați fusul orar) atunci când vă configurați pentru prima dată computerul, telefonul sau browserul sau orice altceva utilizați, și asta este tot – un lucru odată la care nu trebuie să vă gândiți cu adevărat despre mai mult, din fericire. De obicei, telefoanele nici nu trebuie să ceară, deoarece pot obține asta de la operator.
A trecut mult timp! Dar cred că suntem acolo acum. Cu toate acestea, datele de fus orar se schimbă, așa că acesta este unul dintre acele lucruri care apar și necesită actualizări periodice ale software-ului. Ideea că poți să creezi o aplicație și să pleci și să nu o mai actualizezi niciodată este mai mult decât puțin demodată. Modificările fusului orar pot necesita actualizări ale sistemului de operare de bază, sau poate bibliotecile pe care le utilizați în proiectul dvs., browserul sau chiar propriul cod (să sperăm că nu!), sau chiar toate cele de mai sus. În scopurile noastre, vom presupune că folosim cea mai recentă versiune a tuturor lucrurilor și că putem da vina pe furnizorul browserului dacă apare vreodată o problemă. Glumeam. Mai ales.
Partea mai complexă este că Delphi presupune că nu știm nimic despre fusurile orare. Și JavaScript presupune că știm totul despre fusurile orare. Așa că există un mic decalaj de informații de depășit atunci când vă deplasați înainte și înapoi între cele două. Ei bine, TDateTime presupune că nu știm nimic despre fusurile orare. Dar care sunt elementele despre care trebuie să știm cu adevărat? Poate că cea mai critică informație este decalajul nostru local față de UTC. Dacă știm asta, putem face imediat câteva lucruri esențiale, cum ar fi convertirea înainte și înapoi între ora locală și UTC. În mod curios, sursa TMS WEB Core folosește acest lucru pentru a determina decalajul orar local față de UTC:
Funcția GetLocalTimeOffset : Integer; ÎNCEPE Rezultat:=TJSDate.New.getTimezoneOffset(); Sfârşit;
Ceea ce înseamnă în esență că primește compensarea de la JavaScript. Acest lucru are sens, deoarece doar browserul știe ce se întâmplă într-o aplicație TMS WEB Core care rulează, așa că acesta este singurul loc pentru a o obține. Browserul însuși îl va obține din orice mediu în care rulează, așa că ar trebui să funcționeze bine. Delphi VCL este puțin mai cuprinzător, cu suport pentru lucruri precum TTimeZone, care nu funcționează (încă) în TMS WEB Core, dar deoarece nu ne putem baza pe Windows (am putea vreodată?), trebuie să obținem aceste informații de la noua sursă definitivă – browserul. De fapt, putem obține puțin mai multe informații de la browser, dar lucrurile încep să devină puțin șocante în ceea ce privește dacă un browser acceptă aceste apeluri, dacă diferite platforme acceptă aceste apeluri, dacă acel telefon din 2014 acceptă aceste apeluri și așa mai departe . Este posibil să nu funcționeze întotdeauna. Dar merită încercat. Iată ce avem. Nu este un început rău.
procedura TForm1.WebButton1Click(Expeditor: TObject); var tz_name: șir; tz_short: șir; ÎNCEPE asm tz_name = Intl.DateTimeFormat().resolvedOptions().timeZone; tz_short = new Date().toLocaleString('ro', {timeZoneName:'short'}).split(' ').pop(); Sfârşit; console.log('Ora locală: '+FormatDateTime('aaaa-mmm-zz (zz) hh:nn:ss', Acum)); console.log('Nume fus orar local: '+tz_name); console.log('Scurt fus orar local: '+tz_short); console.log('UTC Offset: '+IntToStr(TJSDate.new.gettimezoneoffset())+' minute'); console.log('UTC: '+FormatDateTime('aaaa-mmm-zz (zz) hh:nn:ss', LocalTimeToUniversal(Acum))); console.log('UTC la Ora locală: '+FormatDateTime('aaaa-mmm-zz (zz) hh:nn:ss', UniversalTimeToLocal(EncodeDateTime(2022,5,22,6,0,0,0))) ); Sfârşit; // ieșire console.log: Ora locală: 21 mai 2022 (sâmbătă) 22:40:14 Nume fus orar local: America/Vancouver Fus orar local scurt: PDT UTC Offset: 420 minute UTC: 22-mai-2022 (duminică) 05:40:14 UTC la ora locală: 21 mai 2022 (sâmbătă) 23:00:00
Din păcate, cam asta este tot ceea ce putem determina cu ușurință. Conversia între fusurile orare nu este chiar o opțiune până acum, de exemplu.
Bara laterală pe partea serverului.
Când lucrați cu partea client a unei aplicații de tip client/server, adesea clientului chiar nu îi pasă de fusurile orare. Nu este că nu sunt importante, ci mai degrabă că, de cele mai multe ori, oamenii fie lucrează în propriile fusuri orare, deci toate compensațiile sunt întotdeauna aceleași, fie dacă lucrează cu date din fusuri orare diferite, este tot ora locală. asta este important – nu este necesară nicio conversie.
De exemplu, am petrecut o cantitate considerabilă de timp lucrând la sisteme de timp și de prezență pentru operatorii comerciali de sere (în mare parte cultivatorii de tomate și ardei). Cu aceste sisteme, lucrătorii „perforează” la un computer chioșc client pe tot parcursul zilei lor de lucru, care apoi înregistrează datele și orele și activitățile într-o bază de date de server local (serverul înregistrează ora, nu are încredere în client). Supraveghetorii folosesc apoi aceste date pentru a monitoriza performanța lucrătorilor, fiind conștienți de faptul că timpul lor trebuie să se încadreze în orele de schimb alocate și să îndeplinească diferite criterii bazate pe durata activităților care sunt executate, tipul de fabrici la care lucrează și așa mai departe. . Lucrătorii dintr-o altă locație (în alt fus orar) care lucrează pentru aceeași companie ar putea foarte bine să lovească un alt computer chioșc client conectat la o altă bază de date locală. Administratorul de resurse umane (care lucrează într-un alt fus orar) ar putea reuni toate aceste date pentru a procesa statul de plată săptămânal al organizației. Persoanei respective nu îi pasă neapărat prea mult unde a fost făcută munca și nu are nevoie să convertească orele locale din locațiile îndepărtate într-un anumit fus orar. Administratorul vede doar că lucrătorii intră la, să zicem, 06:00 și ies la 14:00, astfel încât să fie plătiți pentru acea perioadă de timp (ajustat pentru pauze plătite și neplătite, bonusuri de performanță și așa mai departe). Nu este deloc nevoie să vă preocupați de fusurile orare.
Pe de altă parte, dacă aveți un server care înregistrează tot felul de activități într-o bază de date locală de la utilizatori din mai multe fusuri orare, situația ar putea fi destul de diferită. Un server XData poate, de exemplu, să înregistreze conexiuni și tichete de solicitare de servicii către o bază de date locală. Acea bază de date ar putea fi configurată pentru a înregistra marcaje de timp folosind UTC sau ar putea fi configurată să utilizeze ora locală a serverului bazei de date (care ar putea fi chiar diferită de fusul orar al serverului XData). Când un utilizator trimite un bilet de solicitare de serviciu utilizând un punct final al serverului XData, serverul bazei de date poate înregistra ora în propriul fus orar. Când utilizatorul dorește să verifice acel bilet, totuși, ora returnată utilizatorului trebuie convertită înapoi în fusul orar al acestuia. Din perspectiva lor, fusul orar este irelevant, dar pe server, orele înregistrate pentru toate biletele vor avea marcaje temporale înregistrate în fusul orar al serverului bazei de date care reflectă ordinea reală în care au fost create biletele, indiferent de fusul orar al persoanelor care au creat biletul.
Cum putem face acest lucru fără a fi nevoie să stocăm fusul orar al utilizatorului în baza de date? O abordare este de a face conversia numai atunci când utilizatorul face o cerere ulterioară. Când este invocată o operațiune de serviciu care necesită aceste informații, cum ar fi o solicitare de „informații bilet” sau un raport la nivel de utilizator de un fel, fusul orar al clientului poate fi trimis la XData, fie ca parametru de punct final, fie chiar inclus ca element. într-un JWT. Apoi, când se execută baza de date SQL, trecem aceste informații pentru a face conversia. Rezultatul interogării are apoi date în fusul orar corectat.
În DB2, o astfel de conversie ar putea arăta astfel. Fusul orar al serverului și fusul orar al utilizatorului sunt transmise ca parametri de interogare (de exemplu: America/Vancouver).
Selectați fus orar(TICKETTIMESTAMP, :SERVERTZ, :LOCALTZ) TICKETLOCALTIMESTAMP din BILETE Unde USER='franc'
În MySQL (sau MariaDB) poate fi folosită aceeași abordare, dar cu un apel de funcție diferit.
Selectați convert_tz(TICKETTIMESTAMP, :SERVERTZ, :LOCALTZ) TICKETLOCALTIMESTAMP din BILETE Unde USER='franc'
Rețineți că, în ambele baze de date, probabil că trebuie făcută unele lucrări de pregătire inițiale doar pentru a vă asigura că bazele de date au informații actuale despre fusul orar. Și, deși nu sunt sigur că fiecare bază de date are același nivel de suport pentru fusul orar, mi-aș imagina că dacă acestea două o fac, mulți alții o fac și ele.
funcția MyService.GetReport(Parameters:String):TStream; var ClientTimeZone: TBundledTimeZone; ServerTime:TDateTime; ClientTime:TDateTime; GlobalTime:TDateTime; TimeZone: șir; ÎNCEPE ... // Valoarea TimeZone este preluată din JWT ... ClientTimeZone :=TBundledTimeZone.GetTimeZone(TimeZone); ServerTime := Acum; GlobalTime := TTimeZone.Local.ToUniversalTime(ServerTime); ClientTime := ClientTimeZone.ToLocalTime(GlobalTime); Report.FooterLeft.Caption := FormatDateTime('aaaa-mmm-zz (zz) hh:nn:ss', ClientTime); ... Sfârşit;
Aceeași abordare ar putea fi utilizată pentru a transmite informații locale sau alți parametri legați de formatarea datei și orei. Care ar fi, de asemenea, candidați buni de stocat în JWT. Nu este probabil ca cineva să schimbe frecvent limbile sau formatul de dată preferat în timpul sesiunii. Sau dacă ar face-o, ar fi o justificare rezonabilă să generezi un nou JWT oricum.
Luxon intră în chat.
În regulă. Bara laterală peste. Revenind la client acum, ne-am ocupat de o mulțime de lucruri din partea Delphi, așa că haideți să cercetăm puțin mai departe partea JavaScript. Ceea ce aș dori să încep este echivalentul JavaScript al exemplelor pe care le-am oferit pentru Delphi. Sigur că ar avea sens să încep de acolo, nu-i așa? Dar, din păcate, ajungem la a treia intrare în care vrem să formatăm data de ieșire și să ne blocăm imediat. Se pare că nu există o modalitate reală simplă în JavaScript nativ de a face același lucru pe care îl face și funcția Delphi FormatDateTime. Dar așteaptă doar o secundă! Știu la ce te gândești. TMS WEB Core a convertit FormatDateTime în JavaScript și a funcționat foarte bine, nu? Sigur, exact asta am crezut. Așa că m-am dus și am verificat ce au făcut. Cel mai impresionant! Chiar te încurajez să mergi și să te uiți singur. …Core SourceSystem.SysUtils.pas. Deci da. Aș dori să adopt o abordare diferită aici.
Pentru a începe cu Luxon, avem cerința obișnuită de a adăuga un link către fișierul Project.html, fie manual, fie prin funcția Gestionare biblioteci JavaScript. Aș sugera că aceasta este o bibliotecă foarte utilizată și este puțin probabil să fie actualizată cu modificări de ultimă oră, așa că destul de sigur, relativ vorbind, pentru a utiliza un CDN. Ca aceasta:
procedura TForm1.WebButton4Click(Expeditor: TObject); ÎNCEPE asm function testLuxon(aDate) { console.log('Valoarea datei: '+aData); console.log('Format DateTime preferat: ' +aDate.toFormat('aaaa-LL-zz HH:mm:ss')); console.log('Al doilea format DateTime preferat: ' +aDate.toFormat('aaaa-LLL-zz HH:mm:ss')); console.log('Al treilea format de date și oră preferat: ' +aDate.toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('Cel mai scurt format DateTime: '+aDate.toFormat('f')); console.log('Format mai scurt DateTime: '+aDate.toFormat('ff')); console.log('Shortish DateTime Format: '+aDate.toFormat('fff')); console.log('Short DateTime Format: '+aDate.toFormat('ffff')); console.log('Long DateTime Format: '+aDate.toFormat('F')); console.log('Longish DateTime Format: '+aDate.toFormat('FF')); console.log('Format mai lung DateTime: '+aDate.toFormat('FFF')); console.log('Cel mai lung format DateTime: '+aDate.toFormat('FFFF')); console.log('Prima zi a lunii: '+aDate.startOf('lună').toFormat('aaaa-LLL-zz')); console.log('Ultima zi a lunii: '+aDate.endOf('lună').toFormat('aaaa-LLL-zz')); console.log('Prima zi a lunii anterioare: '+aData.plus({luni: -1}).startOf('lună').toFormat('aaaa-LLL-zz')); console.log('Ultima zi a lunii anterioare: '+aDate.plus({luni: -1}).endOf('lună').toFormat('aaaa-LLL-zz')); console.log('Prima zi a lunii următoare: '+aData.plus({luni: 1}).startOf('lună').toFormat('aaaa-LLL-zz')); console.log('Ultima zi a lunii următoare: '+aDate.plus({luni: 1}).endOf('lună').toFormat('aaaa-LLL-zz')); console.log('Ziua săptămânii: '+aDate.toFormat('cccc')); console.log('Ziua anului: '+aData.toFormat('o')); // Începutul săptămânii = luni console.log('Număr ISO Ziua Săptămânii: ' +aDate.zi de săptămână); console.log('Numărul săptămânii ISO: ' +aDate.weekNumber); console.log('ISO Prima zi a săptămânii: '+aDate.startOf('week').toFormat('yyyy-LLL-dd (ccc)')); console.log('ISO Ultima zi a săptămânii: '+aDate.endOf('week').toFormat('yyyy-LLL-dd (ccc)')); console.log('ISO Prima zi a săptămânii anterioare: '+aDate.plus({săptămâni: -1}).startOf('săptămână').toFormat('yyyy-LLL-dd (ccc)')); console.log('ISO Ultima zi a săptămânii anterioare: ' +aDate.plus({săptămâni: -1}).endOf('săptămână').toFormat('yyyy-LLL-dd (ccc)')); console.log('ISO Prima zi a săptămânii viitoare: ' +aDate.plus({săptămâni: 1}).startOf('săptămână').toFormat('yyyy-LLL-dd (ccc)')); console.log('ISO Ultima zi a săptămânii viitoare: ' +aDate.plus({săptămâni: 1}).endOf('week').toFormat('yyyy-LLL-dd (ccc)')); // Începutul săptămânii = duminică console.log('Ziua săptămânii non-ISO: '+aDate.toFormat('cccc')); // Luni=1,Sun=7 >>> Sun=1, Sat=7 console.log('Numărul zilei săptămânii non-ISO: ' +((aDate.zi de săptămână % 7) + 1)); // Dacă este duminică, obțineți weekNumber pentru luni console.log('Numărul săptămânii non-ISO: ' +aDate.plus({zile: Math.trunc(aDate.zi de săptămână / 7)}).weekNumber); console.log('Ziua anului non-ISO: '+aDate.toFormat('o')); console.log('non-ISO Prima zi a săptămânii: ' +aDate.plus({zile: + 1 - ((aDate.zile săptămânii % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc) ')); console.log('non-ISO Ultima zi a săptămânii: ' +aDate.plus({zile: + 7 - ((aDate.zile săptămânii % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc) ')); console.log('non-ISO Prima zi a săptămânii anterioare: ' +aDate.plus({zile: - 6 - ((aDate.zile săptămânii % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc) )')); console.log('non-ISO Ultima zi a săptămânii anterioare: ' +aDate.plus({zile: - ((aDate.zile săptămânii % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc)' )); console.log('non-ISO prima zi a săptămânii următoare: ' +aDate.plus({zile: + 8 - ((aDate.zile săptămânii % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc) )')); console.log('non-ISO Ultima zi a săptămânii viitoare: ' +aDate.plus({zile: +14 - ((aDate.zi de săptămână % 7) + 1)}).toFormat('yyyy-LLL-dd (ccc) )')); console.log('Se calculează durata unei zile: '+Math.trunc(luxon.DateTime.now().diff(luxon.DateTime.local(1971,5,25,0,0,0,0), 'zile' ).zile)); console.log('Calculul unei durate de timp: '+luxon.DateTime.now().diff(luxon.DateTime.now().plus({zile: -1}))+'ms'); } testLuxon(luxon.DateTime.local(2021, 12, 26, 12, 13, 14, 0)); testLuxon(luxon.DateTime.local(2022, 1, 2, 12, 13, 14, 0)); testLuxon(luxon.DateTime.local(2022, 1, 9, 12, 13, 14, 0)); Sfârşit; Sfârşit;
Rezultatul final este că obținem același tabel ca înainte, cu excepția diferitelor formate de dată aproape de început. Rețineți că, dacă rulați acest lucru în propriul browser, formatele ar putea arăta foarte diferit de acesta, dar sperăm că restul tabelului rămâne același. Acesta este un fel de idee, până la urmă.
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
|
Valoarea datei |
1640549594000 |
1641154394000 |
1641759194000 |
Formatul DateTime preferat |
26-12-2021 12:13:14 |
2022-01-02 12:13:14 |
2022-01-09 12:13:14 |
Al doilea format de date și oră preferat |
26-Dec-2021 12:13:14 |
2022-ian-02 12:13:14 |
09-ian-2022 12:13:14 |
Al treilea format preferat de date și oră |
26-dec-2021 (duminică) 12:13:14 |
02-ian-2022 (duminică) 12:13:14 |
09-ian-2022 (duminică) 12:13:14 |
Cel mai scurt format DateTime |
26.12.2021, ora 12:13 |
02.01.2022, ora 12:13 |
09.01.2022, ora 12:13 |
Format mai scurt DateTime |
26 decembrie 2021, 12:13 |
2 ianuarie 2022, 12:13 |
2022-01-09 12:13:14 |
Format scurt DateTime |
26 decembrie 2021, 12:13 PST |
2 ianuarie 2022, 12:13 PST |
9 ianuarie 2022, 12:13 PST |
Format scurt DateTime |
Duminică, 26 decembrie 2021, ora 12:13, ora standard a Pacificului |
Duminică, 2 ianuarie 2022, ora 12:13, ora standard a Pacificului |
Duminică, 9 ianuarie 2022, ora 12:13, ora standard a Pacificului |
Long DateTime Format |
26.12.2021, 12:13:14 |
02.01.2022, 12:13:14 |
09.01.2022, 12:13:14 |
Format DateTime lung |
26 decembrie 2021, 12:13:14 |
2 ianuarie 2022, 12:13:14 |
9 ianuarie 2022, 12:13:14 |
Format DateTime mai lung |
26 decembrie 2021, 12:13:14 PST |
2 ianuarie 2022, 12:13:14 PST |
9 ianuarie 2022, 12:13:14 PST |
Cel mai lung format DateTime |
Duminică, 26 decembrie 2021, 12:13:14 Ora standard a Pacificului |
Duminică, 2 ianuarie 2022, ora 12:13:14, ora standard a Pacificului |
Duminică, 9 ianuarie 2022, ora 12:13:14, ora standard a Pacificului |
Prima zi a lunii |
2021-dec-01 |
01-ian-2022 |
01-ian-2022 |
Ultima zi a lunii |
2021-dec-31 |
31-ian-2022 |
31-ian-2022 |
Prima zi a lunii anterioare |
2021-Nov-01 |
2021-dec-01 |
2021-dec-01 |
Ultima zi a lunii anterioare |
2021-Nov-30 |
2021-dec-31 |
2021-dec-31 |
Prima zi a lunii viitoare |
01-ian-2022 |
2022-feb-01 |
2022-feb-01 |
Ultima zi a lunii viitoare |
31-ian-2022 |
28-feb-2022 |
28-feb-2022 |
Ziua Anului |
360 |
2 |
9 |
Zi a săptămânii |
duminică |
duminică |
duminică |
Numărul ISO al zilei săptămânii |
7 |
7 |
7 |
Numărul săptămânii ISO |
51 |
52 |
1 |
ISO prima zi a săptămânii |
20-dec-2021 (luni) |
27-dec-2021 (luni) |
03-ian-2022 (luni) |
ISO Ultima zi a săptămânii |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
ISO prima zi a săptămânii precedente |
13-dec-2021 (luni) |
20-dec-2021 (luni) |
27-dec-2021 (luni) |
ISO Ultima zi a săptămânii precedente |
19-dec-2021 (duminică) |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
ISO prima zi a săptămânii viitoare |
27-dec-2021 (luni) |
03-ian-2022 (luni) |
10-ian-2022 (luni) |
ISO Ultima zi a săptămânii viitoare |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
16-ian-2022 (duminică) |
Numărul zilei săptămânii non-ISO |
1 |
1 |
1 |
Numărul săptămânii non-ISO |
52 |
1 |
2 |
prima zi a acestei săptămâni non-ISO |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
non-ISO Ultima zi a acestei săptămâni |
01-ian-2022 (sâmbătă) |
08-ian-2022 (sâmbătă) |
15-ian-2022 (sâmbătă) |
non-ISO prima zi a săptămânii precedente |
19-dec-2021 (duminică) |
26-dec-2021 (duminică) |
02-ian-2022 (duminică) |
non-ISO Ultima zi a săptămânii precedente |
01-ian-2022 (sâmbătă) |
01-ian-2022 (sâmbătă) |
08-ian-2022 (sâmbătă) |
non-ISO prima zi a săptămânii viitoare |
02-ian-2022 (duminică) |
09-ian-2022 (duminică) |
16-ian-2022 (duminică) |
non-ISO Ultima zi a săptămânii viitoare |
08-ian-2022 (sâmbătă) |
15-ian-2022 (sâmbătă) |
22-ian-2022 (sâmbătă) |
Calcularea duratei unei zile |
18626 |
18626 |
18626 |
non-ISO Ultima zi a săptămânii viitoare |
86400000ms |
86400000ms |
86400000 ms |
În regulă. Deci acum putem face în JavaScript ceea ce am putea face deja în Delphi. Acest lucru este important, cu siguranță, astfel încât să ne putem verifica munca și să ne asigurăm că lucrurile rămân consecvente. Cu toate acestea, nu suntem aici doar pentru a converti Delphi în JavaScript. Nici să-mi amintesc că sunt bătrân! Mai degrabă, scopul tuturor acestor lucruri este că dorim să putem valorifica ceea ce Luxon poate oferi pentru a îmbunătăți și a integra în continuare proiectele noastre Delphi și TMS WEB Core.
Grozav. Deci, ce altceva poate face Luxon?
Destul de multe, de fapt. În primul rând, conversia între fusurile orare nu este acum deloc dificilă.
asm var vancouver = luxon.DateTime.local(2022, 5, 22, 12, 13, 14, 0); console.log('America/Vancouver: '+vancouver.toFormat('yyyy-LLL-zz (ccc) HH:mm:ss')+' ( fus orar = '+vancouver.zoneName+' )'); console.log('America/New_York: '+vancouver.setZone('America/New_York').toFormat('yyyy-LLL-zz (ccc) HH:mm:ss')); console.log('Europa/Londra: '+vancouver.setZone('Europa/Londra').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('Europa/Paris: '+vancouver.setZone('Europa/Paris').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('Europa/Kiev: '+vancouver.setZone('Europa/Kiev').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('Asia/Singapore: '+vancouver.setZone('Asia/Singapore').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); Sfârşit; // ieșire console.log: America/Vancouver: 22-mai-2022 (duminică) 12:13:14 ( fus orar = America/Vancouver ) America/New_York: 22-mai-2022 (duminică) 15:13:14 Europa/Londra: 22 mai 2022 (duminică) 20:13:14 Europa/Paris: 22-mai-2022 (duminică) 21:13:14 Europa/Kiev: 22 mai 2022 (duminică) 22:13:14 Asia/Singapor: 23 mai 2022 (luni) 03:13:14
Pot fi folosite și diferite variante ale modului în care este exprimat fusul orar, dacă variația continent/oraș nu este pe placul dvs.
asm console.log('America/Vancouver: '+vancouver.toFormat('yyyy-LLL-zz (ccc) HH:mm:ss')+' ( fus orar = '+vancouver.zoneName+' )'); console.log('UTC: '+vancouver.setZone('utc').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('UTC+1: '+vancouver.setZone('utc+1').toFormat('aaaa-LLL-zz (ccc) HH:mm:ss')); console.log('CET (Europa Centrală): '+vancouver.setZone('cet').toFormat('yyyy-LLL-zz (ccc) HH:mm:ss')); Sfârşit; // ieșire console.log: America/Vancouver: 22-mai-2022 (duminică) 12:13:14 ( fus orar = America/Vancouver ) UTC: 22-mai-2022 (duminică) 19:13:14 UTC+1: 22 mai 2022 (duminică) 20:13:14 CET (Europa Centrală): 22 mai 2022 (duminică) 21:13:14
Am văzut deja o mulțime de exemple de ajustare a unei date plus/minus un interval, cum ar fi „zile”, „săptămâni”, „luni” și așa mai departe. Când se calculează diferența dintre două date, există opțiunea de a returna și o valoare care are astfel de intervale, făcând posibilă afișarea unor durate mai prietenoase.
asm var start = luxon.DateTime.local(2022, 5, 21, 0, 13, 14); var finish = luxon.DateTime.local(2022, 5, 22, 12, 13, 14); // 36 de ore mai târziu console.log('start a fost '+Math.trunc(finish.diff(start, 'minute').minutes)+' minut(e) în urmă'); console.log('start a fost '+Math.trunc(finish.diff(start, 'hours').hours)+' ora(e) acum'); console.log('start a fost '+Math.trunc(finish.diff(start, 'zile').zile)+' zi(ile) in urma'); console.log('start a fost '+JSON.stringify(finish.diff(start, ['zile','ore','minute']).toObject())); console.log('start a fost '+finish.diff(start, ['zile','ore']).toHuman()+'acum'); Sfârşit; începutul a fost acum 2160 minut(e). începutul a fost acum 36 ore începutul a fost acum 1 zi(e). începutul a fost {"days":1,"hours":12,"minutes":0} începutul a fost acum 1 zi, 12 ore
Nu este greu de imaginat toate felurile în care acestea ar putea fi folosite pentru a prezenta date mai citite de om.
Deplasarea în jur.
Aceste tipuri de funcții pot fi, de asemenea, bine încapsulate. Am câteva idei despre crearea unor funcții comune care ar putea intra în biblioteca noastră JSExtend, prin ceva de genul Luxon.pas. Iată câțiva concurenți. Ce funcții crezi că ar putea fi utile?
funcția TForm1.ConvertTimezone(aDateTime: TDateTime; TZ: String): TDateTime; var ayear, amonth, aday, ahour, aminute, asecond, amilisecond: word; ÎNCEPE DecodeDateTime(aDateTime, ayear, month, aday, ahour, aminute, asecond, amilisecundă); asm var lDateTime = new luxon.DateTime.local(ayear, month, aday, ahour, aminute, asecond, amillisecond).setZone(TZ); ayear = lDateTime.year; luna = lDateTime.month; aday = lDateTime.day; ahour = lDateTime.hour; aminute = lDateTime.minute; asecond = lDateTime.second; amilisecundă = lDateTime.milisecundă; Sfârşit; Rezultat := EncodeDateTime(un an, o lună, o zi, o oră, un minut, o secundă, amilisecundă); Sfârşit; procedura TForm1.WebButton1Click(Expeditor: TObject); var olddate, newdate: TDateTime; ÎNCEPE data veche := EncodeDateTime(2022, 5, 22, 12, 13, 14, 0); data noua := ConvertTimeZone(data veche, 'Europa/Paris'); console.log(FormatDateTime('aaaa-mmm-zz hh:nn:ss',data veche)); console.log(FormatDateTime('aaaa-mmm-zz hh:nn:ss',newdate)); Sfârşit; // ieșire console.log: 22-mai-2022 12:13:14 22-mai-2022 21:13:14 funcția TForm1.HumanDifference(nowDateTime: TDateTime; thenDateTime: TDateTime): String; var ayear, amonth, aday, ahour, aminute, asecond, amilisecond: word; byear, blună, zi, bhour, bminut, bsecundă, bmilisecundă: cuvânt; ÎNCEPE DecodeDateTime(nowDateTime, ayear, month, aday, ahour, aminute, asecond, amilisecundă); DecodeDateTime(thenDateTime, byear, bmonth, bday, bhour, bminute, bsecond, bmilisecundă); asm var aDateTime = new luxon.DateTime.local(ayear, month, aday, ahour, aminute, asecond, amilisecond); var bDateTime = new luxon.DateTime.local(byear, bmonth, bday, bhour, bminute, bsecond, bmilisecundă); Rezultat = aDateTime.diff(bDateTime, ['days','hours']).toHuman()+'acum'; Sfârşit; Sfârşit; procedura TForm1.WebButton1Click(Expeditor: TObject); var olddate, newdate: TDateTime; ÎNCEPE data veche := EncodeDateTime(2022, 5, 21, 06, 13, 14, 0); data noua := EncodeDateTime(2022, 5, 22, 12, 13, 14, 0); // 30 de ore mai târziu console.log(HumanDifference(data noua, data veche)); Sfârşit; // ieșire console.log: acum 1 zi, 6 ore
Ramas fara timp!
Cred că aproximativ acoperă cel puțin elementele de bază ale Luxon și utilizarea lui pentru a vă ajuta să vă îmbunătățiți proiectele TMS WEB Core. Sper că ați găsit acest lucru util și că puteți profita cu ușurință de Luxon în propriile proiecte, cu orice sisteme de localizare/internaționalizare/numerotare care vi se întâmplă!
Andrew Simard.