From 1370e6870d48d343595d95d033b62b3d79393a08 Mon Sep 17 00:00:00 2001 From: Andreas Guldstrand Date: Wed, 2 Nov 2016 11:45:50 +0100 Subject: [PATCH] Time::P, Time::C, change how strptime works; have it return a struct instead --- lib/Time/C.pm | 234 +++++++++++++++++++++++++++++++++++++++------ lib/Time/P.pm | 53 ++++++---- t/01-synopsis.t | 2 +- t/07-week.t | 4 +- t/08-definedness.t | 93 ++++++++++++++++++ 5 files changed, 333 insertions(+), 53 deletions(-) create mode 100644 t/08-definedness.t diff --git a/lib/Time/C.pm b/lib/Time/C.pm index 2a2f6c1..c21e032 100644 --- a/lib/Time/C.pm +++ b/lib/Time/C.pm @@ -96,10 +96,32 @@ This is the timezone specification such as C or C. If not =cut -method new ($c: $year = undef, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = 'UTC') { - return $c->now_utc() if not defined $year; +method new ($c: $year =, $month =, $day =, $hour =, $minute =, $second =, $tz =) { + my $t; + my %defineds = ( + epoch_d => (defined($year) and defined($month) and defined($day) and defined($hour) and defined($minute) and defined($second)), + year => defined($year), + month => defined($month), + mday => defined($day), + week => 0, + wday => 0, + yday => 0, + hour => defined($hour), + minute => defined($minute), + second => defined($second), + tz_d => defined($tz), + offset => 0, + ); + + if (not defined $year) { + $t = $c->now_utc(); + %$t = ( %$t, %defineds ); + return $t; + } - my $tm = Time::Moment->new(year => $year, month => $month, day => $day, hour => $hour, minute => $minute, second => $second, offset => 0); + my $tm = Time::Moment->new(year => $year, month => $month // 1, day => $day // 1, hour => $hour // 0, minute => $minute // 0, second => $second // 0, offset => 0); + + if (not defined $tz) { $tz = 'UTC'; } if ($tz ne 'UTC' and $tz ne 'GMT') { my $offset = _get_offset($tm->epoch, $tz); @@ -108,7 +130,9 @@ method new ($c: $year = undef, $month = 1, $day = 1, $hour = 0, $minute = 0, $se $tm = $tm->with_offset_same_local($offset); } - $c->localtime($tm->epoch, $tz); + $t = $c->localtime($tm->epoch, $tz); + %$t = (%$t, %defineds); + return $t; } =head2 mktime @@ -193,6 +217,20 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont # Then go on to creating it from the date bits, and the time bits my $t; + my %defineds = ( + epoch_d => defined($epoch), + year => defined($year), + month => defined($month), + mday => defined($mday), + week => defined($week), + wday => defined($wday), + yday => defined($yday), + hour => defined($hour), + minute => defined($minute), + second => defined($second), + tz_d => defined($tz), + offset => defined($offset), + ); if (defined $epoch) { $t = Time::C->gmtime($epoch); @@ -203,6 +241,8 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont $t->offset = $offset; } + $t->{tz_d} = $defineds{tz_d}; + return $t; } elsif (defined $year) { # We have a year at least... if (defined $month) { @@ -213,10 +253,11 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont } } elsif (defined $week) { $t = Time::C->new($year); - $t->day++ while ($t->week > 1); + $t->day_of_week++ while ($t->week > 1); $t = $t->week($week)->day_of_week(1); if (defined $wday) { $t->day_of_week = $wday; } + else { $t->{wday} = 0; } } elsif (defined $yday) { $t = Time::C->new($year)->day($yday); } else { # we have neither month, week, or day of year! @@ -243,9 +284,11 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont if (defined $second) { $t->second = $second; } } elsif (defined $week) { $t = Time::C->new($year); - $t->day++ while ($t->week > 1); + $t->day_of_week++ while ($t->week > 1); $t = $t->week($week)->day_of_week(1); + if (defined $wday) { $t->day_of_week = $wday; } + else { $t->{wday} = 0; } # Now add the time bits on top... if (defined $hour) { $t->hour = $hour; } @@ -273,6 +316,7 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont if (defined $minute) { $t->minute = $minute; } elsif (not defined $hour) { $t->second_of_day = Time::C->now($tz)->tz('UTC', 1)->second(0)->second_of_day; } if (defined $second) { $t->second = $second; } } + $t->{year} = 0; } # And last, adjust for timezone bits @@ -280,7 +324,7 @@ method mktime ($c: :$epoch =, :$second =, :$minute =, :$hour =, :$mday =, :$mont if (defined $tz) { $t = $t->tz($tz, 1); } elsif (defined $offset) { - $t->tm = $t->tm->with_offset_same_local($offset); + $t->_tm = $t->tm->with_offset_same_local($offset); $t->offset = $offset; } @@ -309,9 +353,23 @@ This is the timezone specification, such as C or C. If no =cut method localtime ($c: $epoch, $tz = $ENV{TZ}) { + my %defineds = ( + epoch_d => 1, + year => 1, + month => 1, + mday => 1, + week => 1, + wday => 1, + yday => 1, + hour => 1, + minute => 1, + second => 1, + tz_d => defined($tz), + offset => 0, + ); $tz = 'UTC' unless defined $tz; _verify_tz($tz); - bless {epoch => $epoch, tz => $tz}, $c; + bless {epoch => $epoch, tz => $tz, %defineds}, $c; } =head2 gmtime @@ -398,9 +456,9 @@ If there is no valid timezone specified in the format, but C<$tz> is given and m =cut method from_string ($c: $str, :$format = undef, :$locale = 'C', :$strict = 1, :$tz = 'UTC') { - my @p = _parse($str, $format, $tz, locale => $locale, strict => $strict); + my %p = _parse($str, $format, $tz, locale => $locale, strict => $strict); - bless {epoch => $p[0], tz => $p[1]}, $c; + return $c->mktime(%p); } =head2 strptime @@ -409,8 +467,14 @@ method from_string ($c: $str, :$format = undef, :$locale = 'C', :$strict = 1, :$ my $t = Time::C->strptime($str, $format, locale => $locale); my $t = Time::C->strptime($str, $format, locale => $locale, strict => $strict); + $t = $t->strptime($str, $format); + $t = $t->strptime($str, $format, locale => $locale); + $t = $t->strptime($str, $format, locale => $locale, strict => $strict); + Creates a Time::C object for the specified C<$str> using the C<$format> to parse it with L. +This doesn't need to be used solely as a constructor; if it's called on an already existing C object, the values parsed from the C<$str> will be updated in the object, following the same rules as C<< Time::C->mktime >> for precedence (i.e. if an epoch is supplied, none of the other values matter, and if a month is supplied, the weeks and weekdays won't be considered, and so on). + =over =item C<$str> @@ -434,7 +498,55 @@ Gives the C<$strict> parameter to L. Defaults to C<1>. =cut method strptime ($c: $str, $format, :$locale = 'C', :$strict = 1) { - return Time::P::strptime(@_); + my %struct; + if (ref $c) { + my $t = $c; + if ($t->{epoch_d}) { $struct{epoch} = $t->{epoch}; } + if ($t->{year}) { $struct{year} = $t->year; } + if ($t->{month}) { $struct{month} = $t->month; } + if ($t->{mday}) { $struct{mday} = $t->day; } + if ($t->{week}) { $struct{week} = $t->week; } + if ($t->{wday}) { $struct{wday} = $t->day_of_week; } + if ($t->{yday}) { $struct{yday} = $t->day_of_year; } + if ($t->{hour}) { $struct{hour} = $t->hour; } + if ($t->{minute}) { $struct{minute} = $t->minute; } + if ($t->{second}) { $struct{second} = $t->second; } + if ($t->{tz_d}) { $struct{tz} = $t->{tz}; } + if ($t->{offset}) { $struct{offset} = $t->offset; } + } + %struct = Time::P::strptime($str, $format, locale => $locale, strict => $strict, struct => \%struct); + + if (ref $c) { + my $t = $c; + + if (defined $struct{tz}) { + $t->tz = $struct{tz}; + } elsif (defined $struct{offset}) { + $t->offset = $struct{offset}; + } + + if (defined $struct{epoch}) { return $t->epoch($struct{epoch}); } + + if (defined $struct{year}) { $t->year = $struct{year}; } + + if (defined $struct{month}) { + $t->month = $struct{month}; + if (defined $struct{mday}) { $t->day = $struct{mday}; } + } elsif (defined $struct{week}) { + $t->week = $struct{week}; + if (defined $struct{wday}) { $t->day_of_week = $struct{wday}; } + } elsif (defined $struct{yday}) { + $t->day_of_year = $struct{yday}; + } + + if (defined $struct{hour}) { $t->hour = $struct{hour}; } + if (defined $struct{minute}) { $t->minute = $struct{minute}; } + if (defined $struct{second}) { $t->second = $struct{second}; } + + return $t; + } else { + return $c->mktime(%struct); + } } fun _verify_tz ($tz) { @@ -486,8 +598,9 @@ fun _get_tz ($offset) { fun _parse ($str, $format = undef, $tz = 'UTC', :$locale = 'C', :$strict = 1) { if (defined $format) { - my $t = eval { Time::P::strptime($str, $format, locale => $locale, strict => $strict) }; - return ($t->epoch, $t->tz) if defined $t; + my %struct = (); + my $e = eval { %struct = Time::P::strptime($str, $format, locale => $locale, strict => $strict); 1; }; + return %struct if $e; croak sprintf "Could not parse %s using %s: %s", $str, $format, $@; } @@ -498,10 +611,12 @@ fun _parse ($str, $format = undef, $tz = 'UTC', :$locale = 'C', :$strict = 1) { my $epoch = $tm->epoch; my $offset = $tm->offset; - $tz = _get_tz($offset) unless $offset == - Time::Zone::Olson->new({timezone => $tz})->local_offset($epoch); + my @ret = (epoch => $epoch, offset => $offset); + if ($offset == Time::Zone::Olson->new({timezone => $tz})->local_offset($epoch)) { + push @ret, tz => $tz; + } - return $epoch, $tz; + return @ret; } =head1 ACCESSORS @@ -533,6 +648,9 @@ method epoch ($t: $new_epoch = undef) :lvalue { my $setter = sub { $t->{epoch} = $_[0]; + + %$t = (%$t, epoch_d => 1, year => 1, yday => 1, month => 1, mday => 1, week => 1, wday => 1, hour => 1, minute => 1, second => 1, ); + return $t if defined $new_epoch; return $_[0]; }; @@ -564,10 +682,12 @@ method tz ($t: $new_tz = undef, $override = 0) :lvalue { if ($override) { my $l = Time::C->new($t->year, $t->month, $t->day, $t->hour, $t->minute, $t->second, $_[0]); - $t->epoch = $l->epoch; + $t->{epoch} = $l->epoch; } $t->{tz} = $_[0]; + $t->{tz_d} = 1; + return $t if defined $new_tz; return $t->{tz}; }; @@ -612,6 +732,7 @@ If the form C<< $t->offset($new_offset) >> is used, it likewise sets the timezon method offset ($t: $new_offset = undef) :lvalue { my $setter = sub { $t->{tz} = _get_tz($_[0]); + $t->{offset} = 1; return $t if defined $new_offset; return $_[0]; @@ -638,6 +759,20 @@ If the form C<< $t->tm($new_tm) >> is used, it likewise changes the current epoc =cut method tm ($t: $new_tm = undef) :lvalue { + my $setter = sub { + $t->_tm = $_[0]; + $t->epoch = $t->epoch; # update definedness values + + return $t if defined $new_tm; + return $_[0]; + }; + + return $setter->($new_tm) if defined $new_tm; + + sentinel value => $t->_tm(), set => $setter; +} + +method _tm ($t: $new_tm = undef) :lvalue { $t->{tz} = 'UTC' if not defined $t->{tz}; my $setter = sub { @@ -706,7 +841,31 @@ method string ($t: $new_str = undef, :$format = undef, :$locale = 'C', :$strict $t->{tz} = 'UTC' if not defined $t->{tz}; my $setter = sub { - @{$t}{epoch,tz} = _parse($_[0], $format, $t->{tz}, locale => $locale, strict => $strict); + my %struct = _parse($_[0], $format, $t->{tz}, locale => $locale, strict => $strict); + + if (defined $struct{tz}) { + $t->tz = $struct{tz}; + } elsif (defined $struct{offset}) { + $t->offset = $struct{offset}; + } + + if (defined $struct{epoch}) { return $t->epoch($struct{epoch}); } + + if (defined $struct{year}) { $t->year = $struct{year}; } + + if (defined $struct{month}) { + $t->month = $struct{month}; + if (defined $struct{mday}) { $t->day = $struct{mday}; } + } elsif (defined $struct{week}) { + $t->week = $struct{week}; + if (defined $struct{wday}) { $t->day_of_week = $struct{wday}; } + } elsif (defined $struct{yday}) { + $t->day_of_year = $struct{yday}; + } + + if (defined $struct{hour}) { $t->hour = $struct{hour}; } + if (defined $struct{minute}) { $t->minute = $struct{minute}; } + if (defined $struct{second}) { $t->second = $struct{second}; } return $t if defined $new_str; return $_[0]; @@ -754,7 +913,8 @@ method year ($t: $new_year = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->with_year($_[0]))->year; + my $ret = ($t->_tm = $tm->with_year($_[0]))->year; + $t->{year} = 1; return $t if defined $new_year; return $ret; @@ -787,7 +947,8 @@ method quarter ($t: $new_quarter = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_months(3*$_[0] - $tm->month))->quarter; + my $ret = ($t->_tm = $tm->plus_months(3*$_[0] - $tm->month))->quarter; + $t->{month} = 1; return $t if defined $new_quarter; return $ret; @@ -820,7 +981,8 @@ method month ($t: $new_month = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_months($_[0] - $tm->month))->month; + my $ret = ($t->_tm = $tm->plus_months($_[0] - $tm->month))->month; + $t->{month} = 1; return $t if defined $new_month; return $ret; @@ -853,7 +1015,8 @@ method week ($t: $new_week = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_weeks($_[0] - $tm->week))->week; + my $ret = ($t->_tm = $tm->plus_weeks($_[0] - $tm->week))->week; + $t->{week} = 1; return $t if defined $new_week; return $ret; @@ -894,7 +1057,8 @@ method day_of_month ($t: $new_day = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_days($_[0] - $tm->day_of_month))->day_of_month; + my $ret = ($t->_tm = $tm->plus_days($_[0] - $tm->day_of_month))->day_of_month; + $t->{mday} = 1; return $t if defined $new_day; return $ret; @@ -927,7 +1091,8 @@ method day_of_year ($t: $new_day = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_days($_[0] - $tm->day_of_year))->day_of_year; + my $ret = ($t->_tm = $tm->plus_days($_[0] - $tm->day_of_year))->day_of_year; + $t->{yday} = 1; return $t if defined $new_day; return $ret; @@ -960,7 +1125,8 @@ method day_of_quarter ($t: $new_day = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_days($_[0] - $tm->day_of_quarter))->day_of_quarter; + my $ret = ($t->_tm = $tm->plus_days($_[0] - $tm->day_of_quarter))->day_of_quarter; + $t->{mday} = 1; return $t if defined $new_day; return $ret; @@ -993,7 +1159,8 @@ method day_of_week ($t: $new_day = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_days($_[0] - $tm->day_of_week))->day_of_week; + my $ret = ($t->_tm = $tm->plus_days($_[0] - $tm->day_of_week))->day_of_week; + $t->{wday} = 1; return $t if defined $new_day; return $ret; @@ -1026,7 +1193,8 @@ method hour ($t: $new_hour = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_hours($_[0] - $tm->hour))->hour; + my $ret = ($t->_tm = $tm->plus_hours($_[0] - $tm->hour))->hour; + $t->{hour} = 1; return $t if defined $new_hour; return $ret; @@ -1059,7 +1227,8 @@ method minute ($t: $new_minute = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_minutes($_[0] - $tm->minute))->minute; + my $ret = ($t->_tm = $tm->plus_minutes($_[0] - $tm->minute))->minute; + $t->{minute} = 1; return $t if defined $new_minute; return $ret; @@ -1092,7 +1261,8 @@ method second ($t: $new_second = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_seconds($_[0] - $tm->second))->second; + my $ret = ($t->_tm = $tm->plus_seconds($_[0] - $tm->second))->second; + $t->{second} = 1; return $t if defined $new_second; return $ret; @@ -1125,7 +1295,8 @@ method second_of_day ($t: $new_second = undef) :lvalue { my $tm = $t->tm(); my $setter = sub { - my $ret = ($t->tm = $tm->plus_seconds($_[0] - $tm->second_of_day))->second_of_day; + my $ret = ($t->_tm = $tm->plus_seconds($_[0] - $tm->second_of_day))->second_of_day; + $t->{second} = $t->{minute} = $t->{hour} = 1; return $t if defined $new_second; return $ret; @@ -1170,7 +1341,8 @@ Returns a copy of C<$t1>. method clone($t:) { my $c = ref $t; - return $c->localtime($t->epoch, $t->tz); + my $t2 = { %$t }; + bless $t2, $c; } 1; diff --git a/lib/Time/P.pm b/lib/Time/P.pm index a446a06..de6d9ee 100644 --- a/lib/Time/P.pm +++ b/lib/Time/P.pm @@ -18,9 +18,10 @@ our @EXPORT = qw/ strptime /; =head1 SYNOPSIS use Time::P; # strptime() automatically exported. + use Time::C; # "2016-10-30T16:07:34Z" - my $t = strptime "sön okt 30 16:07:34 UTC 2016", "%a %b %d %T %Z %Y", locale => "sv_SE"; + my $t = Time::C->mktime(strptime("sön okt 30 16:07:34 UTC 2016", "%a %b %d %T %Z %Y", locale => "sv_SE")); =head1 DESCRIPTION @@ -125,10 +126,10 @@ my %parser; %parser = ( =head2 strptime - my $t = strptime($str, $fmt); - my $t = strptime($str, $fmt, locale => $locale, strict => $strict); + my %struct = strptime($str, $fmt); + my %struct = strptime($str, $fmt, locale => $locale, strict => $strict, struct => \%struct); -C takes a string and a format, and tries to parse the string using the format to create a L object representing the time. +C takes a string and a format which it parses the string with, and returns key-value pairs of the parsed bits of time. =over @@ -138,7 +139,7 @@ C<$str> is the string to parse. =item C<$fmt> -C<$fmt> is the format specifier used to parse the C<$str>. If it can't match C<$str> to get a useful date/time it will throw an exception. See L for details on the supported format specifiers. +C<$fmt> is the format specifier used to parse the C<$str>. If it can't match C<$str> it will throw an exception. See L for details on the supported format specifiers. =item C<< locale => $locale >> @@ -148,22 +149,26 @@ C<$locale> is an optional parameter which defaults to C. It is used to determ C<$strict> is an optional boolean flag which defaults to true. If it is a true value, the C<$fmt> must describe the string entirely. If it is false, the C<$fmt> may describe only part of the string, and any extra bits, either before or after, are discarded. +=item C<< struct => \%struct >> + +If passed a reference to a hash C<%struct>, that hash will be updated with the bits that were parsed from the string. The hash will also be equal to the key-value pairs being returned. If it is not supplied, a reference to an empty hash will be used in its stead. + =back -If the format reads in a timezone that isn't well-defined, it will be silently ignored, and any offset that is parsed will be used instead. It uses L to create the C object from the parsed data. +If the format reads in a timezone that isn't well-defined, it will be silently ignored, and any offset that is parsed will be used instead. -=cut +See L for making a C object out of the returned structure. Or see L for a constructor that will do it for you. -fun strptime ($str, $fmt, :$locale = 'C', :$strict = 1) { - require Time::C; +=cut - my %struct = (); +fun strptime ($str, $fmt, :$locale = 'C', :$strict = 1, :$struct = {}) { + my %parse = (); my @res = _compile_fmt($fmt, locale => $locale); @res = (qr/^/, @res, qr/$/) if $strict; while (@res and $str =~ m/\G$res[0]/gc) { - %struct = (%struct, %+); + %parse = (%parse, %+); shift @res; } @@ -171,10 +176,9 @@ fun strptime ($str, $fmt, :$locale = 'C', :$strict = 1) { croak sprintf "Could not match '%s' using '%s'. Match failed at position %d.", $str, $fmt, pos($str); } - %struct = _coerce_struct(\%struct, locale => $locale); - my $time = Time::C->mktime(%struct); + $struct = { %$struct, _coerce_struct(\%parse, $struct, locale => $locale) }; - return $time; + return %$struct; } fun _compile_fmt ($fmt, :$locale) { @@ -196,7 +200,7 @@ fun _compile_fmt ($fmt, :$locale) { return @res; } -fun _coerce_struct ($struct, :$locale) { +fun _coerce_struct ($struct, $orig, :$locale) { # First, if we know the epoch, great my $epoch = $struct->{'s'}; @@ -220,9 +224,11 @@ fun _coerce_struct ($struct, :$locale) { } } elsif (defined $struct->{'y'}) { $year = $struct->{'y'} + 1900; + require Time::C; if ($year < (Time::C->now_utc()->year - 50)) { $year += 100; } } elsif (defined $struct->{'g'}) { $year = $struct->{'g'} + 1900; + require Time::C; if ($year < (Time::C->now_utc()->year - 50)) { $year += 100; } $wyear = 1; } @@ -266,17 +272,25 @@ fun _coerce_struct ($struct, :$locale) { if (not defined $v_week and defined $w_week) { if ($wyear) { croak "Can't strptime a %G/%g year with a %W/%U week"; } - my $t = Time::C->new($year // Time::C->now_utc->year); + require Time::C; + my $t = Time::C->new($year // $orig->{year} // Time::C->now_utc->year); $v_week = $w_week; if (($t->day_of_week > 1) and ($t->day_of_week < 5)) { $v_week++; } } if ($wyear and defined $v_week and $v_week > 1) { + require Time::C; $year = Time::C->mktime(year => $year, week => $v_week)->year; - } elsif (defined $v_week and $v_week > 1) { + } elsif (defined $v_week and $v_week > 1 and defined $year) { + require Time::C; if (Time::C->mktime(year => $year, week => $v_week)->year == $year + 1) { $year-- if not defined $month; } + } elsif (defined $v_week and $v_week > 1 and defined $orig->{year}) { + require Time::C; + if (Time::C->mktime(year => $orig->{year}, week => $v_week)->year == $orig->{year} + 1) { + $year = $orig->{year} - 1 if not defined $month; + } } # Next try to set up time bits -- these are pretty easy in comparison @@ -285,7 +299,7 @@ fun _coerce_struct ($struct, :$locale) { if (not defined $hour) { $hour = $struct->{'k'}; } if (not defined $hour) { $hour = $struct->{'I'} // $struct->{'l'}; - if (defined $hour and defined $struct->{'p'}) { + if (defined $hour and length $struct->{'p'}) { if (_get_index($struct->{'p'}, @{ get_locale(am_pm => $locale) })) { # PM if ($hour < 12) { $hour += 12; } @@ -304,6 +318,7 @@ fun _coerce_struct ($struct, :$locale) { my $tz = $struct->{'Z'}; # should verify that it's a useful tz if (defined $tz) { + require Time::C; undef $tz if not defined eval { Time::C->now($tz); }; } @@ -565,7 +580,7 @@ A literal C<%> sign. =item L -The companion to this module, which represents the actual time we parsed. +The companion to this module, which can create an actual time representation from the structure we parsed. =item L diff --git a/t/01-synopsis.t b/t/01-synopsis.t index 5230218..d1798aa 100644 --- a/t/01-synopsis.t +++ b/t/01-synopsis.t @@ -73,7 +73,7 @@ my $str = strftime(Time::C->from_string("2016-10-31T14:21:57Z"), "%c", locale => is ($str, "mån 31 okt 2016 14:21:57", "strftime works correctly"); # and Time::P synopsis -my $p = strptime "sön okt 30 16:07:34 UTC 2016", "%a %b %d %T %Z %Y", locale => "sv_SE"; +my $p = Time::C->mktime(strptime("sön okt 30 16:07:34 UTC 2016", "%a %b %d %T %Z %Y", locale => "sv_SE")); isa_ok($p, "Time::C"); is ($p, "2016-10-30T16:07:34Z", "strptime works correctly"); diff --git a/t/07-week.t b/t/07-week.t index 70e9c59..035c773 100644 --- a/t/07-week.t +++ b/t/07-week.t @@ -40,7 +40,7 @@ foreach my $t (@ts) { $fmt = "%G: %V-%w"; foreach my $t (@ts) { my $str = strftime $t, $fmt; - my $t2 = strptime $str, $fmt; + my $t2 = Time::C->strptime($str, $fmt); is ($t2, $t, "Week for $t parsed correctly.") or diag "$t => ($fmt) => $str => $t2"; } @@ -48,7 +48,7 @@ foreach my $t (@ts) { $fmt = "%Y: %W-%w"; foreach my $t (@ts) { my $str = strftime $t, $fmt; - my $t2 = strptime $str, $fmt; + my $t2 = Time::C->strptime($str, $fmt); is ($t2, $t, "Week for $t parsed correctly.") or diag "$t => ($fmt) => $str => $t2"; } diff --git a/t/08-definedness.t b/t/08-definedness.t new file mode 100644 index 0000000..b05bbfa --- /dev/null +++ b/t/08-definedness.t @@ -0,0 +1,93 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use utf8; + +use Test::More; + +plan tests => 228; + +use Time::C; + +sub in { + my ($needle, @haystack) = @_; + foreach my $straw (@haystack) { return 1 if $straw eq $needle; } + return 0; +} + +sub check_d { + my $obj = shift; + my $name = shift; + my @true = @_; + my @keys = qw/ epoch_d year month mday week wday yday hour minute second offset tz_d /; + + for my $key (@keys) { + if (in($key, @true)) { + is ($obj->{$key}, 1, "$key true - $name"); + } else { + is ($obj->{$key} + 0, 0, "$key false - $name"); + } + } +} + +my $t = Time::C->new(); +check_d $t, "new"; + +$t->second = 0; +check_d $t, "second set", qw/ second /; + +$t->minute = 0; +check_d $t, "minute set", qw/ second minute /; + +$t->hour = 0; +check_d $t, "hour set", qw/ second minute hour /; + +$t->year = 2016; +check_d $t, "year set", qw/ second minute hour year /; + +$t->month = 1; +check_d $t, "month set", qw/ second minute hour year month /; + +$t->day = 1; +check_d $t, "day set", qw/ second minute hour year month mday /; + +$t->week = 2; +check_d $t, "week set", qw/ second minute hour year month mday week /; + +$t->day_of_week = 1; +check_d $t, "wday set", qw/ second minute hour year month mday week wday /; + +$t->day_of_year = 30; +check_d $t, "yday set", qw/ second minute hour year month mday week wday yday /; + +$t->offset = 0; +check_d $t, "offset set", qw/ second minute hour year month mday week wday yday offset /; + +$t->tz = 'UTC'; +check_d $t, "tz set", qw/ second minute hour year month mday week wday yday offset tz_d /; + +$t->epoch++; +check_d $t, "epoch set", qw/ second minute hour year month mday week wday yday offset tz_d epoch_d /; + +my $t2 = Time::C->new(); + +$t2->second_of_day = 0; +check_d $t2, "second_of_day set", qw/ second minute hour /; + +$t2->day_of_year = 1; +check_d $t2, "day_of_year set", qw/ second minute hour yday /; + +my $t3 = Time::C->strptime("mån 31 okt 2016", "%a %d %b %Y", locale => "sv_SE"); +check_d $t3, "strptime month/mday/year set", qw/ month mday year /; + +$t3->tm = $t3->tm; +check_d $t3, "tm set", qw/ epoch_d month mday year week wday yday second minute hour /; + +my $t4 = Time::C->strptime("mån vecka 3 2016", "%a vecka %-V %G", locale => "sv_SE"); +check_d $t4, "strptime week/wday/year set", qw/ week wday year /; + +$t4->strptime("16:04:48", "%T"); +check_d $t4, "strptime time set", qw/ week wday year hour minute second /; + +#done_testing;