aboutsummaryrefslogtreecommitdiffstats
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
parent764a6b7f8056d55aeba4656cba279b27a60d6b1a (diff)
[Zurich] Factor out working days calculator.
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm43
-rw-r--r--perllib/FixMyStreet/WorkingDays.pm78
-rw-r--r--t/workingdays.t21
3 files changed, 106 insertions, 36 deletions
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index 5635939ac..4b893af40 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -10,6 +10,7 @@ use DateTime::Format::Pg;
use Try::Tiny;
use FixMyStreet::Geocode::Zurich;
+use FixMyStreet::WorkingDays;
use strict;
use warnings;
@@ -221,7 +222,7 @@ sub get_body_sender {
# Report overdue functions
-my %public_holidays = map { $_ => 1 } (
+my @public_holidays = (
# New Year's Day, Saint Berchtold, Good Friday, Easter Monday,
# Sechseläuten, Labour Day, Ascension Day, Whit Monday,
# Swiss National Holiday, Knabenschiessen, Christmas, St Stephen's Day
@@ -247,53 +248,23 @@ my %public_holidays = map { $_ => 1 } (
'2021-09-13',
);
-sub is_public_holiday {
- my $dt = shift;
- return $public_holidays{$dt->ymd};
-}
-
-sub is_weekend {
- my $dt = shift;
- return $dt->dow > 5;
-}
-
-sub add_days {
- my ( $dt, $days ) = @_;
- $dt = $dt->clone;
- while ( $days > 0 ) {
- $dt->add ( days => 1 );
- next if is_public_holiday($dt) or is_weekend($dt);
- $days--;
- }
- return $dt;
-}
-
-sub sub_days {
- my ( $dt, $days ) = @_;
- $dt = $dt->clone;
- while ( $days > 0 ) {
- $dt->subtract ( days => 1 );
- next if is_public_holiday($dt) or is_weekend($dt);
- $days--;
- }
- return $dt;
-}
-
sub overdue {
my ( $self, $problem ) = @_;
my $w = $problem->created;
return 0 unless $w;
+ my $wd = FixMyStreet::WorkingDays->new( public_holidays => \@public_holidays );
+
# call with previous state
if ( $problem->state eq 'submitted' ) {
# One working day
- $w = add_days( $w, 1 );
+ $w = $wd->add_days( $w, 1 );
return $w < DateTime->now() ? 1 : 0;
} elsif ( $problem->state eq 'confirmed' || $problem->state eq 'in progress' || $problem->state eq 'feedback pending' ) {
# States which affect the subdiv_overdue statistic. TODO: this may no longer be required
# Six working days from creation
- $w = add_days( $w, 6 );
+ $w = $wd->add_days( $w, 6 );
return $w < DateTime->now() ? 1 : 0;
# call with new state
@@ -301,7 +272,7 @@ sub overdue {
# States which affect the closed_overdue statistic
# Five working days from moderation (so 6 from creation)
- $w = add_days( $w, 6 );
+ $w = $wd->add_days( $w, 6 );
return $w < DateTime->now() ? 1 : 0;
}
}
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
+
diff --git a/t/workingdays.t b/t/workingdays.t
new file mode 100644
index 000000000..326cf05c9
--- /dev/null
+++ b/t/workingdays.t
@@ -0,0 +1,21 @@
+use Test::More;
+use DateTime;
+
+use_ok 'FixMyStreet::WorkingDays';
+
+
+my $wd = FixMyStreet::WorkingDays->new(
+ public_holidays => [
+ '2020-09-21',
+ '2020-09-15',
+ ],
+);
+
+my $dt = DateTime->new(year => 2020, month => 9, day => 19);
+
+is $wd->add_days($dt, 1)->ymd, '2020-09-22';
+is $wd->sub_days($dt, 5)->ymd, '2020-09-11';
+is $wd->is_public_holiday($dt), undef;
+is $wd->is_weekend($dt), 1;
+
+done_testing;