mirror of
https://github.com/Perl/perl5.git
synced 2026-01-26 16:39:36 +00:00
cpan/Time-Piece - Update to version 1.39
1.39 2025-10-24
- strptime: allow year < 1900 (GH56)
- add add_days() (GH65)
- strptime(): More %z formats (GH74)
- Test failures in 11strptime_defaults.t (GH81)
- XS cleanup (GH80)
- Remove parse()
This commit is contained in:
parent
baca3aa06d
commit
4222a60022
1
MANIFEST
1
MANIFEST
@ -3183,7 +3183,6 @@ cpan/Time-Piece/t/10overload.t Test file related to Time::Piece
|
||||
cpan/Time-Piece/t/11strptime_defaults.t Time-Piece
|
||||
cpan/Time-Piece/t/12strptime_timezones.t Time-Piece
|
||||
cpan/Time-Piece/t/13date_arithmetic_edge_cases.t Time-Piece
|
||||
cpan/Time-Piece/t/99legacy.t Test file related to Time::Piece
|
||||
cpan/Time-Piece/t/lib/Time/Piece/Twin.pm Module related to Time::Piece
|
||||
cpan/Unicode-Collate/Collate.pm Unicode::Collate
|
||||
cpan/Unicode-Collate/Collate.xs Unicode::Collate
|
||||
|
||||
@ -1256,8 +1256,8 @@ our %Modules = (
|
||||
},
|
||||
|
||||
'Time::Piece' => {
|
||||
'DISTRIBUTION' => 'ESAYM/Time-Piece-1.38.tar.gz',
|
||||
'SYNCINFO' => 'jkeenan on Mon Oct 20 21:40:37 2025',
|
||||
'DISTRIBUTION' => 'ESAYM/Time-Piece-1.39.tar.gz',
|
||||
'SYNCINFO' => 'jkeenan on Sat Oct 25 12:20:55 2025',
|
||||
'FILES' => q[cpan/Time-Piece],
|
||||
'EXCLUDED' => [ qw[reverse_deps.txt] ],
|
||||
},
|
||||
|
||||
@ -19,7 +19,7 @@ our %EXPORT_TAGS = (
|
||||
':override' => 'internal',
|
||||
);
|
||||
|
||||
our $VERSION = '1.38';
|
||||
our $VERSION = '1.39';
|
||||
|
||||
XSLoader::load( 'Time::Piece', $VERSION );
|
||||
|
||||
@ -102,24 +102,6 @@ sub new {
|
||||
return bless $self, ref($class) || $class;
|
||||
}
|
||||
|
||||
sub parse {
|
||||
my $proto = shift;
|
||||
my $class = ref($proto) || $proto;
|
||||
my @components;
|
||||
|
||||
warnings::warnif("deprecated",
|
||||
"parse() is deprecated, use strptime() instead.");
|
||||
|
||||
if (@_ > 1) {
|
||||
@components = @_;
|
||||
}
|
||||
else {
|
||||
@components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/;
|
||||
@components = reverse(@components[0..5]);
|
||||
}
|
||||
return $class->new( timelocal(@components ));
|
||||
}
|
||||
|
||||
sub _mktime {
|
||||
my ($class, $time, $islocal) = @_;
|
||||
|
||||
@ -791,6 +773,14 @@ sub compare {
|
||||
return $lhs <=> $rhs;
|
||||
}
|
||||
|
||||
sub add_days {
|
||||
my ( $time, $num_days ) = @_;
|
||||
|
||||
croak("add_days requires a number of days") unless defined($num_days);
|
||||
|
||||
return add( $time, $num_days * ONE_DAY );
|
||||
}
|
||||
|
||||
sub add_months {
|
||||
my ($time, $num_months) = @_;
|
||||
|
||||
@ -1089,6 +1079,9 @@ the actual offset including any DST adjustment.
|
||||
|
||||
$t->is_leap_year # true if it's a leap year
|
||||
$t->month_last_day # 28-31
|
||||
$t->add_days # Add days
|
||||
$t->add_months # Add months
|
||||
$t->add_years # Add years
|
||||
|
||||
=head2 Global Configuration
|
||||
|
||||
@ -1122,6 +1115,7 @@ The following are valid ($t1 and $t2 are Time::Piece objects):
|
||||
$t1 - $t2; # returns Time::Seconds object
|
||||
$t1 - 42; # returns Time::Piece object
|
||||
$t1 + 533; # returns Time::Piece object
|
||||
$t1->add_days(2); # returns Time::Piece object
|
||||
|
||||
B<Note:> All arithmetic uses epoch seconds (UTC). When daylight saving time
|
||||
(DST) changes occur:
|
||||
@ -1213,40 +1207,6 @@ The default format string is C<"%a, %d %b %Y %H:%M:%S %Z">, so these are equival
|
||||
my $t1 = Time::Piece->strptime($string);
|
||||
my $t2 = Time::Piece->strptime($string, "%a, %d %b %Y %H:%M:%S %Z");
|
||||
|
||||
=head2 Handling Partial Dates
|
||||
|
||||
When parsing incomplete date strings, you can provide defaults for missing
|
||||
components in several ways:
|
||||
|
||||
B<Array Reference> - Standard time components (as returned by localtime):
|
||||
|
||||
my @defaults = localtime();
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => \@defaults });
|
||||
|
||||
B<Hash Reference> - Specify only needed components:
|
||||
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => {
|
||||
year => 2023,
|
||||
hour => 14,
|
||||
min => 30
|
||||
} });
|
||||
|
||||
Valid keys: C<sec>, C<min>, C<hour>, C<mday>, C<mon>, C<year>, C<wday>, C<yday>, C<isdst>
|
||||
|
||||
B<Note>: For the C<year> parameter numbers less than 1000 are treated as an
|
||||
offset from 1900. Whereas numbers larger than 1000 are treated as the actual year.
|
||||
|
||||
B<Time::Piece Object> - Uses all components from the object:
|
||||
|
||||
my $base = localtime();
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => $base });
|
||||
|
||||
B<Note:> In all cases, parsed values always override defaults. Only missing
|
||||
components use default values.
|
||||
|
||||
=head2 GMT vs Local Time
|
||||
|
||||
By default, C<strptime> returns GMT objects when called as a class method:
|
||||
@ -1266,37 +1226,6 @@ To get local time objects, you can:
|
||||
my $local = localtime();
|
||||
Time::Piece->strptime($string, $format, { defaults => $local })
|
||||
|
||||
=head3 Locale Considerations
|
||||
|
||||
By default, C<strptime> only parses English day and month names, while
|
||||
C<strftime> uses your system locale. This can cause parsing failures for
|
||||
non-English dates.
|
||||
|
||||
To parse localized dates, call C<Time::Piece-E<gt>use_locale()> to build
|
||||
a list of your locale's day and month names:
|
||||
|
||||
# Enable locale-aware parsing (global setting)
|
||||
Time::Piece->use_locale();
|
||||
|
||||
# Now strptime can parse names in your system locale
|
||||
my $t = Time::Piece->strptime("15 Marzo 2024", "%d %B %Y");
|
||||
|
||||
B<Note:> This is a global change affecting all Time::Piece instances.
|
||||
|
||||
You can also override the day/month names manually:
|
||||
|
||||
my @days = qw( Domingo Lunes Martes Miercoles Jueves Viernes Sabado );
|
||||
my $spanish_day = localtime->day(@days);
|
||||
|
||||
my @months = qw( Enero Febrero Marzo Abril Mayo Junio
|
||||
Julio Agosto Septiembre Octubre Noviembre Diciembre );
|
||||
print localtime->month(@months);
|
||||
|
||||
Set globally with:
|
||||
|
||||
Time::Piece::day_list(@days);
|
||||
Time::Piece::mon_list(@months);
|
||||
|
||||
=head2 Timezone Parsing with %z and %Z
|
||||
|
||||
Time::Piece's C<strptime()> function has some limited support for parsing timezone
|
||||
@ -1307,7 +1236,8 @@ Consider the current implementation somewhat "alpha" and in need of feedback.
|
||||
|
||||
=head3 Numeric Offsets (%z)
|
||||
|
||||
The C<%z> specifier parses numeric timezone offsets (format: C<+HHMM> or C<-HHMM>):
|
||||
The C<%z> specifier parses numeric timezone offsets
|
||||
(format: C<[+-]HHMM>, C<[+-]HH:MM>, or C<[+-]HH>):
|
||||
|
||||
my $t = Time::Piece->strptime("2024-01-15 15:30:00 +0500",
|
||||
"%Y-%m-%d %H:%M:%S %z");
|
||||
@ -1348,9 +1278,81 @@ Other timezone names are parsed B<but ignored>:
|
||||
"%Y-%m-%d %H:%M:%S %Z");
|
||||
print $t2->hour; # prints 10 (PST ignored - no adjustment)
|
||||
|
||||
# Parse and convert to local timezone
|
||||
my $t3 = Time::Piece->strptime("2024-01-15 15:30:00 UTC",
|
||||
"%Y-%m-%d %H:%M:%S %Z",
|
||||
{ islocal => 1 });
|
||||
print $t3->hour; # prints 10:30 UTC converted to your local timezone
|
||||
|
||||
|
||||
B<Note:> Full timezone name support is not currently implemented. For reliable
|
||||
timezone handling beyond GMT/UTC, consider using the L<DateTime> module.
|
||||
|
||||
=head2 Handling Partial Dates
|
||||
|
||||
When parsing incomplete date strings, you can provide defaults for missing
|
||||
components in several ways:
|
||||
|
||||
B<Array Reference> - Standard time components (as returned by localtime):
|
||||
|
||||
my @defaults = localtime();
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => \@defaults });
|
||||
|
||||
B<Hash Reference> - Specify only needed components:
|
||||
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => {
|
||||
year => 2023,
|
||||
hour => 14,
|
||||
min => 30
|
||||
} });
|
||||
|
||||
Valid keys: C<sec>, C<min>, C<hour>, C<mday>, C<mon>, C<year>, C<wday>, C<yday>, C<isdst>
|
||||
|
||||
B<Note>: For the C<year> parameter numbers less than 1000 are treated as an
|
||||
offset from 1900. Whereas numbers larger than 1000 are treated as the actual year.
|
||||
|
||||
B<Time::Piece Object> - Uses all components from the object:
|
||||
|
||||
my $base = localtime();
|
||||
my $t = Time::Piece->strptime("15 Mar", "%d %b",
|
||||
{ defaults => $base });
|
||||
|
||||
B<Note:> In all cases, parsed values always override defaults. Only missing
|
||||
components use default values.
|
||||
|
||||
=head2 Locale Considerations
|
||||
|
||||
By default, C<strptime> only parses English day and month names, while
|
||||
C<strftime> uses your system locale. This can cause parsing failures for
|
||||
non-English dates.
|
||||
|
||||
To parse localized dates, call C<Time::Piece-E<gt>use_locale()> to build
|
||||
a list of your locale's day and month names:
|
||||
|
||||
# Enable locale-aware parsing (global setting)
|
||||
Time::Piece->use_locale();
|
||||
|
||||
# Now strptime can parse names in your system locale
|
||||
my $t = Time::Piece->strptime("15 Marzo 2024", "%d %B %Y");
|
||||
|
||||
B<Note:> This is a global change affecting all Time::Piece instances.
|
||||
|
||||
You can also override the day/month names manually:
|
||||
|
||||
my @days = qw( Domingo Lunes Martes Miercoles Jueves Viernes Sabado );
|
||||
my $spanish_day = localtime->day(@days);
|
||||
|
||||
my @months = qw( Enero Febrero Marzo Abril Mayo Junio
|
||||
Julio Agosto Septiembre Octubre Noviembre Diciembre );
|
||||
print localtime->month(@months);
|
||||
|
||||
Set globally with:
|
||||
|
||||
Time::Piece::day_list(@days);
|
||||
Time::Piece::mon_list(@months);
|
||||
|
||||
=head1 Global Overriding
|
||||
|
||||
To override localtime and gmtime everywhere:
|
||||
|
||||
@ -380,8 +380,8 @@ _strptime(pTHX_ const char *buf, const char *fmt, struct tm *tm, int *got_GMT, H
|
||||
c = *ptr++;
|
||||
|
||||
if (c != '%') {
|
||||
if (isspace((unsigned char)c))
|
||||
while (*buf != 0 && isspace((unsigned char)*buf))
|
||||
if (isSPACE((unsigned char)c))
|
||||
while (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
buf++;
|
||||
else if (c != *buf++) {
|
||||
warn("Time string mismatches format string");
|
||||
@ -408,12 +408,12 @@ label:
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
/* XXX This will break for 3-digit centuries. */
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -477,9 +477,9 @@ label:
|
||||
|
||||
case 'n': /* whitespace */
|
||||
case 't':
|
||||
if (!isspace((unsigned char)*buf))
|
||||
if (!isSPACE((unsigned char)*buf))
|
||||
return NULL;
|
||||
while (isspace((unsigned char)*buf))
|
||||
while (isSPACE((unsigned char)*buf))
|
||||
buf++;
|
||||
break;
|
||||
|
||||
@ -502,11 +502,11 @@ label:
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 3;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -520,14 +520,14 @@ label:
|
||||
|
||||
case 'M':
|
||||
case 'S':
|
||||
if (*buf == 0 || isspace((unsigned char)*buf))
|
||||
if (*buf == 0 || isSPACE((unsigned char)*buf))
|
||||
break;
|
||||
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -543,8 +543,8 @@ label:
|
||||
tm->tm_sec = i;
|
||||
}
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -560,11 +560,11 @@ label:
|
||||
* XXX The %l specifier may gobble one too many
|
||||
* digits if used incorrectly.
|
||||
*/
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -579,8 +579,8 @@ label:
|
||||
|
||||
tm->tm_hour = i;
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -681,11 +681,11 @@ label:
|
||||
* point to calculate a real value, so just check the
|
||||
* range for now.
|
||||
*/
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -693,14 +693,14 @@ label:
|
||||
if (i > 53)
|
||||
return NULL;
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'w':
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
i = *buf - '0';
|
||||
@ -712,8 +712,8 @@ label:
|
||||
tm->tm_wday = i;
|
||||
|
||||
buf++;
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -727,11 +727,11 @@ label:
|
||||
* XXX The %e specifier may gobble one too many
|
||||
* digits if used incorrectly.
|
||||
*/
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -741,8 +741,8 @@ label:
|
||||
|
||||
tm->tm_mday = i;
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -787,11 +787,11 @@ label:
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -801,8 +801,8 @@ label:
|
||||
|
||||
tm->tm_mon = i - 1;
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -842,14 +842,14 @@ label:
|
||||
|
||||
case 'Y':
|
||||
case 'y':
|
||||
if (*buf == 0 || isspace((unsigned char)*buf))
|
||||
if (*buf == 0 || isSPACE((unsigned char)*buf))
|
||||
break;
|
||||
|
||||
if (!isdigit((unsigned char)*buf))
|
||||
if (!isDIGIT((unsigned char)*buf))
|
||||
return NULL;
|
||||
|
||||
len = (c == 'Y') ? 4 : 2;
|
||||
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
|
||||
for (i = 0; len && *buf != 0 && isDIGIT((unsigned char)*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
len--;
|
||||
@ -858,13 +858,11 @@ label:
|
||||
i -= 1900;
|
||||
if (c == 'y' && i < 69)
|
||||
i += 100;
|
||||
if (i < 0)
|
||||
return NULL;
|
||||
|
||||
tm->tm_year = i;
|
||||
|
||||
if (*buf != 0 && isspace((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isspace((unsigned char)*ptr))
|
||||
if (*buf != 0 && isSPACE((unsigned char)*buf))
|
||||
while (*ptr != 0 && !isSPACE((unsigned char)*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
@ -873,7 +871,7 @@ label:
|
||||
const char *cp;
|
||||
char *zonestr;
|
||||
|
||||
for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp)
|
||||
for (cp = buf; *cp && isUPPER((unsigned char)*cp); ++cp)
|
||||
{/*empty*/}
|
||||
if (cp - buf) {
|
||||
zonestr = (char *)safemalloc((size_t) (cp - buf + 1));
|
||||
@ -900,22 +898,32 @@ label:
|
||||
if (*buf != '+') {
|
||||
if (*buf == '-')
|
||||
sign = -1;
|
||||
else
|
||||
else {
|
||||
warn("%%z must contain '-' or '+'");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buf++;
|
||||
i = 0;
|
||||
for (len = 4; len > 0; len--) {
|
||||
if (isdigit((int)*buf)) {
|
||||
if (isDIGIT((unsigned char)*buf)) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
buf++;
|
||||
} else if (len == 2) {
|
||||
i *= 100;
|
||||
break;
|
||||
} else
|
||||
/* Support ISO 8601 HH:MM format in addition to RFC 822 HHMM */
|
||||
if (*buf == ':') {
|
||||
buf++;
|
||||
len++;
|
||||
} else {
|
||||
i *= 100;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
warn("%%z format mismatch");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Valid if between UTC+14 and UTC-12 and minutes <= 60 */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package Time::Seconds;
|
||||
use strict;
|
||||
|
||||
our $VERSION = '1.38';
|
||||
our $VERSION = '1.39';
|
||||
|
||||
use Exporter 5.57 'import';
|
||||
|
||||
|
||||
@ -17,10 +17,13 @@ my $one_year = ONE_YEAR;
|
||||
|
||||
for ( 1 .. 50 ) {
|
||||
$t = $t + $one_year;
|
||||
cmp_ok( $t->year, '==', $base_year + $_,
|
||||
"Year is: " . ( $base_year + $_ ) );
|
||||
cmp_ok(
|
||||
$t->year, '==',
|
||||
Time::Piece->strptime( $t->year . "-07-15 00:00:00", "%F %T" )->year,
|
||||
'==',
|
||||
$base_year + $_,
|
||||
"Year is: " . ( $base_year + $_ )
|
||||
"Strptime year is: " . ( $base_year + $_ )
|
||||
);
|
||||
}
|
||||
|
||||
@ -29,34 +32,46 @@ $base_year = $t->year;
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
cmp_ok(
|
||||
Time::Piece->strptime( $t->year . "-07-15 00:00:00", "%F %T" )->year,
|
||||
'==',
|
||||
$base_year - 25,
|
||||
"Strptime year is: " . ( $base_year - 25 )
|
||||
);
|
||||
$base_year -= 25;
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
cmp_ok(
|
||||
Time::Piece->strptime( $t->year . "-07-15 00:00:00", "%F %T" )->year,
|
||||
'==',
|
||||
$base_year - 25,
|
||||
"Strptime year is: " . ( $base_year - 25 )
|
||||
);
|
||||
$base_year -= 25;
|
||||
|
||||
SKIP: {
|
||||
skip "No time64 on Win32 if perl < 5.12", 5, if $is_win32 && $] < 5.012;
|
||||
skip "No time64 on Win32 if perl < 5.12", 12, if $is_win32 && $] < 5.012;
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
$base_year -= 25;
|
||||
for ( 1 .. 6 ) {
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok(
|
||||
$t->year, '==',
|
||||
$base_year - 25,
|
||||
"Year is: " . ( $base_year - 25 )
|
||||
);
|
||||
cmp_ok(
|
||||
Time::Piece->strptime( $t->year . "-07-15 00:00:00", "%F %T" )
|
||||
->year,
|
||||
'==',
|
||||
$base_year - 25,
|
||||
"Strptime year is: " . ( $base_year - 25 )
|
||||
);
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
$base_year -= 25;
|
||||
$base_year -= 25;
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
$base_year -= 25;
|
||||
}
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
$base_year -= 25;
|
||||
|
||||
$t = $t - ( $one_year * 25 );
|
||||
cmp_ok( $t->year, '==', $base_year - 25, "Year is: " . ( $base_year - 25 ) );
|
||||
$base_year -= 25;
|
||||
}
|
||||
|
||||
done_testing(57);
|
||||
done_testing(116);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 43;
|
||||
use Test::More tests => 52;
|
||||
|
||||
BEGIN { use_ok('Time::Piece'); use_ok('Time::Seconds'); }
|
||||
|
||||
@ -81,3 +81,20 @@ is($s2->seconds, 0, 'Subtract one Time::Seconds object from another');
|
||||
|
||||
eval { $s2 = $s2 + $t; };
|
||||
like($@, qr/Can't use non Seconds object in operator overload/);
|
||||
|
||||
# Tests for add_days
|
||||
$t = Time::Piece->strptime( "01 01 2024", "%d %m %Y" );
|
||||
my $t10 = $t->add_days(59);
|
||||
is( $t10->year, 2024 );
|
||||
is( $t10->mon, 2 );
|
||||
is( $t10->mday, 29 );
|
||||
|
||||
my $t11 = $t->add_days(-366);
|
||||
is( $t11->year, 2022 );
|
||||
is( $t11->mon, 12 );
|
||||
is( $t11->mday, 31 );
|
||||
|
||||
my $t12 = $t->add_days(366);
|
||||
is( $t12->year, 2025 );
|
||||
is( $t12->mon, 1 );
|
||||
is( $t12->mday, 1 );
|
||||
|
||||
@ -5,6 +5,10 @@ my $is_linux = ( $^O =~ /linux/ );
|
||||
|
||||
BEGIN { use_ok('Time::Piece'); }
|
||||
|
||||
# Start with a known TZ
|
||||
$ENV{TZ} = "EST5EDT4,M3.2.0/2,M11.1.0/2";
|
||||
Time::Piece::_tzset();
|
||||
|
||||
# Using known epoch 1753440879 = Friday, July 25, 2025 10:54:39 AM GMT
|
||||
my @known_gmtime = gmtime(1753440879); # (39, 54, 10, 25, 6, 125, 5, 206, 0)
|
||||
my @known_localtime = localtime(1753440879);
|
||||
|
||||
@ -75,6 +75,18 @@ my @z_offset_tests = (
|
||||
[ "-0100", 10, 11, 30, "UTC-1" ],
|
||||
[ "-0500", 10, 15, 30, "UTC-5" ],
|
||||
[ "-0730", 10, 18, 0, "UTC-7:30" ],
|
||||
|
||||
# ISO 8601 [+-]HH format (verify existing support)
|
||||
[ "+00", 10, 10, 30, "UTC (HH format)" ],
|
||||
[ "+05", 10, 5, 30, "UTC+5 (HH format)" ],
|
||||
[ "-08", 10, 18, 30, "UTC-8 (HH format)" ],
|
||||
|
||||
# ISO 8601 [+-]HH:MM format (new support)
|
||||
[ "+00:00", 10, 10, 30, "UTC (HH:MM format)" ],
|
||||
[ "+01:00", 10, 9, 30, "UTC+1 (HH:MM format)" ],
|
||||
[ "+05:30", 10, 5, 0, "UTC+5:30 (HH:MM format)" ],
|
||||
[ "-01:00", 10, 11, 30, "UTC-1 (HH:MM format)" ],
|
||||
[ "-07:30", 10, 18, 0, "UTC-7:30 (HH:MM format)" ],
|
||||
);
|
||||
|
||||
for my $test (@z_offset_tests) {
|
||||
@ -450,4 +462,4 @@ with_tz(
|
||||
}
|
||||
);
|
||||
|
||||
done_testing(234);
|
||||
done_testing(290);
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'deprecated';
|
||||
|
||||
use Test::More tests => 5;
|
||||
|
||||
BEGIN { use_ok('Time::Piece'); }
|
||||
|
||||
# The parse() legacy method is deprecated and will not be maintained.
|
||||
# The tests in this script illustrate both its functionality and some of
|
||||
# its bugs. This script should be removed from the test suite once
|
||||
# parse() has been deleted from Time::Piece.
|
||||
|
||||
SKIP: {
|
||||
skip "Linux only", 4 if $^O !~ /linux/i;
|
||||
|
||||
my $timestring = '2000-01-01T06:00:00';
|
||||
my $t1 = Time::Piece->parse($timestring);
|
||||
isnt( $t1->datetime, $timestring, 'LEGACY: parse string months fail' );
|
||||
my $t2 = $t1->parse( 0, 0, 6, 1, 0, 100 );
|
||||
is( $t2->datetime, $timestring, 'LEGACY: parse array' );
|
||||
eval { $t2 = Time::Piece->parse(); };
|
||||
is( $t2->datetime, $timestring, 'LEGACY: parse with no args dies' );
|
||||
eval { $t2 = Time::Piece::parse( 0, 0, 12, 1, 0, 100 ); };
|
||||
is( $t2->datetime, $timestring, 'LEGACY: parse as non-method dies' );
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user