python weekday and strftime("%U") - python

Is there a workaround for the following
from datetime import datetime, timedelta
a = datetime.now() # <== 2016-03-09 11:06:04.824047
print a.strftime("%U")
>>> 10
#go back to previous Sunday
b = a - timedelta(days = 3)
print b.strftime("%U")
>>> 10
print b.weekday()
>>> 6
Shouldn't b.strftime("%U") be 9 as it the last day of the week?

%U treats weeks as starting on Sunday, not on Monday. From the documentation:
%U
Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0.
You could use the %W format, which gives a zero-padded week number based on Monday being the first day of the week:
%W
Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0.
The alternative is to use b.isocalendar()[1] if you need to get the week number as per ISO 8601. The rules for what is considered week 1 differ from the ISO calendar calculations; %W bases this on the first Monday in the year, while ISO 8601 states that the week that includes January 4 is the first week. For 2016 both systems align, but that's not the case in 2014, 2015 or 2019:
>>> d = datetime(2019, 3, 9)
>>> d.strftime('%W')
'09'
>>> d.isocalendar()[1]
10
If you wait until Python 3.6, you can use the %V format to include the ISO week number, see issue 12006.

Related

sorting by month, week number (integer with string) and year in Python

In python, i have an array of dates in this format (January, Week 1, 2022).
I would like to sort first by year, then month and then week number.
Just to give a visual representation, below is one example of an array of dates.
January, Week 4, 2022
January, Week 3, 2022
January, Week 2, 2022
December, Week 5, 2022
November, Week 1, 2021
October, Week 5, 2021
October, Week 2, 2021
September, Week 3, 2021
September, Week 1, 2021
August, Week 1, 2021
There are multiple solutions, but if you don't mind to use hack for it, you can use strptime with proper format:
from datetime import datetime
s = "January, Week 4, 2022"
fmt = "%B, Week %d, %Y"
dtime = datetime.strptime(s, fmt)
Here %B stands for month full name, %Y is a year and (here is a hack) %d is a day. If we prepare list of datetimes we can sort it with their natural order
sorted([datetime.strptime(s, fmt) for s in input_list]) # or with reverse=True
At the end you can return to str format with datetime.strftime
This should get you started.. If you use the sort() function. It arranges based on your requirements (ascending, depending etc..)
from datetime import datetime
my_dates = ['5-Nov-18', '25-Mar-17', '1-Nov-18', '7-Mar-17']
my_dates.sort(key=lambda date: datetime.strptime(date, "%d-%b-%y"))
print(my_dates)

Python iso calendar 1st Jan

I'm using this function to compute the week number from a date ( it counts the weeks starting from 0 ):
time.strftime("%U", datetime(2017,1,1).timetuple())
it is returning 1. If you try another year, I.e:
time.strftime("%U", datetime(2018,1,1).timetuple())
it return 0. Fine, it is the 1st week for 2018 year.
It is crystal clear that the 2017 begins with Sunday and this day actually belongs to the week before: December 26, 2016 January 1, 2017
But the last week of 2016 is number 52, so why the function is returning 1 instead 51?
%U can return a value ranging from 0 to 53, where each week is defined as starting on a Sunday The values 1 though 52 make sense, as you typically think of a year as containing 52 weeks. So let's look at the situations where a day occurs in week 0 or week 53.
January 1, 2017 was on a Sunday, so as expected, it occurs during Week 1:
>>> datetime(2017, 1, 1).strftime("%U")
'01'
December 24, 2017 is the Sunday that starts Week 52
>>> datetime(2017, 12, 24).strftime("%U")
'52'
But what, then, to make of December 31? Clearly, there is slightly more than 52 weeks in a year (since 7 * 52 == 364), so we treat the week that "mostly" bleeds into the following year as Week 53.
>>> datetime(2017, 12, 31).strftime("%U")
'53'
This week coincides with the week 0 from the perspective of 2018:
>>> datetime(2018, 1, 1).strftime("%U")
'00'
since the first Sunday of 2018 is January 7:
>>> datetime(2018, 1, 7).strftime("%U")
'01'
So Week 53 of 2017 and Week 00 of 2018 refer to the same same span of days, December 31, 2017 through January 6, 2018. We just use different numbers to refer to it, depending on whether we are asking about it as a week containing a day from 2017 or as a week continuing days from 2018.
This also implies that some years (like 2017) don't have a Week 0, and other years (like 2016) do not have a Week 53.
>>> datetime(2016, 12, 31).strftime("%U")
'52'
No year has both Week 0 and Week 53. But in all years, Weeks 1 through 52 consist of 7 days in the given year. Further, if a year has a Week 53, the following year will have a Week 0.
And as a final bit of trivia, Week 53 will usually start on December 31. The occasional exception is a leap year that begins on a Sunday, where Week 53 starts on December 30. The last one was 2012; the next such year is 2040.

