【问题标题】:Getting conflicting information from datetime isocalendar从日期时间等历中获取冲突信息
【发布时间】:2018-10-15 20:58:32
【问题描述】:

我有一个列表,其中给出了给定年份的工作日(1-7 就像周一到周日)和周数。我需要将该信息转换为给定日期。

所以,我写了一个简单的脚本,它接受三个参数: 1年 2. 工作日 3. 周数

然后找出日期。

我的脚本基本上会遍历给定年份的所有日子,并创建一个日期时间对象,然后我在其中提取 isocalendar()[1] 以将其与周数进行比较。

我发现如果我输入 2017 7 52 我会得到两个输出!

本质上是这样的:

#!/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

import datetime

def print_dt(year, month, day):
    dt = datetime.date(year, month, day)
    print("%d-%d-%d (%d) -> week# %d" % (year, month, day, dt.weekday(), dt.isocalendar()[1]))

print_dt(2017, 1, 1)
print_dt(2017, 12, 31)

而且输出是一样的:

Anibals-iMac:RPEG anibal$ ./findDate-fixed-date.py
2017-1-1 (6) -> week# 52
2017-12-31 (6) -> week# 52

这怎么可能?这意味着 2017 年的第 52 周有两天 #6,即两个不同的星期日。这种情况导致我的脚本出现问题。

知道如何解决这个问题吗?

我最初的问题是我在 YYYYMMDD 中给出了事件,我需要按周# 按年对它们进行分组。因此,我可以说在 2017 年第 4 周发生了 X 次事件。对于上述情况,当它下降到第 52 周时它不起作用,因为对于 YYYYMMDD 有多个解决方案。

【问题讨论】:

  • 看起来像在给定年份的开始和结束附近的 ISO 周可以包括上一个或下一个的天数。仔细查看插图shown here(当然还要阅读相关文字)。

标签: python


【解决方案1】:

您混淆了 ISO 日历年和公历年。

日期2017-1-1 是 ISO 日历中 2016 年第 52 周的第 7 天。

ISO 日历将 ISO 日历年的第一周定义为包含相应公历年第一个星期四的那一周。这可能是从 1 月 1 日到 7 日的任何时间。由于 ISO 以星期一 = 1 到星期日 = 7 来编号天数,这意味着在每个新年前后最多三天内,一个日期的公历年和 ISO 日历年不一致。

2015 年 1 月 1 日是星期四,因此尽管是 2014 年 12 月,但它之前的星期一、星期二和星期三是 ISO 日历年 2015。同样,2016 年 1 月 7 日是星期四,2016 年 1 月 1 日星期五到 2016 年 1 月 3 日星期日尽管在 2016 年,但有 ISO 日历年 2015。

您的脚本似乎在公历中使用了一年,遍历该公历年的所有日子,并寻找具有匹配的星期几和 ISO 星期数的日子。您发现这三个值(公历年、ISO 周数、ISO 星期几)不能唯一标识日期。您的脚本需要考虑这样一个事实,即 ISO 日历年和公历年并不总是在 ISO 日历年而不是公历年上一致和匹配。一种方法是:

  • 在您搜索的日期范围内包括上一个公历年的最后三天和下一个公历年的前三天,并且
  • 除了匹配 ISO 周数和 ISO 星期几,确保 ISO 年份也匹配。 ISO 年份位于dt.isocalendar()[0]

或者,作为替代方案,您可以完全避免使用 ISO 日历系统,而是考虑以下内容:

def get_week_and_day(year, month, day):
    wday_of_jan_1 = datetime.date(year, 1, 1).timetuple().tm_wday
    daytuple = datetime.date(year, month, day).timetuple()
    wday = daytuple.tm_wday
    week = (daytuple.tm_yday - 1 + wday_of_jan_1) // 7 + 1
    return (week, wday)

给定年、月和日,这将返回一年中的星期和星期几,星期从星期一开始(根据 time.struct_time),第 1 周是 1 月 1 日所在的那一周in. 周数通常最多为 53,但如果闰年的 12 月 31 日是星期一(如 2012 年那样),这一天将有第 54 周。

这通过使用date.timetuple() 方法来获取日期的工作日和年份,以及该年1 月1 日的星期几。在week的计算中,我们:

  • 从给定日期 (daytuple.tm_yday) 的年份中减去 1,因此 1 月 1 日是 0,1 月 2 日是 1,依此类推。
  • 添加 1 月 1 日的星期几。我们这样做是因为 1 月 1 日的星期几也是一年中第一周“丢失”的天数'到前一年。例如,如果 1 月 1 日是星期三,wday_of_jan_1 将是 2,从第 1 周开始,它会丢失之前的星期一和星期二,因此第一周只有 5 天。
  • 到目前为止的计算给出了给定日期和 1 月 1 日或之前的第一个星期一之间的天数。然后我们可以将其除以 7 得到从这个星期一开始的整周数,最后加 1 使得1 月 1 日是第 1 周,而不是第 0 周。

这种方法还避免了循环一整年的日期并对其执行计算。

【讨论】:

  • 但我使用的是同一个调用。我这里看的不是公历。我正在查看 ISO 日历(因为似乎没有办法获得公历)。如果您查看我的代码,我会使用相同的代码 (ISO),并且给定两个不同的输入,我会得到相同的输出 - 这不应该是这种情况。
  • @AnibalJodorcovsky:我已经扩展了我的答案,以解释更多关于 ISO 和公历年的信息,以及如何修改脚本来解决你遇到的问题。
  • 哇,很好的答案。我现在更好地了解正在发生的事情,尽管我不确定如何解决我的问题。我有以 YYYYMMDD 格式发生的事件。我需要知道每年每周发生多少事件。因此,我创建了一个日期时间对象,提取了周数,然后创建了一个地图,其中键是年-周#-工作日。但是,由于 isocalendar 的这个问题,我最终将 2017 年 1 月 1 日和 2017 年 12 月 31 日的事件一起计算,而我不应该这样做。有没有其他方法可以让我没有这个问题?
  • @AnibalJodorcovsky:您可以尝试我在另一个编辑中包含的功能。它完全避免了 ISO 日历,无论如何你似乎都在反对它。也许你感兴趣,也许不感兴趣。
  • @LukeWoodward 我已经尝试过你的功能,它可以作为解决方案,谢谢
猜你喜欢
  • 2011-11-01
  • 1970-01-01
  • 2012-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-17
相关资源
最近更新 更多