【问题标题】:Convert datetime to Unix timestamp and convert it back in python将 datetime 转换为 Unix 时间戳并将其转换回 python
【发布时间】:2013-11-17 01:53:36
【问题描述】:

我有dt = datetime(2013,9,1,11),我想获取此日期时间对象的 Unix 时间戳。

当我执行(dt - datetime(1970,1,1)).total_seconds() 时,我得到了时间戳1378033200

当使用datetime.fromtimestamp 将其转换回来时,我得到了datetime.datetime(2013, 9, 1, 6, 0)

时间不匹配。我在这里错过了什么?

【问题讨论】:

  • 附带说明,如果您使用的是 Python 3.3+,那么您真的非常想使用 timestamp 方法,而不是自己尝试。一方面,这完全避免了从不同时区减去幼稚时间的可能性。
  • dt 来自哪里?是当地时间还是 UTC 时间?
  • @abarnert 我还想提交清除所有代码页和 unicode 符号的请求,也就是说,禁止所有非 ascii 和非默认代码页语言。仍然允许绘制符号。
  • @DanielF:请求被拒绝。我对在这里创造一种单一世界的语言不感兴趣,即使我们这样做了,我也不想让历史语言学家和托尔金学者的生活变得不可能。 Unicode 已经解决了这个问题,除了某些组织和产品(TRON 联盟、在 UTF-8 上使用 Shift-JIS 的日本软件、Microsoft 仍在为用户文本文件提供默认为 cp1252 的操作系统以及各种假装 UTF -16 是一个固定宽度的字符集和/或与 Unicode 相同的字符集)需要受到惩罚才能使它们对齐。

标签: python datetime timestamp


【解决方案1】:

您在这里错过的是时区。

假设您已经离开 UTC 五个小时,所以 2013-09-01T11:00:00 local 和 2013-09-01T06:00:00Z 是同一时间。

您需要阅读datetime 文档的顶部,其中解释了时区以及“幼稚”和“感知”对象。

如果您最初的原始日期时间是 UTC,则恢复它的方法是使用 utcfromtimestamp 而不是 fromtimestamp

另一方面,如果您最初的原始日期时间是本地的,那么您一开始就不应该从中减去 UTC 时间戳;请改用datetime.fromtimestamp(0)

或者,如果您有一个感知日期时间对象,您需要在双方都使用本地(感知)纪元,或者显式转换为 UTC。

如果您拥有或可以升级到 Python 3.3 或更高版本,则只需使用 timestamp 方法即可避免所有这些问题,而不是自己尝试弄清楚如何去做。即使你不这样做,你也可以考虑borrowing its source code

(如果您可以等待 Python 3.4,看起来PEP 341 可能会进入最终版本,这意味着 JF Sebastian 和我在 cmets 中谈论的所有内容都应该只需要标准库,并且在 Unix 和 Windows 上以相同的方式工作。)

【讨论】:

  • 如果dt 在本地时区,那么问题中的公式不正确datetime.fromtimestamp(0)(当前时区中的纪元)应该使用而不是datetime(1970, 1,1)(UTC 中的unix 纪元)。
  • @J.F.Sebastian:我不想详细介绍所有三种可能性,但我想你是对的,我应该。
  • btw, fromtimestamp(0) 可能会失败,如果系统不存储历史时区信息,例如,在 Windows 上。在这种情况下可以使用pytz
  • @J.F.Sebastian:但是pytz 没有帮助,除非你已经知道你所在的时区;要以编程方式执行此操作,您需要一个不同的库来获取当前 Windows 时区并将其转换为 pytz 时区和/或按名称查找。
  • tzlocal 模块也可以在 Windows 上运行。这是您可以convert utc time to local time 的方法。
【解决方案2】:

而不是这个表达式从dt创建一个POSIX时间戳,

(dt - datetime(1970,1,1)).total_seconds()

使用这个:

int(dt.strftime("%s"))

我在你的例子中使用第二种方法得到了正确的答案。

编辑:一些后续行动......在一些 cmets 之后(见下文),我很好奇 strftime 中缺乏对 %s 的支持或文档。这是我发现的:

datetimetimePython source 中,字符串STRFTIME_FORMAT_CODES 告诉我们:

"Other codes may be available on your platform.
 See documentation for the C library strftime function."

所以现在如果我们man strftime(在诸如 Mac OS X 等 BSD 系统上),你会发现对 %s 的支持:

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

无论如何,这就是%s 在它所使用的系统上工作的原因。但是对于 OP 的问题有更好的解决方案(考虑时区)。在此处查看@abarnert 接受的答案。

【讨论】:

  • 这是无证行为(我相信)。例如在 Windows 上,它会导致“无效的格式字符串”。
  • @CrescentFresh,很有趣。也许你是对的。虽然我在文档中没有看到strftime("%s"),但我只是确认它可以在 Mac 和 Linux 上运行。谢谢。
  • 显然它忽略了 tzinfo 字段。
  • @DarrenStone:你不需要阅读源代码。 time.strftime()datetime.strftime 文档都委托给平台 strftime(3) 函数以获取不受支持的指令。 %s 即使在 Mac OS X 上也可能会失败,例如 datetime.strftime('%s') should respect tzinfo
  • 您永远不应该使用%s,因为您只会使用您所在系统的本地化系统时间。如果你想获取真正的 UNIX 时间戳,你想使用.timestamp()
【解决方案3】:

好吧,当转换为 unix 时间戳时,python 基本上假设为 UTC,但在转换回来时,它会给你一个转换为本地时区的日期。

查看此问题/答案; Get timezone used by datetime.datetime.fromtimestamp()

