Преобразование поля времени mysql UTC в JS?

Мне трудно понять, где я ошибаюсь при вычислении разницы даты и времени. Кажется, это связано с разницей часовых поясов, но неясно, в чем проблема. Ниже представлены все фрагменты. Где я неправ? Спасибо!

Я проверил часовой пояс MySQL:

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | SYSTEM              |
+--------------------+---------------------+

Моя локальная система — macOS, а дата и время установлены с правильным местным временем и часовым поясом Копенгагена (CEST).

У меня есть база данных MySQL с полем, указанным как:

token_time_utc DATETIME DEFAULT NULL

Затем я заполняю это поле, используя NodeJS и соединитель mysql2:

'UPDATE `account` SET token = ?, token_time_utc = UTC_TIMESTAMP() WHERE user_id = ?', [token, account.user_id] ...

Затем я отправляю электронное письмо с токеном и пытаюсь подтвердить его в течение 6 минут, но это не удается:

// did they verify token within 6 minutes UTC time?
let sixMins = (60 * 1000 * 6);
let tokenTime = account.token_time_utc.getTime();
let tokenExpiration = tokenTime + sixMins;
let now = new Date().getTime();
console.info('Account timestamp: ' + account.token_time_utc + ' Token time: ' + tokenTime + ' Token expiration: ' + tokenExpiration + ' Now: ' + now
    + ' Diff: ' + (now - tokenTime) + ' Diff (minutes): ' + ((now - tokenTime) / 1000 / 60));
if (now > tokenExpiration) {
    // return error
    res.status(401).json({ message: 'Token timed out' });
    return;
}

И вот что выводится в консоль:

Account timestamp: Tue May 07 2024 07:25:52 GMT+0200 (Central European Summer Time) Token time: 1715059552000 Token expiration: 1715059912000 Now: 1715066768248 Diff: 7216248 Diff (minutes): 120.2708

Все это работает локально на моей машине. Когда я его запускал, в Копенгагене было 9:25 утра, сейчас время GMT+2. Получение электронного письма и вставка токена заняло меньше минуты, а разница в 120 минут, по-видимому, связана с неправильным часовым поясом. И я пытался сохранить все в формате UTC, и БД сохранила правильное время UTC по сравнению со мной (7:25 утра), но оно помечено как CEST, то есть Копенгаген (что странно?).

Когда я отправляю время в БД, возникает ли проблема, которую команда UTC_TIMESTAMP() говорит об использовании текущего времени в формате UTC? Или неправильно выполняет account.token_time_utc.getTime()? Или я просто испортил использование методов JS Date?

Или мне нужно установить часовой пояс MySQL? Я видел эти сообщения, но не уверен, что это проблема: Должен ли MySQL установить часовой пояс в формате UTC?Как мне установить часовой пояс MySQL?

Вам необходимо войти в ISOString: console.info('Account timestamp UTC: ' + account.token_time_utc.toISOString());

mplungjan 07.05.2024 10:24

И, возможно, добавьте Z к дате, если ее нет на сервере: let tokenTime = new Date(account.token_time_utc + 'Z').getTime();

mplungjan 07.05.2024 10:26

Спасибо @mplungjan за ваши комментарии. Теперь работает. Вывод строки ISO дал 2024-05-07T06:27:31.000Z, что кажется большей разницей. Затем я увидел ваш второй комментарий и изменил строку, о которой идет речь, на ваше предложение, и теперь это работает. Спасибо! Я не понимаю, почему/как это работает? Если вы создадите ответ, я могу принять. Ваше здоровье

mr.b 07.05.2024 10:33

Ошибка возникает из-за того, что Date.now() или new Date() добавляет относительное смещение/разницу часового пояса для env (process.env.TZ, если никакая другая информация не предоставлена), а UTC_TIMESTAMP() игнорирует часовой пояс. Вам следует либо использовать CURRENT_TIMESTAMP() при его сохранении, либо установить TZ сервера узла также в UTC. Комментарий @mplungjan для добавления Z к token_time_utc тоже подойдет.

Christopher 07.05.2024 10:33

Кажется, @Christopher должен ответить :)

mplungjan 07.05.2024 10:36

@Кристофер, спасибо за информацию. Странно, я никогда раньше с этим не сталкивался. Супер полезно. Ценю ответы и вас, и mplungjan.

mr.b 07.05.2024 10:41
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
6
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка возникает из-за того, что Date.now() или new Date() добавляет относительное смещение/разницу часового пояса для env (process.env.TZ, если в метке времени не указана другая информация), а UTC_TIMESTAMP() игнорирует часовой пояс. Вам следует либо использовать CURRENT_TIMESTAMP() при его сохранении, либо установить TZ сервера узла также в UTC.

Комментарий mplungjan для добавления Z к token_time_utc тоже подойдет.

Вы также можете использовать Date.UTC() и передать в него части временной метки UTC.

Что должно быть примерно так:

const [str, year, month, day, hour, minute, seconds, ms] = 
  '2003-08-14 18:08:04.123'.match(
    /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.?(\d+)?$/
  )
console.info(
  new Date(Date.UTC(year, month -1, day, hour, minute, seconds, ms)).toLocaleString()
)

Другие вопросы по теме