Skip Menu |

This queue is for tickets about the Time-Piece CPAN distribution.

Report information
The Basics
Id: 21005
Status: rejected
Priority: 0/
Queue: Time-Piece

People
Owner: Nobody in particular
Requestors: derek [...] ximbiot.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.08
Fixed in: (no value)



Subject: Time::Piece::strptime should preserve stringify format.
This is actually broken in 1.09, but this choice of versions was not in the tracker. I wanted to use Time::Piece parse a timestamps coming out of a MySQL server (but stored as a varchar) in a backwards-compatible manner, in the same sense that Time::Piece::localtime returns a backwards compatible object since it stringifies the same way the scalar output of localtime would. Thus, since the timestamp field was normally formatted as "YYYYmmddHHMMSS", I wanted a Time::Piece object that stringified the same way. To this end, I subclassed Time::Piece with an object that allows the default stringify function to be set via a set_stringify method, via arguments to new(), or via arguments to strptime(). In addition, strptime($string, $format) method calls set_stringify (\&Time::Piece::strftime, $format) on the object it creates before returning it, regardless. This seems like good default behavior to me and would be trivial to add it to Time::Piece in a backwards compatible manner (except for the non-&cdate default stringify for objects created by strptime, but I think this would be a Good Thing (tm)). I've attached the subclass I created. Moving the new functionality into Time::Piece should be trivial, but please let me know if you have any questions. Also, please let me know what you decide to do with it, whatever that is.
Subject: Adaptive.pm
package Time::Piece::Adaptive; use warnings; use strict; =head1 VERSION Version 0.01 =cut our $VERSION = 0.01; =head1 NAME Time::Piece::Adaptive - subclass of Time::Piece which allows the default stringification function to be set. =head1 REQUIRES Subclasses Time::Piece. =head1 SYNOPSIS See Time::Piece I actually think this subclass encapsulates the behavior I would expect from Time::Piece, but I haven't been able to elicit a response from the authors of Time::Piece. =head1 EXPORT =over 4 =item * gmtime =item * localtime =item * :override: =back See Time::Piece for more. =cut use vars qw(@ISA @EXPORT %EXPORT_TAGS); require Exporter; require DynaLoader; use Time::Piece; @ISA = qw(Time::Piece); @EXPORT = qw( localtime gmtime ); %EXPORT_TAGS = ( ':override' => 'internal', ); =head1 METHODS =head2 new my $t1 = new Time::Piece::Adaptive (time, stringify => "%Y%m%d%H%M%S"); print "The MySql timestamp was $t1."; my $t2 = new Time::Piece::Adaptive (time, stringify => \&my_func, stringify_args => $my_data); Like the constructor for Time::Piece, except it may set the default stringify function. The above examples are semanticly equivalent to: my $t1 = new Time::Piece::Adaptive (time); $t1->set_stringify ("%Y%m%d%H%M%S"); print "The MySql timestamp was $t1."; my $t2 = new Time::Piece::Adaptive (time); $t2->set_stringify (\&my_func, $my_data); =cut sub new { my ($class, $time, %args) = @_; my $self = $class->SUPER::new ($time); my $stringify = $args{stringify} if exists $args{stringify}; my $stringify_args = $args{stringify_args} if exists $args{stringify_args}; $self->set_stringify ($stringify, $stringify_args); return $self; } =head2 localtime =head2 gmtime C<localtime> and C<gmtime> work like Time::Piece's versions, except they accept stringify arguments, as C<new>. =cut sub localtime { unshift @_, __PACKAGE__ unless eval {$_[0]->isa ('Time::Piece')}; my $class = shift; my $time = shift; $time = time unless defined $time; return $class->_mktime ($time, 1, @_); } sub gmtime { unshift @_, __PACKAGE__ unless eval {$_[0]->isa ('Time::Piece')}; my $class = shift; my $time = shift; $time = time unless defined $time; return $class->_mktime ($time, 0, @_); } sub _mktime { my ($class, $time, $islocal, %args) = @_; return $class->SUPER::_mktime ($time) if wantarray; my $self = $class->SUPER::_mktime ($time); my $stringify = $args{stringify} if exists $args{stringify}; my $stringify_args = $args{stringify_args} if exists $args{stringify_args}; $self->set_stringify ($stringify, $stringify_args); return $self; } =head2 set_stringify $t->set_stringify ($format, $arg); print "The date is $t."; If C<$format> is a reference to a function, set the stringify function to C<$format>, which should return a string when passed a reference to an instantiated Time::Piece and C<$arg>. If C<$format> is a string, use it to format an output string using C<strftime> (any C<$arg> is ignored). When called without specifying C<$format>, restore the default stringifier (&Time::Piece::cdate). =cut use overload '""' => \&_stringify; use constant 'c_stringify_func' => 11; use constant 'c_stringify_arg' => 12; sub _stringify { my ($self) = @_; my $func = $self->[c_stringify_func]; my $arg = $self->[c_stringify_arg]; my $string = &{$func}($self, $arg); return $string; } sub set_stringify { my ($self, $format, $arg) = @_; if (ref $format) { $self->[c_stringify_func] = $format; if (defined $arg) { $self->[c_stringify_arg] = $arg if defined $arg; } else { delete $self->[c_stringify_arg]; } } elsif (defined $format) { $self->[c_stringify_func] = \&Time::Piece::strftime; $self->[c_stringify_arg] = $format; } else { $self->[c_stringify_func] = \&Time::Piece::cdate; delete $self->[c_stringify_arg]; } } =head2 add =head2 subtract Like the Time::Piece functions of the same name, except C<stringify_func> and C<stringify_arg> arguments are accepted. Also, when a Time::Piece::Adaptive object is subtracted from an arbitrary object, it is converted to a string according to its stringify function and passed to perl for handling. =cut use overload '-' => \&subtract, '+' => \&add; sub subtract { my $time = shift; if ($_[1]) { # SWAPED is set and our parent doesn't know how to handle # NOTDATE - DATE. For backwards compatibility reasons, return # the result as if the string $time resolves to was subtracted # from NOTDATE. return $_[0] - "$time"; } my $new = $time->SUPER::subtract (@_); $new->set_stringify ($time->[c_stringify_func], $time->[c_stringify_arg]) if $new->isa ('Time::Piece'); return $new; } sub add { my ($time) = shift; my $new = $time->SUPER::add (@_); $new->set_stringify ($time->[c_stringify_func], $time->[c_stringify_arg]); return $new; } =head2 strptime my $t = Time::Piece::Adaptive::strptime ($mysqltime, "%Y%m%d%H%M%S"); print "The MySql timestamp was $t."; my $t = Time::Piece::Adaptive::strptime ($mysqltime, "%Y%m%d%H%M%S", stringify => \&Time::Piece::Adaptive::cdate); print "The MySql timestamp was $t."; Like the C<Time::Piece::strptime>, except a stringify function may be set as per C<Time::Piece::Adaptive::new> and, if the stringify function is not explicitly specified, then it is set by calling C<set_stringify ($format)> on the new object with the same C<$format> string passed to C<strptime>. =cut sub strptime { my ($time, $string, $format, %args) = @_; my $self = $time->SUPER::strptime ($string, $format); my $stringify = exists $args{stringify} ? $args{stringify} : $format; my $stringify_args = $args{stringify_args} if exists $args{stringify_args}; $self->set_stringify ($stringify, $stringify_args); return $self; } =head1 AUTHOR Derek Price, C<< <derek at ximbiot.com> >> =head1 BUGS Please report any bugs or feature requests to C<bug-cgi-wiki-store-mediawiki at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Time-Piece-Adaptive>. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc Time::Piece::Adaptive You can also look for information at: =over 4 =item * AnnoCPAN: Annotated CPAN documentation L<http://annocpan.org/dist/Time-Piece-Adaptive> =item * CPAN Ratings L<http://cpanratings.perl.org/d/Time-Piece-Adaptive> =item * RT: CPAN's request tracker L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Time-Piece-Adaptive> =item * Search CPAN L<http://search.cpan.org/dist/Time-Piece-Adaptive> =back =head1 COPYRIGHT & LICENSE Copyright 2006 Derek Price, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;
The latest version of my modifications has been uploaded to CPAN as Time::Piece::Adaptive.pm (currently version 0.02). I still think these changes should be merged with Time::Piece and, in fact, I was denied the Time::Piece::Adaptive name space on CPAN on the grounds that this module was too close to Time::Piece and should be merged. If the backwards compatibility of strptime is an issue (I chose to set the default to stringify in reverse whatever string was read), then perhaps a new function could be added which combines strptime and the new set_stringify calls into one. I believe the rest of my modifications should be backwards compatible.
I disagree that strptime should keep the stringify format. That seems a sane thing for a subclass to do - marking bug as "rejected".