Data si timpul in JavaScript
Cum lucram cu data calendaristica in JavaScript
Despre obiectul Data
Faceti urmatorul calcul:
let acum = Date.now();
// impartim la 1000 (rotunjim)
let s = Math.round(acum / 1000);
// impartim apoi la 60 de doua ori
let m = Math.round(s / 60);
let h = Math.round(m / 60);
// mai impartim o data la 24
let z = Math.round(h / 24);
// si la final mai impartim si la 365
let a = Math.round(z / 365);
// apoi scadem rezultatul din anul curent
let start = (new Date()).getFullYear() - a;
// Ar trebui sa obtinem 1970
Un obiect de tipul Date are un numar intern (o primitiva) care specifica timpul scurs de la 1 ianuarie 1970 UTC
(in milisecunde). Calculele de mai sus ne vor duce intotdeauna la anul 1970
pentru ca este chiar definitia datei
in JavaScript.
Printr-un obiect de tipul Date, avem la dispozitie metode care ne permit afisarea si conversia datei in diferite formate.
Timezone
Am vazut mai sus momentul genezei in JavaScript: 1 ianuarie 1970 UTC
. Ce-i cu acel UTC
agatat de o data, de altfel, normala?
Intern, JavaScript mentine valorile in UTC ( Coordinated Universal Time ), insa functiile de manipulare a datei lucreaza cu timpul local (adica ia in calcul timpul dat de sistemul de operare).
Fiecare dintre noi ne uitam la ceas (…ul de la telefon) si citim: 8 AM
sau 8 dimineata
.
Indiferent unde suntem pe glob, cand zicem 8 AM
, este dimineata chiar daca in partea opusa a pamantului e noapte; acolo poate este ora 8 PM
. Acestea sunt datele locale (local time
).
Acum sa ne gandim ca sunam pe cineva dintr-o tara care are alt timezone. La finalul convorbirii stabilim sa ne auzim din nou la ora 21:00. Va trebui sa-l intrebam cat e ora la el, sa ne gandim cate ore sunt pana la ora 21 (in timpul local) apoi sa adunam acel numar la ora curenta din tara lui si ii comunicam ora de intalnire.
O alta alternativa ar fi sa comunicam in acelasi limbaj al timpului, cum ar fi UTC
.
De multe ori exista confuzie intre
UTC
siGMT
(Greenwich Mean Time), ceea ce este si normal, pentru ca indica acelasi moment. Definitiile sunt diferite: GMT indica ora 12:00 cand soarele este la cel mai inalt punct deasupra Observatorului Regal Greenwich din Londra. GMT este un punct de referinta pentru toate celelalte zone (GMT+2
). UTC-ul este masurat atomic.
Ca o curiozitate, din cauza rotatiilor pamantului, secundele nu sunt egale in GMT. In UTC toate secundele au aceeasi lungime (fiind masurate atomic) iar ca sa nu se decaleze fata de GMT cu mai mult de o secunda, sunt introduse asa numitele leap seconds din cand in cand. (la 6 luni se anunta daca se adauga sau nu o secunda la UTC; de exemplu, din 2017 nu s-a mai adaugat, insa in 2015 si 2016 au fost adaugate aceste leap seconds).
In JavaScript lucram cu UTC nu cu GMT.
Cand lucram cu Date/Time ne mai lovim si de DTS (Daylight Savings Time). O mai denumim ora de vara/ora de iarna. Obiectul Date in JavaScript nu mentine intern nimic legat de DTS, pur si simplu e o valoare in milisecunde de la
1 ianuarie 1970
, insa daca afisam data ca string, de exemplu, aceasta va lua in calcul timpul sistemului, deci va tine cont de DTS.
Crearea unei variabile de tipul Date
Pentru a lucra cu Date/Time avem functia constructor Date()
pusa la dispozitie de limbaj.
let d1 = new Date();
// Fri Apr 03 2020 23:33:45 GMT+0300 (Eastern European Summer Time)
let d2 = new Date('2019-10-21');
// Mon Oct 21 2019 03:00:00 GMT+0300 (Eastern European Summer Time)
let d2e = new Date('2019-21-10');
// Invalid Date
Observam ca nu este permisa construirea unei date folosind un string cu formatul yyyy-dd-mm
.
Trebuie sa fim atenti cu datele care pot provoca confuzie si erori in aplicatie, cum ar fi 2012-10-12
; este 10 decembrie
sau 12 octombrie
.
ISO 8601
Exista un standard care ne ajuta sa evitam confuziile de genul celei evidentiate mai sus (2012-10-12
). Acesta este standardul
ISO 8601
pentru Date/Time:
Date 2020-04-04
Date and time in UTC 2020-04-04T09:07:50+00:00 // +00 sau Z este acelasi lucru
2020-04-04T09:07:50Z // UTC time (fara offset)
ISO foloseste pentru ore sistemul 24h
. O zi incepe cu ora 00
si se termina cu 23
; ora 24
care este folosit pentru a indica miezul noptii la nivelul unei zile calendaristice.
Alte exemple ISO:
hh:mm:ss.sss sau hhmmss.sss
hh:mm:ss sau hhmmss
hh:mm sau hhmm
hh
Specificarea orei in sistemul UTC:
<time>Z // timpul UTC
<time>±hh:mm // cu offset (timezone)
<time>±hhmm
<time>±hh
Ora specificata in UTC pentru timezone-ul Romaniei (Bucuresti): 2020-10-21T22:10+02:00
. Asta inseamna ca am specificat ora locala din Romania 22:10
. Adica ora in UTC
va fi 20:00
:
let d3 = new Date(`2020-10-21T22:10+02:00`);
d3.getUTCHours(); // 20
Conventiile ISO pentru formatul datei:
valoare ISO | definitie |
---|---|
YYYY | anul in format cu 4 digiti |
MM | luna (ianuarie = 01, decembrie = 12 ) |
DD | ziua lunii (0 - 31) |
- | delimitator data |
T | la dreapta lui T se afla timpul |
HH | orele (0 - 23) |
mm | minute (0 - 59) |
ss | secunde (0 - 59) |
sss | milisecunde (0 - 999) |
: | delimitator timp |
Z | Z la final indica timpul in format UTC. Lipsa lui Z indica timpul local |
Atentie la crearea unei variabile de tipul Date din forma simplificata:
let d4 = new Date(`2010-10-14`);
Daca sunteti in New York (GMT-5 de exemplu) data va avea valoarea
Thu Oct 13 2010 19:00:00 GMT-0500
. Daca suntem in Romania valoarea zilei se pastreaza:Thu Oct 14 2010 03:00:00 GMT+0300
Asta se intampla pentru ca nu am specificat timpul, iar JavaScript creeaza variabila in formatul UTC. Deci, daca vrem sa cream o data in timpul local, va trebui sa specificam si timpul (chiar daca nu ne intereseaza in apicatie, este de ajuns sa punem momentul 0 al zilei:
00:00:00
).
Vom crea o noua data astfel:
let d5 = new Date('2010-10-14T00:00');
Pentru Bucuresti avem valoarea Thu Oct 14 2010 00:00:00 GMT+0300
care in UTC se traduce astfel:
let d6 = new Date('2010-10-14T00:00');
d6.toUTCString(); // 'Wed, 13 Oct 2010 21:00:00 GMT'
Persoana care locuieste in New York va crea o data cu timpul local specificat, chiar daca JavaScript stocheaza intern valoarea in UTC:
let d6ny = new Date('2010-10-14T00:00');
console.log(d6ny); // 'Thu Oct 14 2010 00:00:00 GMT-0500'
d6ny.toUTCString(); // 'Thu, 14 Oct 2010 05:00:00 GMT'
Deci cand timpul local in New York este 00:00
, la Greenwich este ora 05:00
, adica data in format UTC este
Thu, 14 Oct 2010 05:00:00 GMT
Alte moduri de creare a datelor
Am vazut cum cream variabile Date/Time folosind string-uri. Din cauza erorilor ce pot aparea datorita modului in care browser-ele pot interpreta string-urile de initializare, un mod mai bun de a initializa o data este sa folosim parametri dedicati pentru an, luna, zi, ora, etc. Sau putem folosi timestamps care, la fel, nu provoaca confuzie.
let d7 = new Date(2010, 10, 24, 10, 30, 00);
// new Date(yyyy, mm, dd, hh, mm, ss)
Daca verificati data returnata de d7
avem rezultatul Wed Nov 24 2010 10:30:00 GMT+0200
.
Daca nu observati nimic ciudat, mai uitati-va o data la luna:
Nov
. Luna este specificata pornind de la 0 la 11 (Ianuarie - 0, Decembrie - 11).
Nu uitam ca daca folosim stringuri ISO nu este la fel:
let d7iso = new Date('2010-10-24T10:30:00');
console.log(d7iso);
// 'Sun Oct 24 2010 10:30:00 GMT+0300'
Orice data creata cu constructorul Date()
, folosind parametri, va fi considerat timp local:
let d8 = new Date(2010, 10, 24);
console.log( d8 ); // 'Wed Nov 24 2010 00:00:00 GMT+0200'
console.log( d8.toUTCString() ); // 'Tue, 23 Nov 2010 22:00:00 GMT'
Daca totusi vrem sa cream date folosind UTC putem sa utilizam metoda UTC()
pusa la dispozitie pe obiectul Date
:
let d8utc = new Date( Date.UTC(2010, 10, 24) );
console.log( d8utc ); // 'Wed Nov 24 2010 02:00:00 GMT+0200'
console.log( d8utc.toUTCString() ); // 'Wed, 24 Nov 2010 00:00:00 GMT'
JavaScript stie acum ca am folosit UTC asa ca atunci cand afisam timpul local va adauga doua ore (pentru Romania); d8utc.toUTCString()
va afisa fix ce am trimis noi contructorului.
Putem crea o data care sa reprezinte timpul curent folosind contructorul fara parametri.
let d8now = new Date();
console.log(d8now); // 'Sat Mar 04 2020 17:47:38 GMT+0300'
Timestamps
Timestamp in JavaScript masoara milisecundele scurse de la 1 ianuarie 1970 UTC
.
Daca avem datele stocate in timestamps, putem crea un obiect de tipul Date folosindu-l ca parametru pentru constructorul Date()
:
let d9 = new Date(1290630600000);
console.log(d9); // 'Wed Nov 24 2010 22:30:00 GMT+0200'
Timestamps-urile sunt utile si pentru a compara doua date. Mai intai obtinem valoarea in milisecunde si apoi comparam aceste doua numere.
Putem obtine timestamp-ul folosind metoda getTime()
(Date.prototype.getTime
):
d0.getTime()
.
Aceeasi valoare o putem folosi cu valueOf()
care ne returneaza valoarea primitivei interne, este chiar timestamp-ul de care avem nevoie:
let d10a = new Date(2010, 10, 24);
let d10b = new Date(2010, 10, 26);
let d10a_ts = d10a.getTime(); // sau d10a.valueOf();
let d10b_ts = d10b.getTime(); // sau d10b.valueOf();
let diff_ts = d10b_ts - d10a_ts; // diferenta in milisecunde
let diff_h = Math.round( diff_ts / 1000 / 60 / 60 ); // diferenta in ore
console.log(diff_h); // 48
Mai sus am obtinut diferenta in ore intre doua date, transformandu-le in timestamps.
Problema: Cate zile au trecut de la data 12.12.2012
?
Putem folosi metoda Date.now()
ca sa aflam timestam-ul curent.
let d11now_ts = Date.now();
let d11then = new Date(2012,11,12); // nu uitam ca valoarea pentru luna incepe de la 0 - ianuarie
let d11then_ts = d11then.getTime(); // timestamp-ul - aceeasi valoare cu valueOf()
let z11 = Math.round( (d11now_ts - d11then_ts) / 1000 / 60 / 60 / 24 );
// 2671
valueOf()
este o metoda standard prezenta pe prototipul lui Object: Object.prototype.valueOf
. Constructorul Data
are implementata o varianta specifica pentru lucrul cu Date/Time, adica Date.prototype.valueOf
returneaza valoarea interna a primitivei, adica timestamp-ul. In cazul nostru poate inlocui utilizarea lui getTime()
, care este metoda recomandata pentru obtinerea valorii timestamp.
Varianta la calculul de sus:
let d12now_ts = Date.now(); // timestamp
let d12then = new Date(2012,11,12); // 'Wed Dec 12 2012 00:00:00 GMT+0200'
let z12 = Math.round( (d12now_ts - d12then) / 1000 / 60 / 60 / 24 );
// 2671
Un calcul in minus si aceeasi valoare ca rezultat. Functioneaza si daca inlocuim timestamp-ul curent cu data curenta, adica in loc de Date.now()
utilizam new Date()
:
let d13now = new Date(); // 'Sat Apr 04 2020 18:17:37 GMT+0300'
let d13then = new Date(2012,11,12); // 'Wed Dec 12 2012 00:00:00 GMT+0200'
let z12 = Math.round( (d13now - d13then) / 1000 / 60 / 60 / 24 );
// 2671
d13now - d13then
returneaza automat diferenta dintre timestamp-uri. Se intampla asta pentru ca folosim doua tipuri de date referinta intr-un context numeric iar JavaScript va apela intern functia valueOf
care returneaza exact timestamp.
Haideti acum sa adunam o saptamana (in milisecunde) la data de azi:
let weekMiliSeconds = 7 * 24 * 60 * 60 * 1000; // 7z*24h*60m*60s*1000ms = 604800000
let d14now = new Date(); // data de azi
// urmam procedeul de mai sus
let nextWeekDate_ts = d14now + weekMiliSeconds; // timestamp-ul peste o saptamana (!)
let nextWeekDate = new Date(nextWeekDate_ts);
Rezultatul final nu este ceea ce asteptam:
"Sat Apr 04 2020 18:42:40 GMT+0300 (Eastern European Summer Time)604800000"
Este o concatenare intre data curenta ca string si timestampul transformat in string.
Aici valueOf()
nu ne ajuta pentru ca avem un string + number
care prin mecanismul de coercion (conversie implicita) al lui javascript ajunge sa concateneze string + string
:
Putem simplifica ce se intampla prin codul de mai jos:
console.log("200" - 10); // 190
console.log("200" + 10); // 20010
Cum putem rezolva problema cu adunarea unei saptamani?
let weekMiliseconds = 7 * 24 * 60 * 60 * 1000; // 7z*24h*60m*60s*1000ms = 604800000
let d14now = new Date(); // data de azi
// let nextWeekDate_ts = d14now + weekMiliseconds; // (!) concatenare intre string si number = string
// fortam context numeric pentru d14now
// acum se forteaza apelarea interna a lui valueOf pentru d14now
let nextWeekDate_ts = +d14now + weekMiliseconds;
// a doua varianta foloseste explicit getTime() ( sau valueOf() )
let nextWeekDate_ts_v2 = d14now.getTime() + weekMiliseconds;
let nextWeekDate = new Date(nextWeekDate_ts); // 'Sat Apr 11 2020 18:53:17 GMT+0300'
let nextWeekDate_v2 = new Date(nextWeekDate_ts_v2); // 'Sat Apr 11 2020 18:53:17 GMT+0300'
Formatarea pentru afisare
Nu putem specifica in JavaScript un format de tipul ‘dd MM yyyy’ (nu vorbim aici de utilizarea altor librarii, precum
Moment.js
, care are o metoda format()
). In JavaScript avem la dispozitie obiectul Intl.DateTimeFormat
pe al carui prototip exista metoda format()
care chiar daca nu functioneaza cu string-uri de formatare precum dd MM yyyy
, ne ajuta cu formatarea datelor. O sa-i dedicam o sectiune separata mai spre finalul articolului.
Sa vedem cateva exemple de afisari standard implicite:
let d15 = new Date(2012, 9, 24);
d15.toString()
// "Wed Oct 24 2012 00:00:00 GMT+0300 (Eastern European Summer Time)"
d15.toDateString()
// "Wed Oct 24 2012"
d15.toTimeString()
// "00:00:00 GMT+0300 (Eastern European Summer Time)"
d15.toUTCString()
// "Tue, 23 Oct 2012 21:00:00 GMT"
d15.toGMTString()
// "Tue, 23 Oct 2012 21:00:00 GMT"
d15.toISOString()
// "2012-10-23T21:00:00.000Z"
d15.toLocaleString()
// "10/24/2012, 12:00:00 AM"
d15.toLocaleDateString()
// "10/24/2012"
d15.toLocaleTimeString()
// "12:00:00 AM"
Functiile toLocale
ne permit intr-o oarecare masura configurarea modului de afisare al datelor.
De exemplu:
let d15base = new Date(2012, 9, 24);
const options = { weekday: 'Long', year: 'numeric', month: 'long', day: 'numeric' };
let d15final = d15base.toLocaleDateString('ro-RO', options);
console.log(d15base); // Wed Oct 24 2012 00:00:00 GMT+0300
console.log(d15final); // miercuri, 24 octombrie 2012
Control total al formatarii
Sa vedem cum putem prelua controlul modului de afisare. Practic putem sa ne construim singuri o functie care sa se ocupe de modurile custom care poate nu sunt puse la dispozitie de JavaScript si obiectele lui.
Daca unul din aceste moduri de afisare sunt de ajuns, atunci le putem utiliza si am scapat de problema cu efort minim, altfel ar trebui sa folosim metodele care ne ofera valorile pentru an, luna, zi, ora, etc.
Sa zicem ca avem nevoie de formatul custom dd month yyyy
, adica 24 octombrie 2012
.
Sa vedem ce avem la dispozitie de la JavaScript:
let d16 = new Date(2012, 9, 24);
// pentru a obtine ziua
let z16 = d16.getDate(); // 24
// pentru a obtine anul
let y16 = d16.getFullYear(); // 2012
// pentru a obtine luna
let m16 = d16.getMonth(); // 9 - nu este ce am cerut
Pentru a obtine luna ca denumire ar trebui sa avem o functie/obiect/array care sa faca corespondenta intre luna ca numar si luna ca denumire:
const getMonthAs = (monthNumber = 0, type = 0) => {
// type = 0: Ianuarie
// type = 1: Ian
let fullNames = ['Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie'];
// vom implementa doar primul tip
switch (type) {
case 0:
default:
return fullNames[monthNumber];
}
}
Acum avem tot ce ne trebuie ca sa formatam data in formatul dorit. Mai intai vom incepe o functie formatter
:
const formatData = (data, format) => {
switch (format) {
case 'dd month yyyy':
default:
return `${ data.getDate() } ${ getMonthAs( data.getMonth(), 0) } ${ data.getFullYear() }`;
}
}
Acum utilizam functia de formatare a datelor:
let d16 = new Date(2012, 9, 24);
formatDataAs(d16, 'dd month yyyy'); // "24 Octombrie 2012"
Cum comparam doua date?
Vom defini doua date diferite si le comparam:
let d17a = new Date(2012, 9, 24);
let d17b = new Date(2012, 9, 28);
console.log( d17a < d17b ); // true
console.log( d17a > d17b ); // false
console.log( d17a == d17b ); // false
Sa rulam acum urmatorul cod:
let d18a = new Date(2012, 9, 24);
let d18b = new Date(2012, 9, 24);
console.log( d18a == d18b ); // (!) false
console.log( d18a > d18b ); // false
console.log( d18a < d18b ); // (!) false
Se pare ca atunci cand cream doua date care ne asteptam sa fie egale, niciun comparator nu le multumeste.
Insa mai avem doi operatori de verificat: <=
si >=
console.log( d18a <= d18b ); // true
console.log( d18a >= d18b ); // true
Deci daca cele doua conditii sunt adevarate, atunci datele sunt egale (!). Nu prea ne place modul asta de a verifica daca doua date sunt egale, asa ca vrem sa mai verificam ceva:
console.log( d18a.getTime() === d18b.getTime() ); // true (timestamp = 1351026000000)
// sau
console.log( +d18a === +d18b ); // true
// inducem un context numeric, deci fortam utilizarea functiei valueOf (adica timestamp-urile)
// echivalent cu
console.log( d18a.valueOf() === d18b.valueOf() )
Putem sa facem o functie care sa ne ajute cu verificarea egalitatii datelor:
const equalDates = (d1, d2) => {
return d1.getTime() === d2.getTime()
}
console.log( equalDates(d18a, d18b) );
Modificari ale datelor
Avem mai multe metode prin care putem sa alteram obiectele de tip Date/Time.
d18a.setDate(25);
console.log(d18a); // 'Thu Oct 25 2012 00:00:00 GMT+0300'
Functiile de actualizare returneaza o valoare timestamp cu noua valoare a datei:
let rez = d18a.setDate(25);
console.log(rez); // 1351112400000
Alte metode utile pentru modificarea datelor:
var d = new Date(2020, 01, 31);
d.setFullYear(2021);
d.setMonth(10);
d.setDate(30);
d.setHours(21);
d.setMinutes(15);
d.setSeconds(00);
d.setMilliseconds(500);
// deprecated
d.setYear(80); // returneaza anul 1980
// versus
d.setFullYear(80); // se refera la anul 80
Pentru fiecare dintre aceste metode, exista in oglinda varianta UTC (cu exceptia lui setYear()
):
var d = new Date(2020, 01, 31);
d.setUTCFullYear(2021);
d.setUTCMonth(10);
d.setUTCDate(30);
d.setUTCHours(21);
d.setUTCMinutes(15);
d.setUTCSeconds(00);
d.setUTCMilliseconds(500);
Adunari cu Date/Time
Am vazut mai sus un exemplu in care am adunat o saptamana la data curenta. Am calculat cate milisecunde sunt intr-o saptamana si am adunat la data curenta, ca timestamp. Mai departe stim sa obtinem o data daca avem timestamp-ul:
let d = new Date(timestamp);
Sa vedem acum alte moduri de rezolvare a aceleiasi probleme: adunarea unei saptamani la o anumita data. Similar cu adunarea/scaderea zilei putem sa utilizam aceleasi tehnici pentru ani, luni, ore, minute, etc.
// sa adunam 7 zile la data '24 octombrie 2012'
let d19base = new Date(2012, 9, 24);
// am vazut ca putem folosi metodele set pentru modificarea unui obiect Date
// vom crea o noua data pornind de la data de baza
let d19final = new Date(d19base);
// acum putem adauga linistiti 7 zile la d19final
d19final.setDate( d19base.getDate() + 7 ); // d19base ramane nealterat
console.log( d19final ); // 'Wed Oct 31 2012 00:00:00 GMT+0200'
Similar cu a aduna zile, putem aduna orice alte unitati (ore, minute, luni, …).
Daca ne uitam la rezultatul final (Wed Oct 31 2012
) pare ca am fost atenti sa nu depasim luna octombrie cand am adaugat numarul de zile (24 + 7 = 31
).
Haideti sa vedem ce se intampla daca in loc de 7 adunam 10 zile la aceeasi data. Deci vrem sa facem calculul:
24 octombrie 2012 + 10 zile
34 octombrie
nu exista. Sa vedem cum se descurca JavaScript cu asta:
let d20base = new Date(2012, 9, 24);
let d20final = new Date(d20base);
d20final.setDate( d20base.getDate() + 10 );
console.log(d20final); // 'Sat Nov 03 2012 00:00:00 GMT+0200'
Nu trebuie sa ne facem griji cu aceste depasiri, JavaScript se ocupa de asta (macar atat …).
O alta abordare pentru aceeasi problema:
let d21base = new Date(2012, 9, 24);
// Extragem fiecare valoare in parte
const y = d21base.getFullYear();
const m = d21base.getMonth();
const z = d21base.getDate();
// Cream o noua data cu adunarea saptamanii facuta in constructor
const d21final = new Date(y, m, z + 7);
console.log(d21final); // 'Wed Oct 31 2012 00:00:00 GMT+0200'
Am vazut trei moduri prin care putem face operatii de adunare/scadere cu tipul Date:
-
transformarea in timestamp-uri
-
utilizarea metodelor
set
-
crearea unei noi date cu calculele facute in constructor
Metoda
Date.now()
utilizata in articol nu e suportata de IE<8.
Sa implementam afisare custom pentru dd-mm-yyyy
Pentru solutii de afisare custom aveti la dispozitie intregul limbaj JavaScript si in functie de cerinte alegeti ce vi se potriveste. De exemplu, vrem sa imbunatatim functia de formatare a datei inceputa ceva mai sus.
Vrem sa adaugam posibilitatea sa putem formata o data ca dd-mm-yyyy
( 24-10-2012
).
Imbunatatim functia:
const formatData = (data, format) => {
switch (format) {
case 'dd-mm-yyyy':
return `${ data.getDate() }-${ data.getMonth()+1 }-${ data.getFullYear() }`;
case 'dd month yyyy':
default:
return `${ data.getDate() } ${ getMonthAs( data.getMonth(), 0) } ${ data.getFullYear() }`;
}
}
Simplu nu? Sa facem cateva teste (nu uitati sa rulati codul care creeaza functiile getMonthAs()
si formatData()
):
let d22 = new Date(2012, 9, 24);
console.log( formatData(d22) ); // 24 Octombrie 2012
console.log( formatData(d22, 'dd-mm-yyyy') ); // 24-10-2012
console.log( formatData(d22, 'dd month yyyy') ); // 24 Octombrie 2012
Gata. Sau mai putem imbunatati ceva? Parca ar mai trebui facut un test:
let d23 = new Date(2012, 5, 4);
console.log( formatData(d23) ); // 4 Iunie 2012
console.log( formatData(d23, 'dd-mm-yyyy') ); // 4-6-2012
console.log( formatData(d23, 'dd month yyyy') ); // 4 Iunie 2012
Nu mai avem doi digiti pentru zile/luni. Suntem multumiti de rezultat? Rezultatul pentru dd month yyyy
putem sa-l lasam asa cum este, insa in cazul formatarii dd-mm-yyyy
poate am putea sa imbunatatim putin afisarea. Ar cam trebui sa avem raspunsul:
04-06-2012
// un digit afisat ca doi digiti, precedat de 0
// 4 -> 04
const to2 = (d) => d <= 9 ? `0${d}` : `${d}`;
// utilizam to2() pentru zi si luna pe cazul 'dd-mm-yyyy'
const formatData = (data, format) => {
switch (format) {
case 'dd-mm-yyyy':
return `${ to2(data.getDate()) }-${ to2(data.getMonth()+1) }-${ data.getFullYear() }`;
...
}
}
let d23 = new Date(2012, 5, 4);
console.log( formatData(d23, 'dd-mm-yyyy') ); // 04-06-2012
Stocarea datelor
Cum persistam valorile de tip Date/Time? Este aproape obligatoriu ca serverul sa primeasca datele in format UTC. Putem trimite serverului un string in format standard ISO sau un timestamp.
Lasam browserul sa se ocupe de afisarea datelor in timpul local iar serverele trebuie sa foloseasca UTC.
In JavaScript putem utiliza functiile toJSON()
sau toISOString()
:
let d24 = new Date(2012, 9, 24, 22, 30);
let d24iso = d24.toISOString();
let d24json = d24.toJSON();
console.log( d24iso ); // 2012-10-24T19:30:00.000Z
console.log( d24json ); // 2012-10-24T19:30:00.000Z
Intl.DateTimeFormat
De ceva timp avem la dispozitie un obiect util pentru formatarea tipurilor Date: Intl: DateTimeFormat
.
IE 10 si mai jos nu au access la acest obiect. Edge il are implementat, iar versiunile Chrome/Firefox mai noi de 2013/2014 au, deasemenea, access la el.
Pe obiectul global gasim obiectul Intl
. Pe acest obiect mai gasim niste proprietati, printre care si Intl.DateTimeFormat
. Daca mergem mai departe gasim si Intl.DateTimeFormat.format()
.
Intl.DateTimeFormat
este o functie constructor ce ne ajuta sa formatam valorile Date/Time luand in calcul si limba sau tara pentru care se face afisarea.
Acum sa trecem la treaba. Mai intai sa privim un tabel cu valori, s-ar putea sa ne foloseasca in cod:
Property | Values |
---|---|
“weekday” | “narrow”, “short”, “long” |
“year” | “2-digit”, “numeric” |
“month” | “2-digit”, “numeric”, “narrow”, “short”, “long” |
“day” | “2-digit”, “numeric” |
“hour” | “2-digit”, “numeric” |
“minute” | “2-digit”, “numeric” |
“second” | “2-digit”, “numeric” |
“timeZoneName” | “short”, “long” |
Vom crea o data in format UTC si o vom afisa diferit in functie de tara:
const d25 = new Date( Date.UTC(2012, 9, 24, 8, 30) ); // '2012-10-24T08:30:00.000Z'
const d25en = new Intl.DateTimeFormat('en-US');
const d25ro = new Intl.DateTimeFormat('ro-RO');
const d25ja = new Intl.DateTimeFormat('ja-JP');
console.log(d25en.format(d25)); // 10/24/2012
console.log(d25ro.format(d25)); // 24.10.2012
console.log(d25ja.format(d25)); // 2012/10/24
Sa observam similitudinile cu functiile toLocale
de pe obiectul Date
:
const d26 = new Date( Date.UTC(2012, 9, 24, 8, 30) ); // '2012-10-24T08:30:00.000Z'
console.log( d26.toLocaleDateString('en-US') ); // 10/24/2012
console.log( d26.toLocaleDateString('ro-RO') ); // 24.10.2012
console.log( d26.toLocaleDateString('ja-JP') ); // 2012/10/24
console.log( d26.toLocaleString('en-US') ); // 10/24/2012, 11:30:00 AM
console.log( d26.toLocaleString('ro-RO') ); // 24.10.2012, 11:30:00
console.log( d26.toLocaleString('ja-JP') ); // 2012/10/24 11:30:00
console.log( d26.toLocaleTimeString('en-US') ); // 11:30:00 AM
console.log( d26.toLocaleTimeString('ro-RO') ); // 11:30:00
console.log( d26.toLocaleTimeString('ja-JP') ); // 11:30:00
Nu comparati rezultatele formatarilor cu string-uri statice pentru ca pot exista diferente de implementare intre browsere; pe unele poate functiona iar pe altele nu.
De exemplu:
"1/1/2020, 01:00:00" === new Date("2020-01-01T01:00:00Z").toLocaleString("en-US");
// true in Firefox
// false in IE/Edge/Chrome
Acum sa revenim la DateTimeFormat
. Daca avem o multime de formatari de facut, este recomandat sa construim un obiect de tipul Intl.DateTimeFormat
si sa-i utilizam metoda format()
. Este mai performant.
Atat functiile toLocale
de pe obiectul Date
cat si constructorul DateTimeFormat
pot primi ca al doilea parametru un obiect cu optiuni de formatare:
const d27 = new Date( Date.UTC(2012, 9, 24, 8, 30) ); // '2012-10-24T08:30:00.000Z'
// vezi tabelul de mai sus
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
const d27en = new Intl.DateTimeFormat('en-US', options);
const d27ro = new Intl.DateTimeFormat('ro-RO', options);
const d27ja = new Intl.DateTimeFormat('ja-JP', options);
console.log(d27en.format(d27)); // Wednesday, October 24, 2012
console.log(d27ro.format(d27)); // miercuri, 24 octombrie 2012
console.log(d27ja.format(d27)); // 2012年10月24日水曜日
Alte exemple:
const d28 = new Date( Date.UTC(2012, 9, 24, 2, 30) ); // '2012-10-24T02:30:00.000Z'
options = {
year: 'numeric', month: 'numeric', day: 'numeric',
hour: 'numeric', minute: 'numeric', second: 'numeric',
hour12: false,
timeZone: 'America/Los_Angeles'
};
const d28en_default = new Intl.DateTimeFormat('en-US');
const d28en_custom = new Intl.DateTimeFormat('en-US', options);
console.log(d28en_default.format(d28)); // 10/24/2012 - UTC ora 2:30 (chiar daca nu e afisat timpul)
console.log(d28en_custom.format(d28)); // 10/23/2012, 19:30:00 - aici avem timeZone deci GMT-7
Mai multe informatii despre obiectul Intl.DateTimeFormat
aici
Pentru functiile toLocale
de pe obiectul Data
urmati link-urile:
toLocaleString
,
toLocaleDateString
si
toLocaleTimeString
Daca prin documentatie intalniti functia
d.toLocaleFormat('%A, %B %e, %Y')
nu incercati sa o folositi. Face parte din trecutul indepartat al JavaScript. Este chiar inspirata din functiastrftime
a limbajuluiC
.
Share this post
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Pinterest
Email