DateTime::Duration: always normalize nanoseconds
It seems consistent and logical to normalize nanoseconds when multiplying durations. There is also a comment about normalization that seems both redundant and misleading (since comparison doesn't depend on nanoseconds being normalized; I assume comparison used to be done without a reference time). Although, looking at _normalize_nanoseconds and the tests for it, I don't understand the sense of "normalizing" to (-1, 1) at all. Andrew --- lib/DateTime/Duration.pm.orig 2003-11-14 22:13:52.0 -0500 +++ lib/DateTime/Duration.pm2004-02-09 21:56:16.0 -0500 @@ -162,7 +162,6 @@ $self->{$_} += $dur->{$_}; } -# we might have to normalize_nanoseconds before comparing durations $self->_normalize_nanoseconds if $self->{nanoseconds}; return $self; @@ -194,6 +193,8 @@ $self->{$_} *= $multiplier; } +$self->_normalize_nanoseconds if $self->{nanoseconds}; + return $self; } --- t/11duration.t.orig 2004-02-09 22:00:36.0 -0500 +++ t/11duration.t 2004-02-09 22:02:08.0 -0500 @@ -2,7 +2,7 @@ use strict; -use Test::More tests => 86; +use Test::More tests => 88; use DateTime; use DateTime::Duration; @@ -163,6 +163,12 @@ $new2->subtract( nanoseconds => 1 ); is( $new2->delta_nanoseconds, 100300400, 'sub nanoseconds works' ); + +my $new3 = $dur2 * 3; + +is( $new3->delta_seconds, 4, 'seconds normalized after multiplication'); +is( $new3->delta_nanoseconds, 5, +'nanoseconds normalized after multiplication' ); } {
off-by-one re leap seconds in subtract_datetime
Miscalculation of when we're in a leap minute. Andrew --- lib/DateTime.pm.orig2004-01-07 17:39:02.0 -0500 +++ lib/DateTime.pm 2004-02-09 22:19:24.0 -0500 @@ -908,7 +908,7 @@ { my ( $utc_rd_days, $utc_rd_secs ) = $smaller->utc_rd_values; -if ( $utc_rd_secs > 86340 && ! $is_floating ) +if ( $utc_rd_secs >= 86340 && ! $is_floating ) { # If the bigger of the two datetimes occurs in the last UTC minute # of the UTC day, then that minute may not be 60 seconds long. If --- t/19leap_second.t.orig 2004-02-09 22:20:09.0 -0500 +++ t/19leap_second.t 2004-02-09 22:20:13.0 -0500 @@ -2,7 +2,7 @@ use strict; -use Test::More tests => 71; +use Test::More tests => 74; use DateTime; @@ -299,3 +299,23 @@ is( $neg_dur->delta_minutes, 0, 'delta_minutes is 0' ); is( $neg_dur->delta_seconds, -36, 'delta_seconds is -36' ); } + +# catch off-by-one when carrying a leap second +{ +my $dt1 = DateTime->new( year => 1998, month => 12, day => 31, + hour => 23, minute => 59, second => 0, + nanosecond => 1, + time_zone => 'UTC', + ); + +my $dt2 = DateTime->new( year => 1999, month => 1, day => 1, + hour => 0, minute => 0, second => 0, + time_zone => 'UTC', + ); + +my $pos_dur = $dt2 - $dt1; + +is( $pos_dur->delta_minutes, 0, 'delta_minutes is 0' ); +is( $pos_dur->delta_seconds, 60, 'delta_seconds is 60' ); +is( $pos_dur->delta_nanoseconds, 9, 'delta_nanoseconds is 999...' ); +}
Re: DateTime::Duration: always normalize nanoseconds
On Tue, Feb 10, 2004 at 10:01:51AM -0600, Dave Rolsky wrote: > On Mon, 9 Feb 2004, Andrew Pimlott wrote: > > > Although, looking at _normalize_nanoseconds and the tests for it, I > > don't understand the sense of "normalizing" to (-1, 1) at all. > > I'm not sure what you're referring to. I don't see why nanoseconds aren't normalized to [0, 1s). The tests seem to indicate that this is intentional, but I don't see what good negative nanoseconds do. It doesn't seem to make any difference in any calculation; the only visible effect appears to be in ->delta_nanoseconds. And by what logic should Duration->new(seconds => 1) - Duration->new(nanoseconds => 5) and Duration->new(nanoseconds => 5) differ? Andrew
Re: [OT] Re: DateTime::Stringify ... & Data::Dumper'ing DT objects
On Sat, Feb 21, 2004 at 03:42:40PM -0600, Dave Rolsky wrote: > I think the problem is that Data::Dumper has historically had two > orthogonal uses. One was serializing data structures for persistence, ala > Storable, and the other was for debugging. > > Nowadays, I'm guessing most people use Storable for the first, and so it's > probably used more for debugging. But just dumping the structure as is > may not be ideal for debugging. This dichotomy is unfortunate. It's quite nice to have a readable serialized format, when space is not important. However, you must use Data::Dumper _very_ carefully to get reliable serialization, and when I suggested that it be made easier, people said "Data::Dumper is for pretty-printing, use Storable". Meanwhile, Data::Dumper is much more verbose than a pretty-printer needs to be. So it's sort of stuck in no-man's land. > So I suspect what we really need is something like Data::DebugDumper or > something like that, which is _only_ used for debugging. Is there already > something on CPAN that might be suitable for this? Dumpvalue is what the debugger uses (actually, I think it's a copy of it :-/), so that's the natural choice. It is much more concise and readable than Data::Dumper, IMO. Andrew
Re: startSet() and endSet() for DateTime::SpanSet
On Wed, Mar 03, 2004 at 10:45:57AM -0300, Flavio S. Glock wrote: > * iterate > > This method apply a callback subroutine to all spans of a spanset. > > The callback parameter is a DateTime::Span. > > sub callback { > $_[0]->set_time_zone( $tz ); > } > > # assign a timezone to the spanset > $set->iterate( \&callback ); > > # create a new spanset with the new timezone, > # $set is unchanged > $set2 = $set->clone->iterate( \&callback ); > > If the callback returns undef, the span is removed from the set. As an immediate reaction from someone who hasn't used any of the Set/Span modules, I don't like that last part. One, it's too easy for someone who only skims the documentation to miss it, and end up with a very subtle bug. Two, lots of functions return undef, so people are going to end up with ugly code like $set->iterate( sub { myfunc($_); 1 } ); just to avoid the effect. I think if you want to be able to modify the set, you should provide different methods for that. ->map and ->grep come to mind. I notice that this method with the same undef semantics already exists in Set, however it is marked experimental, so perhaps it can still change. Andrew
Re: startSet() and endSet() for DateTime::SpanSet
On Thu, Mar 04, 2004 at 04:05:21AM +, [EMAIL PROTECTED] wrote: > Andrew Pimlott wrote: > > $set->iterate( sub { myfunc($_); 1 } ); > > The result would be: $set = [ 1 ] > because that's the _only_ returned value. Boy, that's confusing to me. I didn't realize (because I didn't read the documentation fully) that the return value of the callback replaces the element on which it is called. This is not what I would expect from a method called "iterate"; I would expect iterate to ignore its return value, so that the set would only be modified if $_[0] is modified. I find your examples confusing for this reason: sub callback { $_[0]->add( hours => 1 ); } looks as though it modifies the elements because ->add is destructive. In fact, it "also" modifies the elements via the return value. I think the following example would more clearly demonstrate the behavior of ->iterate. sub callback { $_[0]->clone->add( hours => 1 ); } Also, this makes it cumbersome to use ->iterate without modifying the set, because you'd have to do sub callback { myfunc($_[0]); $_[0]; } At very least the documentation could be more explicit. The first sentences could be, This method modifies a set by applying a callback function to each element. The element is replaced by the return value of the function unless the function return sundef, in which case the element is removed. Andrew
Re: startSet() and endSet() for DateTime::SpanSet
On Thu, Mar 04, 2004 at 11:28:20AM -0600, Dave Rolsky wrote: > Actually, this doesn't encourage it and we _still_ need iterate() for > sure. We can have set_map() only be used to create a new set, and > iterate() only be used to alter the current set in place. To clarify, do you mean that iterate can be used to alter the current set in place because you can modify $_[0], or because the return value of the callback will replace the current element in the set? Ie, does $set->iterate( sub { $_[0]->clone->add( days => 1 ) } ); alter $set? I think you intend that it would not (in fact, it would have no effect at all), which is what I would choose. After all, you might want to iterate through the set without modifying anything: $set->iterate( sub { print $_[0]->hms, "\n" } ); If this is what you mean, then I think that having both ->iterate and ->set_map (as well as possibly ->set_grep) makes perfect sense. You might argue that the last example is better done with foreach ($set->as_list) { ... } which is a legitimate alternative. I guess my main point is that ->iterate doesn't sound like it should modify the set (again, unless you modify $_[0]). And since modification of $_[0] is always available, I think it is better not to update the set using the return value of the callback. Andrew
Re: startSet() and endSet() for DateTime::SpanSet
On Fri, Mar 05, 2004 at 02:57:57AM +, [EMAIL PROTECTED] wrote: > This will not work. In infinite sets, the 'iterate' > subroutine is _stored_ into the object - it is not > executed immediately. In retrospect, that makes sense. Then all I think you should do is pick a different name, as you suggested. ->set_map_inplace is ok, or maybe ->update or ->set_update. Also, make it clear in the document that the function is not called immediately, and so it is unwise to count on any side-effects. Sorry for my confusion. Andrew
DateTime::Format::Strptime defaults to UTC
I noticed that DateTime::Format::Strptime defaults to returning DateTimes in the UTC time zone. Eg, DateTime::Format::Strptime->new(pattern => '%Y%m%d%H%M%S') ->parse_datetime('2004110200') ->time_zone->name ==> 'UTC' This is at odds with DateTime, which defaults to floating. This caused a mysterious inconsistency in my code. I think it would be right to change this to floating. I also found the use of the time zone given to the parser object confusing. I think the following is a clearer documentation of the current code: --- lib/DateTime/Format/Strptime.pm.orig2004-11-02 14:56:37.0 -0800 +++ lib/DateTime/Format/Strptime.pm 2004-11-02 14:56:40.0 -0800 @@ -859,12 +859,13 @@ =item * new( pattern=>$strptime_pattern ) -Creates the format object. You must specify a pattern, you can also -specify a C and a C. If you specify a time zone -then any resulting C object will be in that time zone. If you -do not specify a C parameter, but there is a time zone in the -string you pass to C, then the resulting C will -use that time zone. +Creates the format object. You must specify a pattern, and may also +specify a C and a C. If you specify a time zone, it +will be used as the default time zone if none is found by parsing, and +the resulting C object will be converted to that time zone. If +you do not specify a time zone, 'UTC' will be used as the default time +zone, and the resulting C object will remain in the time zone +found by parsing. You can optionally use an on_error parameter. This parameter has three valid options: Change 'UTC' to 'floating' if you take my suggestion. Andrew