Get week start date from week number

This question is related to Get date from week number, and is possibly a duplicate of the latter, however, I think what is suggested in the accepted answer to that question does not really work.
In [6]: datetime.datetime.strptime('2019-18-1', "%Y-%W-%w")
Out[6]: datetime.datetime(2019, 5, 6, 0, 0)
Notice how it returns Monday 2019-5-6. However, according to the calendar (I use http://whatweekisit.org for reference), 2019-5-6 the Monday of week 19.
Similarly, the example provided in the original question:
In [7]: datetime.datetime.strptime('2013-26-1', "%Y-%W-%w")
Out[7]: datetime.datetime(2013, 7, 1, 0, 0)
According to http://whatweekisit.org/calendar-2013.html 2013-7-1 is the Monday of week 27.
Also
In [8]: datetime.datetime.strptime('2019-18-1', "%Y-%W-%w").isocalendar()[1]
Out[8]: 19
Notice how I give week 18 to strptime, and get week 19 back from isocalendar.
I am completely lost and would very much appreciate if someone could explain what is going on here. My original goal though is to get week start date from week number.
Based off of my testing, datetime does not consider the first week of 2019 (i.e. Jan 1-Jan 6) as week 1 because it isn't a full week; December 31st, 2018 is part of the week but is not in 2019. I suppose you'll have to accomodate for that by checking the output of datetime.datetime.strptime('year-1-1', "%Y-%W-%w") == datetime.datetime.strptime('year-0-1', "%Y-%W-%w"). If false, subtract 1.
2018 is an example of a year where datetime does return the same value as isocalendar because the first Monday of the year is Jan 1.
From the isocalendar docs:
The ISO year consists of 52 or 53 full weeks, and where a week starts on a Monday and ends on a Sunday. The first week of an ISO year is the first (Gregorian) calendar week of a year containing a Thursday. This is called week number 1, and the ISO year of that Thursday is the same as its Gregorian year.
On the other hand, strptime starts from the first full week, in fact, since 2019 starts from Tuesday, they start from different weeks:
import datetime as dt
strp_first = dt.datetime.strptime('2019-1-1', "%Y-%W-%w")
>>> print(strp_first)
2019-01-07 00:00:00
>>> print(strp_first.isocalendar()[1])
2
While in 2021, which starts from Friday:
strp_first = dt.datetime.strptime('2021-1-1', "%Y-%W-%w")
>>> print(strp_first)
2021-01-04 00:00:00
>>> print(strp_first.isocalendar()[1])
1

Converting python date to week

datetime.date(2010, 1, 1).isocalendar()[1]
gives week number 53 since 1st Jan 2010 was in a week which started in 2009. However, I would like to start Jan 1, 2010 as week 1. Is there any option in datetime isocalendar to do this?
If I follow the solution at How can I get the current week using Python?, I get 53 as result
Compute the number of days since the first of the year, integer-divide by 7 and add 1:
>>> import datetime as DT
>>> (DT.date(2010,1,1)-DT.date(2010,1,1)).days // 7 + 1
1
This notion of week number is very different from the ISO week definition, so you aren't going to find an option to do this in isocalendar.
If you're going to be getting data in total weeks since a point, you can mod that number by the number of weeks in a year (52) to get the remainder (ie, how many weeks into the year you are):
>>> 53 % 52
>>> 1
>>> 925 % 52
>>> 41

Get next and last ISO week number in a year

By this I am getting current week number
datetime.date(2014, 9, 30).isocalendar()[1]
but I want to get what is next ISO week number and max ISO week number in current year in python.
I can't add current week number + 1 to get next week number, because it may be that year doesn't have that week number.
To get next week's week number, add a timedelta:
>>> import datetime
>>> today = datetime.date(2014, 9, 30)
>>> next_week = today + datetime.timedelta(days=7)
>>> next_week.isocalendar()[1]
41
To get the last week number in the year, note that the following rule is used:
The following years have 53 weeks:
years starting with Thursday
leap years starting with Wednesday

Categories