Datum a čas

Pojďme se seznámit s novým vestavěným objektem:Date. Ukládá datum, čas a poskytuje metody pro správu data/času.

Můžeme jej například použít k uložení časů vytvoření/úprav, k měření času nebo jen k vytištění aktuálního data.

Vytvoření

Chcete-li vytvořit nový Date volání objektu new Date() s jedním z následujících argumentů:

new Date()

Bez argumentů – vytvořte Date objekt pro aktuální datum a čas:

let now = new Date();
alert( now ); // shows current date/time
new Date(milliseconds)

Vytvořte Date objekt s časem rovným počtu milisekund (1/1000 sekundy) uplynulým po 1. lednu 1970 UTC+0.

// 0 means 01.01.1970 UTC+0
let Jan01_1970 = new Date(0);
alert( Jan01_1970 );

// now add 24 hours, get 02.01.1970 UTC+0
let Jan02_1970 = new Date(24 * 3600 * 1000);
alert( Jan02_1970 );

Celé číslo představující počet milisekund, které uplynuly od začátku roku 1970, se nazývá časové razítko. .

Je to odlehčená číselná reprezentace data. Vždy můžeme vytvořit datum z časového razítka pomocí new Date(timestamp) a převést existující Date objekt na časové razítko pomocí date.getTime() metoda (viz níže).

Data před 01.01.1970 mají záporná časová razítka, např.:

// 31 Dec 1969
let Dec31_1969 = new Date(-24 * 3600 * 1000);
alert( Dec31_1969 );
new Date(datestring)

Pokud existuje jediný argument a je to řetězec, je automaticky analyzován. Algoritmus je stejný jako Date.parse použití, probereme to později.

let date = new Date("2017-01-26");
alert(date);
// The time is not set, so it's assumed to be midnight GMT and
// is adjusted according to the timezone the code is run in
// So the result could be
// Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time)
// or
// Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time)
new Date(year, month, date, hours, minutes, seconds, ms)

Vytvořte datum s danými komponentami v místním časovém pásmu. Pouze první dva argumenty jsou povinné.

  • year musí mít 4 číslice. Z důvodu kompatibility jsou přijímány také 2 číslice a považovány za 19xx , např. 98 je stejný jako 1998 zde, ale důrazně se doporučuje používat vždy 4 číslice.
  • month počet začíná 0 (leden), až do 11 (prosinec).
  • date parametr je ve skutečnosti den v měsíci, pokud chybí, pak 1 se předpokládá.
  • Pokud hours/minutes/seconds/ms chybí, předpokládá se, že jsou rovny 0 .

Například:

new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00
new Date(2011, 0, 1); // the same, hours etc are 0 by default

Maximální přesnost je 1 ms (1/1000 s):

let date = new Date(2011, 0, 1, 2, 3, 4, 567);
alert( date ); // 1.01.2011, 02:03:04.567

Přístup ke komponentám data

Existují metody pro přístup k roku, měsíci a tak dále z Date objekt:

getFullYear()
Získejte rok (4 číslice)
getMonth()
Získejte měsíc od 0 do 11 .
getDate()
Získejte den v měsíci, od 1 do 31, název metody vypadá trochu divně.
getHours(), getMinutes(), getSeconds(), getMilliseconds()
Získejte odpovídající časové složky.
Ne getYear() , ale getFullYear()

Mnoho JavaScriptových motorů implementuje nestandardní metodu getYear() . Tato metoda je zastaralá. Někdy vrací 2-ciferný rok. Nikdy jej prosím nepoužívejte. Existuje getFullYear() za rok.

Navíc můžeme získat den v týdnu:

getDay()
Získejte den v týdnu z 0 (neděle) na 6 (Sobota). První den je vždy neděle, v některých zemích tomu tak není, ale nelze to změnit.

Všechny výše uvedené metody vracejí komponenty vzhledem k místnímu časovému pásmu.

Existují také jejich protějšky UTC, které vracejí den, měsíc, rok a tak dále pro časové pásmo UTC+0:getUTCFullYear(), getUTCMonth(), getUTCDay(). Stačí vložit "UTC" hned za "get" .

Pokud je vaše místní časové pásmo posunuto vzhledem k UTC, pak kód níže zobrazuje různé hodiny:

// current date
let date = new Date();

// the hour in your current time zone
alert( date.getHours() );

// the hour in UTC+0 time zone (London time without daylight savings)
alert( date.getUTCHours() );

Kromě uvedených metod existují dvě speciální, které nemají variantu UTC:

getTime()

Vrátí časové razítko pro datum – počet milisekund uplynulých od 1. ledna 1970 UTC+0.

