aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/WorkingDays.pm
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2020-06-16 16:04:21 +0100
committerM Somerville <matthew-github@dracos.co.uk>2020-09-02 14:56:41 +0100
commit32c80504c0f4aad36f7d9eaef5ff3f2f6d851b77 (patch)
tree2b13714b6419d58ee9025e831fbc02f657e4cfc8 /perllib/FixMyStreet/WorkingDays.pm
parent764a6b7f8056d55aeba4656cba279b27a60d6b1a (diff)
[Zurich] Factor out working days calculator.
Diffstat (limited to 'perllib/FixMyStreet/WorkingDays.pm')
-rw-r--r--perllib/FixMyStreet/WorkingDays.pm78
1 files changed, 78 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/WorkingDays.pm b/perllib/FixMyStreet/WorkingDays.pm
new file mode 100644
index 000000000..615b226c6
--- /dev/null
+++ b/perllib/FixMyStreet/WorkingDays.pm
@@ -0,0 +1,78 @@
+package FixMyStreet::WorkingDays;
+
+use Moo;
+
+=head1 FixMyStreet::WorkingDays
+
+Given a list of public holiday dates, creates an object that can be used to
+add/subtract days from a date, only counting working days (excluding public
+holidays and weekends).
+
+=over
+
+=cut
+
+has public_holidays => (
+ is => 'ro',
+ coerce => sub {
+ return { map { $_ => 1 } @{$_[0]} };
+ },
+);
+
+=item add_days
+
+Given a DateTime object and a number of days, returns a new DateTime object
+that many working days (excluding public holidays and weekends) later.
+
+=cut
+
+sub add_days {
+ my ( $self, $dt, $days, $subtract ) = @_;
+ $dt = $dt->clone;
+ while ( $days > 0 ) {
+ $dt->add ( days => $subtract ? -1 : 1 );
+ next if $self->is_public_holiday($dt);
+ next if $self->is_weekend($dt);
+ $days--;
+ }
+ return $dt;
+}
+
+=item sub_days
+
+Given a DateTime object and a number of days, returns a new DateTime object
+that many working days (excluding public holidays and weekends) earlier.
+
+=cut
+
+sub sub_days {
+ my $self = shift;
+ return $self->add_days(@_, 1);
+}
+
+=item is_public_holiday
+
+Given a DateTime object, return true if it is a public holiday.
+
+=cut
+
+sub is_public_holiday {
+ my ($self, $dt) = @_;
+ return $self->public_holidays->{$dt->ymd};
+}
+
+=item is_weekend
+
+Given a DateTime object, return true if it is a weekend.
+
+=cut
+
+sub is_weekend {
+ my ($self, $dt) = @_;
+ return $dt->dow > 5;
+}
+
+1;
+
+=back
+