【问题标题】:Ruby: Parse Time String to accept in MySql as a valid date timeRuby:解析时间字符串以在 MySql 中接受为有效的日期时间
【发布时间】:2014-02-09 23:13:26
【问题描述】:

我正在解析一组具有时间戳字符串的 xml 记录。我的最终目标是解析这些记录并将它们放入 mysql 数据库中。我是 ruby​​ 新手,通过在线查看其他示例将脚本组合在一起:

这是我的 xml 记录的样子:

  <row Id="253828" UserId="56959" Name="Teacher" Date="2009-03-08T00:27:31.807" />
  <row Id="253829" UserId="22221" Name="Popular Question" Date="2009-03-08T00:32:32.217" />

这是 ruby​​ 方法的样子:

require 'date'

    @st = @my.prepare("insert into badge(id, user_id, name, created) values(?, ?, ?, ?)")
    if element == 'row'
      @st.execute(attributes['Id'], attributes['UserId'], attributes['Name'], DateTime.parse(attributes['Date']).strftime("%F %T"))
    end

但问题是在解析近 10,000 条记录后,我得到一个 mysql 错误:

Incorrect datetime value: '2009-03-08 02:02:32' for column 'created' at row 1 (Mysql::Error)

我开始在 repl 中检查这个,这是 repl 的输出:

irb(main):016:0> DateTime.parse('2009-03-08T00:27:31.807').strftime("%F %T")
=> "2009-03-08 00:27:31"
irb(main):017:0> DateTime.parse('2009-03-08T00:32:32.217').strftime("%F %T")
=> "2009-03-08 00:32:32"

如果您仔细观察,您会发现原始时间字符串具有 2009-03-08T00:27:31.807 和值 807 并没有对转换产生任何影响。因为如果我们将两个时间字符串更改为准确,不同的是 . 之后的最后三位数字,那么我感觉转换不正确。我想知道在保持数据完整性的同时将其转换为有效的 mysql 时间戳的最佳方法是什么。

假设时间字符串是 2009-03-08T00:27:31.8072009-03-08T00:27:31.507 在 repl 上尝试这个会给我们:

irb(main):018:0> DateTime.parse('2009-03-08T00:27:31.807').strftime("%F %T")
=> "2009-03-08 00:27:31"
irb(main):019:0> DateTime.parse('2009-03-08T00:27:31.507').strftime("%F %T")
=> "2009-03-08 00:27:31"

它们都是相同的时间戳,但它们是吗?

我在 StackExchange 数据库管理部分发现了以下帖子:https://dba.stackexchange.com/questions/48704/mysql-5-6-datetime-incorrect-datetime-value-2013-08-25t1700000000-with-er 不确定我是否应该这样做。

从mysql方面给出一个完整的图片:这是我的表的样子:

CREATE TABLE badge
(
    id INT NOT NULL PRIMARY KEY,
    user_id INT NOT NULL,
    name VARCHAR(40) NULL,
    created TIMESTAMP
);

【问题讨论】:

  • 为了在Ruby中表示时间戳,还需要加上%N来获取毫秒。 DateTime.parse('2009-03-08T00:27:31.807').strftime("%F %T.%N") =&gt; "2009-03-08 00:27:31.807000000"
  • @CBroe 哇,那真是一场灾难,因为我对这些数据所做的任何分析都将不准确。我可以采取哪些步骤?
  • @SeanRedmond 谢谢,看起来现在我们正在捕获它,但正如 CBroe 所说,MySQL 会放弃它。我想知道这方面的最佳做法是什么。我敢打赌我不是第一个看到这个问题的人:)
  • 如果您需要小数秒数据,则必须将其存储在单独的列中。

标签: mysql ruby


【解决方案1】:

在 MySQL 中,存储时间信息的分辨率是一秒。您显示的毫秒值 (.807) 等无法存储。就您的桌子而言,2009-03-08T00:27:31.8072009-03-08T00:27:31.507 恰好发生在同一秒。

从 MySQL 5.6.4 版开始,如果您正确定义列的数据类型,则可以存储小数时间数据。见https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html

您可以通过将您的ISO 8601 timestamps 作为文本字符串传递给数据库,然后使用具有如下形式的 MySQL 查询进行日期/时间转换,从而成功完成 xml 到 MySQL 的转换过程:

 INSERT INTO whatever
    ...
  VALUES 
     (..., 
      CAST(STR_TO_DATE( ? ,'%Y-%m-%dT%H:%i:%s.%f') AS DATETIME),    
      ...)

我已经在各种服务器版本上进行了尝试。它似乎是版本证明。

如果您使用的是 5.6.4 之前的 MySQL,并且需要保持毫秒数,那么您在不久的将来会感到头疼。您可能会考虑将时间戳存储为 UNIX 风格的微秒在 bigint 中。您的应用程序代码将需要使用 strftime("%Q") 来获取微秒级 UNIX 时间戳。

如果您的任何日期在 1970 年 1 月 1 日之前,这也不起作用。

【讨论】:

  • 刚刚编辑了问题以添加表创建信息。还有我如何在红宝石中进行插入。你认为我应该以不同的方式创建列吗?
  • 所以我应该首先使用strftime("%Q")获取unix时间,然后使用该时间插入数据库,然后再转换。
  • 在不知道自己要做什么的情况下,很难更具体地说明应该做什么。对于许多应用来说,一秒的时间分辨率就足够了。它可能不适用于此应用程序。但如果您需要毫秒时间戳,了解原因会有所帮助。
  • XML 数据文件是数据转储,我创建了一个 MySQL 数据库来存储它们以进行行为分析等分析工作。在这种情况下,毫秒并不是那么重要,但我想我会使用strftime("%Q"),正如你所说的那样来获取 UNIXTIME 并将其存储在数据库中,这样我就不会丢失任何信息。在分析过程中,只需从 ruby​​ 或 python 或 R 转换为年、月、日期、时间......
猜你喜欢
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-12
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
相关资源
最近更新 更多