diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-03-07 12:31:42 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-07 12:31:42 +0000 |
| commit | f75b0a0928458bed74ccebaf23f8103cdfe990f4 (patch) | |
| tree | 1be848f0c6f84253af33833c05b722a9b5ec0920 | |
| parent | cc95037b0a5eadd466851cc5d554fda2f636bf60 (diff) | |
| parent | 23e8f5eab3ad4ef62889c0078284e0980230213e (diff) | |
| download | perlweeklychallenge-club-f75b0a0928458bed74ccebaf23f8103cdfe990f4.tar.gz perlweeklychallenge-club-f75b0a0928458bed74ccebaf23f8103cdfe990f4.tar.bz2 perlweeklychallenge-club-f75b0a0928458bed74ccebaf23f8103cdfe990f4.zip | |
Merge pull request #9704 from mattneleigh/pwc259
Pwc259
| -rwxr-xr-x | challenge-259/mattneleigh/perl/ch-1.pl | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/challenge-259/mattneleigh/perl/ch-1.pl b/challenge-259/mattneleigh/perl/ch-1.pl new file mode 100755 index 0000000000..5e3231ad14 --- /dev/null +++ b/challenge-259/mattneleigh/perl/ch-1.pl @@ -0,0 +1,181 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use English; + +################################################################################ +# Begin main execution +################################################################################ + +my @dates = ( + [ + "2018-06-28", + 3, + [ + "2018-07-03" + ] + ], + [ + "2018-06-28", + 3, + undef + ] +); + +print("\n"); +foreach my $date (@dates){ + printf( + "\$start_date = %s\n\$offset = %d\n" + . + "\$bank_holidays = %s\nOutput: %s\n\n", + $date->[0], + $date->[1], + defined($date->[2]) ? + sprintf( + "[\n%s\n ]", + join( + "\n", + map( + " " . $_, + @{$date->[2]} + ) + ) + ) + : + "undef (none)", + calculate_offset_business_day($date) + ); +} + +exit(0); +################################################################################ +# End main execution; subroutines follow +################################################################################ + + + +################################################################################ +# Given a start date and an offset in days, as well as an optional list of Bank +# Holidays, determine the date that is $offset business days (not weekends, not +# Bank Holidays) after the start date +# Takes one argument: +# * A ref to an array that contains a start date in ISO format, an offset in +# days, and an optional ref to a list of Bank Holidays, also in ISO format +# (e.g. +# [ +# # Start date +# "2018-06-28", +# +# # Offset +# 3, +# +# # Bank holidays; this field should be undef +# # if not used +# [ +# "2018-07-03" +# ] +# ] +# ) +# Returns: +# * The date of the calculated business day in ISO format (e.g. "2018-07-04" ) +################################################################################ +sub calculate_offset_business_day{ + use constant secs_per_day => 86400; + + my $date = shift(); + + my $base = date_to_gmtime($date->[0]); + my $offset = $date->[1]; + my @date; + my @holidays; + + if(defined($date->[2])){ + # Get a sorted list of bank holidays in gmtime + @holidays = sort( + { $a <=> $b } + map( + { + my $gmtime = date_to_gmtime($_); + + # Only pass along bank holidays that aren't + # before our base date + $gmtime < $base ? + () + : + $gmtime; + } + @{$date->[2]} + ) + ); + } + + # Loop while we still have unused offset days + while($offset){ + # Advance the base date by one day and see + # what day of the week this is + $base += secs_per_day; + + # See if this date is a bank holiday... + if(@holidays && ($base == $holidays[0])){ + # It was- strip the bank holiday from the list + # and skip ahead to the next date without + # decrementing the offset + shift(@holidays); + next; + } + + # Skip ahead without decrementing the offset + # if this is a weekend date + @date = gmtime($base); + next + if(($date[6] == 0) || ($date[6] == 6)); + + $offset--; + } + + # Get date fields for our computed base time + @date = gmtime($base); + + return( + sprintf( + "%04d-%02d-%02d", + 1900 + $date[5], + 1 + $date[4], + $date[3] + ) + ); + +} + + + +################################################################################ +# Convert a date in ISO format (YYYY-MM-DD) to the time in seconds since the +# start of the UNIX epoch, GMT +# Takes one argument: +# * The date to convert (e.g. "2018-06-28" ) +# Returns: +# * The number of seconds from the start of the UNIX epoch to midnight at the +# start of the specified date, in GMT (e.g. 1530144000 ) +################################################################################ +sub date_to_gmtime{ + use Time::Local qw(timegm); + + # Split the input date on hyphens + my @date = split(/-/, shift()); + + # Calculate the seconds since the start of the + # epoch, in GMT, for midnight on the specified + # date + return( + # Theoretically timegm_modern() would be better + # here but this is more compatible with older + # Perl installs... + timegm(0, 0, 0, $date[2], $date[1] - 1, $date[0] - 1900) + ); + +} + + + |
