aboutsummaryrefslogtreecommitdiff
path: root/challenge-259
diff options
context:
space:
mode:
Diffstat (limited to 'challenge-259')
-rw-r--r--challenge-259/wlmb/blog.txt1
-rwxr-xr-xchallenge-259/wlmb/perl/ch-1.pl40
-rwxr-xr-xchallenge-259/wlmb/perl/ch-2.pl40
3 files changed, 81 insertions, 0 deletions
diff --git a/challenge-259/wlmb/blog.txt b/challenge-259/wlmb/blog.txt
new file mode 100644
index 0000000000..78da93642d
--- /dev/null
+++ b/challenge-259/wlmb/blog.txt
@@ -0,0 +1 @@
+https://wlmb.github.io/2024/03/04/PWC259/
diff --git a/challenge-259/wlmb/perl/ch-1.pl b/challenge-259/wlmb/perl/ch-1.pl
new file mode 100755
index 0000000000..66be0993b7
--- /dev/null
+++ b/challenge-259/wlmb/perl/ch-1.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/env perl
+# Perl weekly challenge 259
+# Task 1: Banking Day Offset
+#
+# See https://wlmb.github.io/2024/03/04/PWC259/#task-1-banking-day-offset
+use v5.36;
+use DateTime;
+use DateTime::Format::DateParse qw(parse_datetime);
+use List::AllUtils qw(uniq_by);
+use POSIX qw(floor);
+die <<~"FIN" unless @ARGV >= 2;
+ Usage ch-1.pl S D [B1 B2...]
+ to bump daye S by D days skipping weekends and
+ the (optional) bank holidays B1 B2...
+ FIN
+my ($start_str, $offset, @bank_str)=@ARGV;
+my ($start, @bank)= # convert to dates
+ map
+ {DateTime::Format::DateParse->parse_datetime($_)->truncate(to=>'day')}
+ ($start_str, @bank_str);
+my $fullweeks=floor($offset/5);
+my $remaining=$offset%5;
+my $end=$start->clone;
+my $weekday=$end->day_of_week;
+$end->add(days=>8-$weekday), $weekday=1 if $weekday>5;
+$end->add(days=>7*$fullweeks+$remaining);
+skip_weekend($end);
+bank_adjust($_,$start,$end) for
+ sort {DateTime->compare($a, $b)} uniq_by {"".$_} @bank; # remove duplicate dates and sort
+say "Start: $start_str. Offset $offset. Holidays: @bank_str -> ", $end->ymd;
+sub skip_weekend($date){
+ my $weekday=$date->day_of_week;
+ $date->add(days=>2) if $weekday>5;
+}
+sub bank_adjust($date, $start, $end){
+ return if $date->day_of_week >5 ||
+ DateTime->compare($date, $start) < 0 || DateTime->compare($date, $end) > 0;
+ $end->add(days=>1);
+ $end->add(days=>2) if $end->day_of_week>5; # skip weekend
+}
diff --git a/challenge-259/wlmb/perl/ch-2.pl b/challenge-259/wlmb/perl/ch-2.pl
new file mode 100755
index 0000000000..e37f23333b
--- /dev/null
+++ b/challenge-259/wlmb/perl/ch-2.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/env perl
+# Perl weekly challenge 259
+# Task 2: Line Parser
+#
+# See https://wlmb.github.io/2024/03/04/PWC259/#task-2-line-parser
+use v5.36;
+use Parse::RecDescent;
+use Data::Dumper;
+local $/;
+my $input=<>;
+our @result;
+my $grammar=q{
+ {my $id;}
+ startrule: record(s) eof
+ { $return = $item[1] }
+ record: single lines
+ { $return = {
+ %{$item[1]},
+ text => join " ", $item[2]->@* }
+ }
+ | single
+ single: '{%' id keyval(s) '%}'
+ { $return = { name => $item[2], fields => { map {%$_} $item[3]->@*} }; }
+ id: /\w+/
+ { $id=$item[1]; }
+ lines: line(s) '{%' "end" "$id" '%}'
+ { $return = $item[1]; }
+ line: /.*/
+ { $return=$item[1]; $item[1]=~/^\{%/?undef:1; }
+ keyval: key "=" val
+ { $return = {$item[1]=>$item[3]} }
+ key: /\w+/
+ val: number | string
+ number: /\d+/
+ string: /"(?:[^"\n]|\\")*"/
+ eof: /^\Z/
+};
+my $parser=Parse::RecDescent->new($grammar);
+my $parse=$parser->startrule($input);
+say Dumper($parse);