Как читать и хранить дату и время как от javascript до mysql

Я создаю приложение node.js, в котором пользователь создает запись с полем с именем даты и времени тура. Я использую плагин дата для отображения раскрывающегося окна даты и времени. Как только пользователь сохраняет запись, она сохраняется в таблице MySQL как поле datetime.

Затем я использую fullcalendar для отображения всех дат тура для данного месяца-года.

Но вот в чем проблема. Допустим, я выбрал 28/11/2018 18:30 в качестве даты и времени тура. В средстве выбора диапазона дат он сохраняется как

2018-11-28 18:30

$('input#tour_date').daterangepicker({
    singleDatePicker: true,
    showDropdowns: true,
    timePicker: true,
    timePickerIncrement: 30,
    locale: {
        format: 'DD/MM/YYYY hh:mm A'
    }
}, function (chosendate) {
    $('input[name = "tour_date"]').val(moment(chosendate).format('YYYY-MM-DD hh:mm'));
    //the value for input becomes 2018-11-28 18:30
});

Я не установил часовой пояс для daterangepicker или momentjs. Дата и время, которые я получаю из формы (перед сохранением в базу данных), одинаковы. то есть он приходит как 2018-11-28 18:30.

Однако при сохранении в базу данных он сохраняется как

2018-11-28 01:00:00

Он добавляет +06: 30 (IST, значение индийского стандартного времени) к входящему полю даты и времени.

Поэтому, когда я открываю свой календарь, дата правильная (28/11/2018), но время неверное. Пользователь сохранил поле, ожидая, что время будет 18:30, но вместо этого видит 01:00.

Я сохраняю дату и время как

var tourDate = new Date(req.body.tour_date).toISOString();

Я использую Sequelize ORM, и я не указал конкретный часовой пояс.

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
    host: process.env.DB_HOST,
    port: 3306,
    dialect: 'mysql',
    pool: {
        max: 10,
        min: 0,
        acquire: 30000,
        idle: 10000
    },
    logging: false
});

Что я хочу сделать, так это вне зависимости от того, в каком часовом поясе находится пользователь. Я хочу сохранить данные дату и время, как они есть в базе данных, и получить их как есть, чтобы они отображались в календаре.

Как мне этого добиться?

Вы внимательно прочитали руководство по моменту js? Вы даже не задумывались, почему всегда 11? А какое число ноябрь?

Salman A 30.11.2018 09:38

Я изменил строку формата на «ГГГГ-ММ-ДД чч: мм» в формате momentjs, поэтому проблема дополнительных 11 минут была решена. Однако он по-прежнему сохраняет дату и время, добавляя к нему значение IST.

codeinprogress 30.11.2018 09:46

вы установили часовой пояс в momentJS или fullCalendar? А как насчет самого веб-сервера? Как вы разбираете дату, когда она туда приходит? Вы отлаживали, чтобы увидеть, есть ли еще желаемое время, когда оно прибывает на сервер (но до того, как оно будет записано в базу данных)? Установлен ли часовой пояс на самом сервере mySQL (а не в подключении sequelize)? Здесь много недостающей информации.

ADyson 30.11.2018 09:49

Я обновил информацию по своему вопросу. Я не устанавливаю часовой пояс для momentjs, fullcalendar и daterangepicker. Когда дата и время поступают на сервер, оно имеет тот же формат, что и в поле ввода.

codeinprogress 30.11.2018 10:11

Так что насчет веб-сервера и сервера mysql? Есть какие-нибудь настройки времени на тех? Вы не упомянули, что нашли там.

ADyson 30.11.2018 11:27
(new Date()).toISOString() вернет дату и время в формате UTC (путем добавления / вычитания смещения часового пояса к местному времени ... 18:30 - 05:30 = 01:00). Остальные детали вы не опубликовали. Но вы, вероятно, могли бы использовать момент js для преобразования локального datetime в формат, который ожидает MySQL.
Salman A 30.11.2018 12:06
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
6
3 379
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Если вы сохраняете дату через sequelize, она сохранит дату как UTC,

Итак, с передней стороны просто передайте дату в формате UTC, чтобы она была сохранена и если вы используете средство выбора даты и времени, оно автоматически преобразует UTC в ваш часовой пояс, просто передайте данные UTC в свой плагин.

Просто используйте UTC при прохождении, и все готово.

