Мне трудно понять, где я ошибаюсь при вычислении разницы даты и времени. Кажется, это связано с разницей часовых поясов, но неясно, в чем проблема. Ниже представлены все фрагменты. Где я неправ? Спасибо!
Я проверил часовой пояс 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?
И, возможно, добавьте Z к дате, если ее нет на сервере: let tokenTime = new Date(account.token_time_utc + 'Z').getTime();
Спасибо @mplungjan за ваши комментарии. Теперь работает. Вывод строки ISO дал 2024-05-07T06:27:31.000Z, что кажется большей разницей. Затем я увидел ваш второй комментарий и изменил строку, о которой идет речь, на ваше предложение, и теперь это работает. Спасибо! Я не понимаю, почему/как это работает? Если вы создадите ответ, я могу принять. Ваше здоровье
Ошибка возникает из-за того, что Date.now() или new Date() добавляет относительное смещение/разницу часового пояса для env (process.env.TZ, если никакая другая информация не предоставлена), а UTC_TIMESTAMP() игнорирует часовой пояс. Вам следует либо использовать CURRENT_TIMESTAMP() при его сохранении, либо установить TZ сервера узла также в UTC. Комментарий @mplungjan для добавления Z к token_time_utc тоже подойдет.
Кажется, @Christopher должен ответить :)
@Кристофер, спасибо за информацию. Странно, я никогда раньше с этим не сталкивался. Супер полезно. Ценю ответы и вас, и mplungjan.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ошибка возникает из-за того, что 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()
)
Вам необходимо войти в ISOString:
console.info('Account timestamp UTC: ' + account.token_time_utc.toISOString());