【讨论】:

    【解决方案4】:

    解决方案是

    import time
    import datetime
    d = datetime.date(2015,1,5)
    
    unixtime = time.mktime(d.timetuple())
    

    【讨论】:

    • 它假定 d 是一个表示本地时间的天真日期/日期时间对象(如果操作系统不提供历史 tz db (UTC过去本地时区的偏移量可能有所不同))。 More options.
    • 看起来没人介意浮点解决方案。对每个人来说都那么明显吗?
    • 这会减少微秒。可能很有趣。
    • 唯一的问题是您没有考虑时区。
    • 不应该。如果需要调整 TZ,则需要先进行调整。
    【解决方案5】:

    如果你想将 python 日期时间转换为自纪元以来的秒数,你应该明确地这样做:

    >>> import datetime
    >>> datetime.datetime(2012, 04, 01, 0, 0).strftime('%s')
    '1333234800'
    >>> (datetime.datetime(2012, 04, 01, 0, 0) - datetime.datetime(1970, 1, 1)).total_seconds()
    1333238400.0
    

    在 Python 3.3+ 中,您可以改用 timestamp()

    >>> import datetime
    >>> datetime.datetime(2012, 4, 1, 0, 0).timestamp()
    1333234800.0
    

    【讨论】:

    • 不考虑时区。
    • 您不想使用%s,因为它将被本地化为您当前所在系统的时钟。您应该只使用 .timestamp() 来获得正确的 Epoch/UNIX 时间。
    • %s 不适用于 Windows 系统 (ValueError: Invalid format string)
    • timestamp() 是浮点数的结果有什么特别的原因吗?将其变成int 是否安全? IE 的返回值timestamp() 是否会返回一些我应该考虑的小数?
    【解决方案6】:

    您错过了时区信息(已回答,同意)

    arrow package 可以避免这种日期时间的折磨;它已经编写、测试、pypi-published、cross-python (2.6 - 3.xx)。

    所有你需要的:pip install arrow(或添加到依赖项)

    适合您的情况的解决方案

    dt = datetime(2013,9,1,11)
    arrow.get(dt).timestamp
    # >>> 1378033200
    
    bc = arrow.get(1378033200).datetime
    print(bc)
    # >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
    print(bc.isoformat())
    # >>> '2013-09-01T11:00:00+00:00'
    

    【讨论】:

      【解决方案7】:

      如果您的 datetime 对象表示 UTC 时间,请不要使用 time.mktime,因为它假定元组位于您的本地时区。相反,请使用 calendar.timegm:

      >>> import datetime, calendar
      >>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
      >>> calendar.timegm(d.timetuple())
      60
      

      【讨论】:

      • 最佳答案,在使用 UTC 时间时完美运行。非常感谢!
      【解决方案8】:
      def dt2ts(dt, utc=False):
          if utc:
              return calendar.timegm(dt.timetuple())
          if dt.tzinfo is None:
              return int(time.mktime(dt.timetuple()))
          utc_dt = dt.astimezone(tz.tzutc()).timetuple()
          return calendar.timegm(utc_dt)
      

      如果您希望 UTC 时间戳 :time.mktime 仅用于 local dt 。使用 calendar.timegm 是安全的,但 dt 必须是 utc 区域,因此将区域更改为 utc。如果 UTC 中的 dt 只需使用 calendar.timegm

      【讨论】:

        【解决方案9】:

        使用 UTC 时区:

        time_stamp = calendar.timegm(dt.timetuple())
        
        datetime.utcfromtimestamp(time_stamp)
        

        【讨论】:

        • 经过一个小时的搜索,这是唯一有效的答案:')
        【解决方案10】:
        def datetime_to_epoch(d1):
        
            # create 1,1,1970 in same timezone as d1
            d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
            time_delta = d1 - d2
            ts = int(time_delta.total_seconds())
            return ts
        
        
        def epoch_to_datetime_string(ts, tz_name="UTC"):
            x_timezone = timezone(tz_name)
            d1 = datetime.fromtimestamp(ts, x_timezone)
            x = d1.strftime("%d %B %Y %H:%M:%S")
            return x
        

        【讨论】:

          【解决方案11】:

          这个类将满足您的需求,您可以将变量传递给 ConvertUnixToDatetime 并根据您希望它操作的函数调用它。

          from datetime import datetime
          import time
          
          class ConvertUnixToDatetime:
              def __init__(self, date):
                  self.date = date
          
              # Convert unix to date object
              def convert_unix(self):
                  unix = self.date
          
                  # Check if unix is a string or int & proceeds with correct conversion
                  if type(unix).__name__ == 'str':
                      unix = int(unix[0:10])
                  else:
                      unix = int(str(unix)[0:10])
          
                  date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')
          
                  return date
          
              # Convert date to unix object
              def convert_date(self):
                  date = self.date
          
                  # Check if datetime object or raise ValueError
                  if type(date).__name__ == 'datetime':
                      unixtime = int(time.mktime(date.timetuple()))
                  else:
                      raise ValueError('You are trying to pass a None Datetime object')
                  return type(unixtime).__name__, unixtime
          
          
          if __name__ == '__main__':
          
              # Test Date
              date_test = ConvertUnixToDatetime(datetime.today())
              date_test = date_test.convert_date()
              print(date_test)
          
              # Test Unix
              unix_test = ConvertUnixToDatetime(date_test[1])
              print(unix_test.convert_unix())
          

          【讨论】:

            【解决方案12】:
            import time
            from datetime import datetime
            time.mktime(datetime.now().timetuple())
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-10-26
              • 2013-12-14
              • 1970-01-01
              • 2020-10-09
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多