【问题标题】:Python: Date manipulation codePython:日期操作代码
【发布时间】:2012-06-22 13:31:08
【问题描述】:

使用 python,我想计算 day_of_a_year 天及其对应月份的增量天数,以及月份 + 1 的增量天数。

*抱歉我忘了说年份是一个已知变量 例如。

def a(day_of_year):
    <...>
    return [(days_from_start_of_month),(days_untill_end_of_month)]

所以 如果

day_of_year = 32 
a(32) = (2,28) #assuming the month which the day_of_year corresponds to starts from day 30 and ends to day 60.

到目前为止,我正在研究 datetime 、 timeutils 和 calendar 模块,我真的无法弄清楚代码的逻辑!我希望我能展示一些可靠的东西,但我在 timedelta 函数的某个地方迷路了。

【问题讨论】:

  • 你能澄清你的例子吗?它很难遵循。你也试过什么?你到底想要什么作为输出?
  • 一年的第32天是2月1日;一月有 31 天。
  • 您还需要将年份传递给您的函数,因为有些年份的天数不同
  • 是的,我知道你是对的。我说的数字是缩进的例子
  • 当你说“我无法弄清楚代码的逻辑”时,你在说什么?

标签: python datetime time


【解决方案1】:

一个月的第一天很容易构建,下个月的第一天也是如此。一旦你有了这些,剩下的就更容易了。正如 OP 所指出的,calendar.monthrange function 为我们提供了获取一个月最后一天的最易读的方法。

>>> from datetime import date, year
>>> import calendar
>>> def first_day(dt):
...      # Simply copy year and month into new date instance
...      return date(dt.year, dt.month, 1)
...
>>> def last_day(dt):
...      days_in_month = calendar.monthrange(dt.year, dt.month)[1]
...      return date(dt.year, dt.month, days_in_month)
...
>>> nth_day = 32
>>> day_of_year = date(2012, 1, 1) + timedelta(days=nth_day - 1)
>>> day_of_year
datetime.date(2012, 2, 1)
>>> first_day(day_of_year), last_day(day_of_year)
(datetime.date(2012, 2, 1), datetime.date(2012, 2, 29))
>>> day_of_year - first_day(day_of_year), last_day(day_of_year) - day_of_year
(datetime.timedelta(0), datetime.timedelta(28))

将这些技术组合成一个功能:

def delta_to_start_and_end(year, day_of_year):
    dt = date(year, 1, 1) + timedelta(days=(day_of_year - 1))

    def first_day(dt):
         return date(dt.year, dt.month, 1)
    def last_day(dt):
         days_in_month = calendar.monthrange(dt.year, dt.month)[1]
         return date(dt.year, dt.month, days_in_month)

    return (dt - first_day(dt)).days, (last_day(dt) - dt).days

输出:

>>> delta_to_start_and_end(2012, 32)
(0, 28)
>>> delta_to_start_and_end(2011, 32)
(0, 27)
>>> delta_to_start_and_end(2012, 34)
(2, 26)
>>> delta_to_start_and_end(2012, 364)
(28, 2)

我不确定您是否要将1 添加到这两个值中的每一个;目前,当月的第一天(第一个示例)为您提供 0 作为第一个值和 (days-in-the-month - 1) 作为第二个值,因为这是与这些点的天数差异。如果需要,在delta_to_start_and_end 函数的最后一行添加两次+ 1 很简单。

作为历史记录,此答案的先前版本使用不同的方法来计算一个月的最后一天,而没有日历模块:

def last_day(dt):
     rest, month = divmod(dt.month, 12)
     return date(dt.year + rest, month + 1, 1) - timedelta(days=1) 

这个函数使用divmod builtin function 来处理'当前月份是十二月'的边缘情况;在这种情况下,下个月不是13,而是1,我们也需要将年份增加一。将数字返回到“开始”是该数字的模数,但divmod 函数也为我们提供了除数,如果当前月份为12,则它恰好是1。这为我们提供了一个方便的指标,何时增加年份。

【讨论】:

  • 啊,你注意到 days=31 的问题,我只是想指出:P
  • 一个月的最后一天也可以用calendar.monthrange(year,month) -> (0~6(0=mon,6=Sun), days_of_month) calendar.monthrange(2000 ,30) -> (3,31)
  • 如果可能的话,您能否解释一下 last_day 函数?我在试图弄清楚发生了什么时迷路了
  • @user528025:天哪,忘了日历模块。 :-) 我已经在last_day 函数中包含了一些 cmets,你看到了吗(稍后编辑)。
  • @user528025:使用日历模块更容易,所以我用calendar.monthrange调用替换了旧的基于divmod的函数。
【解决方案2】:

我认为没有一个现有的库可以解决这个问题。你必须自己做一些东西,像这样:

monthdays = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

day = 32

total = 0
for i in monthdays:
    if day - total - i < 0:
        before = day - total
        after = total + i - day
        break
    total += i

print before, after

(只是快速入门,可能还有更优雅的方式)

【讨论】:

  • 这将在闰年打破,比如 2012 年。
  • 这就是为什么我说'只是一个快速开始':D
  • 我想过,但不幸的是我必须考虑闰年
  • 据我所知,您只需执行if year % 4: #not leap 即可检查闰年。或者闰年还有其他规则吗?
  • @BrtH 是的,如果年份是100的倍数,那么如果它也是400的倍数,那么它只是闰年。例如,1900年不是闰年,但2000年是闰年一。
猜你喜欢
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2017-08-17
相关资源
最近更新 更多