You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
time.strptime() with year rollover returns out-of-range tm_yday #73267
I believe this is working as intended. Remember, the '%w' directive instructs strptime to consider 0 to be Sunday, while tm_wday considers 0 Monday. In 2016, the %W directive means that the first week (week #1) starts on Monday, January 4th. If you go 52 weeks forward from the 4th, you get to Monday, December 26th. By asking for day 0 (%w=0), you want the *Sunday* of the 52nd week *from the first Monday of the year*. Since Monday is day 0 of that week, you want the Sunday that is 6 days from the 26th, or Jan 1, 2017.
One can certainly argue that tm_yday is documented to return an integer between [0,366] and thus we should never see 367, but it's the correct value given your input. The only other choice would be to raise an exception, which definitely shouldn't happen since the values you entered clearly match the format string spec.
Perhaps the docs should be updated, but when you consider that %W goes from [0,53], tm_yday can go well past 366 and still represent a semantically valid value.
./python.exe
Python 3.8.0a0 (heads/master:1dd035954b, Dec 18 2018, 10:12:34)
[Clang 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> value ='2016 51 0'
>>> format='%Y %W %w'
>>> time.strftime(format, time.strptime('2016 51 0', format)) == value
True
>>> time.strptime('2016 52 0', format)
time.struct_time(tm_year=2017, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=367, tm_isdst=-1)
>>> time.strftime(format, time.strptime('2016 52 0', format)) == value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: day of year out of range
It returns what you asked for :-) In the %W format, weeks start on Monday, and week 1 is the first week containing a Monday in that year. Week 52 in 2016 spans from December 26, 2016 to January 1, 2017. When you specify day 0, that's Sunday in this format -- the Sunday of week 52 in 2016 is January 1, 2017.
Do we want to throw an error like Ruby? I guess we could.
C seems to differ wildly depending on platform looking at the previous comment and my output...
To me it seems like the issue here is consistency.
time.strftime cannot, as far as I can tell, cannot produce the string "2016 52 0". This represents 2017-01-01 and strftime will produce "2017 00 0"
For backwards rollovers, ambiguous representations are explicitly accepted and normalize to the "canonical" representation: "2015 00 1" and "2014 52 1" both produce the same time_struct with tm_year=2014.
The docs explicitly say that the output of tm_yday is in the range [1, 366]
I think without the second point about backwards rollovers, it would make sense to forbid ambiguous representations, but if we want to be consistent, it would make sense for us to normalize the outputs here.
In any case, we should not be producing something that is out of spec with the docs and where the output of time.strptime cannot be parsed by time.strftime.
Activity
hywl51 commentedon Dec 27, 2016
In [1]:import time
In [2]: time.strptime('2016 52 0', '%Y %W %w')
Out[2]: time.struct_time(tm_year=2017, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=367, tm_isdst=-1)
When given the parameters above, the function return the struct_time object with tm_yday=367, that is wrong.
I test the codes on Python 2.7.11 and 3.5.1, the error is same.
jeffknupp commentedon Jan 8, 2017
I believe this is working as intended. Remember, the '%w' directive instructs strptime to consider 0 to be Sunday, while tm_wday considers 0 Monday. In 2016, the %W directive means that the first week (week #1) starts on Monday, January 4th. If you go 52 weeks forward from the 4th, you get to Monday, December 26th. By asking for day 0 (%w=0), you want the *Sunday* of the 52nd week *from the first Monday of the year*. Since Monday is day 0 of that week, you want the Sunday that is 6 days from the 26th, or Jan 1, 2017.
One can certainly argue that tm_yday is documented to return an integer between [0,366] and thus we should never see 367, but it's the correct value given your input. The only other choice would be to raise an exception, which definitely shouldn't happen since the values you entered clearly match the format string spec.
Perhaps the docs should be updated, but when you consider that %W goes from [0,53], tm_yday can go well past 366 and still represent a semantically valid value.
tirkarthi commentedon Dec 19, 2018
This causes the round trip to be a ValueError.
On Ruby this causes runtime error
irb(main):005:0> DateTime::strptime("2016 52 0", "%Y %W %w") Traceback (most recent call last): 3: from /usr/local/bin/irb:11:in `<main>' 2: from (irb):5 1: from (irb):5:in `strptime' ArgumentError (invalid date)With C it returns 2016 00 5 on Mac OS 10.10.4 and 2017 00 0 on Ubuntu
Output :
Mac
tm year 116
tm yday 0
tm wday 5
2016 00 5
Ubuntu
tm year 117
tm yday 0
tm wday 0
2017 00 0
StanFromIreland commentedon Mar 20, 2025
It returns what you asked for :-) In the %W format, weeks start on Monday, and week 1 is the first week containing a Monday in that year. Week 52 in 2016 spans from December 26, 2016 to January 1, 2017. When you specify day 0, that's Sunday in this format -- the Sunday of week 52 in 2016 is January 1, 2017.
Do we want to throw an error like Ruby? I guess we could.
C seems to differ wildly depending on platform looking at the previous comment and my output...
[-]time.strptime() return wrong result[/-][+]time.strptime() with year rollover returns out-of-range tm_yday[/+]pganssle commentedon Sep 27, 2026
To me it seems like the issue here is consistency.
time.strftimecannot, as far as I can tell, cannot produce the string "2016 52 0". This represents 2017-01-01 andstrftimewill produce"2017 00 0""2015 00 1"and"2014 52 1"both produce the sametime_structwithtm_year=2014.tm_ydayis in the range [1, 366]I think without the second point about backwards rollovers, it would make sense to forbid ambiguous representations, but if we want to be consistent, it would make sense for us to normalize the outputs here.
In any case, we should not be producing something that is out of spec with the docs and where the output of
time.strptimecannot be parsed bytime.strftime.