Проблема 1: Одна и та же версия ноды, и там и там системное время задано правильно, временная зона Europe/Moscow с двух сторон, DST настроено правильно. Проблема 2: Дата на фронте преобразуется в UTC -> отправляется на сервер -> сохраняется в MySQL. Возвращается с сервера -> преобразуется в локальное время -> выводится.
В момент возврата с сервера старое доброе смещение на 1 час, а при преобразовании в локальное — на 1 день(!!!).
При этом, если бекэнд запущен под виндой(Windows 10 Pro, x64) — никакого смещения вообще нет, если под дебианом(Debian 9.4 stretch, x64) — 1 час -> 1 день
Из-за чего может возникать подобная ошибка?
Фронтэнд (вырезано все то, что с ней не связано): Используется JQuery 3.3.1 и Vue 2.5.13 Используется заголовок
Content-Type: application/json
Получение:
$.ajax({
type: "get",
url: "/sns/getAccount",
data: { id: id },
success: function (result) {
profileUI.vue.account = result;
if (result.birthDate)
Vue.nextTick(function () {
if (!profileUI.birthDatePicker)
profileUI.birthDatePicker = $('#profileUI .editProfileContainer input.birthDateInput.datepicker-here').datepicker({
toggleSelected: false,
onSelect: function (formattedDate, date, inst) {
profileUI.vue.account.birthDate = date.toISOString();
}
}).data('datepicker');
profileUI.birthDatePicker.selectDate(birthDate);
})
}
});
Отправка:
profileUI.saveProfile = function () {
var account = profileUI.vue.account;
$.ajax({
url: '/sns/editAccount',
type: 'post',
data: profileUI.vue.account,
success: function (result) {
switchSubWindow('#profileUI', '.profileInfoContainer');
profileUI.loadAccount(account.id);
},
error: function (err) {
console.log(err);
}
});
}
Бекэнд(вырезано все, что не связано с датой) Используются пакеты NodeJS 9.11.1, express 4.16.2 и mysql 2.15.0 MySQL Community Server(в обоих случаях один и тот же, запущен на машине с дебианом(см выше))
Сохранение в БД:
router.post('/editAccount', (req, res) => {
connectionPool.query(sql.editAccountSQL,
req.body.birthDate?new Date(req.body.birthDate):null,
req.body.id],
err => {
if (!err) replyOk(res);
else replyError(res, err, 500);
});
})
Получение из БД:
queryDbAuthSensitive(req.cookies.token, sql.getAccountByIdSQL, [req.query.id], (err, rows) => {
replyOk(res, rows[0]);
});
replyOk:
export function replyOk(res: Response, data: any = null) {
if (!res.headersSent) res.writeHead(200);
res.end(data ? JSON.stringify(data, null, 2) : '{}');
}
sql.getAccountByIdSQL =
SELECT * FROM Account WHERE id = ? LIMIT 2;
sql.editAccount =
UPDATE Account
SET birthDate = ?
WHERE id = ?;
Костыль, достаточно прочный, чтобы временно решить проблему:
Время по UTC получается на 1 день раньше нашего. Собственно, вырезал все дальше T(т.к. для даты рождения просто не нужно) -> распарсил как наше -> +1 день.
var birthDate = new Date(result.birthDate.split('T')[0]);
birthDate.setDate(birthDate.getDate()+1);
Внимание! Гарантированно работает только по Москве. Меня это пока устраивает. Для других временных зон - на свой страх и риск.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей