Познайомтеся з новим вбудованим об’єктом: Date. Він зберігає дату, час і надає методи для управління датою/часом.
Наприклад, ми можемо використовувати його для зберігання часу створення/модифікації, щоб виміряти час, або просто для друку поточної дати.
Створення
Щоб створити новий об’єкт Date викличемо new Date() з одним з наступних аргументів:
new Date()-
Без аргументів – створює об’єкт
Dateдля поточної дати та часу: new Date(milliseconds)-
Створює об’єкт
Dateз часом, що дорівнює кількості мілісекунд (1/1000 секунди), що минули після 1 січня 1970 UTC+0.Ціле число, яке являє собою кількість мілісекунд, що пройшли з початку 1970 року, називається міткою часу (timestamp).
Це легке числове представлення дати. Ми завжди можемо створити дату з timestamp за допомогою
new Date(timestamp)і перетворити об’єктDate, що існує, до timestamp за допомогою методуdate.getTime()(див. нижче).Дати до 01.01.1970 р. мають негативний timestamp, наприклад:
new Date(datestring)-
Якщо є єдиний аргумент, і це рядок, то він автоматично аналізується. Алгоритм той же, що використовує
Date.parse, ми розглянемо це пізніше.let date = new Date("2017-01-26"); alert(date); // Час не встановлений, тому припускається, що це буде північ за GMT і // регулюється відповідно до того часового поясу, де запускається код // Тому результат може бути // Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time) // або // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) new Date(year, month, date, hours, minutes, seconds, ms)-
Створює дату з заданими компонентами у місцевому часовому поясі. Тільки перші два аргументи обов’язкові.
yearмає містити 4 цифри. Для сумісності також допускаються 2 цифри, які вважаються19xx, напр.98тут те саме, що й1998, але настійно рекомендується завжди використовувати 4 цифри.- Рахунок місяців починається з
0(січня), до11(грудня). - Параметр
dateнасправді день місяця, якщо він відсутній, то береться1. - Якщо
hours/minutes/seconds/msвідсутні, вони вважаються рівними0.
Наприклад:
new Date(2011, 0, 1, 0, 0, 0, 0); // 1 січня 2011 року, 00:00:00 new Date(2011, 0, 1); // те ж саме, години тощо -- 0 за замовчуваннямМаксимальна точність становить 1 мс (1/1000 сек):
Доступ до компонентів дати
Існують методи доступу до року, місяця і так далі з об’єкта Date:
- getFullYear()
- Отримати рік (4 цифри)
- getMonth()
- Отримати місяць, від 0 до 11.
- getDate()
- Отримати день місяця, від 1 до 31, назва методу виглядає трохи дивно.
- getHours(), getMinutes(), getSeconds(), getMilliseconds()
- Отримати відповідні компоненти часу.
getYear(), а getFullYear()Багато рушіїв JavaScript реалізують нестандартний метод getYear(). Цей метод застарілий. Іноді він повертає 2-значний рік. Будь ласка, не використовуйте його. Щоб отримати рік є getFullYear().
Крім того, ми можемо отримати день тижня:
- getDay()
- Отримати день тижня, від
0(неділя) до6(субота). Перший день завжди неділя, в деяких країнах це не так, але ми не можемо змінити поведінку методу.
Всі методи, наведені вище, повертають компоненти відносно місцевого часового поясу.
Є також їхні UTC-аналоги, що повертається день, місяць, рік і так далі за часовим поясом UTC+0: getUTCFullYear(), getUTCMonth(), getUTCDay(). Просто вставте "UTC" відразу після "get".
Якщо ваш місцевий часовий пояс зміщений відносно UTC, то код нижче показує різні години:
Окрім наведених методів, є два спеціальних, які не мають UTC-варіанту:
- getTime()
-
Повертає timestamp для дати – кількість мілісекунд, що пройшли з 1 січня 1970 UTC+0.
- getTimezoneOffset()
-
Повертає різницю між UTC та місцевим часовим поясом, у хвилинах:
Налаштування компонентів дати
Наступні методи дозволяють встановити дату/часові компоненти:
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)(встановлює всю дату в мілісекундах з 01.01.1970 UTC)
Кожен з них, крім setTime() має UTC-аналог, наприклад: setUTCHours().
Як ми бачимо, деякі методи можуть встановити кілька компонентів відразу, наприклад setHours. Компоненти дати/часу, які не згадуються, – не модифікуються.
Наприклад:
Автокорекція
Автокорекція – це дуже зручна особливість об’єктів Date. Ми можемо встановити данні за межами діапазону, і вони будуть автоматично налаштувати себе.
Наприклад:
Компоненти поза межами діапазону розподіляються автоматично.
Скажімо, нам потрібно збільшити дату “28 лютого 2016” на 2 дні. Це може бути “2 березня” або “1 березня” у випадку високосного року. Нам не потрібно думати про це. Просто додайте 2 дні. Об’єкт Date зробить все інше:
Ця особливість часто використовується для отримання дати після певного проміжку часу. Наприклад, отримаймо дату “70 секунд після зараз”:
Ми також можемо встановити нуль або навіть негативні значення. Наприклад:
Перетворення дати до числа, різниця дат
Коли Date об’єкт перетворюється на номер, він стає timestamp так само, як date.getTime():
Важливий побічний ефект: дати можуть відніматися, результатом є їх різниця в мілісекундах.
Це можна використовувати для вимірювання часу:
Date.now()
Якщо ми хочемо тільки виміряти час, нам не потрібен об’єкт Date.
Існує спеціальний метод Date.now(), що повертає поточний timestamp.
Це семантично еквівалентно до new Date().getTime(), але не створює проміжного об’єкта Date. Так що цей підхід працює швидше і не навантажує збирач сміття.
Він використовується в основному для зручності або коли важлива продуктивність, як в іграх на JavaScript або інших спеціалізованих застосунках.
Отже, це, мабуть, краще:
Вимірювання швидкодії (Benchmarking)
Якщо ми хочемо достовірний аналіз швидкодії функції, що залежить від процесора, ми повинні бути обережними.
Наприклад, давайте вимірюємо дві функції, які обчислюють різницю між двома датами: яка з них швидше?
Такі вимірювання продуктивності часто називаються “бенчмарками”.
// У нас є date1 і date2. Яка функція швидше поверне їхню різницю в мс?
function diffSubtract(date1, date2) {
return date2 - date1;
}
// чи
function diffGetTime(date1, date2) {
return date2.getTime() - date1.getTime();
}
Ці дві функції роблять схожі речі, але одна з них використовує явний date.getTime(), щоб отримати дату в мс, а інша покладається на перетворення дати до числа. Їх результат завжди однаковий.
Отже, яка з цих функцій швидша?
Перша ідея полягає в тому, що можна багато разів запустити їх поспіль і виміряти різницю часу. Для нашого випадку функції дуже прості, тому ми повинні запустити їх щонайменше 100000 разів.
Вимірюємо:
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( 'Час diffSubtract: ' + bench(diffSubtract) + 'мс' );
alert( 'Час diffGetTime: ' + bench(diffGetTime) + 'мс' );
Оце так! Використання getTime() набагато швидше! Це тому, що немає перетворення типу, це набагато простіше для оптимізації.
Гаразд, у нас є щось. Але це ще не хороший бенчмарк.
Уявіть собі, що під час запуску bench(diffSubtract) процесор робив щось паралельно, і це забирало певні ресурси. І до часу роботи bench(diffGetTime) ця робота закінчилася.
Досить реальний сценарій для сучасної багатопроцесорної ОС.
Як результат, перший бенчмарк буде мати менше ресурсів процесора, ніж другий. Це може призвести до неправильних результатів.
Для більш достовірного порівняльного аналізу, весь пакет бенчмарків повинен бути повторно запущений кілька разів.
Наприклад, як це:
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;
// запустіть bench(diffSubtract) і bench(diffGetTime) кожен по 10 разів
for (let i = 0; i < 10; i++) {
time1 += bench(diffSubtract);
time2 += bench(diffGetTime);
}
alert( 'Загальний час для diffSubtract: ' + time1 );
alert( 'Загальний час для diffGetTime: ' + time2 );
Сучасні рушії JavaScript починають застосовувати передові оптимізації лише до “гарячого коду”, який виконує багато разів (не потрібно оптимізувати рідко виконані речі). Отже, у наведеному вище прикладі перші виконання не оптимізовані. Ми можемо захотіти додати “нагрівання”:
// додано для "нагрівання" до основного циклу
bench(diffSubtract);
bench(diffGetTime);
// тепер бенчмарк
for (let i = 0; i < 10; i++) {
time1 += bench(diffSubtract);
time2 += bench(diffGetTime);
}
Сучасні рушії JavaScript застосовують багато оптимізацій. Вони можуть підналаштувати результати “штучних тестів” у порівнянні з “нормальним використанням”, особливо коли ми тестуємо щось дуже мале, наприклад, як працює оператор, або вбудована функція. Отже, якщо ви серйозно хочете оцінити продуктивність, то, будь ласка, дослідіть, як працює рушій JavaScript. І тоді ви, мабуть, не потребуєте мікробенчмаркінгів взагалі.
Великий набір статей про V8 можна знайти на https://mrale.ph.
Date.parse з рядка
Метод Date.parse(str) може читати дату з рядка.
Формат рядка повинен бути: YYYY-MM-DDTHH:mm:ss.sssZ, де:
YYYY-MM-DD– це дата: рік-місяць-день.- Символ
"T"використовується як роздільник. HH:mm:ss.sss– це час: години, хвилини, секунди і мілісекунди.- Необов’язкова частина
'Z'позначає часовий пояс у форматі+-hh:mm. Одинична букваZбуде означати UTC+0.
Коротші варіанти також можливі, як YYYY-MM-DD або YYYY-MM або навіть YYYY.
Виклик Date.parse(str) аналізує рядок у заданому форматі та повертає timestamp (кількість мілісекунд з 1 січня 1970 UTC+0). Якщо формат недійсний, повертає NaN.
Наприклад:
Ми можемо миттєво створити об’єкт за допомогою new Date з timestamp:
Підсумки
- Дата та час у JavaScript представлені об’єктом Date. Ми не можемо створити “тільки дату” або “тільки час”: об’єкти
Dateзавжди несуть в собі обидва значення. - Місяці рахуються з нуля (так, січень – це нульовий місяць).
- Дні тижня в
getDay()також рахуються з нуля (з неділі). Dateавтоматично виправляє себе, коли встановлено компоненти, які виходять за межі. Це добре для додавання/віднімання днів/місяців/годин.- Дати можуть відніматися, даючи їхню різницю в мілісекундах. Це тому, що
Dateстає timestamp, коли перетворюється на число. - Використовуйте
Date.now(), щоб швидко отримати поточний timestamp.
Зауважте, що на відміну від багатьох інших систем, значенния timestamp в JavaScript вимірюється в мілісекундах, а не в секундах.
Іноді нам потрібно більш точні вимірювання часу. Сам JavaScript не має способу вимірювання часу в мікросекундах (1 мільйон у секунду), але більшість середовищ забезпечують його. Наприклад, браузер має performance.now(), що дає кількість мілісекунд з початку завантаження сторінки з мікросекундною точністю (3 цифри після крапки):
Node.js має модуль microtime та інші способи. Технічно, майже будь-який пристрій та середовище дозволяє отримати більшу точність, просто її немає в Date.