【问题标题】:How to read and store datetime as is from javascript to mysql如何从 javascript 到 mysql 读取和存储日期时间
【发布时间】:2018-12-02 23:45:48
【问题描述】:

我正在构建一个应用程序 node.js,用户在其中创建一个记录,其中包含一个名为游览日期和时间的字段。我正在使用daterangepicker 插件来显示日期和时间下拉窗口。一旦用户保存记录,它就会作为日期时间字段保存在 MySQL 表中。

然后我使用fullcalendar 显示给定月份-年份的所有巡演日期。

但这就是问题所在。假设我选择 28/11/2018 下午 6: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)但时间不正确。用户保存了期望时间为下午 6.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
});

我想要做的是无论用户在哪个时区。我想将给定的日期和时间按原样保存在数据库中并按原样检索它,以显示在日历中。

我如何做到这一点?

【问题讨论】:

  • 你仔细阅读moment js手册了吗?你有没有想过为什么总是11? 11 月是多少?
  • 我将momentjs格式的格式字符串改为'YYYY-MM-DD hh:mm',所以额外11分钟的问题已经解决。但是,它仍然通过向其添加 IST 值来保存日期时间
  • 你是在 momentJS 还是 fullCalendar 中设置了时区?网络服务器本身呢?你如何解析它到达那里的日期?你有没有调试过它到达服务器时是否仍然有所需的时间(但在它被写入数据库之前)? mySQL 服务器本身(不是 sequelize 连接)是否设置了时区?这里缺少很多信息。
  • 我更新了关于我的问题的信息。我没有在 momentjs、fullcalendar 和 daterangepicker 上设置时区。当日期时间到达服务器时,它的格式与输入字段中的格式相同。
  • (new Date()).toISOString() 将返回 UTC 日期时间(通过添加/减去时区偏移到本地时间... 18:30 - 05:30 = 01:00)。您没有发布剩余的详细信息。但是你可能可以使用 moment js 将本地日期时间转换为 MySQL 期望的格式。

标签: mysql datetime sequelize.js momentjs


【解决方案1】:

如果您通过 sequelize 存储日期,则它将日期存储为 UTC,

所以从前端只需传递 UTC 中的日期,这样它就会被存储 如果您使用日期时间选择器,它会自动将 UTC 转换为您的时区,只需将 UTC 数据传递给您的插件。

通过时只需使用 UTC 即可。

【讨论】:

  • 这就是我想要做的。我想按原样读取用户选择的日期时间值并按原样保存,无论用户在哪个时区。到目前为止,唯一的成功是能够在服务器端一次性获取选定的日期时间值,但是一旦 Sequelize 将其保存到表中,它就会被转换:(
  • 所以,你是对的。看来我再次需要使用时刻将服务器端的日期转换为 utc。
  • 即使使用 UTC 选项也不起作用。一些如何有几个设置不起作用。 Node js 确实需要一个内置的,sequelize 维护得很差。看起来 sequelize 对时区一无所知。
【解决方案2】:
  1. 如果你在mysql中使用DATETIME数据类型,那么值save as is 独立于 mysql time_zone 系统变量。见herehere
  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 调试变量)。 Sequelize(或 mysql2 包,我不知道)也使用 timezone 选项将 mysql 返回的结果转换为 js Date 对象。所以:

    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 插入/选择数据,则无需更改时区选项。

为了在我的工作中正确使用日期时间,我使用以下规则:

  • 对于客户端和服务器之间的传输日期时间,使用唯一确定的格式:UNIXISO 8601(字符串如2017-09-05T13:43:00.000Z);
  • Mysql DB 中的所有 DATETIME 值都以零时区 (+00:00) 存储;所以 Sequelize 的时区选项是 '+00:00';

最后,浏览器使用您计算机上的时区设置。检查所有步骤的值并消除与时区解释错误相关的不确定性。

【讨论】:

  • 这就是发生的事情。我在续集中将时区值设置为 +00:00。如果我在日历中选择 2018 年 5 月 12 日上午 9:00,它在我的服务器端以 2018-12-05T09:00:00 的形式出现(保存之前)。但是插入日期后,变成了2018-12-05 03:30:00。
  • @codeinprogress 您使用什么格式在客户端和服务器之间进行传输?简单的解决方案是从客户端发送dateString = date.toISOString() 的结果并在nodejs 服务器上使用Date.parse(dateString)。请注意,您应该使用这种格式的时区来确定结果,在 ISO 8601 中,“Z”是“+00:00”时区。
【解决方案3】:

好的,经过一番困惑,这是如何解决的。我必须将客户端的日期转换为 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 AM

我还将moment.utc(act.tour_date).format('YYYY-MM-DDTHH:mm:ss') 传递回隐藏输入,以防用户更新记录

感谢所有帮助我解决这个问题的人。感谢您的时间和努力。

【讨论】:

    猜你喜欢
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2011-01-24
    • 2012-12-27
    • 2012-07-16
    • 1970-01-01
    相关资源
    最近更新 更多