Lad os se pÄ et andet indbygget objekt: Date. Det gemmer datoen, tiden og giver metoder til hÄndtering af dato/tid.
For eksempel kan vi bruge det til at gemme oprettelses-/Êndringstider, mÄle tid eller blot udskrive den nuvÊrende dato.
Oprettelse
For at oprette et nyt Date objekt kalder vi new Date() med en af fĂžlgende argumenter:
new Date()-
uden argumenter â opretter et
Dateobjekt med nuvĂŠrende dato og tid:let now = new Date(); alert( now ); // viser nuvĂŠrende dato/tid new Date(millisekunder)-
Opretter et
Dateobjekt med tiden lig med antallet af millisekunder (1/1000 af en sekund) der er gÄet efter 1. januar 1970 UTC+0.// 0 betyder 01.01.1970 UTC+0 let Jan01_1970 = new Date(0); alert( Jan01_1970 ); // tilfÞjer 24 timer, giver 02.01.1970 UTC+0 let Jan02_1970 = new Date(24 * 3600 * 1000); alert( Jan02_1970 );Et heltal der reprÊsenterer antallet af millisekunder der er gÄet siden 1. januar 1970 UTC+0 kaldes en timestamp (tidsstempel).
Det er en simpel numerisk reprĂŠsentation af en dato som heltal. Vi kan altid oprette en dato fra et timestamp ved hjĂŠlp af
new Date(timestamp)og konvertere et eksisterendeDateobjekt til et timestamp ved hjĂŠlp af metodendate.getTime()(se nedenfor).Datoer fĂžr 01.01.1970 har negative timestamps, e.g.:
// 31 Dec 1969 let Dec31_1969 = new Date(-24 * 3600 * 1000); alert( Dec31_1969 ); new Date(datestring)-
Hvis der sendes et enkelt argument og det er en streng, sÄ bliver den automatisk fortolket. Algoritmen er den samme som
Date.parsebruger â den ser vi pĂ„ senere.let date = new Date("2017-01-26"); alert(date); // Tiden er ikke defineret, sĂ„ det antages at vĂŠre midnat GMT og // justeres i forhold til tidszonen hvor koden kĂžres // SĂ„ resultatet kan vĂŠre // Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time) // eller // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) new Date(Ă„r, mĂ„ned, dag, timer, minutter, sekunder, millisekunder)-
Opretter et date objekt med de givne komponenter i den lokale tidszone. Kun de fĂžrste to argumenter er obligatoriske.
Ärskal have 4 tal. For kompatibilitet er to tal ogsÄ tilladt og betragtes som19xx. F.eks.98er det samme som1998. Men, brug af 4 tal er stÊrkt anbefalet.mÄnedtallet for mÄned starter fra0(Jan), op til11(Dec).dagparameteren er den aktuelle dag i mÄneden. Hvis den ikke gives sÊttes den til1.- Hvis
timer/minutter/sekunder/millisekunderikke gives, sĂŠttes de til0.
For eksempel, for at oprette et
Dateobjekt for 1. januar 2011 kl. 00:00:00, kan vi bruge:new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00 new Date(2011, 0, 1); // samme resultat, timer osv. er sat til 0 som standardMaksimal prĂŠcision er 1 ms (1/1000 sekund):
let date = new Date(2011, 0, 1, 2, 3, 4, 567); alert( date ); // 1.01.2011, 02:03:04.567
TilgÄ de enkelte komponenter i et dato objekt
Der er metoder til at tilgÄ Är, mÄned og sÄ videre fra et Date objekt:
- getFullYear()
- Henter Ärstallet (4 cifre)
- getMonth()
- Henter mÄneden, fra 0 til 11.
- getDate()
- Henter dagen i mÄneden, fra 1 til 31 (Metodens navn er lidt mÊrkeligt).
- getHours(), getMinutes(), getSeconds(), getMilliseconds()
- Henter de tilsvarende tidskomponenter.
getYear(), men getFullYear()Mange JavaScript motorer har implememnteret en ikke-standard metode ved navn getYear(). Denne metode er udfaset. Den returnerer ofte 2-cifret Är. Brug getFullYear() til at hente Ärstallet.
Derudover kan vi ogsÄ fÄ ugedagen:
- getDay()
- Henter ugedagen, fra
0(sĂžndag) til6(lĂžrdag). Den fĂžrste dag er som standard altid sĂžndag. I Danmark er det mandag der betragtes som fĂžrste ugedag, men det kan ikke ĂŠndres.
Alle metoderne ovenfor returnerer komponenterne i forhold til den lokale tidszone.
Der er ogsÄ deres UTC-modsvar, som returnerer dag, mÄned, Är og sÄ videre for tidszonen UTC+0: getUTCFullYear(), getUTCMonth(), getUTCDay(). Bare indsÊt "UTC" lige efter "get".
Hvis din lokale tidszone er forskellig fra UTC, sÄ viser koden nedenfor forskellige timer:
Hvis din lokale tidszone er forskellig fra UTC, sÄ viser koden nedenfor forskellige timer:
// nuvĂŠrende dato
let date = new Date();
// Timer i den lokale tidszone
alert( date.getHours() );
// Timer i UTC+0 tidszone (London tid uden sommertid)
alert( date.getUTCHours() );
Udover de givne metoder er der to specielle der ikke har en UTC-variant:
- getTime()
-
Returnerer en timestamp for datoen â det antal millisekunder der er gĂ„et fra 1. januar 1970 UTC+0.
- getTimezoneOffset()
-
Returnerer forskellen mellem UTC og den lokale tidszone, i minutter. For eksempel, hvis du er i tidszonen UTC-1, sÄ returnerer den
60(fordi UTC er 60 minutter foran). Hvis du er i tidszonen UTC+3, sÄ returnerer den-180(fordi UTC er 180 minutter bagud).:// hvis du er i tidszonen UTC-1, gives 60 // hvis du er i tidszonen UTC+3, gives -180 alert( new Date().getTimezoneOffset() );
SĂŠt de enkelte komponenter i et dato objekt
De fĂžlgende metoder tillader at sĂŠtte dato/tidskomponenter:
setFullYear(year, [month], [date])setMonth(month, [date])setDate(date)setHours(hour, [min], [sec], [ms])setMinutes(min, [sec], [ms])setSeconds(sec, [ms])setMilliseconds(ms)setTime(milliseconds)(sÊtter hele datoen baseret pÄ antal millisekunder siden 01.01.1970 UTC)
Hver af disse undtaget setTime() har en UTC-variant, for eksempel: setUTCHours().
Som vi kan se, kan nogle metoder sÊtte flere komponenter pÄ én gang, for eksempel setHours. De komponenter der ikke er nÊvnt Êndres ikke.
For eksempel:
let today = new Date();
today.setHours(0);
alert(today); // stadig dagen idag, men timer er ĂŠndret til 0
today.setHours(0, 0, 0, 0);
alert(today); // stadig dagen idag, men tiden er sat til 00:00:00.
Automatisk korrektion
autokorrektion er en praktisk feature af Date objekter. Vi kan sĂŠtte vĂŠrdier uden for det normale interval, og det vil automatisk justere sig.
For eksempel:
let date = new Date(2013, 0, 32); // 32 Jan 2013 ?!?
alert(date); // ...bliver til 1st februar 2013!
Datokomponenter uden for det normale interval distribueres automatisk.
Lad os sige at vi vil forĂžge datoen â28 Feb 2016â med 2 dage. Det kan vĂŠre â2 Marâ eller â1 Marâ i tilfĂŠldet af et skudĂ„r. Vi behĂžver ikke at tĂŠnke over det. Bare tilfĂžj 2 dage. Date objektet vil gĂžre resten:
let date = new Date(2016, 1, 28);
date.setDate(date.getDate() + 2);
alert( date ); // 1. marts 2016
Denne feature er ofte brugt til at fĂ„ datoen efter en given tidsperiode. For eksempel, lad os fĂ„ datoen for â70 sekunder efter nuâ:
let date = new Date();
date.setSeconds(date.getSeconds() + 70);
alert( date ); // viser den korrekte dato, 70 sekunder efter nu
Vi kan ogsÄ indstille nul eller endda negative vÊrdier. For eksempel, hvis vi sÊtter dag til nul, sÄ bliver det den sidste dag i den forrige mÄned:
let date = new Date(2016, 0, 2); // 2. januar 2016
date.setDate(1); // sÊt dagen til den 1. i mÄneden
alert( date );
date.setDate(0); // mindste dag er 1, sÄ 0 vil sÊtte den til sidste dag i mÄneden fÞr
alert( date ); // 31. december 2015
Date til tal kan bruges til at trĂŠkke datoer fra hinanden
NÄr et Date objekt konverteres til et tal, bliver det til en timestamp pÄ samme mÄde som date.getTime():
let date = new Date();
alert(+date); // antal millisekunder, samme som date.getTime()
En vigtig sideeffekt: datoer kan trĂŠkkes fra, og resultatet er deres forskel i millisekunder.
Det kan bruges til tidsmÄlinger:
let start = new Date(); // start mÄling af tid
// do the job
for (let i = 0; i < 100000; i++) {
let doSomething = i * i * i;
}
let end = new Date(); // slut tidsmÄling
alert( `Loopet tog ${end - start} ms at gennemfĂžre` );
Date.now()
Hvis vi kun vil mÄle tid, behÞver vi ikke hele Date objektet.
Der er en speciel metode Date.now() som returnerer den aktuelle timestamp.
Det er det samme som hvis du skriver new Date().getTime(), men det opretter ikke selve Date objektet. PÄ den mÄde er det en hurtigere metode uden at pÄvirke garbage collection.
Det bruges mest fordi det er bekvemmeligt og hvis hastighed er kritisk, som ved udvikling af spil eller andre specialiserede programmer.
SĂ„ viil dette nok vĂŠre bedre:
let start = Date.now(); // millisekunder tĂŠller fra 1. januar 1970
// UdfĂžr en hansling
for (let i = 0; i < 100000; i++) {
let doSomething = i * i * i;
}
let end = Date.now(); // fĂŠrdig
alert( `Loopet tog ${end - start} ms at gennemfĂžre` ); // trĂŠk de to tal fra hinanden
HastighedsmÄling (benchmarking)
Hvis vi Þnsker en pÄlidelig benchmark af en CPU-intensiv funktion, bÞr vi vÊre forsigtige.
For eksempel, lad os mÄle to funktioner der beregner forskellen mellem to datoer: hvilken er hurtigere?
SĂ„danne ydeevne-mĂ„linger kaldes ofte âbenchmarksâ.
// Vi har date1 og date2. Hvilken funktion er hurtigere til at returnere forskellen i ms?
function diffSubtract(date1, date2) {
return date2 - date1;
}
// eller mÄske denne?
function diffGetTime(date1, date2) {
return date2.getTime() - date1.getTime();
}
Disse to funktioner gÞr prÊcis det samme, men en af dem bruger et eksplicit date.getTime() for at fÄ datoen i millisekunder, og den anden bruger en dato-til-tal konvertering. Deres resultat er altid det samme.
SĂ„, hvilken er hurtigere?
Den fÞrste idé kan vÊre at kÞre dem mange gange i trÊk og mÄle tidsforskellen. For vores tilfÊlde er funktionerne meget simple, sÄ vi skal gÞre det mindst 100000 gange.
Lad os mÄle det:
function diffSubtract(date1, date2) {
return date2 - date1;
}
function diffGetTime(date1, date2) {
return date2.getTime() - date1.getTime();
}
function bench(f) {
let date1 = new Date(0);
let date2 = new Date();
let start = Date.now();
for (let i = 0; i < 100000; i++) f(date1, date2);
return Date.now() - start;
}
alert( 'Tiden for diffSubtract: ' + bench(diffSubtract) + 'ms' );
alert( 'Tiden for diffGetTime: ' + bench(diffGetTime) + 'ms' );
Wow! Brugen af getTime() er ret meget hurtigere! HovedÄrsagen er at der ikke er nogen konvertering af datatype, det er meget lettere for motorer at optimere.
Okay, vi er pÄ vej med noget. Men det er ikke en god benchmark endnu.
Forestil dig at der, mens bench(diffSubtract) kĂžrer, at CPUâen havde brug for at kĂžre noget parallelt der optog ressourcer. Hvad hvis den opgave sĂ„ var slut i den periode hvor bench(diffGetTime) kĂžrer?
Det er et meget realistisk scenarie i et moderne OS med flere porcesser der kĂžrer samtidig.
Resultatet vil vĂŠre at den fĂžrste benchmark vil have mindre CPU-ressourcer end den anden. Det kan fĂžre til forkerte resultater.
For en mere trovĂŠrdig benchmarking, bĂžr hele bunken af benchmarks blive kĂžrt flere gange.
For eksempel, som dette:
function diffSubtract(date1, date2) {
return date2 - date1;
}
function diffGetTime(date1, date2) {
return date2.getTime() - date1.getTime();
}
function bench(f) {
let date1 = new Date(0);
let date2 = new Date();
let start = Date.now();
for (let i = 0; i < 100000; i++) f(date1, date2);
return Date.now() - start;
}
let time1 = 0;
let time2 = 0;
// run bench(diffSubtract) and bench(diffGetTime) each 10 times alternating
for (let i = 0; i < 10; i++) {
time1 += bench(diffSubtract);
time2 += bench(diffGetTime);
}
alert( 'Total time for diffSubtract: ' + time1 );
alert( 'Total time for diffGetTime: ' + time2 );
Moderne JavaScript motorer er begyndt at udfĂžre avanceret optimering med fokus pĂ„ âhot codeâ der kĂžrer mange gange â der er sjĂŠldent behov for at optimere kode der bruges sjĂŠldent. SĂ„ i eksemplet ovenfor er de fĂžrste par afviklinger ikke godt optimerede. Vi Ăžnsker mĂ„ske at tilfĂžje en âheat-upâ kĂžrsel fĂžr den egentlige benchmark for at fĂ„ mere pĂ„lidelige resultater.:
// TilfĂžj en "opvarming" fĂžr loopet
bench(diffSubtract);
bench(diffGetTime);
// nu til benchmark
for (let i = 0; i < 10; i++) {
time1 += bench(diffSubtract);
time2 += bench(diffGetTime);
}
Moderne JavaScript motorer udfĂžrer mange optimeringer. De kan godt tweake âartificielle testsâ i forhold til ânormal brugâ, isĂŠr nĂ„r vi benchmarker noget meget lille, som hvordan en operator virker eller en indbygget funktion. SĂ„ hvis du Ăžnsker at forstĂ„ ydeevne, sĂ„ studĂ©r venligst hvordan JavaScript-motoren virker. Og sĂ„ vil du sandsynligvis ikke have brug for microbenchmarks overhovedet.
Der findes en god samling af artikler om V8 pÄ https://mrale.ph.
Date.parse fra en streng
Metoden Date.parse(str) kan lĂŠse en dato fra en streng.
Strengformatet skal vĂŠre: YYYY-MM-DDTHH:mm:ss.sssZ, hvor:
YYYY-MM-DDâ er datoen: Ă„r-mĂ„ned-dag.- Tegnet
"T"bruges som separator. HH:mm:ss.sssâ er tiden: timer, minutter, sekunder og millisekunder.- Den frivillige
'Z'del markerer tidszonen i formatet+-hh:mm. En enkeltkarakterZvil betyde UTC+0.
Kortere varianter er ogsÄ mulige, f.eks. YYYY-MM-DD eller YYYY-MM eller endda YYYY.
Kaldet til Date.parse(str) tolker strengen i det givne format og returnerer tidsstempel (antal millisekunder fra 1. januar 1970 UTC+0). Hvis formatet er ugyldigt, returneres NaN.
For eksempel:
let ms = Date.parse('2012-01-26T13:51:50.417-07:00');
alert(ms); // 1327611110417 (timestamp)
Vi kan med det samme oprette et new Date objekt fra tidsstempel:
let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') );
alert(date);
Opsummering
- Dato og tid i JavaScript er reprĂŠsenteret med Date objektet. Vi kan ikke oprette âkun datoâ eller âkun tidâ:
Dateobjekter bÊrer altid begge dele. - MÄneder tÊlles fra nul (ja, januar er mÄneden 0).
- Dagen pÄ ugen hentes med
getDay(). Den er ogsÄ talt fra nul (det er sÞndag). Dateautokorrigerer sig selv nÄr delkomponenter sÊttes. Det er praktisk for at tilfÞje eller trÊkke dage/mÄneder/timer fra hinanden.- Datoer kan trÊkkes fra hinanden, hvilket giver deres forskel i millisekunder. Det skyldes at et
Dateobjekt bliver et tidsstempel nÄr det konverteres til et tal. - Brug
Date.now()for hurtigt at fÄ det aktuelle tidsstempel.
BemĂŠrk at, ulig mange andre systemer, er tidsstempel i JavaScript i millisekunder, ikke sekunder.
Nogle gange har vi brug for en mere prÊcis mÄling af tid. JavaScript har ikke en mÄde at mÄle tid i mikrosekunder (1 milliontedel af en sekund), men de fleste miljÞer har det. For eksempel har browseren performance.now() som giver antallet af millisekunder fra starten af sideindlÊsningen med mikrosekund prÊcision (3 cifre efter kommaet):
alert(`Siden blev indlĂŠst for ${performance.now()}ms siden`);
// Noget i stil med: "Siden blev indlĂŠst for 34731.26000000001ms siden"
// .26 er mikrosekunder (260 mikrosekunder)
// mere end 3 cifre efter kommaet er prĂŠcisionsfejl, kun de fĂžrste 3 er korrekte
Node.js har microtime modulet og andre mÄder. NÊsten alle enheder har miljÞer tilgÊngeligt, der tillader stor prÊcision. Teknisk set tillader nÊsten enhver enhed og miljÞ at fÄ mere prÊcise mÄlinger, det er bare ikke i Date.
Kommentarer
<code>-taggen, for flere linjer - omslut dem i<pre>-tag, for mere end 10 linjer - brug en sandbox (plnkr, jsbin, codepenâŠ)