【问题标题】:How to create list of datetimes without a leap day?如何在没有闰日的情况下创建日期时间列表?
【发布时间】:2019-02-03 15:16:38
【问题描述】:

我需要从 2007-01-01 00:00 到 2016-01-01 00:00 每分钟创建一个日期时间元素列表,但不包括 2 月 29 日。我的代码是下一个:

dates = []
date0 = datetime(2007, 1, 1, 0, 0)
delta = td(minutes=1)
while date0 < datetime(2016, 1, 1, 0, 0):
    if date0.date != date(2008, 2, 29) and date0.date != date(2012, 2, 29):
        dates.append(date0)
    date0 = date0 + delta

我应该有一个 9 年没有 29.02 的列表。但我的日期列表仍然包含 2008 年 2 月 29 日和 2012 年。我试图应用此代码:

while date0 < datetime(2016, 1, 1, 0, 0):
    if date0.month != 2 and date0.day != 29:
        dates.append(date0)
    date0 = date0 + delta 

但结果我有一个列表,其中不包含适当的天数,只有 8 年零 14 天。 您对解决问题有任何解决方案或想法吗?

【问题讨论】:

  • datatimes 的数量可能很大(每年 525K),而您生成它们的总体方法非常效率低下。你为什么要这样做?我怀疑可能是XY-Problem
  • 同意@martineau - 但如果你确实需要一个日期范围,那么你可以查看pandas - 请参阅下面的答案。

标签: python list python-datetime


【解决方案1】:

您可以使用流行的外部数据操作包pandas 轻松做到这一点:

In []:
import pandas as pd
dr = pd.date_range(start='1/1/2007', end='1/1/2016', freq='1min')
dates = dr[(dr.day != 29) | (dr.month != 2)]

len(dr), len(dates)

Out[]:
(4733281, 4730401)

这在我的机器上大约需要700ms

In []:
dates

Out[]:
DatetimeIndex(['2007-01-01 00:00:00', '2007-01-01 00:01:00', '2007-01-01 00:02:00', '2007-01-01 00:03:00',
               '2007-01-01 00:04:00', '2007-01-01 00:05:00', '2007-01-01 00:06:00', '2007-01-01 00:07:00',
               '2007-01-01 00:08:00', '2007-01-01 00:09:00',
               ...
               '2015-12-31 23:51:00', '2015-12-31 23:52:00', '2015-12-31 23:53:00', '2015-12-31 23:54:00',
               '2015-12-31 23:55:00', '2015-12-31 23:56:00', '2015-12-31 23:57:00', '2015-12-31 23:58:00',
               '2015-12-31 23:59:00', '2016-01-01 00:00:00'],
              dtype='datetime64[ns]', length=4730401, freq=None)

【讨论】:

    【解决方案2】:

    这是一种相对高效的 Pure Python™ 方法。跳过闰日的方法是将它们包含在_DAYS_IN_MONTH 表中(因此根据处理的当前年份是否为闰年,没有什么特别的操作)。

    我不知道你为什么[认为]你需要这个,但最好通过generator function来做,这样就不需要同时在内存中存储这么多datatime对象时间。

    from datetime import datetime
    
    _DAYS_IN_MONTH = [31,28,31,30,31,30,31,31,30,31,30,31]  # Ignores leap days.
    
    start_year, end_year = 2007, 2016
    dates = []
    for year in range(start_year, end_year):
        for month in range(1, 13):
            for day in range(1, _DAYS_IN_MONTH[month-1]+1):
                for hour in range(0, 24):
                    for minute in range(0, 60):
                        dates.append(datetime(year, month, day, hour, minute))
    
    
    print('len(dates): {:,d}'.format(len(dates)))  # -> len(dates): 4,730,400
    

    【讨论】:

      【解决方案3】:

      怎么样:

      if not (date0.month == 2 and date0.day == 29):
      

      【讨论】:

      • 谢谢,这是最简单的方法
      【解决方案4】:

      您无法将 datetime 对象的属性与对象本身进行比较,这就是导致问题的原因。

      from datetime import datetime, timedelta
      
      dates = []
      date0 = datetime(2007, 1, 1, 0, 0)
      delta = timedelta(minutes=1)
      
      
      def get_leaps(startyear, endyear):
          leapyears = []
          for i in range(startyear, endyear):
              if (i%400 == 0)or ((i%4 == 0) and (i%100 != 0)):
                  leapyears.append(i)
          for y in leapyears:
              for i in range(24):
                  for j in range(60): 
                      yield datetime(y, 2, 29, i, j))
      
      
      while date0 < datetime(2016, 1, 1, 0, 0):
          if date0 not in get_leaps(2007, 2016):
              dates.append(date0)
          date0 += delta 
      

      这应该是解决方案。这绝不是优化的,而且非常不合 Python,但看看你是否可以改进它。我明天有化学考试,我没有时间。干杯!

      【讨论】:

      • i % 4 == 0 不是有效的闰年测试。
      猜你喜欢
      • 1970-01-01
      • 2021-08-24
      • 2023-03-25
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 2022-11-29
      • 2016-11-11
      相关资源
      最近更新 更多