Это то, что я пытаюсь сделать. Я хочу прочитать значение datetime, выбранное пользователем как есть, и сохранить его как есть, независимо от того, в каком часовом поясе находится пользователь. Пока единственный успех - это возможность получить выбранное значение datetime на стороне сервера целиком, но как только Sequelize сохраняет его в таблицу, он конвертируется :(

codeinprogress 02.12.2018 14:44

Итак, вы были правы. Кажется, мне снова нужно преобразовать дату на стороне сервера в utc, используя момент.

codeinprogress 02.12.2018 16:35

Это не работает даже с опцией UTC. Как-то есть несколько настроек, которые не работают. Node js действительно нужен встроенный, sequelize плохо поддерживается. Похоже, сиквелиз ничего не знает о часовых поясах.

wondim 25.10.2020 10:23
  1. Если вы используете тип данных DATETIME в mysql, тогда значение сохранится как есть не зависит от системной переменной mysql time_zone. См. здесь и здесь.
  2. mysql возвращает разные значения для некоторых функций в зависимости от переменной системы time_zone. Например:

    SET time_zone='+00:00'; 
    SELECT now(); //2018-11-30 17-52-00
    
    SET time_zone='+03:00'; 
    SELECT now(); //2018-11-30 20-52-00
    
  3. Вы можете передать параметр часового пояса в продолжение соединения с БД. По умолчанию это '+00: 00'. Прежде всего, Sequelize использует это значение для установки time_zone опция для каждого соединения (вы можете увидеть это, если запустить Sequelize с Переменная DEBUG). Также Sequelize (или пакет mysql2, я не знаю) использует параметр часового пояса для преобразования результатов, возвращаемых mysql, в объекты Date js. Так:

    const sequelize = new Sequelize('database', 'user', 'password', {timezone: "+00:00"});
    
    sequelize.query('SELECT now() AS now;', {type: sequelize.QueryTypes.SELECT})
    //2018-11-30T17:52:00.000Z
    
    sequelize.query('SELECT createdAt FROM users WHERE userId = 1;', {type: sequelize.QueryTypes.SELECT})
    //2017-09-05T13:43:00.000Z
    
    
    const sequelize = new Sequelize('database', 'user', 'password', {timezone: "+03:00"});
    
    sequelize.query('SELECT now() AS now;', {type: sequelize.QueryTypes.SELECT})
    //2018-11-30T17:52:00.000Z
    
    sequelize.query('SELECT createdAt FROM users WHERE userId = 1;', {type: sequelize.QueryTypes.SELECT})
    //2017-09-05T10:43:00.000Z 
    

Объяснять:

Для now:

+-----------+---------------------+----------------------------+--------------------------+
| time_zone | mysql return        | sequelize read result as   | sequelize return         |
+-----------+---------------------+----------------------------+--------------------------+
|  +00:00   | 2018-11-30 17-52-00 | 2018-11-30 17-52-00 +00:00 | 2018-11-30T17:52:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+
|  +03:00   | 2018-11-30 20-52-00 | 2018-11-30 20-52-00 +03:00 | 2018-11-30T17:52:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+

Для createdAt:

+-----------+---------------------+----------------------------+--------------------------+
| time_zone | mysql return        | sequelize read result as   | sequelize return         |
+-----------+---------------------+----------------------------+--------------------------+
|  +00:00   | 2017-09-05 13-43-00 | 2017-09-05 13-43-00 +00:00 | 2017-09-05T13:43:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+
|  +03:00   | 2017-09-05 13-43-00 | 2017-09-05 13-43-00 +03:00 | 2017-09-05T10:43:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+

Поэтому будьте осторожны при установке параметра часового пояса при использовании типа данных DATETIME. Если вы вставляете / выбираете свои данные только с помощью sequelize, вам не нужно менять параметр часового пояса.

Для корректной работы с datetime в своей работе я использую следующие правила:

  • Для передачи даты и времени между клиентом и сервером используйте однозначно определенный формат: UNIX, ISO 8601 (строка как 2017-09-05T13:43:00.000Z);
  • Все значения DATETIME в БД Mysql хранятся с нулевым часовым поясом (+00: 00); Таким образом, параметр часового пояса для Sequelize равен «+00: 00»;

Наконец, браузеры используют настройку часового пояса на вашем компьютере. Проверяйте значения на всех этапах и устраняйте неопределенности, связанные с неправильной интерпретацией часового пояса.

Итак, вот что происходит. В своем продолжении я установил значение часового пояса на +00: 00. Если я выбрал 05/12/2018 9:00 AM в своем календаре, на моем сервере будет указано 2018-12-05T09: 00: 00 (до сохранения). Но после вставки даты она становится 2018-12-05 03:30:00.

codeinprogress 02.12.2018 14:26

@codeinprogress Какой формат вы используете для передачи между клиентом и сервером? Простое решение - отправить результат dateString = date.toISOString() от клиента и использовать Date.parse(dateString) на сервере nodejs. Обратите внимание, что вы должны использовать часовой пояс в этом формате для определенного результата, в ISO 8601 «Z» - это часовой пояс «+00: 00».

Faris 02.12.2018 17:41

Хорошо, после долгой неразберихи вот как это было решено. Мне пришлось преобразовать дату на моей стороне клиента в utc, а затем, когда дело доходит до моего сервера node.js, мне нужно снова преобразовать ее в UTC, прежде чем сохранять в базе данных.

На стороне клиента я устанавливаю дату в скрытом поле ввода (это то, что я отправляю на сервер), используя

$('input#tour_date').daterangepicker({
  singleDatePicker: true,
  showDropdowns: true,
  timePicker: true,
  timePickerIncrement: 30,
  locale: {
    format: 'DD/MM/YYYY hh:mm A'
  }
}, function (chosendate) {
    //this is the hidden input where the set date is being sent
    $('input[name = "tour_date"]').val(moment(chosendate).format('YYYY-MM-DDTHH:mm:ss'));
});

Итак, один сервер входит как

2018-12-31T10:30:00.000Z

Что затем мне нужно обработать снова, используя такой момент:

moment.utc(req.body.tour_date); //this is saved to db

Когда я читаю запись и показываю ее пользователю, я обрабатываю дату как

moment.utc(act.tour_date).format('DD/MM/YYYY hh:mm A')

Таким образом, пользователь видит 31/12/2018 10:30 в указателе даты.

Я также передаю moment.utc(act.tour_date).format('YYYY-MM-DDTHH:mm:ss') обратно на скрытый ввод, на случай, если пользователь обновит запись

Спасибо всем, кто помог мне разобраться в этом. Цените свое время и усилия.

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