我有数千张在坦桑尼亚拍摄的照片,我想将每张照片的拍摄日期和时间存储在MySQL数据库中。然而,服务器位于美国,当我试图存储坦桑尼亚的日期时间时,遇到了问题,该日期福尔斯 Spring 夏令时(美国)的“无效”小时内。坦桑尼亚不执行夏令时,因此该时间实际上是有效时间。
其他复杂的情况是,有来自许多不同时区的合作者,他们将需要访问存储在数据库中的日期-时间值。我希望它们 * 总是 * 显示为坦桑尼亚时间,而不是不同合作者所在的当地时间。
我不愿意设置会话时间,因为我知道有时候有人忘记设置会话时间,而得到的时间都是错误的,这会有问题。而且我没有权限更改服务器的任何内容。
我已经读过了
但它们似乎都没有解决我的问题。在设置DATETIME时,有没有办法指定时区?我还没有看到过。另外,如果有任何关于如何解决这个问题的建议,我们将非常感谢。
编辑:下面是我遇到的问题的一个例子。
INSERT INTO Images (CaptureEvent, SequenceNum, PathFilename, TimestampJPG)
VALUES (122,1,"S2/B04/B04_R1/IMAG0148.JPG","2011-03-13 02:49:10")
然后我得到错误:
Error 1292: Incorrect datetime value: '2011-03-13 02:49:10' for column 'TimestampJPG'
此日期和时间在坦桑尼亚存在,但在数据库所在的美国不存在。
7条答案
按热度按时间qacovj5a1#
你说:
我希望他们总是出来作为坦桑尼亚时间,而不是在当地时间,各种合作者都在。
如果是这样的话,那么你就不应该使用UTC。你所需要做的就是在MySQL中使用
DATETIME
类型,而不是TIMESTAMP
类型。From the MySQL documentation:
MySQL将
TIMESTAMP
值从当前时区转换为UTC以进行存储,然后将其从UTC转换回当前时区以进行检索。(对于其他类型,如DATETIME
,则不会发生这种情况。)如果您 * 已经 * 使用
DATETIME
类型,那么您一定没有在本地时间开始设置它。您需要少关注数据库,多关注您的应用程序代码-您在这里没有显示。问题和解决方案将根据语言的不同而有很大差异,所以请确保使用您的应用程序代码的适当语言来标记问题。sdnqo3pr2#
这里没有一个答案是一针见血的。
如何在MySQL中使用时区信息存储日期时间
使用两列:
DATETIME
,以及VARCHAR
,用于保存时区信息,时区信息可以是以下几种形式:timezone或 * 位置 *(如
America/New_York
)是最高的数据保真度。timezone abbreviation(如
PST
)是下一个最高保真度。在这方面,诸如
-2:00
的 * 时间偏移 * 是最小的数据量。一些要点:
TIMESTAMP
,因为它仅限于2038年,并且MySQL将其与服务器时区相关联,这可能是不希望的。INT
字段中,因为存在半小时和刻钟偏移量。如果让MySQL按时间顺序 * 比较 * 或 * 排序 * 这些日期对您的用例很重要,那么
DATETIME
就有一个问题:'2009-11-10 11:00:00 -0500'
在“瞬时时间”方面在'2009-11-10 10:00:00 -0700'
之前,但是当插入到DATETIME
中时,它们将以另一种方式排序。您可以自己转换为UTC。
'2009-11-10 16:00:00'
和'2009-11-10 17:00:00'
,这将正确排序。在检索数据时,您将使用时区信息将其还原为原始形式。我非常喜欢的一个recommendation有 * 三 * 列:
local_time DATETIME
utc_time DATETIME
time_zone VARCHAR(X)
,其中X表示您在其中存储的数据类型。(我会选择64个字符表示时区/位置。)3列方法的一个优点是它是显式的:对于单个
DATETIME
列,您无法一眼看出它在插入之前是否已转换为UTC。关于准确性随时区/缩写/偏移量的下降:
America/Juneau
),您就可以精确地知道他们在过去或未来任何时间点的挂钟时间(除非变更该位置行程日光节约的方式)。DST的开始/结束点,以及是否使用它,都取决于位置,因此这是唯一可靠的方式。-0700
之类的普通偏移量,您将无法预测过去或未来的挂钟时间。例如,在美国,科罗拉多州和亚利桑那州都使用MST,但亚利桑那州不遵守DST。因此,如果用户在冬季月份上传了14:00 -0700
的猫照片,他在亚利桑那州还是加州州?如果在该日期上加上六个月,用户的日期是14:00
还是13:00
?当您的应用程序将时间、日期或调度作为核心功能时,这些事情是需要考虑的。
参考文献:
(披露:我没有读这整篇文章。)
xesrikrc3#
MySQL存储DATETIME * 时没有 * 时区信息。假设您将'2019-01-01 20:00:00'存储到DATETIME字段中,当您检索该值时,您 * 应该知道 * 它属于哪个时区。
因此,在您的情况下,当您将值存储到DATETIME字段中时,请确保它是坦桑尼亚时间。然后,当您将它取出时,它将是坦桑尼亚时间。耶!
现在,棘手的问题是:当我执行INSERT/UPDATE时,如何确保值是坦桑尼亚时间?两种情况:
1.你做
INSERT INTO table (dateCreated) VALUES (CURRENT_TIMESTAMP or NOW())
。1.执行
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的内容。如果你传递某种类型的Date对象,那么这将取决于 * db驱动程序如何解释该Date对象 *,以及最终它提供给MySQL存储的'YYYY-MM-DD HH:mm:ss'字符串。db驱动程序的文档应该告诉你。pxiryf3j4#
您所描述的所有症状都表明您从未告诉MySQL使用哪个时区,因此它默认为系统时区。如果它只有
'2011-03-13 02:49:10'
,它怎么能猜出这是坦桑尼亚本地日期?据我所知,MySQL没有提供任何语法来指定日期中的时区信息。类似于:
如果这不起作用(要使用命名区域,您需要the server has been configured来完成,但通常情况下并非如此),您可以使用UTC偏移量,因为在编写本文时Tanzania does not observe daylight saving time,但当然这不是最佳选择:
oalqel3c5#
从**MySQL 8.0.19**开始,您可以在将
TIMESTAMP
和DATETIME
值插入数据表时指定时区位移。偏移量附加到日期时间文字的时间部分,中间没有空格,并且使用与设置
time_zone
系统变量相同的格式,但以下情况除外:EET
”和“Asia/Shanghai
”之类的时区名称;“SYSTEM
”也不能用于此上下文中。插入的值的月部分、日部分或两者都不能为零。从MySQL 8.0.22开始强制执行此操作,无论服务器SQL模式设置如何。
示例:
此范例说明如何使用不同的time_zone设定,将具有时区位移的日期时间值插入
TIMESTAMP
和DATETIME
数据行,然后撷取它们:注意事项:
TIMESTAMP
值从当前时区转换为UTC以进行存储,然后将其从UTC转换回当前时区以进行检索。(对于其他类型,如DATETIME
,则不会发生这种情况。)a0zr77ik6#
我曾经也遇到过这样一个问题,我需要保存不同合作者使用的数据,最后我以unix时间戳的形式存储时间,它表示自1970年1月以来的秒数,是一种整数格式。例如,坦桑尼亚的今天的日期和时间是
Friday, September 13, 2019 9:44:01 PM
,当存储在unix时间戳中时将是1568400241
现在阅读数据时,只需使用php或任何其他语言,从unix时间戳中提取日期。
这使得与其他协作者在不同的位置存储数据变得更加容易。他们可以简单地将日期转换为带有自己的gmt偏移量的unix时间戳,并以整数格式存储它,当输出时,只需使用
xesrikrc7#
你不能...你会发现很多答案说你“这是不必要的,存储使用UTC”,但它是:您需要存储带时区的日期时间,而MySQL不能...
我在Postgres工作了10年,所有这类问题都不存在(日期时间和时区的管理没有摩擦,您可以透明地存储和比较不同时区中表示的日期时间,ISOString格式的管理很自然,等等...)。
我实际上在MariaDB工作,我不明白为什么在2022年,在一个全球化的世界,MySQL仍然不支持每值时区。