You are given a year,
$year
in 4-digits form.Write a script to calculate the total number of workdays in the given year.
For the task, we consider, Monday - Friday as workdays.
Input: $year = 2021
Output: 261
Input: $year = 2020
Output: 262
Every year has 260, 261 or 262 workdays. The only variables are the on which day of the week the year starts, and whether the year is a leap year or not.
For regular years, if the year starts on weekday, it ends on the same weekday, and the year has 261 work days. If a regular year starts on a weekend, it ends on a weekend, and the year has 260 work days.
For leap years, if the year starts on a Monday to Thursday, it ends on Tuesday to Friday, giving the year 262 work days. If a leap year starts on a Friday, it ends on a Saturday, giving 261 work days. If a leap year starts on a Saturday, it ends on a Sunday, giving 260 work days. If a leap year starts on a Sunday, it ends on a Monday, giving the year 261 work days. So, we can just a lookup table, with 14 values (7 for regular years, and 7 for leap years).
But we don't have to calculate the weekday of Jan 1. As long as we have the weekday of a particular date, there will be fixed 'offset' from that date to Jan 1 (the offset may differ between a leap year and a regular year). For this challenge, we will use the doomsday value, which we have used as in the alternative solution of the challenge of week 137.
This gives the following lookup table:
Regular Year | Leap Year | |||
---|---|---|---|---|
Doomsday Value | Jan 1 | Work days | Jan 1 | Work days |
0 | Friday | 261 | Thursday | 262 |
1 | Saturday | 260 | Friday | 261 |
2 | Sunday | 260 | Saturday | 260 |
3 | Monday | 261 | Sunday | 261 |
4 | Tuesday | 261 | Monday | 262 |
5 | Wednesday | 261 | Tuesday | 262 |
6 | Thursday | 261 | Wednesday | 262 |
Enter a year in the (proleptic) Gregorian calendar, and hit the Calculate button to calculate the number of work days in that year.
Enter a year:
Our solutions will be reading years from standard input (one year per line), and write the number of work days of those year to standard output.
First, we copy the calculation of the doomsday value and the check whether a year is a leap year from the previous week:
my $SUNDAY = 0;
my $MONDAY = 1;
my $TUESDAY = 2;
my $WEDNESDAY = 3;
my $THURSDAY = 4;
my $FRIDAY = 5;
my $SATURDAY = 6;
sub doomsday ($year = $_) {
use integer;
my $anchor = ($TUESDAY, $SUNDAY, $FRIDAY, $WEDNESDAY) [($year / 100) % 4];
my $y = $year % 100;
my $doomsday = ((($y / 12) + ($y % 12) + (($y % 12) / 4)) + $anchor) % 7;
$doomsday;
}
sub is_leap ($year = $_) {
($year % 400 == 0) || ($year % 4 == 0) && ($year % 100 != 0) ? 1 : 0
}
Then it's just a matter of defining a lookup table, reading the input, and printing the value we can look up:
while (<>) {
say $lookup [is_leap] [doomsday]
}
Find the full program on GitHub.
We also have implementation in a bunch of different language; they all use the same algorithm as the Perl implementation:
AWK, Bash, bc, C, Go, Java, Lua, Node.js, Pascal, Python, R, Ruby, Scheme, and Tcl.