Работа с часовыми поясами в JavaScript

В одном из проектов, при создании календаря и панели аукционов, в очередной раз пришлось столкнуться с временем и часовыми поясами в JavaScript.

В JavaScript работа с датой и временем можно обойтись Date()
Вот если нужны специфические манипуляции, то тогда можно использовать библиотеки вроде moment.js, luxon, spacetime, day.js или date-fns.

Сравнение в npmtrends — https://www.npmtrends.com/date-fns-vs-spacetime-vs-dayjs-vs-luxon-vs-moment

Выбор зависит от задачи и требований. Вкратце описание ситуации по часовым поясам есть в статье Habr «Работа с часовыми поясами в JavaScript» — https://habr.com/ru/company/mailru/blog/438286/

Обычно при стеке NodeJS (MongoDB) + JS framework дату сохраняем в базе как тип ISO date со смещением относительно времени сервера. Исходный код с примером из этой статьи можно взять из — bitbucket

let productSchema = new Schema({
title: String,
owner: String,
description: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
},
qty: Number,
qrcode: String,
timeZone: String
});
// clientDateTime = "Fri Mar 8 2019 11:11:11 GMT+0300 (EET)"; 
let dateTime = `${clientDateTime}`;
// eventTimeZoneName = "Europe/Kiev";
let timeZone = `${eventTimeZoneName}`;

После сохранения в базе будет сохраненна дата : ISODate("2019-05-02T08:11:11.000Z")
Видим, что произошло смещение к дате по UTC.

Получение списка всех товаров (http://localhost:8081/products):

{
    "products": [
        {
            "_id": "5ccbf1fbc518163a1ed37329",
            "title": "Product5",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-05T08:47:00.000Z",
            "qty": 90
        },
        {
            "_id": "5ccbf1fbc518163a1ed37328",
            "title": "Product4",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-04T08:47:00.000Z",
            "qty": 78
        },
        {
            "_id": "5ccbf1fbc518163a1ed37327",
            "title": "Product3",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-03T08:47:00.000Z",
            "qty": 30
        },
        {
            "_id": "5ccbf1fbc518163a1ed37326",
            "title": "Product2",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-02T08:47:00.000Z",
            "qty": 42
        },
        {
            "_id": "5ccbf1fbc518163a1ed37325",
            "title": "Product1",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-01T08:47:00.000Z",
            "qty": 33
        }
    ]
}

Отдельным запросом по API front-end получал товары сегоднешнего дня.
http://localhost:8081/products_today

{
    "products": [
        {
            "_id": "5ccbf1fbc518163a1ed37327",
            "title": "Product3",
            "owner": "Owner",
            "comments": [],
            "date": "2019-05-03T08:47:00.000Z",
            "qty": 30
        }
    ]
}

А теперь выведем список дней этого месяца и количество товаров со средним количеством http://localhost:8081/products_calendar.

{
    "products": [
        {
            "date": "2019-5-1",
            "averageQuantity": 33,
            "count": 1
        },
        {
            "date": "2019-5-2",
            "averageQuantity": 42,
            "count": 1
        },
        {
            "date": "2019-5-3",
            "averageQuantity": 30,
            "count": 1
        },
        {
            "date": "2019-5-4",
            "averageQuantity": 78,
            "count": 1
        },
        {
            "date": "2019-5-5",
            "averageQuantity": 90,
            "count": 1
        }
    ]
}

Вывод списка товаров на front-end, для сегодняшнего дня выводит детальный список и точную дату.

Hello!

May 03, 2019 15:14 Europe/Vilnius

Date — 2019-5-1

Count — 1
AverageQuantity — 33

Date — 2019-5-2

Count — 1
AverageQuantity — 42

Date — 2019-5-3 (today)

Count — 1
AverageQuantity — 30

  • Product3 ( 2019-05-03T08:47:00.000Z ) 11:47

Date — 2019-5-4

Count — 1
AverageQuantity — 78

Date — 2019-5-5

Count — 1
AverageQuantity — 90

Как видно из выше отображённого списка время — коректно.
Если выведем эту же страницу в часовом поясе — Asia/Shanghai и America/New_York
Для запуска браузера в другом часовом поясе используем — TZ='Asia/Shanghai' google-chrome "--user-data-dir=$HOME/chrome-profile2"

Hello!

May 03, 2019 20:47 Asia/Shanghai

Date — 2019-5-1

Count — 1
AverageQuantity — 33

Date — 2019-5-2

Count — 1
AverageQuantity — 42

Date — 2019-5-3 (today)

Count — 1
AverageQuantity — 30

  • Product3 ( 2019-05-03T08:47:00.000Z ) 16:47

Date — 2019-5-4

Count — 1
AverageQuantity — 78

Date — 2019-5-5

Count — 1
AverageQuantity — 90

Hello!

May 03, 2019 08:49 America/New_York

Date — 2019-5-1

Count — 1
AverageQuantity — 33

Date — 2019-5-2

Count — 1
AverageQuantity — 42

Date — 2019-5-3 (today)

Count — 1
AverageQuantity — 30

  • Product3 ( 2019-05-03T08:47:00.000Z ) 04:47

Date — 2019-5-4

Count — 1
AverageQuantity — 78

Date — 2019-5-5

Count — 1
AverageQuantity — 90

Проверяем с

Vilnius, Lithuania Fri, 3 May 2019 at 11:47 EEST <br> Kyiv, Ukraine Fri, 3 May 2019 at 11:47 EEST <br> Beijing, China Fri, 3 May 2019 at 16:47 CST <br> New York, USA Fri, 3 May 2019 at 04:47 EDT

Для простого сохранения дат и их отображения в относительно времени клиента достаточно.

В следующей статье будет расмотрена ситуация когда нужно создать календарь с аукционами, которые запускаются только по времени начала и конца в определённые дни недели. То есть нету конкретной даты и времени с часовым поясом, а есть список дней и время начала и конца аукциона.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.