【问题标题】:python 2.7 mktime gives different values of the same inputspython 2.7 mktime 给出相同输入的不同值
【发布时间】:2016-05-20 02:39:47
【问题描述】:

以下代码在 Windows 上运行良好,在 Linux[Ubuntu] 上的结果很奇怪。 我的python版本是2.7

from datetime import datetime
from datetime import timedelta
import time

def time_diff(date_str_1, date_str_2):
    time_stamp_1 = time.mktime(time.strptime(date_str_1, '%Y-%m-%d-%H-%M-%S'))
    time_stamp_2 = time.mktime(time.strptime(date_str_2, '%Y-%m-%d-%H-%M-%S'))
    print '==='
    print date_str_1,date_str_2
    print time_stamp_1,time_stamp_2
    delta1 = time_stamp_2 - time_stamp_1
    return delta1

print time_diff('2015-11-01-01-00-00', '2015-11-01-01-30-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-02-00-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-02-30-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-03-00-00')

Windows 中的结果

===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446310800.0 1446312600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446310800.0 1446314400.0
3600.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446310800.0 1446316200.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446310800.0 1446318000.0
7200.0

Linux 中的结果

===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446364800.0 1446366600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446364800.0 1446372000.0
7200.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446368400.0 1446373800.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446368400.0 1446375600.0
7200.0

在 Linux 上 '2015-11-01-01-00-00' 有时是 1446364800.0 然后变成 1446368400.0

这是什么原因?是bug吗?

