среда, 22 августа 2018 г.

ИСЧЕРПЫВАЮЩЕЕ РУКОВОДСТВО ПО РАБОТЕ С ДАТАМИ В JAVASCRIPT


Работа с датами в javascript может быть непростой. В данной статье мы рассмотрим принципы работы с ними.

Введение
Работа с датами может быть очень сложной. Вне зависимости от используемой технологии.
JavaScript предоставляет функциональность по работе с датами через объект Date.

Данная статься не рассматривает библиотеку Moment.js которая ялвяется самой лучшей библиотекой по работе с датами, и вы всегда можете ей пользоваться.

Объект Date
Экземпляр объекта Date представляет точку времени.

Несмотря на название Date, объект также обрабатывает и время.
Инициализация объекта Date
Ниже показано как мы инициализируем объект Date.

new Date()

Этот код создает объект Date который указывает на текущий  момент времени.
Внутри объекта информация о времени хранится в милисекундах от 1го января 1970 года (UTC). Эта дата используется как время начало компьютерной эры.
Вам может быть знаком штамп времени UNIX: он представляет собой число секунд от известной даты.
Важно: обратите внимание что штамп времен UNIX  в секундах, а время в JavaScript в милисекундах.

Если у нас есть время UNIX, то следующим образом мы можем создать объект Date:

const timestamp = 1530826365
new Date(timestamp * 1000)

Если мы передадим 0 при создании объекта, то получим дату 1 января 1970 года (UTC).

new Date(0)
Если мы передадим не число а строку, то объект будет использовать метода parse для определения даты, котору необходимо присвоить объекту.
Например:

new Date('2018-07-22')
new Date('2018-07') //July 1st 2018, 00:00:00
new Date('2018') //Jan 1st 2018, 00:00:00
new Date('07/22/2018')
new Date('2018/07/22')
new Date('2018/7/22')
new Date('July 22, 2018')
new Date('July 22, 2018 07:22:13')
new Date('2018-07-22 07:22:13')
new Date('2018-07-22T07:22:13')
new Date('25 March 2018')
new Date('25 Mar 2018')
new Date('25 March, 2018')
new Date('March 25, 2018')
new Date('March 25 2018')
new Date('March 2018') //Mar 1st 2018, 00:00:00
new Date('2018 March') //Mar 1st 2018, 00:00:00
new Date('2018 MARCH') //Mar 1st 2018, 00:00:00
new Date('2018 march') //Mar 1st 2018, 00:00:00

Здесь все достаточно гибко. Вы можете добавлять или убирать дополнительные нули в месяцы и дни.
Будте внимательны с позицией месяца/дня, иначе вы можете их перепутать и получить совсем не то что ожидали.
Также вы можете использовать метод Date.parse:

Date.parse('2018-07-22')
Date.parse('2018-07') //July 1st 2018, 00:00:00
Date.parse('2018') //Jan 1st 2018, 00:00:00
Date.parse('07/22/2018')
Date.parse('2018/07/22')
Date.parse('2018/7/22')
Date.parse('July 22, 2018')
Date.parse('July 22, 2018 07:22:13')
Date.parse('2018-07-22 07:22:13')
Date.parse('2018-07-22T07:22:13')

Этот объект вернет вам штамп времени в милисекундах а не объект Date.
Вы также можете передать набор упорядоченных значений который представляют части даты: год, месяц (начиная с 0), день, час, минуты, секунды и милисекунды.

new Date(2018, 6, 22, 7, 22, 13, 0)
new Date(2018, 6, 22)

Как минимум вы должны предоставить три параметра, но многие интерпретаторы позволяют и меньшее число параметров:

new Date(2018, 6) //Sun Jul 01 2018 00:00:00 GMT+0200 (Central European Summer Time)
new Date(2018) //Thu Jan 01 1970 01:00:02 GMT+0100 (Central European Standard Time)

В каждом из этих случаев, в результате будет дата указанная относительно вашей временной зоны. Это значит что результат на двух компьютерах может отличаться результат работы с одним и тем же объектом.
JavaScript без предоставления ему какой либо информации о временных зоназ будет считать, что время в UTC, и будет автоматически переводить его в локальное время.
Таким образом, вы можете создать новый объект Date  четырмя способами:
 - Не передавая никаких параметров, в этом случае объект Date будет представлять текущее врмя.
 - Передавая число, которое представляет собой число милисекунд с 1 января 1970 года.
 - Передавая строку, которая описывает дату.

 - Передавая набор параметров, которые представляют информацию о различных частях даты.
Временные зоны
Когда мы инициализируем дату вы можете передать временную зону, такоим образом объект Date не будет предполагать что это UTC дата и не будет осуществлять перевод к вашей временной зоне.
Вы можете передать временную зону в +HOURS формате, или передавая название зоны в скобках:

new Date('July 22, 2018 07:22:13 +0700')
new Date('July 22, 2018 07:22:13 (CET)')

Если вы укажете временную зону неправильно в скобках, JavaScript без предупреждений будет эту дату трактовать как UTC.
Если вы укажете неправильно числовой формат, JavaScript будет полагать что это неправильная дата.
Преобразование и форматирование даты
Если есть объект Date, то для него существует много способов преобразования в строку:

const date = new Date('July 22, 2018 07:22:13')
 
