DateTime::Duration: always normalize nanoseconds

2004-02-09 Thread Andrew Pimlott
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

2004-02-09 Thread Andrew Pimlott
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

2004-02-10 Thread Andrew Pimlott
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

2004-02-22 Thread Andrew Pimlott
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

2004-03-03 Thread Andrew Pimlott
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

2004-03-03 Thread Andrew Pimlott
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

2004-03-04 Thread Andrew Pimlott
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

2004-03-05 Thread Andrew Pimlott
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

2004-11-02 Thread Andrew Pimlott
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