getTimezoneOffset()

Vrátí rozdíl mezi UTC a místním časovým pásmem v minutách:

// if you are in timezone UTC-1, outputs 60
// if you are in timezone UTC+3, outputs -180
alert( new Date().getTimezoneOffset() );

Nastavení komponent data

Následující metody umožňují nastavit komponenty data/času:

  • 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) (nastaví celé datum po milisekundách od 01.01.1970 UTC)

Každý z nich kromě setTime() má variantu UTC, například:setUTCHours() .

Jak vidíme, některé metody mohou nastavit více komponent najednou, například setHours . Komponenty, které nejsou uvedeny, se nezmění.

Například:

let today = new Date();

today.setHours(0);
alert(today); // still today, but the hour is changed to 0

today.setHours(0, 0, 0, 0);
alert(today); // still today, now 00:00:00 sharp.

Automatická oprava

automatická oprava je velmi užitečná funkce Date objektů. Můžeme nastavit hodnoty mimo rozsah a sám se automaticky upraví.

Například:

let date = new Date(2013, 0, 32); // 32 Jan 2013 ?!?
alert(date); // ...is 1st Feb 2013!

Komponenty dat mimo rozsah jsou distribuovány automaticky.

Řekněme, že potřebujeme prodloužit datum „28. února 2016“ o 2 dny. Může to být „2 Mar“ nebo „1 Mar“ v případě přestupného roku. nemusíme o tom přemýšlet. Stačí přidat 2 dny. Date objekt udělá zbytek:

let date = new Date(2016, 1, 28);
date.setDate(date.getDate() + 2);

alert( date ); // 1 Mar 2016

Tato funkce se často používá k získání data po daném časovém období. Řekněme například datum „70 sekund poté“:

let date = new Date();
date.setSeconds(date.getSeconds() + 70);

alert( date ); // shows the correct date

Můžeme také nastavit nulové nebo dokonce záporné hodnoty. Například:

let date = new Date(2016, 0, 2); // 2 Jan 2016

date.setDate(1); // set day 1 of month
alert( date );

date.setDate(0); // min day is 1, so the last day of the previous month is assumed
alert( date ); // 31 Dec 2015

Datum k číslu, datum rozdíl

Když Date objekt se převede na číslo, stane se časovým razítkem stejným jako date.getTime() :

let date = new Date();
alert(+date); // the number of milliseconds, same as date.getTime()

Důležitý vedlejší efekt:data lze odečíst, výsledkem je jejich rozdíl v ms.

To lze použít pro měření času:

let start = new Date(); // start measuring time

// do the job
for (let i = 0; i < 100000; i++) {
 let doSomething = i * i * i;
}

let end = new Date(); // end measuring time

alert( `The loop took ${end - start} ms` );

Date.now()

Pokud chceme měřit pouze čas, nepotřebujeme Date objekt.

Existuje speciální metoda Date.now() který vrátí aktuální časové razítko.

Je sémanticky ekvivalentní new Date().getTime() , ale nevytváří mezilehlý Date objekt. Je tedy rychlejší a nevyvíjí tlak na svoz odpadu.

Používá se většinou pro pohodlí nebo když záleží na výkonu, jako jsou hry v JavaScriptu nebo jiné specializované aplikace.

Takže tohle je asi lepší:

let start = Date.now(); // milliseconds count from 1 Jan 1970

// do the job
for (let i = 0; i < 100000; i++) {
 let doSomething = i * i * i;
}

let end = Date.now(); // done

alert( `The loop took ${end - start} ms` ); // subtract numbers, not dates

Srovnávání

Pokud chceme spolehlivý benchmark funkcí náročných na CPU, měli bychom být opatrní.

Změřme například dvě funkce, které počítají rozdíl mezi dvěma daty:které z nich je rychlejší?

Taková měření výkonu se často nazývají „benchmarky“.

// we have date1 and date2, which function faster returns their difference in ms?
function diffSubtract(date1, date2) {
 return date2 - date1;
}

// or
function diffGetTime(date1, date2) {
 return date2.getTime() - date1.getTime();
}

Tyto dva dělají přesně to samé, ale jeden z nich používá explicitní date.getTime() získat datum v ms a druhý spoléhá na transformaci data na číslo. Jejich výsledek je vždy stejný.

Takže, který z nich je rychlejší?

První nápad může být spustit je mnohokrát za sebou a změřit časový rozdíl. V našem případě jsou funkce velmi jednoduché, takže to musíme udělat alespoň 100 000krát.