date.toString() // "Sun Jul 22 2018 07:22:13 GMT+0200 (Central European Summer Time)"
date.toTimeString() //"07:22:13 GMT+0200 (Central European Summer Time)"
date.toUTCString() //"Sun, 22 Jul 2018 05:22:13 GMT"
date.toDateString() //"Sun Jul 22 2018"
date.toISOString() //"2018-07-22T05:22:13.000Z" (ISO 8601 format)
date.toLocaleString() //"22/07/2018, 07:22:13"
date.toLocaleTimeString()   //"07:22:13"
date.getTime() //1532236933000
Методы получения объекта Date
Объект Date предоставляет несколько методов для проверки значения. Все они зависят от текущей временной зоны компьютера:

const date = new Date('July 22, 2018 07:22:13')
date.getDate() //22
date.getDay() //0 (0 means sunday, 1 means monday..)
date.getFullYear() //2018
date.getMonth() //6 (starts from 0)
date.getHours() //7
date.getMinutes() //22
date.getSeconds() //13
date.getMilliseconds() //0 (not specified)
date.getTime() //1532236933000
date.getTimezoneOffset() //-120 (will vary depending on where you are and when you check - this is CET during the summer). Returns the timezone difference expressed in minutes
Вот эквивалентные методы для UTC, они возвращают UTC значение  а не значение для вашей зоны:

date.getUTCDate() //22
date.getUTCDay() //0 (0 means sunday, 1 means monday..)
date.getUTCFullYear() //2018
date.getUTCMonth() //6 (starts from 0)
date.getUTCHours() //5 (not 7 like above)
date.getUTCMinutes() //22
date.getUTCSeconds() //13
date.getUTCMilliseconds() //0 (not specified)
Редактирование даты
Объект Date предоставляет несколько методов для редактирования значения:

const date = new Date('July 22, 2018 07:22:13')
 
date.setDate(newValue)
date.setDay(newValue)
date.setFullYear(newValue) //note: avoid setYear(), it's deprecated
date.setMonth(newValue)
date.setHours(newValue)
date.setMinutes(newValue)
date.setSeconds(newValue)
date.setMilliseconds(newValue)
date.setTime(newValue)
date.setTimezoneOffset(newValue)
setDay  и setMonth  начинают отсчет с 0, то есть скажем март – это номер 2.
Интересный факт: эти методы «перекрывающие», то есть если вы введете например date.setHours(48), то это метод увеличит и день.
Полезно знать: в можете передать больше чем один параметр в setHours() для того что бы указать минуты, секунды и милисекунды. setHours(0, 0, 0, 0) – то же самое касается и setMinutes  и setSeconds.
Как и для getXXX, эти методы имеют UTC эквиваленты:

const date = new Date('July 22, 2018 07:22:13')
date.setUTCDate(newalue)
date.setUTCDay(newValue)
date.setUTCFullYear(newValue)
date.setUTCMonth(newValue)
date.setUTCHours(newValue)
date.setUTCMinutes(newValue)
date.setUTCSeconds(newValue)
date.setUTCMilliseconds(newValue)
Получение текущего штампа вермени
Если вы хотите получить текущий штамп времени в милисекундах, вы можете использовать сокращение вида:
Date.now()
вместо

new Date().getTime()
JavaScript старается работать хорошо
Обратите внимание. Если вы переполните месяц числом дней, то это не приведет к ошибке, и в дате просто сменится месяц:

new Date(2018, 6, 40) //Thu Aug 09 2018 00:00:00 GMT+0200 (Central European Summer Time)
То же самое касается месяцев, часов, минут, секунд или милисекунд.
Форматирование даты в локальном формате
API интернационализации, которое хорошо поддерживается в нынешних браузерах (за исключением UC Browser), позволяют вам преобразовывать дату.
Это достигается с помощью объекта Intl, которые также помогает в локализации чисел, строк и валют.
Нам же инетерсна в первую очередь функция Intl.DateTimeFormat().
Ниже показан пример ее использования.
Форматирование даты в соответствии с текущей локалью компьютера:

// "12/22/2017"
const date = new Date('July 22, 2018 07:22:13')
new Intl.DateTimeFormat().format(date) //"22/07/2018" in my locale
Форматирование даты для другой локали:

new Intl.DateTimeFormat('en-US').format(date) //"7/22/2018"
Метод Intl.DateTimeFormat принимает опциональный параметр, который позволяет кастомизировать результат. Для того что бы отобразить часы, минуты и секунды:

const options = {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
}
 
new Intl.DateTimeFormat('en-US', options).format(date) //"7/22/2018, 7:22:13 AM"
new Intl.DateTimeFormat('it-IT', options2).format(date) //"22/7/2018, 07:22:13"
Здесь представлены все параметры которые можно использовать.
Сравнение двух дат
Вы можете вычислить разницу между двумя датами используя метод Date.getTime():
const date1 = new Date('July 10, 2018 07:22:13')
const date2 = new Date('July 22, 2018 07:22:13')
const diff = date2.getTime() - date1.getTime() //difference in milliseconds
Подобным образом вы можете проверить равны ли две даты:
const date1 = new Date('July 10, 2018 07:22:13')
const date2 = new Date('July 10, 2018 07:22:13')
if (date2.getTime() === date1.getTime()) {
  //dates are equal
}

Имейте ввиду, что метод getTime() возвращает количество милисекунд, таким образом вам нужно учитывать время в сравнении. July 10, 2018 07:22:13 не равен July 10, 2018. В данном случае вы можете использовать setHours(0, 0, 0, 0) для сброса времени.