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.


  1. 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"). ↩︎

  2. Again, see Calendrical Calculations. ↩︎