Pojďme měřit:

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( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' );
alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' );

Páni! Pomocí getTime() je mnohem rychlejší! Je to proto, že neexistuje žádná konverze typu, optimalizace pro motory je mnohem snazší.

Dobře, něco máme. Ale to ještě není dobré měřítko.

Představte si, že v době spuštění bench(diffSubtract) CPU něco dělal paralelně a ubíral zdroje. A v době spuštění bench(diffGetTime) že práce skončila.

Docela reálný scénář pro moderní víceprocesový OS.

Výsledkem je, že první benchmark bude mít méně prostředků CPU než druhý. To může vést k nesprávným výsledkům.

Pro spolehlivější srovnávání by měl být celý balík srovnávacích testů spuštěn několikrát.

Například takto:

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

Moderní JavaScriptové motory začínají uplatňovat pokročilé optimalizace pouze na „horký kód“, který se spouští mnohokrát (není třeba optimalizovat zřídka prováděné věci). Takže ve výše uvedeném příkladu nejsou první spuštění dobře optimalizována. Možná budeme chtít přidat zahřívací běh:

// added for "heating up" prior to the main loop
bench(diffSubtract);
bench(diffGetTime);

// now benchmark
for (let i = 0; i < 10; i++) {
 time1 += bench(diffSubtract);
 time2 += bench(diffGetTime);
}
Při mikrobenchmarkingu buďte opatrní

Moderní JavaScript motory provádějí mnoho optimalizací. Mohou vylepšit výsledky „umělých testů“ ve srovnání s „normálním použitím“, zvláště když srovnáváme něco velmi malého, například jak funguje operátor nebo vestavěnou funkci. Pokud tedy chcete vážně porozumět výkonu, prostudujte si prosím, jak funguje JavaScript engine. A pak pravděpodobně nebudete mikrobenchmarky vůbec potřebovat.

Velký balík článků o V8 lze nalézt na http://mrale.ph.

Date.parse z řetězce

Metoda Date.parse(str) dokáže přečíst datum z řetězce.

Formát řetězce by měl být:YYYY-MM-DDTHH:mm:ss.sssZ , kde:

  • YYYY-MM-DD – je datum:rok-měsíc-den.
  • Znak "T" se používá jako oddělovač.
  • HH:mm:ss.sss – je čas:hodiny, minuty, sekundy a milisekundy.
  • Volitelný 'Z' část označuje časové pásmo ve formátu +-hh:mm . Jedno písmeno Z by znamenalo UTC+0.

Možné jsou i kratší varianty, například YYYY-MM-DD nebo YYYY-MM nebo dokonce YYYY .

Volání na Date.parse(str) analyzuje řetězec v daném formátu a vrátí časové razítko (počet milisekund od 1. ledna 1970 UTC+0). Pokud je formát neplatný, vrátí NaN .

Například:

let ms = Date.parse('2012-01-26T13:51:50.417-07:00');

alert(ms); // 1327611110417 (timestamp)

Můžeme okamžitě vytvořit new Date objekt z časového razítka:

let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') );

alert(date);

Shrnutí

  • Datum a čas v JavaScriptu jsou reprezentovány objektem Date. Nemůžeme vytvořit „pouze datum“ nebo „pouze čas“:Date předměty vždy nesou obojí.
  • Měsíce se počítají od nuly (ano, leden je nula).
  • Dny v týdnu v getDay() se také počítají od nuly (to je neděle).
  • Date automaticky se opraví, když jsou nastaveny komponenty mimo rozsah. Dobré pro sčítání/odečítání dnů/měsíců/hodin.
  • Data lze odečíst a udělit jejich rozdíl v milisekundách. Je to proto, že Date se po převodu na číslo stane časovým razítkem.
  • Použijte Date.now() pro rychlé získání aktuálního časového razítka.

Všimněte si, že na rozdíl od mnoha jiných systémů jsou časová razítka v JavaScriptu v milisekundách, nikoli v sekundách.

Někdy potřebujeme přesnější měření času. JavaScript sám o sobě nemá způsob, jak měřit čas v mikrosekundách (1 miliontina sekundy), ale většina prostředí to poskytuje. Prohlížeč má například performance.now(), která udává počet milisekund od začátku načítání stránky s přesností na mikrosekundy (3 číslice za bodem):

alert(`Loading started ${performance.now()}ms ago`);
// Something like: "Loading started 34731.26000000001ms ago"
// .26 is microseconds (260 microseconds)
// more than 3 digits after the decimal point are precision errors, only the first 3 are correct

Node.js má microtime modul a další způsoby. Technicky téměř každé zařízení a prostředí umožňuje získat větší přesnost, jen to není v Date .


No