# ETOOBUSY ðŸš€ minimal blogging for the impatient

# PWC227 - Friday 13th

**TL;DR**

Here we are with TASK #1 from The Weekly Challenge #227. Enjoy!

# The challenge

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 questions

My initial question was *why 1753?*. It might be related to the fact that
the Gregorian calendar was adopted in 1752, so itâ€™s to be on the safe
side. Well, actually, it seems that they adopted something equivalent,
right?

Then there is the choice of the upper limit for the range. Donâ€™t get me
wrong, Iâ€™m *happy* there is a range, only curiosity.

# The solution

We will start with Raku as usual, also because it provides the most sane solution of what weâ€™re going to see here:

```
#!/usr/bin/env raku
use v6;
sub MAIN (*@years) { @years.map({ put $_, ' ', friday_13th($_) }) }
sub friday_13th ($year) {
(1..12).grep({ Date.new($year, $_, 13).day-of-week == 5 }).elems
}
```

I claim itâ€™s the most sane of them all because itâ€™s easy to see whatâ€™s going
on: an official `Date`

object is initialized, the `day-of-week`

is extracted
and compared to `5`

, which means friday. Well, maybe we might get rid of the
`5`

as a *magic number* and make it more explicit, but whatever.

My initial scaffolding for a Perl counterpart was to try and make it readable too:

```
#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
say $_, ' ', friday_13th($_) for @ARGV;
sub friday_13th ($year) {
return scalar grep { dow($year, $_, 13) == 5 } 1 .. 12;
}
```

So we moved the *juicy* part into function `dow()`

, which is supposed to
receive a date and give back a day of the week (with the usual convention
that Sunday is 0, Monday is 1, etc.)

OK, how to implement it? My first take was to rely on Perlâ€™s gmtime
and Time::Local, which are in CORE. From the date we get to an *epoch*,
then back to a date with the additional bit of information weâ€™re after:

```
sub dow_timegm ($y, $m, $d) {
require Time::Local;
my $epoch = Time::Local::timegm_modern(30, 30, 12, $d, $_ - 1, $y);
return (gmtime($epoch))[6];
}
```

One drawback of this approach is that, officially speaking, the *epoch*
starts in 1970 and using it as early as 1753 is a bit of an abuse (weâ€™re
assuming that we will not be hit by the 2038).

Anyway, I checked and the results are the same as the Raku alternative,
over the whole range. So I confidently say: *it works for me!*

And yet, if we donâ€™t still feel completely confident, we can look around and land on the following:

```
# https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
sub dow_algorithm ($y, $m, $d) {
state $t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];
use integer;
--$y if $m < 3;
return ($y + $y / 4 - $y / 100 + $y / 400 + $t->[$m - 1] + $d) % 7;
}
```

This is the least readable of them all, but it works.

We just miss some *sugar* to complete the program:

```
sub dow ($y, $m, $d) {
state $calculator = $ENV{DOW_TIMEGM} ? \&dow_timegm : \&dow_algorithm;
return $calculator->($y, $m, $d);
}
```

So there you go, either understand it at the risk of missing the point in some machines that are not mine, or get the correct result but out of faith in the code.

Yes, we could go the full DateTime solution, but it installs 34 MB of stuff and it seems a little overkill for such a simple task. It gives us the readability of the Raku solution, though.

Cheers!

*Comments? Octodon, , GitHub, Reddit, or drop me a line!*