我使用的是美国/纽约时区。在秋天我们"回落"的一个小时--有效地"获得"一个小时,凌晨2点。在过渡点的出现以下情况:

这是01:59:00-04:00
然后1分钟后就变为:
01:00:00 -05:00

所以如果你只是说"1:30"它的含糊不清的作为是否或不你是指第一时间1:30卷周围的或第二位。我想保存的调度数据的一个数据库并不能确定如何节省的时间正确。

这里的问题:
"2009-11-01 00:30:00"在内部存储为2009-11-01 00:30:00-04:00
"2009-11-01 01:30:00"在内部存储为2009-11-01 01:30:00 -05:00

这是好的和相当预期的。但我怎么拯救任何01:30:00 -04:00?的 文档 没有显示任何支持,用于规定的偏移的,因此,当我试着指定的偏移它已经适当忽略。

唯一的解决方案,我已经想到了涉及设置的服务器时不使用日光节省时间并做必要的变革在我的脚本(我采用PHP为此)。但是,这似乎不是应该有必要的。

非常感谢任何建议。

有帮助吗?

解决方案

坦率地说,MySQL 的日期类型已损坏且无法存储 全部 除非您的系统设置为恒定偏移时区,例如 UTC 或 GMT-5,否则时间正确。(我使用的是MySQL 5.0.45)

这是因为 您无法存储夏令时结束前一小时内的任何时间. 。无论您如何输入日期,每个日期函数都会将这些时间视为切换后的一小时内。

我的系统时区是 America/New_York. 。让我们尝试存储 1257051600(Sun, 01 Nov 2009 06:00:00 +0100)。

这里使用专有的 INTERVAL 语法:

SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3599 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3600 SECOND); # 1257055200

SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 1 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 0 SECOND); # 1257055200

甚至 FROM_UNIXTIME() 不会返回准确的时间。

SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051599)); # 1257051599
SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051600)); # 1257055200

奇怪的是,日期时间 将要 当 DST 开始时(例如, 2009-03-08 02:59:59)。但在任何 MySQL 函数中使用这些日期都是有风险的:

SELECT UNIX_TIMESTAMP('2009-03-08 01:59:59'); # 1236495599
SELECT UNIX_TIMESTAMP('2009-03-08 02:00:00'); # 1236495600
# ...
SELECT UNIX_TIMESTAMP('2009-03-08 02:59:59'); # 1236495600
SELECT UNIX_TIMESTAMP('2009-03-08 03:00:00'); # 1236495600

要点:如果您需要存储和检索 每一个 一年中的某个时候,您有一些不受欢迎的选择:

  1. 将系统时区设置为 GMT + 一些常量偏移量。例如。世界标准时间
  2. 将日期存储为 INT(正如 Aaron 发现的那样,TIMESTAMP 甚至不可靠)

  3. 假设 DATETIME 类型有一些恒定的时区偏移量。例如。如果你在 America/New_York, ,将您的日期转换为 GMT-5 MySQL 之外, ,然后存储为 DATETIME (事实证明这很重要:参见亚伦的回答)。那么你必须非常小心地使用 MySQL 的日期/时间函数,因为有些函数假设你的值是系统时区,而其他函数(尤其是系统时区)则假设你的值是系统时区。时间算术函数)是“与时区无关的”(它们的行为可能就像时间是 UTC 一样)。

Aaron 和我怀疑自动生成的 TIMESTAMP 列也被破坏了。两个都 2009-11-01 01:30 -04002009-11-01 01:30 -0500 将被存储为不明确的 2009-11-01 01:30.

其他提示

我已经想通弄明白了,我的目的。我总结一下我学会了(不好意思,这些钞票是冗长的,他们尽可能多的为我的未来转诊别的)。

相反的是我在我以前的评论,DATETIME和TIMESTAMP领域一说就表现不同。时间戳字段(如文档显示)采取任何你在“YYYY-MM-DD HH:MM:SS”给他们格式,并从当前时区转换为UTC时间。当你检索数据的反向透明地发生。 DATETIME字段不进行这种转换。他们采取任何你给他们,只是直接存储。

<强>无论是DATETIME也不时间戳字段类型可以精确地将数据存储在用于观察DST 时区。如果存储“2009-11-01 01:30:00”的字段没有办法区分哪些1:30版本是你想要的 - 在-04:00或-05:00版

好了,所以我们必须存储我们在非DST时区(如UTC)的数据。时间戳字段无法准确地处理这些数据的原因,我将解释:如果您的系统设置为DST时区那么你投入TIMESTAMP可能不是你所得到的退了出去。即使你把它,你已经转换为UTC数据时,它仍然会承担数据在您的本地时区,做又转换为UTC。此时间戳强制本地至UTC-后端到本地往返是有损当本地时区观察DST(因为“2009-11-01 01:30:00”映射到2个不同的可能的倍)。

使用DATETIME,你可以存储你的数据在任何你想要的时区,并且相信你会回来不管你把它(你不要逼成时间戳字段你强加有损往返转换)。所以,解决的办法是保存到现场之前,使用日期时间字段和 从您的系统时区转换成你想要将其保存在任何非DST区(我认为UTC可能是最好的选择) 。这允许你建立转换逻辑到你的脚本语言,这样就可以明确地保存UTC相当于“2009-11-01 01:30:00 -04:00”或“” 2009-11-01 01:30: 00 -05:00"

