Мы все знаем, что JavaScript имеет некоторые плохие стороны. Однако об одном из них обычно забывают и пропускают в большинстве списков «JavaScript Bad Parts» в Интернете. Это Date
объект. Вам может быть трудно работать с ним, особенно если вы хотите поддерживать часовые пояса. В этом посте я хотел бы изложить причуды Date
в JavaScript.
основы
Чтобы создать Date
объект, вы просто делаете:
var now = new Date();
Это создаст дату, установленную на сейчас.
Если вы хотите создать Date
в определенный день:
var year = 2015; var month = 2-1; // February var day = 27; var now = new Date(year, month, day);
Здесь вы сталкиваетесь с первой причудой: месяцы пронумерованы от 0 до 11. Январь — 0, декабрь — 11.
Вы также можете указать часы, минуты, секунды и миллисекунды в качестве дополнительных параметров (здесь больше нет ошибок):
var year = 2015; var month = 2-1; // February var day = 27; var hours = 14; // 2PM var minutes = 56; var seconds = 37; var milliseconds = 997; var now = new Date(year, month, day, hours, minutes, seconds, milliseconds);
Для более подробной информации о создании Date
, проверьте Дата на MDN .
Форматирование
Если вы хотите отобразить дату, есть несколько доступных конвертеров. Вот наиболее часто используемые:
var date = new Date(2015, 1, 27, 14, 56, 37, 997); console.log(date.toDateString()); // Fri Feb 27 2015 console.log(date.toTimeString()); // 14:56:37 GMT-0800 (Pacific Standard Time) console.log(date.toLocaleDateString()); // 2/27/2015 console.log(date.toLocaleTimeString()); // 2:56:37 PM console.log(date.toUTCString()); // Fri, 27 Feb 2015 22:56:37 GMT console.log(date.toGMTString()); // Fri, 27 Feb 2015 22:56:37 GMT console.log(date.toISOString()); // 2015-02-27T22:56:37.997Z console.log(date.toJSON()); // 2015-02-27T22:56:37.997Z
Будьте осторожны с 3 и 4. Оба дают разные результаты, в зависимости от настроек компьютера пользователя и географического положения. Это может вызвать проблемы с пользовательским интерфейсом (некоторые форматы даты могут быть длинными).
Конвертеры 5 и 6 эквивалентны во всех самых популярных браузерах. Однако toGMTString
не рекомендуется.
Преобразователи 7 и 8 также эквивалентны. Кроме того, toJSON
используйте toISOString
внизу, чтобы вернуть результат.
Нет существенных проблем с отображением даты, но нет способа отформатировать ее в произвольном формате (например, «ГГГГ-ММ-ДД ЧЧ: мм»), как в C # или Java.
Альтернативой для форматирования является объект Intl.DateTimeFormat из API интернационализации ECMAScript . Однако этот API еще не поддерживается старыми браузерами, большинством мобильных браузеров и Safari (проверьте совместимость браузера в MDN ).
анализ
Более сложным, чем отображение дат, является их анализ. Есть два распространенных способа анализа даты из строки:
var parsedDate1 = new Date("2015-02-27 22:56:37"); var parsedDate2 = Date.parse("2015-02-27 22:56:37");
Первый возвращает Date
объект, второй — номер 1425106597000 (миллисекунды с 1 января 1970 года, 00:00:00 UTC).
В разборе есть одна очень неприятная деталь:
При заданной строке даты «7 марта 2014 года» parse () предполагает наличие местного часового пояса , но с учетом формата ISO, такого как «2014-03-07», будет принят часовой пояс UTC . Поэтому объекты Date, созданные с использованием этих строк, будут представлять разные моменты времени, если в системе не установлен местный часовой пояс UTC. Это означает, что две строки даты, которые выглядят эквивалентными, могут привести к двум различным значениям в зависимости от формата преобразуемой строки ( это поведение изменено в ECMAScript ed 6, так что обе будут рассматриваться как локальные ).
Источник:
MDN
Это означает, что date1
и date2
ниже (созданные из машины, расположенной в Сиэтле, штат Вашингтон) различаются:
var date1 = new Date("2014-01-02"); var date2 = new Date("1/2/2014"); console.log(date1); // Wed Jan 01 2014 16:00:00 GMT-0800 (Pacific Standard Time) console.log(date2); // Thu Jan 02 2014 00:00:00 GMT-0800 (Pacific Standard Time)
Рекомендуемый формат разбора: YYYY/MM/DD
— независимые локальные настройки пользователя. Он всегда предполагает смещение местного часового пояса для строки даты, заданной в качестве параметра
var date1 = new Date("2014/01/02"); console.log(date1); // Thu Jan 02 2014 00:00:00 GMT-0800 (Pacific Standard Time)
Часовые пояса
JavaScript- Date
объект всегда предполагает локальное смещение часового пояса для машины, на которой он отображается. Что важно: JavaScript Date
не поддерживает часовые пояса, а только смещения часовых поясов. Это определение обоих из Википедии :
Часовой пояс является географическим регионом , где почти каждый замечает то же самое стандартное время. Смещение по времени является количество времени вычитают из или добавлены к UTC , чтобы получить текущее гражданское время — будь то стандартное время или Переход на летнее время.
Другими словами: часовой пояс является постоянным (пока правительство не меняло его) для некоторого места (например, Сан-Франциско) все время, в то время как смещение часового пояса изменяется (обычно, два раза в год — это то, что мы называем «дневной свет» экономия).
var myDate = new Date(); var timezoneOffset = myDate.getTimezoneOffset(); // result in minutes
Результат в минутах. Вот еще одна странность: часовые пояса, которые «западнее» от UTC (смещение = 0), имеют положительные значения (60–720), а часовые пояса, которые «восточнее» от UTC, имеют отрицательные значения (-60 — -780). Таким образом, стандартное тихоокеанское время (UTC- 8: 00 ) в JavaScript имеет смещение часового пояса 480 , а центрально-европейское время (UTC +1: 00 ) имеет смещение часового пояса -60 .
Еще один подводный камень: локальное смещение часового пояса всегда устанавливается в зависимости от значения Date
объекта. Таким образом, для компьютера, расположенного в Сиэтле, штат Вашингтон:
var date1 = new Date(2015,1,20); // date in Pacific Standard Time (before timezone offset change) var date2 = new Date(2015,2,20); // date in Pacific Daylight Time (after timezone offset change) console.log(date1.getTimezoneOffset()); // 480 console.log(date2.getTimezoneOffset()); // 420
В этом случае ваше текущее «местное» смещение часового пояса (для времени, в которое вы создаете объект Date) не имеет значения.
Даже если вы создадите объект Date с датой до изменения времени, а затем измените его на дату после изменения времени — его смещение часового пояса изменится, чтобы отразить смещение для нового (текущего) значения:
var date = new Date(2015,1,20); // date in Pacific Standard Time console.log(date.getTimezoneOffset()); // 480 date.setMonth(2); // change month so date is in Pacific Daylight Time now console.log(date.getTimezoneOffset()); // 420
Moment.js
Moment.js — это библиотека JavaScript, предназначенная для работы на стороне клиента (в браузере) и на стороне сервера (в файле node.js). В нем много функций для разбора, отображения и манипулирования датами. Это делает работу с датами менее болезненной.
Часовой пояс Moment — библиотека, созданная поверх Moment.js — поддерживает зоны реального времени (не только смещения часовых поясов). Данные для часового пояса Момент поступают из базы данных часовых поясов IANA — самой популярной базы данных часовых поясов. Новые версии периодически выпускаются по мере изменения законов о часовых поясах в разных странах.
Подумайте об использовании Moment.js и Moment Timezone в вашем приложении, когда вы делаете более сложные операции с датами. Особенно, если вы хотите поддерживать часовые пояса.
Резюме
Действительно удивительно, что работа с датами в программировании все еще вызывает много проблем. Тем не менее, мы становимся лучше в этом. Чтобы получить исчерпывающий обзор даты / времени на языке программирования, я рекомендую Основы даты и времени от Мэтта Джонсона . Вы также можете проверить блог Мэтта Джонсона . Он пишет в основном о дате / времени в различных средах. Его статья JavaScript Тип даты ужасно испорчена, может быть хорошим дополнением к этому сообщению
Чтобы быстро понять, почему работать с часовыми поясами очень сложно, посмотрите это видео .