【问题标题】:Get yesterday's date in Python, DST-safe在 Python 中获取昨天的日期,DST 安全
【发布时间】:2013-03-11 17:23:09
【问题描述】:

我有一个 python 脚本,它使用此调用以 YYYY-MM-DD 格式获取昨天的日期:

str(date.today() - timedelta(days=1)))

它大部分时间都有效,但是今天早上在2013-03-11 0:35 CDT 运行脚本时,它返回"2013-03-09" 而不是"2013-03-10"

大概是夏令时(昨天开始)是罪魁祸首。我猜timedelta(days=1)的实现方式是减去24小时,而2013-03-11 0:35 CDT之前的24小时是2013-03-09 23:35 CST,这导致了"2013-03-09"的结果。

那么在 python 中获取昨天日期的 DST 安全的好方法是什么?

更新: 在 bukzor 指出我的代码应该可以正常工作之后,我回到脚本并确定它没有被使用。它设置了默认值,但包装器外壳脚本明确设置了日期。所以 bug 是在 shell 脚本中,而不是在 python 脚本中。

【问题讨论】:

  • 这样的问题只会发生在支持 timezeone 的日期时间对象上,date.today() 不是。对象具体是如何实例化的?
  • @bukzor 你是对的。原来是一个 shell 脚本传入了错误的日期,请参阅上面的更新。
  • 这个问题应该被关闭; OP 断言他的错误在其他地方。
  • @Robᵩ:来自 google 的人可能会觉得这个问题很有用。时区不是小事。例如,您的回答(带有序数)清楚地表明需要“昨天”而不是“24 年前”,因为问题显示可能是不同的一天。 date.today() - timedelta(days=1) 更短,但意图不太清楚。如果你想提前一天是正确的。如果你想要一个 24 小时前的时刻,这是不正确的。

标签: python


【解决方案1】:

我无法在 python2.7 或 python3.2 中重现您的问题:

>>> import datetime
>>> today = datetime.date(2013, 3, 11)
>>> print today
2013-03-11
>>> day = datetime.timedelta(days=1)
>>> print today - day
2013-03-10

在我看来,这已经是“夏令时保险箱”yesterday() 函数的最简单实现了。

【讨论】:

  • 在尝试此操作之前,您是否将系统时间设置为 2013-03-11 0:35?当应用夏令时时,在午夜后 1 小时内会出现问题 - 一天只有 23 小时。
  • @tdelaney:设置系统时间是获得相同结果的迂回方式。在这两种情况下,您都会得到一个具有此值的“天真” datetime.date 对象。
  • @tdelaney:代码按原样工作,因为它使用 naive date 对象。它正确打印了本地日期,但它没有告诉我们相对于 UTC 的实际时间:it might be ambiguous or even non-existing time(例如,巴西的时区在午夜有 DST 转换)。特别是,todaytoday - DAY 处的 UTC 偏移量可能不同。你需要tz数据库到find the corresponding UTC time (e.g., expressed as aware datetime objects)
【解决方案2】:
datetime.date.fromordinal(datetime.date.today().toordinal()-1)

【讨论】:

    【解决方案3】:

    如果您使用对时区(尤其是 DST)一无所知的天真 datetime 对象,您将获得 2013-03-10

    from datetime import datetime, timedelta
    
    dt_naive = datetime(2013, 3, 11, 0, 35)
    print((dt_naive - timedelta(days=1)).date()) # ignores DST
    # -> 2013-03-10
    

    2013-03-09 是正确的,如果您对 24 小时前的日期感兴趣的话。

    import pytz # $ pip install pytz
    
    local_tz = pytz.timezone("America/Chicago") # specify your local timezone
    dt = local_tz.localize(dt_naive, is_dst=None) # raise if dt_naive is ambiguous
    yesterday = local_tz.normalize(dt - timedelta(days=1)).date()
    print(yesterday)
    # -> 2013-03-09
    

    注意:.date() 会去除时区信息,因此您将再次获得 2013-03-10

    print(dt.date() - timedelta(days=1))
    # -> 2013-03-10
    

    在特定时区获取昨天:

    from datetime import datetime, time, timedelta
    import pytz # $ pip install pytz
    
    tz = pytz.timezone("America/Chicago")
    yesterday = datetime.now(tz).date() - timedelta(days=1)
    
    # to add timezone info back (to get yesterday's midnight)
    midnight = tz.localize(datetime.combine(yesterday, time(0, 0)), is_dst=None)
    

    如果时区在该时间前后缺少几天,则通过剥离时区信息获取昨天可能会失败。然后此方法将在给定时区生成不存在的日期(tz.localize() 引发错误)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      相关资源
      最近更新 更多