This is my response to the Perl Weekly Challenge #37.
Write a script to calculate the total number of weekdays (Mon-Fri) in each month of the year 2019. Jan: 23 days Feb: 20 days Mar: 21 days Apr: 22 days May: 23 days Jun: 20 days Jul: 23 days Aug: 22 days Sep: 21 days Oct: 23 days Nov: 21 days Dec: 22 days |
This is straight forward when we use a «Date» object, so I have chosen to add some extras:
File: weekdays
unit sub MAIN (Int $year = 2019, Bool :$sum); # [1]
my @day-count; # [2]
my @month-name = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun", # [3]
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
my $date = Date.new($year, 1, 1); # [4]
while $date.year == $year # [5]
{
@day-count[$date.month]++ if $date.day-of-week <= 5; # [6]
$date.=later(days => 1); # [7]
}
say "Year: $year" unless $year == 2019; # [8]
say "@month-name[$_]: @day-count[$_] days" for 1 .. 12; # [9]
say "Total: { @day-count.sum}" if $sum; # [10]
[1] The program lists a lot of numbers (weekdays), but doesn't add them up. Use the «--sum» command line option to get the sum. Specify another year, if 2019 doesn't suit you.
[2] We keep track of the number of days in each month here.
[3] We need the month names (abridged) for the output. They are numbered 1..12 (when we inspect the «Date» object; see below), so the first value in this array (with index 0) is empty.
[4] Create a «Date» object for New Year's Day of the given year.
[5] As long as the date is in the same year,
[6] • increase the daycount (numer of weekdays) for the given month
(«.month
») if the day is one of monday-friday
(«$date.day-of-week <= 5
»).
[7] • get the next day. Note the «.=» method call and assignent, so that
we get the new «Date» back in the same variable. This is the same as
«$date = $date.later(days => 1)
, but shorter.
[8] Print the year, if we have specified one on the command line.
[9] Print the 12 months, with names and the count.
[10] Print the total numer of weekdays, if requested with the «--sum» command line
option. Note the use of «.sum
» on an array to get the sum.
See docs.raku.org/type/Date for more information about the «Date» class.
Running it without arguments gives the output requested by the challenge:
$ raku weekdays
Jan: 23 days
Feb: 20 days
Mar: 21 days
Apr: 22 days
May: 23 days
Jun: 20 days
Jul: 23 days
Aug: 22 days
Sep: 21 days
Oct: 23 days
Nov: 21 days
Dec: 22 days
Get the sum of the weekdays:
$ raku weekdays --sum
Jan: 23 days
Feb: 20 days
Mar: 21 days
Apr: 22 days
May: 23 days
Jun: 20 days
Jul: 23 days
Aug: 22 days
Sep: 21 days
Oct: 23 days
Nov: 21 days
Dec: 22 days
Total: 261
Another year:
$ raku weekdays --sum 2020
Year: 2020
Jan: 23 days
Feb: 20 days
Mar: 22 days
Apr: 22 days
May: 21 days
Jun: 22 days
Jul: 23 days
Aug: 21 days
Sep: 22 days
Oct: 22 days
Nov: 21 days
Dec: 23 days
Total: 262
Write a script to find out the DayLight gain/loss in the month of December 2019 as compared to November 2019 in the city of London. You can find out sunrise and sunset data for November 2019 and December 2019 for London |
I am not sure what the challenge actually asks for, but have chosen to present the daylight loss/gain for each day in November compared with the same day in December.
This time I'll show the result first, and the program afterwards:
$ raku daylight
Day November December Difference
1 9:40:44 8:11:53 -1:28:51
2 9:37:10 8:09:53 -1:27:17
3 9:33:37 8:07:57 -1:25:40
4 9:30:07 8:06:07 -1:24:00
5 9:26:38 8:04:22 -1:22:16
6 9:23:11 8:02:42 -1:20:29
7 9:19:45 8:01:08 -1:18:37
8 9:16:22 7:59:40 -1:16:42
9 9:13:01 7:58:17 -1:14:44
10 9:09:42 7:57:00 -1:12:42
11 9:06:25 7:55:50 -1:10:35
12 9:03:11 7:54:45 -1:08:26
13 8:59:59 7:53:46 -1:06:13
14 8:56:50 7:52:54 -1:03:56
15 8:53:44 7:52:07 -1:01:37
16 8:50:40 7:51:27 -59:13
17 8:47:39 7:50:54 -56:45
18 8:44:42 7:50:27 -54:15
19 8:41:48 7:50:06 -51:42
20 8:38:57 7:49:52 -49:05
21 8:36:09 7:49:44 -46:25
22 8:33:25 7:49:43 -43:42
23 8:30:45 7:49:48 -40:57
24 8:28:09 7:50:00 -38:09
25 8:25:36 7:50:19 -35:17
26 8:23:08 7:50:44 -32:24
27 8:20:44 7:51:15 -29:29
28 8:18:24 7:51:53 -26:31
29 8:16:09 7:52:37 -23:32
30 8:13:59 7:53:27 -20:32
31 7:54:24
use LWP::Simple; # [1]
my %url = # [2]
(
nov => 'https://www.timeanddate.com/sun/uk/london?month=11&year=2019',
dec => 'https://www.timeanddate.com/sun/uk/london?month=12&year=2019'
);
my %data; # [3]
read-data("nov"); # [4]
read-data("dec"); # [4]
[1] We use this module to feth the web pages. Install it with «zef» if you don't have it.
[2] The URLs for the the two web pages.
[3] The data structure to hold the daylight values.
[4] Read the values. (I'll show this procedure in the next section.)
Fetching web pages all the time when writing and modifying a program is a waste of time and resources, so I have added caching:
File: daylight (partial)
my %file = # [5]
(
nov => '2019-nov.html',
dec => '2019-dec.html'
);
sub read-data ($month) # [6]
{
my $line; # [7]
if %file{$month}.IO.e # [8]
{
$line = slurp %file{$month}; # [8a]
}
else # [9]
{
$line = LWP::Simple.get(%url{$month}).lines.join("\n"); # [9a]
spurt %file{$month}, $line; # [9b]
}
$line ~~ /\<tbody\>(.*?)\<\/tbody\>/; # [10]
for $0.Str.split("</tr>") -> $line # [11]
{
$line ~~ # [12]
/data\-day\=(\d+) \s .*? \"c \s tr \s sep\-l\"\>(\d+\:\d+\:\d+)\<\/td\>/;
# ########## 12a ############################## 12b 12b 12b 12b #######
next unless $0; # [13]
%data{$month}{$0.Str} = $1.Str; # [14]
}
}
[5] The names for the cached file version of the web pages.
[6] The procedure doing the job (fetching the web page and building up the data structure).
[7] I read the entire file in as a single line, as the source doesn't have newlines where they are useful for my parsing.
[8] If we have the cached file, read that file (8b) - instead of fetching it from the web.
[9] If not cached, get the web page as a single line (9a) and save it to the cached file (9b).
[10] The tabular data is located in a html table, between the «<tbody>» and «</tbody>» tags. The data is in the «$0» match object.
[11] We have to iterate over the dates, and splitting on the «</tr>» tag (end of table row) works. Note that we get a false row after the last date when doing things this way, but (13) takes care of that.
[12] Get the day («data-day=XXX») and the daylight value (placed inside a
unique markup like this:
«<td class="c tr sep-l">8:11:53<td>
». The other
fields (columns in the html table) have other classes.
[13] Skip non-matching lines. See (11).
[14] Update the data structure. Note that I coerce the match object to a string to avoid problems later on.
Then all that is left is printing the values, and the difference. I could have written a custom class for the time values («hh:mm:ss»), but have chosen the old fashion procedure approach instead:
File: daylight (partial)
say "Day November December Difference"; # [15]
for 1..30 -> $day # [16]
{
my $nov = %data<nov>{$day}; # [17]
my $dec = %data<dec>{$day}; # [18]
say "{ $day.fmt('%2d') } { $nov.fmt('%9s') } { $dec.fmt('%9s') } " ~ # [19]
"{ (s2hms( hms2s($dec) - hms2s($nov))).fmt('%10s') }";
}
say "{ "31".fmt('%2d') } { %data<dec>{31}.fmt('%9s') }"; # [20]
sub hms2s ($hms) # [21]
{
my @parts = $hms.split(":") // return 0;
return @parts[0] * 60 * 60 + @parts[1] * 60 + @parts[2];
}
sub s2hms ($s is copy) # [22]
{
my $sign = "";
if $s < 0 { $s = -$s; $sign = "-"; }
my $h = $s div 3600; $s -= $h * 3600;
my $m = $s div 60; $s -= $m * 60;
return "$sign$h:{ $m.fmt('%02d') }:{ $s.fmt('%02d') }" if $h;
return "$sign$m:{ $s.fmt('%02d') }" if $s;
return "$sign$s";
}
[15] The table header.
[16] Foreach day (the first 30 ones only, as November stops there).
[17] • print the November daylight value.
[18] • ditto for December.
[19] • and the difference between the two values.
[20] The 31st December value.
[21] The procedure converting «hh:mm:ss» values to seconds.
[22] The procedure converting seconds to «hh:mm:ss» values.
Note the extensive use of «fmt» to right justify the values (and zero pad minutes and hours; we want «1:01:04» and not «1:1:4»). The format strings are the same as for «printf» and «sprintf».
The complete program:
File: daylight
use LWP::Simple;
my %file = (
nov => '2019-nov.html',
dec => '2019-dec.html'
);
my %url = (
nov => 'https://www.timeanddate.com/sun/uk/london?month=11&year=2019',
dec => 'https://www.timeanddate.com/sun/uk/london?month=12&year=2019'
);
my %data;
read-data("nov");
read-data("dec");
sub read-data ($month)
{
my $line;
if %file{$month}.IO.e
{
$line = slurp %file{$month};
}
else
{
$line = LWP::Simple.get(%url{$month}).lines.join("\n");
spurt %file{$month}, $line;
}
$line ~~ /\<tbody\>(.*?)\<\/tbody\>/;
for $0.Str.split("</tr>") -> $line
{
$line ~~ /data\-day\=(\d+) \s .*? \"c \s tr \s sep\-l\"\>(\d+\:\d+\:\d+)\<\/td\>/;
next unless $0;
%data{$month}{$0.Str} = $1.Str;
}
}
say "Day November December Difference";
for 1..30 -> $day
{
my $nov = %data<nov>{$day};
my $dec = %data<dec>{$day};
say "{ $day.fmt('%2d') } { $nov.fmt('%9s') } { $dec.fmt('%9s') } { (s2hms( hms2s($dec) - hms2s($nov))).fmt('%10s') }";
}
say "{ "31".fmt('%2d') } { %data<dec>{31}.fmt('%9s') }";
sub hms2s ($hms)
{
my @parts = $hms.split(":") // return 0;
return @parts[0] * 60 * 60 + @parts[1] * 60 + @parts[2];
}
sub s2hms ($s is copy)
{
my $sign = "";
if $s < 0 { $s = -$s; $sign = "-"; }
my $h = $s div 3600; $s -= $h * 3600;
my $m = $s div 60; $s -= $m * 60;
return "$sign$h:{ $m.fmt('%02d') }:{ $s.fmt('%02d') }" if $h;
return "$sign$m:{ $s.fmt('%02d') }" if $s;
return "$sign$s";
}
I'll start with the output this time as well.
$ raku daylight-turbo
London London
Day November December Difference
2019 2019
1 9:40:44 8:11:53 -1:28:51
2 9:37:10 8:09:53 -1:27:17
3 9:33:37 8:07:57 -1:25:40
4 9:30:07 8:06:07 -1:24:00
5 9:26:38 8:04:22 -1:22:16
6 9:23:11 8:02:42 -1:20:29
7 9:19:45 8:01:08 -1:18:37
8 9:16:22 7:59:40 -1:16:42
9 9:13:01 7:58:17 -1:14:44
10 9:09:42 7:57:00 -1:12:42
11 9:06:25 7:55:50 -1:10:35
12 9:03:11 7:54:45 -1:08:26
13 8:59:59 7:53:46 -1:06:13
14 8:56:50 7:52:54 -1:03:56
15 8:53:44 7:52:07 -1:01:37
16 8:50:40 7:51:27 -59:13
17 8:47:39 7:50:54 -56:45
18 8:44:42 7:50:27 -54:15
19 8:41:48 7:50:06 -51:42
20 8:38:57 7:49:52 -49:05
21 8:36:09 7:49:44 -46:25
22 8:33:25 7:49:43 -43:42
23 8:30:45 7:49:48 -40:57
24 8:28:09 7:50:00 -38:09
25 8:25:36 7:50:19 -35:17
26 8:23:08 7:50:44 -32:24
27 8:20:44 7:51:15 -29:29
28 8:18:24 7:51:53 -26:31
29 8:16:09 7:52:37 -23:32
30 8:13:59 7:53:27 -20:32
31 7:54:24
Looks familiar? We have used the default values, but can specify them explicitly like this:
$ raku daylight-turbo --left="London:2019:11" --right="London:2019:12"
That gives the same output as without the arguments, so it isn't shown here.
We can swap the order:
$ raku daylight-turbo --left="London:2019:12" --right="London:2019:11"
London London
Day December November Difference
2019 2019
1 8:11:53 9:40:44 1:28:51
2 8:09:53 9:37:10 1:27:17
3 8:07:57 9:33:37 1:25:40
4 8:06:07 9:30:07 1:24:00
5 8:04:22 9:26:38 1:22:16
6 8:02:42 9:23:11 1:20:29
7 8:01:08 9:19:45 1:18:37
8 7:59:40 9:16:22 1:16:42
9 7:58:17 9:13:01 1:14:44
10 7:57:00 9:09:42 1:12:42
11 7:55:50 9:06:25 1:10:35
12 7:54:45 9:03:11 1:08:26
13 7:53:46 8:59:59 1:06:13
14 7:52:54 8:56:50 1:03:56
15 7:52:07 8:53:44 1:01:37
16 7:51:27 8:50:40 59:13
17 7:50:54 8:47:39 56:45
18 7:50:27 8:44:42 54:15
19 7:50:06 8:41:48 51:42
20 7:49:52 8:38:57 49:05
21 7:49:44 8:36:09 46:25
22 7:49:43 8:33:25 43:42
23 7:49:48 8:30:45 40:57
24 7:50:00 8:28:09 38:09
25 7:50:19 8:25:36 35:17
26 7:50:44 8:23:08 32:24
27 7:51:15 8:20:44 29:29
28 7:51:53 8:18:24 26:31
29 7:52:37 8:16:09 23:32
30 7:53:27 8:13:59 20:32
31 7:54:24
We can change one of the months:
$ raku daylight-turbo --left="London:2019:02" --right="London:2019:12"
London London
Day February December Difference
2019 2019
1 9:10:06 8:11:53 -58:13
2 9:13:28 8:09:53 -1:03:35
3 9:16:51 8:07:57 -1:08:54
4 9:20:17 8:06:07 -1:14:10
5 9:23:45 8:04:22 -1:19:23
6 9:27:15 8:02:42 -1:24:33
7 9:30:47 8:01:08 -1:29:39
8 9:34:20 7:59:40 -1:34:40
9 9:37:55 7:58:17 -1:39:38
10 9:41:32 7:57:00 -1:44:32
11 9:45:11 7:55:50 -1:49:21
12 9:48:50 7:54:45 -1:54:05
13 9:52:31 7:53:46 -1:58:45
14 9:56:14 7:52:54 -2:03:20
15 9:59:57 7:52:07 -2:07:50
16 10:03:42 7:51:27 -2:12:15
17 10:07:28 7:50:54 -2:16:34
18 10:11:15 7:50:27 -2:20:48
19 10:15:03 7:50:06 -2:24:57
20 10:18:51 7:49:52 -2:28:59
21 10:22:41 7:49:44 -2:32:57
22 10:26:31 7:49:43 -2:36:48
23 10:30:22 7:49:48 -2:40:34
24 10:34:14 7:50:00 -2:44:14
25 10:38:07 7:50:19 -2:47:48
26 10:42:00 7:50:44 -2:51:16
27 10:45:53 7:51:15 -2:54:38
28 10:49:48 7:51:53 -2:57:55
29 7:52:37
30 7:53:27
31 7:54:24
It handles short months (as February) without problems.
Or we can compare London with another city, e.g. Paris:
$ raku daylight-turbo --left="Paris:2019:02" --right="London:2019:02"
Paris London
Day February February Difference
2019 2019
1 9:26:24 9:10:06 -16:18
2 9:29:25 9:13:28 -15:57
3 9:32:28 9:16:51 -15:37
4 9:35:33 9:20:17 -15:16
5 9:38:41 9:23:45 -14:56
6 9:41:49 9:27:15 -14:34
7 9:45:00 9:30:47 -14:13
8 9:48:13 9:34:20 -13:53
9 9:51:27 9:37:55 -13:32
10 9:54:42 9:41:32 -13:10
11 9:57:59 9:45:11 -12:48
12 10:01:17 9:48:50 -12:27
13 10:04:37 9:52:31 -12:06
14 10:07:58 9:56:14 -11:44
15 10:11:20 9:59:57 -11:23
16 10:14:43 10:03:42 -11:01
17 10:18:08 10:07:28 -10:40
18 10:21:33 10:11:15 -10:18
19 10:24:59 10:15:03 -9:56
20 10:28:26 10:18:51 -9:35
21 10:31:54 10:22:41 -9:13
22 10:35:23 10:26:31 -8:52
23 10:38:53 10:30:22 -8:31
24 10:42:23 10:34:14 -8:09
25 10:45:54 10:38:07 -7:47
26 10:49:25 10:42:00 -7:25
27 10:52:57 10:45:53 -7:04
28 10:56:30 10:49:48 -6:42
I used the same month/year, but we don' have to.
Only some cities are supported, and the program gives the list:
$ raku daylight-turbo --left="Paris:2019:02" --right="Moss:2019:02"
City 'Moss' not supported. Use one of Berlin Birmingham Edinburgh
London Manchester New York Oslo Paris Sydney.
in sub read-data at ./daylight-turbo line 30
in sub MAIN at ./daylight-turbo line 22
in block at ./daylight-turbo line 3
And finally, the modified program:
File: daylight-turbo
use LWP::Simple;
unit sub MAIN (:$left = "London:2019:11", :$right = "London:2019:12"); # [1]
my $base-url = 'https://www.timeanddate.com/sun/'; # [2]
my @months = ('', 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November',
'December'); # [3]
my %city2url = (
Berlin => 'germany/berlin', # [4]
Birmingham => 'uk/birmingham',
Edinburgh => 'uk/edinburgh',
London => 'uk/london',
Manchester => 'uk/manchester',
'New York' => 'usa/new-york',
Oslo => 'norway/oslo',
Paris => 'france/paris',
Sydney => 'australia/sydney',
);
my %data;
read-data($left); # [5]
read-data($right); # [5]
sub read-data ($city-month) # [5]
{
my $line;
my ($city, $year, $month) = $city-month.split(':'); # [6]
die "City '$city' not supported. Use one of { %city2url.keys.sort }."
unless %city2url{$city}; # [7]
if "$city-month.html".IO.e # [8]
{
$line = slurp "$city-month.html";
}
else
{
my $url = $base-url ~ %city2url{$city} ~
"?month=" ~ $month ~ "&year=" ~ $year;
$line = LWP::Simple.get($url).lines.join("\n");
spurt "$city-month.html", $line;
}
$line ~~ /\<tbody\>(.*?)\<\/tbody\>/
for $0.Str.split("</tr>") -> $line
{
$line ~~
/data\-day\=(\d+) \s .*? \"c \s tr \s sep\-l\"\>(\d+\:\d+\:\d+)\<\/td\>/;
next unless $0;
%data{$city-month}{$0.Str} = $1.Str; # [9]
}
}
my ($left-city, $left-year, $left-month) = $left.split(':');
my ($right-city, $right-year, $right-month) = $right.split(':');
say " { $left-city.fmt('%8s') } { $right-city.fmt('%8s') }";
say "Day { @months[$left-month].fmt('%8s') } " ~
"{ @months[$right-month].fmt('%8s') } Difference";
say " { $left-year.fmt('%8s')} { $right-year.fmt('%8s') }";
for 1..31 -> $day
{
my $left-value = %data{$left}{$day};
my $right-value = %data{$right}{$day};
! $left-value && ! $right-value && last; # [10]
print $day.fmt('%2d') ~ ' ';
print $left-value # [11]
?? $left-value.fmt('%9s') ~ ' '
!! ' ' x 11;
print $right-value # [12]
?? $right-value.fmt('%9s') ~ ' '
!! ' ' x 11;
print "{ (s2hms( hms2s($right-value) - hms2s($left-value))).fmt('%10s') }"
if $left-value && $right-value; # [13]
say '';
}
sub hms2s ($hms)
{
my @parts = $hms.split(':') // return 0;
return @parts[0] * 60 * 60 + @parts[1] * 60 + @parts[2];
}
sub s2hms ($s is copy)
{
my $sign = "";
if $s < 0 { $s = -$s; $sign = "-"; }
my $h = $s div 3600; $s -= $h * 3600;
my $m = $s div 60; $s -= $m * 60;
return "$sign$h:{ $m.fmt('%02d') }:{ $s.fmt('%02d') }" if $h;
return "$sign$m:{ $s.fmt('%02d') }" if $s;
return "$sign$s";
}
[1] The default values. Note the syntax; «city:year:month». I have named the columns «left value» and «right value», and this is reflected in the variable names in the entire program.
[2] The base URL. We get the actual URL by appending the city, year and month.
[3] The month names.
[4] The supported cities (and the corresponding URL part).
[5] Use «city:year:month» as arguments this time.
[6] Get the individual parts (city, year and month). Note the lack of error checking.
[7] Check for supported cities, and print a nice error message if it isn't.
[8] The cached files has the city, year and month in the file names.
[9] Use the city, year and month as key in the data structure.
[10] Exit the loop (1..31) if there are no data for the current day (both the left value and the right value). That is the case if both months are shorter than 31 days.
[11] Print the left value, if given, or padding otherwise.
[12] As above, but for the right value.
[13] Print the difference, if we have both values (left and right).
Perhaps a last running to show that the calculations back and forth are correct:
$ raku daylight-turbo --left="Berlin:2009:02" --right="Berlin:2009:02"
Berlin Berlin
Day February February Difference
2009 2009
1 9:04:40 9:04:40 0
2 9:08:11 9:08:11 0
3 9:11:45 9:11:45 0
4 9:15:20 9:15:20 0
5 9:18:58 9:18:58 0
6 9:22:37 9:22:37 0
7 9:26:18 9:26:18 0
8 9:30:01 9:30:01 0
9 9:33:46 9:33:46 0
10 9:37:32 9:37:32 0
11 9:41:20 9:41:20 0
12 9:45:09 9:45:09 0
13 9:49:00 9:49:00 0
14 9:52:52 9:52:52 0
15 9:56:45 9:56:45 0
16 10:00:39 10:00:39 0
17 10:04:34 10:04:34 0
18 10:08:30 10:08:30 0
19 10:12:28 10:12:28 0
20 10:16:26 10:16:26 0
21 10:20:25 10:20:25 0
22 10:24:25 10:24:25 0
23 10:28:25 10:28:25 0
24 10:32:26 10:32:26 0
25 10:36:28 10:36:28 0
26 10:40:31 10:40:31 0
27 10:44:34 10:44:34 0
28 10:48:37 10:48:37 0
sub read-data ($city-month)
{
my $line;
my ($city, $year, $month) = $city-month.split(':');
die "Illegal month \"$month\" (use 01..12)"
unless $month eq one <<01 02 03 04 05 06 07 08 09 10 11 12>>
die "Illegal year \"$year\" (use 1900..2199)"
unless 1900 <= $year.Int <= 2199;
die "City '$city' not supported. Use one of { %city2url.keys.sort }."
unless %city2url{$city};
Adding support for additional cities is tedious, but we can let the user do it:
File: daylight-turbo2 (changes only)
unit sub MAIN (*@citymapping,
:$left = "London:2019:11",
:$right = "London:2019:12");
my $base-url = 'https://www.timeanddate.com/sun/';
my @months = ('', 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November',
'December');
my %city2url = (
Berlin => 'germany/berlin',
Birmingham => 'uk/birmingham',
Edinburgh => 'uk/edinburgh',
London => 'uk/london',
Manchester => 'uk/manchester',
'New York' => 'usa/new-york',
Oslo => 'norway/oslo',
Paris => 'france/paris',
Sydney => 'australia/sydney',
);
if @citymapping
{
for @citymapping -> $line
{
my ($city, $url) = $line.split(":");
%city2url{$city} = $url;
}
}
Running it:
$ raku daylight-turbo2 --left=Ulaanbaatar:2019:12 Ulaanbaatar:mongolia/ulaanbaatar
Ulaanbaatar London
Day December December Difference
2019 2019
1 8:42:17 8:11:53 -30:24
2 8:40:33 8:09:53 -30:40
3 8:38:53 8:07:57 -30:56
4 8:37:18 8:06:07 -31:11
5 8:35:47 8:04:22 -31:25
6 8:34:21 8:02:42 -31:39
7 8:33:00 8:01:08 -31:52
8 8:31:44 7:59:40 -32:04
9 8:30:32 7:58:17 -32:15
10 8:29:26 7:57:00 -32:26
11 8:28:24 7:55:50 -32:34
12 8:27:28 7:54:45 -32:43
13 8:26:37 7:53:46 -32:51
14 8:25:51 7:52:54 -32:57
15 8:25:10 7:52:07 -33:03
16 8:24:35 7:51:27 -33:08
17 8:24:05 7:50:54 -33:11
18 8:23:40 7:50:27 -33:13
19 8:23:21 7:50:06 -33:15
20 8:23:07 7:49:52 -33:15
21 8:22:59 7:49:44 -33:15
22 8:22:57 7:49:43 -33:14
23 8:23:00 7:49:48 -33:12
24 8:23:08 7:50:00 -33:08
25 8:23:22 7:50:19 -33:03
26 8:23:41 7:50:44 -32:57
27 8:24:06 7:51:15 -32:51
28 8:24:37 7:51:53 -32:44
29 8:25:12 7:52:37 -32:35
30 8:25:53 7:53:27 -32:26
31 8:26:40 7:54:24 -32:16
Note that «London» is too far right in the header, as «Ulaanbaatar» is too long.
Note the missing error checking in the parsing of new cities (we should allow letters and "-" only - and insist on a single "/" in the middle of the URL part), and that it is possible to do naughty things like this: «Oxford:spain/madrid«.
Also note that the caching functionality will clutter the current directory with html files, e.g.:
$ ls -l
total 1020
-rw-r--r-- 1 arne arne 72137 des. 4 21:38 2019-dec.html
-rw-r--r-- 1 arne arne 71544 des. 4 21:15 2019-nov.html
-rw-r--r-- 1 arne arne 70483 des. 7 11:48 Berlin:2009:02.html
-rw-r--r-- 1 arne arne 69832 des. 7 11:49 Berlin:2019:02.html
-rw-r--r-- 1 arne arne 70654 des. 7 12:11 Berlin:2119:02.html
-rwxr-xr-x 1 arne arne 1800 des. 4 22:11 daylight
-rwxr-xr-x 1 arne arne 2694 des. 6 23:03 daylight-turbo
-rwxr-xr-x 1 arne arne 3024 des. 7 12:24 daylight-turbo2
-rw-r--r-- 1 arne arne 70017 des. 6 22:37 London:2019:02.html
-rw-r--r-- 1 arne arne 71457 des. 6 22:18 London:2019:11.html
-rw-r--r-- 1 arne arne 72112 des. 6 22:18 London:2019:12.html
-rw-r--r-- 1 arne arne 69989 des. 6 22:37 Paris:2019:02.html
-rw-r--r-- 1 arne arne 72325 des. 6 22:57 Paris:2019:12.html
-rw-r--r-- 1 arne arne 72145 des. 6 22:57 Paris:2019:22.html
-rw-r--r-- 1 arne arne 73184 des. 6 23:03 Sydney:2019:12.html
-rw-r--r-- 1 arne arne 72611 des. 7 12:21 Ulaanbaatar:2019:12.html
-rwxr-xr-x 1 arne arne 475 des. 2 13:06 weekdays
And that's it.