【问题标题】:Adding years in python在 python 中添加年份
【发布时间】:2015-12-24 07:18:11
【问题描述】:

如果我想在我的程序中添加 100 年,为什么会显示错误的日期?

import datetime
stringDate= "January 10, 1920"
dateObject= datetime.datetime.strptime(stringDate, "%B %d, %Y")
endDate= dateObject+datetime.timedelta(days=100*365)
print dateObject.date()
print endDate.date()

【问题讨论】:

  • 因为年份并不完全是 365 天长?

标签: python datetime python-3.x python-datetime


【解决方案1】:

在过去的 5 年里,我一直在使用 pandas TimestampTimedelta 来处理与日期相关的所有事情。

例如,以字符串格式将 3 年添加到任何日期:

date = "2003-07-01"
date_start = Timestamp(date)
date_end = Timestamp(date_start.year+3, date_start.month, date_start.day)
date_end
# Out:
Timestamp('2006-07-01 00:00:00')

要将日期加上 40 天,请使用 Timedelta(它不支持年份,否则我们可以将它用于最后一个问题):

date_end = date_start + Timedelta(40, unit="days")
date_end
# Out:
Timestamp('2003-08-10 00:00:00')

【讨论】:

    【解决方案2】:

    man 3 mktime

    做过 C 的人都知道答案。

    mktime 自动将溢出值添加到下一个更大的单元。您只需要将其转换回日期时间。

    例如,您可以使用 2019-07-40 喂它,它会转换为 2019-08-09。

    >>> datetime.fromtimestamp(mktime((2019, 7, 40, 0, 0, 0, 0, 0, 0)))
    datetime.datetime(2019, 8, 9, 0, 0)
    

    或 2019-03-(-1) 转换为 2019-02-27:

    >>> datetime.fromtimestamp(mktime((2019, 3, -1, 0, 0, 0, 0, 0, 0)))
    datetime.datetime(2019, 2, 27, 0, 0)
    

    因此,您只需使用旧日期并添加您喜欢的任何内容:

    now = datetime.datetime.now()
    hundred_days_later = datetime.datetime.fromtimestamp(mktime((now.year, now.month, now.day + 100, now.hour, now.minute, now.second, 0, 0, 0)))
    

    【讨论】:

      【解决方案3】:

      The number of seconds in a year is not fixedThink you know how many days are in a year? Think again.

      要执行周期(日历)算术,您可以使用dateutil.relativedelta

      #!/usr/bin/env python
      from datetime import date
      from dateutil.relativedelta import relativedelta # $ pip install python-dateutil
      
      print(date(1920, 1, 10) + relativedelta(years=+100))
      # -> 2020-01-10
      

      要了解为什么d.replace(year=d.year + 100) 会失败,请考虑:

      print(date(2000, 2, 29) + relativedelta(years=+100))
      2100-02-28
      

      注意2100 不是闰年,而2000 是闰年。

      如果您要添加的唯一单位是年份,那么您可以仅使用 stdlib 来实现它:

      from calendar import isleap
      
      def add_years(d, years):
          new_year = d.year + years
          try:
              return d.replace(year=new_year)
          except ValueError:
              if (d.month == 2 and d.day == 29 and # leap day
                  isleap(d.year) and not isleap(new_year)):
                  return d.replace(year=new_year, day=28)
              raise
      

      例子:

      from datetime import date
      
      print(add_years(date(1920, 1, 10), 100))
      # -> 2020-01-10
      print(add_years(date(2000, 2, 29), 100))
      # -> 2100-02-28
      print(add_years(date(2000, 2, 29), 4))
      # -> 2004-02-29
      

      【讨论】:

      • @amunnelly 这不是错字。这是为了可读性(突出显示操作的符号)。
      • @jfs 你是对的。刚刚注意到+在哪一侧。我的道歉 - 我有一个缓慢的早晨。我会删除原来的评论。
      • @jfs 您的前两个链接指向一个已删除的问题和一个付费网站。
      • @ekhumoro 我可以在两个链接中看到信息。它们提供背景信息——如果你看不到它们,就忽略它们(尽管我认为你应该能够看到它们)——没有它们也可以使用答案。乍一看,它看起来不像您链接的重复处理 OP 案例中接受的答案。
      • @jfs 只有 10k 用户可以看到已删除的问题,而且并非所有人都可以访问付费网站。这个问题很明显是重复的,因为唯一的区别是年数。 linked question 有几个答案,one of which 包含与您相同的解决方案。没有可接受的答案。
      【解决方案4】:

      您不能只添加 100 * 365 天,因为在该时间跨度中有 366 天的闰年。在您的 100 年跨度中,您缺少 25 天。

      最好在这里使用datetime.replace() method

      endDate = dateObject.replace(year=dateObject.year + 100)
      

      在闰年的 2 月 29 日,这仍然可能会失败,因为根据您添加的年数,您最终会得到一个无效的日期。在这种情况下,您可以回到 2 月 28 日,或者使用 3 月 31 日;处理抛出的异常并切换到您选择的替换:

      years = 100
      try:
          endDate = dateObject.replace(year=dateObject.year + years)
      except ValueError::
          # Leap day in a leap year, move date to February 28th
          endDate = dateObject.replace(year=dateObject.year + years, day=28)
      

      演示:

      >>> import datetime
      >>> dateObject = datetime.datetime(1920, 1, 10, 0, 0)
      >>> dateObject.replace(year=dateObject.year + 100)
      datetime.datetime(2020, 1, 10, 0, 0)
      

      【讨论】:

        猜你喜欢
        • 2022-12-30
        • 1970-01-01
        • 1970-01-01
        • 2011-05-24
        • 2019-06-21
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2021-12-31
        相关资源
        最近更新 更多