【问题讨论】:

    标签: python linux datetime


    【解决方案1】:

    我猜你的 linux 系统有问题。我在一个类似于 BSD unix 的 macOS 上运行,也在 pythonanywhere 上运行,一个 linux 服务器,两者都得到了与你的 Windows 完全相同的结果。

    ===
    2015-11-01-01-00-00 2015-11-01-01-30-00
    1446339600.0 1446341400.0
    1800.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-00-00
    1446339600.0 1446343200.0
    3600.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-30-00
    1446339600.0 1446345000.0
    5400.0
    ===
    2015-11-01-01-00-00 2015-11-01-03-00-00
    1446339600.0 1446346800.0
    7200.0
    

    我建议您检查所有语言环境配置以了解更改内容,例如 datetime。您可以通过在 bash 中输入 locale 来检查。我这里的两个环境都有LC_CTYPE="UTF-8"。其他人要么是"C"要么是POSIX

    LANG=
    LC_COLLATE="C"
    LC_CTYPE="UTF-8"
    LC_MESSAGES="C"
    LC_MONETARY="C"
    LC_NUMERIC="C"
    LC_TIME="C"
    LC_ALL=
    

    【讨论】:

    • 结果取决于本地时区(即,如果您和 OP 在不同时区的计算机上运行代码,则结果可能会有所不同)。 mktime() 可能会在 Linux 上使用 tz 数据库(不同时间本地时区的 utc 偏移量可能不同)。
    【解决方案2】:

    time.mktime() 返回自 1970.01.01 00:00:00 以来添加操作系统时区的秒数。如果值更改,则可能您的操作系统时区已更改。

    deepin@deepin-pc:~/test$ python testtime.py 
    ===
    2015-11-01-01-00-00 2015-11-01-01-30-00
    1446310800.0 1446312600.0
    1800.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-00-00
    1446310800.0 1446314400.0
    3600.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-30-00
    1446310800.0 1446316200.0
    5400.0
    ===
    2015-11-01-01-00-00 2015-11-01-03-00-00
    1446310800.0 1446318000.0
    7200.0
    deepin@deepin-pc:~/test$ date -R
    Fri, 20 May 2016 11:26:43 +0800
    deepin@deepin-pc:~/test$ python testtime.py 
    ===
    2015-11-01-01-00-00 2015-11-01-01-30-00
    1446373800.0 1446375600.0
    1800.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-00-00
    1446373800.0 1446377400.0
    3600.0
    ===
    2015-11-01-01-00-00 2015-11-01-02-30-00
    1446373800.0 1446379200.0
    5400.0
    ===
    2015-11-01-01-00-00 2015-11-01-03-00-00
    1446373800.0 1446381000.0
    7200.0
    deepin@deepin-pc:~/test$ date -R
    Thu, 19 May 2016 17:56:59 -0930
    deepin@deepin-pc:~/test$
    

    【讨论】:

      【解决方案3】:

      1446364800.01446368400.0 都是 '2015-11-01 01:00:00' 输入的有效时间戳(在 America/Los_Angeles 时区中):

      >>> from datetime import datetime
      >>> import pytz     # $ pip install pytz
      >>> import tzlocal  # $ pip install tzlocal
      >>> tz = tzlocal.get_localzone()
      >>> epoch = datetime(1970, 1, 1, tzinfo=pytz.utc)
      >>> (tz.localize(datetime(2015, 11, 1, 1), is_dst=True) - epoch).total_seconds()
      1446364800.0
      >>> (tz.localize(datetime(2015, 11, 1, 1), is_dst=False) - epoch).total_seconds()
      1446368400.0
      

      time.mktime() 是对应 C mktime() 函数的薄包装。 mktime() 可能可以访问 Linux 上的 tz 数据库,因此它会尝试在那里找到正确的 utc 偏移量。如果时间像您的情况一样不明确,那么结果可能取决于mktime() 调用的历史记录:

      >>> import time
      >>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # ambiguous time in Los Angeles
      1446364800.0                                        # random value
      >>> time.mktime((2015, 11, 1, 3, 0, 0, -1, -1, -1)) # unambiguous
      1446375600.0                                        # EST time
      >>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # EST utc offset is chosen
      1446368400.0
      >>> time.mktime((2015, 11, 1, 0, 0, 0, -1, -1, -1)) # unambiguous
      1446361200.0                                        # EDT time
      >>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # EDT utc offset is chosen
      1446364800.0
      

      在这种情况下,如果输入不明确,mktime() 默认为最后一个 utc 偏移量(在我的机器上)。

      Windows 不提供对the tz databasepython 进程的访问权限,因此mktime() 可能会使用当前的(可能对于过去的日期不正确)UTC 偏移量。

      python converting string in localtime to UTC epoch timestamp

      【讨论】:

        【解决方案4】:

        看起来像 DST 问题...

        大部分日期只是舍入误差,除了 ...

        2015-11-01-01-00-00 2015-11-01-02-00-00
        

        Windows 提供 3600.0 与 linux 7200.0。这正好相差一小时。

        您选择的这两个日期恰好是 2015 年从夏令时到标准时间的过渡时间。

        因此,所有其他因素都相同(例如,时区设置正确)可能是如何处理的一个因素。日期是在 DST 转换之前还是之后考虑的。

        也就是说,mktime 是否认为您有一个以 DST 表示的日期。这可能会根据 libc mktime 实现而有所不同。

        不久前,我的 perl 代码需要一个[更好的]mktime 实现,所以我查看了glibc 与(例如netBSD)中的mktime 源代码,它们在做事方式上绝对不同.

        我查看了*BSDandroidminux 和 IIRC 上的许多实现,它们都与netBSD 版本相似/相同。不知道,自从我这样做以来已经有一段时间了。但是,glibc 版本看起来像是从头开始编写的,而不是从其他任何版本派生而来的。

        显然,我不知道 Window 的版本,但如果他们想借用一些代码,他们可能会借用 BSD 风格的实现,部分是为了许可,但也因为他们可能在 linux 出现之前就借用了代码在现场。再说一次,不知道。

        2015 年的夏令时过渡是:

        03/08/2015 02:00:00 [Sun] --> 03/08/2015 03:00:00 [Sun] (spring forward)
        11/01/2015 01:00:00 [Sun] <-- 11/01/2015 02:00:00 [Sun] (fall back)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-19
          • 1970-01-01
          相关资源
          最近更新 更多