如何在Python中获取当前季度的星期数? [英] How to get the week number of the current quarter in Python?

查看:74
本文介绍了如何在Python中获取当前季度的星期数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遍历了每个问题,并且每个第三方库都试图找到一种无需手动映射日期的方法.

I've been through every question and every third party library trying to figure out a way to do this where I don't have to manually map dates.

我正在尝试获取当前财政季度的星期数.每个季度从1月,4月,7月或10月1日开始.

I'm trying to get the week number of the current fiscal quarter. Each quarter starts on the 1st of either January, April, July or October.

给出日期(字符串或对象,都没关系),我需要能够计算出它所在的财政季度的星期数.

Given a date (string or object, it doesn't matter), I need to be able to calculate the week number of the fiscal quarter that it's in.

为了使事情复杂一点,会计年度从4月开始.

To make matters a little more complicated, the Fiscal year starts in April.

例如,今天,2020年7月9日是该财政季度(Q2)的第2周,因为该季度始于4月.同样,2020年6月29日至30日是第一季度的第14周.

So for example, today, July 9th 2020 is week 2 of this Fiscal quarter (Q2), because the quarter starts in April. Similarly, the 29 and 30th of June 2020 are week 14 of quarter 1.

大多数时间格式化库甚至标准库都具有ISO日期之类的方法,在这些方法中我可以精确地提取星期数.但这是从一年的第一天起的星期几.

Most time formatting libraries and even the standard library ones have methods like ISO date where I can extract the week number fine. But it's the week number from the 1st day of the year.

我不能使用算术来简单地删除到当前日期的星期数,因为每个季度有不同的星期数.根据年份,每个季度可以有12、13或14周.

I can't use arithmetic to simply remove the number of weeks to the current date as there are a different number of weeks in each quarter. Quarters can have 12, 13 or 14 weeks depending on the year.

我最近得到的是使用FiscalYear库,它很棒,因为它带有一个Fiscal Quarter类.不幸的是,继承的方法isoformat()不适用于它.只有FiscalDate类,它没有给我我所需要的四分之一.

The closest I've gotten is using the FiscalYear library which is great as it has a Fiscal Quarter class with it. Unfortunately, the inherited method isoformat() doesn't apply to it. Only the FiscalDate class, which doesn't give me the quarter which I need.

有人碰到这个吗?有人可以指出我正确的方向吗?

Has anyone run into this? Can someone point me in the right direction?

我会发布代码段,但这只是Python中获取当前星期数的100种方法(到今天为止,是28).

I'd post code snippets but it's just the 100 ways there are in Python to get the current week number (as of today, that's 28).

我已经尝试在dateutils中使用rrules和deltas,但是我能得到的最接近的是使用偏移量的第一季度的周数.第二季度,它分崩离析.

I've tried using rrules and deltas in dateutils but the closest I can get is the week number of the 1st quarter using offsets. The second quarter, it falls apart.

我很高兴使用熊猫或任何其他第三方库,如果它可以帮助我避免对四分之一日期或周数到日期的映射进行硬编码.

I'm happy to use pandas or any other 3rd party library if it will help me avoid hard coding the quarter dates or, god forbid, the week number to dates mappings.

在正确方向上的任何帮助将不胜感激.

Any help in the right direction would be very much appreciated.

以下所有三个答案均以不同方式为我解决了此问题.我很难与哪个人给出正确的答案,但我还是把它交给了@Paul的答案,因为这是我作为一个不是高年级的人时最容易得到的答案.这也是与我的个人用例(我没有提到)相适应的答案,该用例正在接收日期时间对象并获得结果.因此,这给了它优势.抱歉,其他人提供了惊人的答案.我很高兴能得到我所希望的代码,它是朝着正确的方向前进的.谢谢大家.

推荐答案

除非这是一种计算周编号的非常常用的方法,否则我不知道您是否会找到一个可以完全为您做到这一点的库,但是使用 dateutil relativedelta 和一些逻辑即可轻松完成.这是一个简单的实现,返回一个元组(季度,周).因为您说Q1从4月1日开始,所以我假设从1月1日到4月1日的时间称为Q0:

Unless this is a very common way to reckon week numbering, I don't know if you are going to find a library that will do this exactly for you, but it's easy enough to accomplish using dateutil's relativedelta and a little logic. Here's a simple implementation that returns a tuple (quarter, week). Since you said that Q1 starts April 1st, I am assuming that the period from January 1st to April 1st is called Q0:

from datetime import date, datetime, timedelta
import typing

from dateutil import relativedelta

NEXT_MONDAY = relativedelta.relativedelta(weekday=relativedelta.MO)
LAST_MONDAY = relativedelta.relativedelta(weekday=relativedelta.MO(-1))
ONE_WEEK = timedelta(weeks=1)


def week_in_quarter(dt: datetime) -> typing.Tuple[int, int]:
    d: date = dt.date()
    year = d.year

    # Q0 = January 1, Q1 = April 1, Q2 = July 1, Q3 = October 1
    quarter = ((d.month - 1) // 3)
    quarter_start = date(year, (quarter * 3) + 1, 1)
    quarter_week_2_monday = quarter_start + NEXT_MONDAY

    if d < quarter_week_2_monday:
        week = 1
    else:
        cur_week_monday = d + LAST_MONDAY
        week = int((cur_week_monday - quarter_week_2_monday) / ONE_WEEK) + 2

    return quarter, week

哪个返回:

$ python week_in_quarter.py 
2020-01-01: Q0-W01
2020-02-01: Q0-W05
2020-02-29: Q0-W09
2020-03-01: Q0-W09
2020-06-30: Q1-W14
2020-07-01: Q2-W01
2020-09-04: Q2-W10
2020-12-31: Q3-W14

如果我误解了日历年的第一季度,并且实际上是将X年的1月1日至4月1日视为X-1年的Q4,那么您可以更改返回季度,行的最后一行(并更改返回类型注释):

If I've misunderstood the first quarter of the calendar year, and it's actually the case that January 1–April 1 of year X is considered Q4 of year X-1, then you can change the return quarter, week line at the end to this (and change the return type annotation):

if quarter == 0:
    year -= 1
    quarter = 4

return year, quarter, week

将返回值更改为:

$ python week_in_quarter.py 
2020-01-01: FY2019-Q4-W01
2020-02-01: FY2019-Q4-W05
2020-02-29: FY2019-Q4-W09
2020-03-01: FY2019-Q4-W09
2020-06-30: FY2020-Q1-W14
2020-07-01: FY2020-Q2-W01
2020-09-04: FY2020-Q2-W10
2020-12-31: FY2020-Q3-W14

如果这是一个速度瓶颈,那么编写不使用 dateutil.relativedelta 的优化版本应该很容易,而是根据一周中的某天进行计算,一年中的某一天以及是否为leap年(如果可以在过程中尽早将其转换为整数运算,Python中的日历计算通常会更快),但是我怀疑在大多数情况下,此版本应该是最简单的阅读和理解.

If this is something that is a speed bottleneck, it should probably be easy to write an optimized version of this that does not use dateutil.relativedelta, but instead calculates this based on day of week, day of year and whether or not this is a leap year (calendar calculations in Python usually go faster if you can turn it into integer operations as early in the process as possible), but I suspect that in most cases this version should be the easiest to read and understand.

如果要避免依赖于 dateutil ,则可以用简单的函数替换 NEXT_MONDAY LAST_MONDAY :

If you would like to avoid the dependency on dateutil, you can replace NEXT_MONDAY and LAST_MONDAY with simple functions:

def next_monday(dt: date) -> date:
    weekday = dt.weekday()
    return dt + timedelta(days=(7 - weekday) % 7)

def last_monday(dt: date) -> date:
    weekday = dt.weekday()
    return dt - timedelta(days=weekday)

在这种情况下,您应将两个 _monday 变量分别指定为 quarter_week_2_monday = next_monday(quarter_start) cur_week_monday = last_monday(dt)

In which case you would assign the two _monday variables as quarter_week_2_monday = next_monday(quarter_start) and cur_week_monday = last_monday(dt), respectively.

请注意:如果我正在编写此函数,则可能不希望它返回一个整数的元组,而是使用数据类为此目的创建一个简单的类,就像这样:

As a note: if I were writing this function, I'd probably not have it return a bare tuple of integers, but instead use attrs or a dataclass to create a simple class for the purpose, like so:

import attr

@attr.s(auto_attribs=True, frozen=True, slots=True)
class QuarterInWeek:
    year: int
    quarter: int
    week: int

    def __str__(self):
        return f"FY{self.year}-Q{self.quarter}-W{self.week:02d}"

(请注意, slots = True 是可选的,我认为如果使用 dataclasses.dataclass 则不可用-只是这是一个简单的结构,我倾向于将插槽类用于简单结构).

(Note that slots=True is optional, and I think not available if you use dataclasses.dataclass instead — it's just that this is a simple struct and I tend to use slots classes for simple structs).

这篇关于如何在Python中获取当前季度的星期数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