Skip Menu |

This queue is for tickets about the Date-PeriodParser CPAN distribution.

Report information
The Basics
Id: 25001
Status: resolved
Worked: 10 min
Priority: 0/
Queue: Date-PeriodParser

People
Owner: mcmahon [...] cpan.org
Requestors: michael [...] ndrix.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Support "this week", "last week", "this month" and "last month"
The attached patch adds support for the following phrases: "this week", "last week", "this month" and "last month". The patch also adds tests for those phrases.
Subject: this-week.txt
=== t/this-week.t ================================================================== --- t/this-week.t (revision 1920) +++ t/this-week.t (patch - level 1) @@ -0,0 +1,49 @@ +use strict; +use warnings; +use Test::More; +use Time::Local; +use Date::PeriodParser; +use POSIX qw( strftime ); +require 't/helpers.pl'; + +# Tests for "this week" and "last week" + +my %phrases = ( + 'this week' => [ + [ + '2006-12-28T21:33:40', # base + '2006-12-25T00:00:00', # expected from + '2006-12-31T23:59:59', # expected to + ], + [ + '2007-01-19T10:07:22', # base + '2007-01-15T00:00:00', # expected from + '2007-01-21T23:59:59', # expected to + ], + ], + 'last week' => [ + [ + '2006-12-28T21:33:40', # base + '2006-12-18T00:00:00', # expected from + '2006-12-24T23:59:59', # expected to + ], + [ + '2007-01-19T10:07:22', # base + '2007-01-08T00:00:00', # expected from + '2007-01-14T23:59:59', # expected to + ], + ], +); + +plan tests => 2 * 4; + +while ( my ($phrase, $tests) = each %phrases ) { + for my $test (@$tests) { + my ($base, $right_from, $right_to) = @$test; + set_time($base); + + my ( $from, $to ) = parse_period($phrase); + is( iso($from), $right_from, "$phrase 'from' ok" ); + is( iso($to), $right_to, "$phrase 'to' ok" ); + } +} === t/helpers.pl ================================================================== --- t/helpers.pl (revision 1920) +++ t/helpers.pl (patch - level 1) @@ -0,0 +1,20 @@ +use strict; +use warnings; + +1; + +sub set_time { + my ($timestamp) = @_; + + my ($year, $mon, $day, $hour, $min, $sec) = split /[-T:]/, $timestamp; + $year -= 1900; + $mon--; + + $Date::PeriodParser::TestTime = + timelocal( $sec, $min, $hour, $day, $mon, $year ); +} + +sub iso { + my ($time) = @_; + return strftime( "%Y-%m-%dT%H:%M:%S", localtime($time) ); +} === t/this-month.t ================================================================== --- t/this-month.t (revision 1920) +++ t/this-month.t (patch - level 1) @@ -0,0 +1,49 @@ +use strict; +use warnings; +use Test::More; +use Time::Local; +use Date::PeriodParser; +use POSIX qw( strftime ); +require 't/helpers.pl'; + +# Tests for "this month" and "last month" + +my %phrases = ( + 'this month' => [ + [ + '2006-12-28T21:33:40', # base + '2006-12-01T00:00:00', # expected from + '2006-12-31T23:59:59', # expected to + ], + [ + '2007-01-19T10:07:22', # base + '2007-01-01T00:00:00', # expected from + '2007-01-31T23:59:59', # expected to + ], + ], + 'last month' => [ + [ + '2006-12-28T21:33:40', # base + '2006-11-01T00:00:00', # expected from + '2006-11-30T23:59:59', # expected to + ], + [ + '2007-01-19T10:07:22', # base + '2006-12-01T00:00:00', # expected from + '2006-12-31T23:59:59', # expected to + ], + ], +); + +plan tests => 4 * 2; + +while ( my ($phrase, $tests) = each %phrases ) { + for my $test (@$tests) { + my ($base, $right_from, $right_to) = @$test; + set_time($base); + + my ( $from, $to ) = parse_period($phrase); + is( iso($from), $right_from, "$phrase 'from' ok" ); + is( iso($to), $right_to, "$phrase 'to' ok" ); + } +} === MANIFEST ================================================================== --- MANIFEST (revision 1920) +++ MANIFEST (patch - level 1) @@ -12,6 +12,9 @@ t/07junk.t t/08now.t t/09vague.t +t/helpers.pl t/pod.t t/pod-coverage.t +t/this-week.t +t/this-month.t META.yml Module meta-data (added by MakeMaker) === PeriodParser.pm ================================================================== --- PeriodParser.pm (revision 1920) +++ PeriodParser.pm (patch - level 1) @@ -5,7 +5,12 @@ use strict; use warnings; use Time::Local; -use Date::Calc; +use Date::Calc qw( + Add_Delta_Days + Date_to_Time + Day_of_Week + Days_in_Month +); use constant GIBBERISH => -1; use constant AMBIGUOUS => -2; @@ -60,6 +65,41 @@ return ($from, $to); } + # "this week", "last week" + if ( m/(this|last) week/ ) { + my $modifier = $1; + my @today = _today(); + if ( $modifier eq 'last' ) { + @today = Add_Delta_Days( @today, -7 ); + } + my $today = Day_of_Week(@today); + my $monday = 1; + my $sunday = 7; + + # Monday at midnight and sunday just before midnight + my @monday = ( Add_Delta_Days(@today, $monday - $today), 0, 0, 0 ); + my @sunday = ( Add_Delta_Days(@today, $sunday - $today), 23, 59, 59 ); + + return ( _timelocal(@monday), _timelocal(@sunday) ); + } + + # "this month", "last month" + if (m/(this|last) month/) { + my $modifier = $1; + my ( $year, $month, undef ) = _today(); + + # find a day in the previous month + if ( $modifier eq 'last' ) { + ( $year, $month ) = Add_Delta_Days( $year, $month, 1, -1 ); + } + + my @first = ( $year, $month, 1, 0, 0, 0 ); # first day at midnight + my $last_day_of_month = Days_in_Month( $year, $month ); + my @last = ( $year, $month, $last_day_of_month , 23, 59, 59 ); + + return ( _timelocal(@first), _timelocal(@last) ); + } + # Recent times if (/(the day (before|after) )?(yesterday|today|tomorrow)/ || /^this (morning|afternoon|evening|lunchtime)/ || @@ -202,6 +242,29 @@ $from -= $leeway; $to += $leeway; return ($from, $to); } + +# similar to Time::Local::timelocal but accepts the offsets returned by +# Date::Calc::Today_and_Now() +sub _timelocal { + my ( $year, $mon, $day, $hour, $min, $sec ) = @_; + + # make offsets as expected by timelocal + $year -= 1900; + $mon--; + + return timelocal( $sec, $min, $hour, $day, $mon, $year ); +} + +# same as Date::Calc::Today but respect $TestTime so that +# we can test periods based on today's date +sub _today { + my $now = $TestTime || time; + my ( $day, $month, $year ) = ( localtime $now )[ 3 .. 5 ]; + $year += 1900; + $month++; + return ($year, $month, $day); +} + 1; __END__ @@ -260,6 +323,12 @@ disambiguate relative to the current time. For instance, if it's afternoon and "in the morning" is specified, this implies "tomorrow morning". +=item * this week, last week, this month, last month + +"This" means the week or month which includes the current day. Weeks begin on +Monday and end of Sunday. "Last" means the week or month preceeding "this +week/month". + =item * "ago" and "from now" Offsets in days and "a week" are accepted; you cannot cross a month
Thanks, applied. Will be in 0.05.