Python solutions to the weekly challenge 326
Task 1: Day of the Year:
You are given a date in the format YYYY-MM-DD.
Write a script to find day number of the year that the given date represent.
First of all, what calendar the date is in is not given, nor is a location to allow us to use the calendar used in that location at that time. So I will just assume the Gregorian calendar.
The correct answer in python is to just use the standard library:
from datetime import date
input_date = '2025-05-02'
try:
print(date.fromisoformat(input_date).timetuple().tm_yday)
except ValueError as inst:
print(inst)
but that's no fun. Let's look at some math.
For a minute, lets pretend February has 30 days. Then there are 7 31 day months spread as evenly as possible through the year and on average, a month would have 367/12 days. One possible even spread of 31 day months gives the days of the year before month m as:
[367*(m-1) // 12 for m in range(1,13)]
(//
is integer division) which gives:
[0, 30, 61, 91, 122, 152, 183, 214, 244, 275, 305, 336]
and the length of each month is 31 if m*7 % 12 < 7 else 30
[1]:
[30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31]
This doesn't match our calendar, but there are 12 / gcd(7,12) possible different sequences that are equally as even as possible; their formulas just include an offset. The offset that matches our calendar is 11: (m+11)*7 % 12 < 7
, giving:
[31, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
with the days in the year before month m given by (367*(m-1) + 7*11 % 12) // 12
[2], which simplifies to (367*m - 362)//12
.
So if February had 30 days all the time, the day of the year would be given by:
(y,m,d) = [ int(i) for i in input_date.split('-') ]
day_of_year = (367*m - 362) // 12 + d
Now all that is missing is correcting for February's length when the month is March or later. In the Gregorian calendar, every year that is a multiple of 400 or is a multiple of 4 and not of 100 is a leap year. So:
day_of_year = (
(367*m - 362) // 12 + d
- (0 if m<=2 else 1 if y%4==0 and y%100!=0 or y%400==0 else 2)
)
But note that, unlike with the standard library, we are no longer checking that the date is valid.
full script
in Perl, for comparison
Task 2: Decompressed List:
.You are given an array of positive integers having even elements.
Write a script to to return the decompress list. To decompress, pick adjacent pair (i, j) and replace it with j, i times.
While you can now iterate over couples using only built-in functions:
for couple in zip(_x := iter(evenlist), _x):
you cannot use an assignment expression in a comprehension iterable expresion, for policy reasons.
But itertools provides the needed pieces:
import sys
from itertools import repeat, batched
ints = [ int(i) for i in sys.argv[1:] ];
print([n for ij in batched(ints, n=2) for n in repeat(ij[1], ij[0])])
full script
in Perl, for comparison
See you next week.
Essentially, this looks for months where the built up fractional days have just reached or passed a full day. For more formal reasoning, see "Calendrical Calculations", section 1.14 "Cycles of Years"). ↩︎
Again, see Calendrical Calculations. ↩︎