Sundays and totients
Weekly challenge 175 — 25 July 2022
Week 175: 25 Jul 2022
Write a script to list the last Sunday of every month in a given $year.
Example 1: Year: 2022 2022-01-30 2022-02-27 2022-03-27 2022-04-24 2022-05-29 2022-06-26 2022-07-31 2022-08-28 2022-09-25 2022-10-30 2022-11-27 2022-12-25
It's a slightly awkward calculation. There can be 4 or 5 Sundays in a month, and that depends on the day of the week the month starts on and how many days there are in the month. So I hit on the idea of looking at the 12 months starting with the February of the given year. If we take the 1st of each of these 12 months, we can construct the Unix time of noon like this:
$time = timelocal_posix(0, 0, 12, 1, $month, $year - 1900);
and then use timelocal to get the day of the week as $t[6]
in@t = localtime($time)
Then, to get the last Sunday of the preceding month, if the 1st of the month is a Sunday, ie $t[6] == 0
, we need to
move back 7 days, or otherwise we just move back $t[6]
days. To do that we subtract 86400 seconds for each day we're
moving back, and then a final localtime
gives us the desired date.
The Posix version can cover (at least) 1753 - 3999 in the Gregorian calendar.
#!/usr/bin/perl # Peter Campbell Smith - 2022-07-25 # PWC 175 task 1 use v5.28; use utf8; use warnings; binmode(STDOUT, ':utf8'); use Time::Local 'timelocal_posix'; my (@years, $year, $m, $month, $time, @t, $back, $y, $sundays); @years = (2022, 1753, 3999); for $y (@years) { # loop over months Feb to next Jan, and move back to the Sunday preceding the 1st of each month $year = $y; say qq[\nInput: $y]; $sundays = ''; for $m (1 .. 12) { # last time reset year and month $year ++ if $m == 12; $month = $m % 12; # unix time on 1st of month $time = timelocal_posix(0, 0, 12, 1, $month, $year - 1900); @t = localtime($time); # move back 7 days if Sunday, 6 if Saturday ... $back = $t[6] == 0 ? 7 : $t[6]; $time -= $back * 86400; # and get the date @t = localtime($time); $sundays .= sprintf('%04d-%02d-%02d, ', $t[5] + 1900, $t[4] + 1, $t[3]); $sundays = substr($sundays, 0, -2) . qq[\n] if $m =~ m/^(4|8|12)$/; } print qq[Output:\n$sundays]; }
Input: 2022 Output: 2022-01-30, 2022-02-27, 2022-03-27, 2022-04-24 2022-05-29, 2022-06-26, 2022-07-31, 2022-08-28 2022-09-25, 2022-10-30, 2022-11-27, 2022-12-25 Input: 1753 Output: 1753-01-28, 1753-02-25, 1753-03-25, 1753-04-29 1753-05-27, 1753-06-24, 1753-07-29, 1753-08-26 1753-09-30, 1753-10-28, 1753-11-25, 1753-12-30 Input: 3999 Output: 3999-01-31, 3999-02-28, 3999-03-28, 3999-04-25 3999-05-30, 3999-06-27, 3999-07-25, 3999-08-29 3999-09-26, 3999-10-31, 3999-11-28, 3999-12-26
Any content of this website which has been created by Peter Campbell Smith is in the public domain