Perl Weekly Challenge 227: Friday 13th
These are some answers to the Week 227, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.
Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 30, 2023 at 23:59). This blog post offers some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.
Task 1: Friday 13th
You are given a year number in the range 1753 to 9999.
Write a script to find out how many dates in the year are Friday 13th, assume that the current Gregorian calendar applies.
Example
Input: $year = 2023
Output: 2
Since there are only 2 Friday 13th in the given year 2023 i.e. 13th Jan and 13th Oct.
The Gregorian calendar is the calendar used in most parts of the world. It was introduced in October 1582 by Pope Gregory XIII as a modification of, and replacement for, the previously used Julian calendar. The main change was to space leap years differently.
Date calculations are notoriously cumbersome and error-prone. So we will rely on well-tested core modules, which can tell us whether a given date in history or in the future is a Friday or some other day of the week.
Friday 13th in Raku
Raku has a built-in Date class that will compute the hard stuff for us. It has a new
constructor that can take three parameters, year, month and day in the month, and return an immutable object (of type Date
) identifying a day in the Gregorian calendar. It also has a day-of-week
method, which returns an integer between 1 and 7, representing the day in the week (with Monday being 1 and Sunday being 7).
So, all we need to do for a given year is to check whether, for each month, the 13th falls on a Friday (day-of week
== 5) and count how many times this happens in the year.
sub friday_13 ($y) {
my $count = 0;
for 1..12 -> $m {
# For the Raku Date class, Friday is the
# 5th day of the week
$count++ if Date.new($y, $m, 13).day-of-week == 5;
}
return $count;
}
for 1753, |(2023..2030), 9998 -> $year {
say $year, " => ", friday_13 $year;
}
This program displays the following output:
$ raku ./friday13.raku
1753 => 2
2023 => 2
2024 => 2
2025 => 1
2026 => 3
2027 => 1
2028 => 1
2029 => 2
2030 => 2
9998 => 3
Friday 13th in Perl
There are very powerful date and time calculation modules on the CPAN, such as, especially DateTime by Dave Rolsky. However, it is not a core module and, for various reasons, I prefer to use a core module such as Time::Piece, although its documentation has some opportunities for improvement.
Here, we use the (POSIX-inspired) strptime
method as a constructor and the wday
method to find the day in the week of any given date.
Just as in Raku, all we need to do for a given year is to check whether, for each month, the 13th falls on a Friday (day of week == 6) and count how many times this happens. Note that, for Time::Piece
, the week starts on Sunday and, therefore, the integer representing Friday is 6.
use strict;
use warnings;
use feature 'say';
use Time::Piece;
sub friday_13 {
my $year = shift;
my $count = 0;
my $day = 13;
for my $month (1..12) {
my $dt = Time::Piece->strptime("$month/$day/$year",
"%m/%d/%Y");
$count++ if $dt->wday == 6; # Friday == 6th day
}
return $count;
}
for my $year (2023..2030, 9998) {
say $year, " => ", friday_13 $year;
}
This program displays the following output:
2023 => 2
2024 => 2
2025 => 1
2026 => 3
2027 => 1
2028 => 1
2029 => 2
2030 => 2
9998 => 3
Note that we haven't computed the number of Friday 13th for the year 1753, because it appears that the Time::Piece
module can't handle such old dates.
Wrapping up
The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on August 6 , 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.
Leave a comment