需要注意的另一个重要的事情是,MySQL的日期/时间的数学函数不正确周围DST界限,如果你存储在DST TZ日期工作。因此,更有理由在UTC保存。

在简而言之我现在这样做:

当从数据库中检索数据:

显式解释,以获得精确的Unix时间戳从数据库为UTC的MySQL以外的数据。我使用PHP的的strtotime()函数或本公司DateTime类。它不能可靠内部使用MySQL的CONVERT_TZ()或UNIX_TIMESTAMP()函数,因为CONVERT_TZ将只输出一个“:MM:YYYY-MM-DD HH SS”完成的MySQL从歧义问题遭受值,和UNIX_TIMESTAMP()假定其输入是在系统中的时区,而不是数据实际上存储在(UTC)时区。

当将数据存储到数据库中:

将您的日期,你的愿望的MySQL之外的精确UTC时间。例如:用PHP的DateTime类可以指定“2009-11-01 1:30:00 EST”,有别于“2009-11-01 1:30:00 EDT”,然后将其转换为UTC和保存正确的UTC时间您的日期时间字段。

呼。非常感谢大家的输入和帮助。希望这样可以节省别人有些头疼的道路。

顺便说一句,我看到这在MySQL 5.0.22和5.0.27

我觉得micahwittman的链接拥有这些最好的实际解决方案MySQL的局限性:当您连接设置会话时区为UTC:

SET SESSION time_zone = '+0:00'

然后你只需把它的Unix时间戳,一切都应该罚款。

此线程让我抓狂,因为我们使用TIMESTAMP On UPDATE CURRENT_TIMESTAMP列(即:recordTimestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)来跟踪更改的记录和ETL的数据仓库

在的情况下有人怀疑,在这种情况下,正确地TIMESTAMP行为并可以由TIMESTAMP转换为Unix时间戳的两个类似的日期之间的区分:

select TestFact.*, UNIX_TIMESTAMP(recordTimestamp) from TestFact;

id  recordTimestamp         UNIX_TIMESTAMP(recordTimestamp)
1   2012-11-04 01:00:10.0   1352005210
2   2012-11-04 01:00:10.0   1352008810

但我怎么拯救任何01:30:00 -04:00?

你可以转换为UTC,如:

SELECT CONVERT_TZ('2009-11-29 01:30:00','-04:00','+00:00');


更好的是,保存日期为 时间戳 领域。这就是始终存在UTC,并UTC不知道夏季/冬天的时候。

你可以把从UTC到使用localtime CONVERT_TZ:

SELECT CONVERT_TZ(UTC_TIMESTAMP(),'+00:00','SYSTEM');

其中'+00:00'是UTC,从时区,和"系统"是当地的时区系统,其中MySQL运行。

Mysql的固有解决使用TIME_ZONE_NAME表从MySQL分贝这个问题。 使用CONVERT_TZ而CRUD到,而无需担心夏令时更新日期时间。

SELECT
  CONVERT_TZ('2019-04-01 00:00:00','Europe/London','UTC') AS time1,
  CONVERT_TZ('2019-03-01 00:00:00','Europe/London','UTC') AS time2;

我正在记录的页面访问计数和显示在图中的计数(使用FLOT jQuery插件)。我充满了测试数据和一切表中查找罚款,但我注意到,在图的结束点是根据在x轴标签休息一天。考试结束后,我注意到,对于2015年10月25日当天的观看次数已经从数据库所以每天两次检索并传递到海军报,在此之后的日期是由一天向右移动。结果 在我的代码寻找错误一段时间后,我意识到,这个日期是DST发生。然后,我来到这个页面SO ...点击 ...但建议的解决方案是什么,我需要或他们有其他缺点的矫枉过正。 我不是不能够含糊时间戳之间的区分很担心。我只需要每天数和显示记录。

首先,我检索的时间范围:

SELECT 
    DATE(MIN(created_timestamp)) AS min_date, 
    DATE(MAX(created_timestamp)) AS max_date 
FROM page_display_log
WHERE item_id = :item_id

然后,在for循环中,从min_date,与max_date结束,通过一天(60*60*24)的步骤,我检索计数:

for( $day = $min_date_timestamp; $day <= $max_date_timestamp; $day += 60 * 60 * 24 ) {
    $query = "
        SELECT COUNT(*) AS count_per_day
        FROM page_display_log
        WHERE 
            item_id = :item_id AND
            ( 
                created_timestamp BETWEEN 
                '" . date( "Y-m-d 00:00:00", $day ) . "' AND
                '" . date( "Y-m-d 23:59:59", $day ) . "'
            )
    ";
    //execute query and do stuff with the result
}

我的最终快捷的解决方案的问题是这样的:

$min_date_timestamp += 60 * 60 * 2; // To avoid DST problems
for( $day = $min_date_timestamp; $day <= $max_da.....

所以我的不盯着在当天开始的循环,但两个小时后。这一天还是一样,我仍然获取正确的次数,因为我明确要求00:00:00,一天的23:59:59之间的记录的数据库,无论时间戳的实际时间。而当时间跳跃一个小时,我仍然在正确的日期。

注:我知道这是5岁的线程,我知道这是不是一个答案,有机磷农药的问题,但它可能会帮助我这样的人谁遇到这样的页面寻找解决我所描述的问题

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top