如何使用时区信息在MySQL中存储日期时间

How to store a datetime in MySQL with timezone info

我有数千张在坦桑尼亚拍摄的照片,我想把每张照片的拍摄日期和时间存储在MySQL数据库中。但是,服务器位于美国,当我试图存储一个坦桑尼亚日期时间时,会遇到问题,该时间在春季夏令时(在美国)的"无效"时间内。坦桑尼亚不做DST,所以时间实际上是一个有效的时间。

另外一个复杂的情况是,来自许多不同时区的合作者需要访问数据库中存储的日期时间值。我希望他们总是以坦桑尼亚时代的形式出现,而不是在各个合作者所处的当地时代。

我不愿意设置会话时间,因为我知道当有人某个时候忘记设置会话时间而把时间搞错时,会出现问题。我无权更改服务器的任何内容。

我读过:夏令时和时区最佳实践mysql日期时间字段和夏令时——如何引用"额外"小时?和将datetime存储为php/mysql中的UTC

但他们似乎都没有解决我的特殊问题。我不是SQL专家;在设置日期时间时是否有指定时区的方法?我没见过。否则,任何关于如何处理这个问题的建议都将受到极大的赞赏。

编辑:下面是我遇到的问题的一个例子。我发送命令:

1
2
INSERT INTO Images (CaptureEvent, SequenceNum, PathFilename, TimestampJPG)
VALUES (122,1,"S2/B04/B04_R1/IMAG0148.JPG","2011-03-13 02:49:10")

我得到了错误:

1
Error 1292: Incorrect datetime value: '2011-03-13 02:49:10' for column 'TimestampJPG'

这个日期和时间存在于坦桑尼亚,但不存在于数据库所在的美国。


你说:

I want them to always come out as Tanzanian time and not in the local times that various collaborator are in.

如果是这种情况,则不应使用UTC。您只需要在MySQL中使用DATETIME类型,而不是TIMESTAMP类型。

从MySQL文档中:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.)

如果已经在使用DATETIME类型,则不能在本地时间开始设置。您将需要较少地关注数据库,而更多地关注您的应用程序代码——这里没有显示这些代码。根据语言的不同,问题和解决方案会有很大的不同,因此请确保用应用程序代码的适当语言标记问题。


您描述的所有症状都表明您永远不会告诉MySQL使用什么时区,所以它默认为系统的时区。想一想:如果它只剩下'2011-03-13 02:49:10',怎么能猜到它是当地的坦桑尼亚日期?

据我所知,MySQL没有提供任何语法来指定日期中的时区信息。您必须根据每个连接对其进行更改;例如:

1
SET time_zone = 'EAT';

如果这不起作用(要使用命名区域,您需要将服务器配置为这样做,但通常情况并非如此),您可以简单地使用UTC偏移量:

1
SET time_zone = '+03:00';


MySQL存储的日期时间不包含时区信息。假设您将"2019-01-01 20:00:00"存储到一个日期时间字段中,当您检索该值时,您应该知道它属于哪个时区。

所以在您的例子中,当您将一个值存储到日期时间字段中时,请确保它是坦桑尼亚时间。当你把它拿出来的时候,坦桑尼亚时间到了。哎呀!

现在,最棘手的问题是:当我进行插入/更新时,如何确保值是坦桑尼亚时间?两例:

  • 你做的是INSERT INTO table (dateCreated) VALUES (CURRENT_TIMESTAMP or NOW())

  • 您执行INSERT INTO table (dateCreated) VALUES (?),并从应用程序代码中指定当前时间。

  • 第1案

    MySQL将采用当前时间,假设是"2019-01-01 20:00:00"坦桑尼亚时间。然后mysql会将其转换为utc,结果是"2019-01-01 17:00:00",并将该值存储到字段中。

    那么,你如何获得坦桑尼亚时间,也就是20:00:00,储存到野外?这是不可能的。从该字段读取时,您的代码需要预计UTC时间。

    第2案

    这取决于作为?传递的值的类型。如果您通过字符串"2019-01-01 20:00:00",那么这对您很好,这正是将存储到数据库的内容。如果传递某种类型的日期对象,那么它将取决于db驱动程序如何解释该日期对象,以及它为MySQL提供的最终"YYYY-MM-DD hh:mm:ss"字符串。数据库驱动程序的文档应该告诉您。