Re: More flexibly subtract/difference methods

2003-10-12 Thread Rick Measham
I said:
  Looks good to me ... however for _standard_ subtraction I'd like it
  stored the way I think about it:
 
  2004-04-11 - 2003-04-20 = 1 year, -9 days.
 
  I know this breaks some of the internal logic so far as 'if one element
  is negative, it's a negative duration', but I still think of the
  difference in terms of the individual units.

Dave Rolsky replied:
 Hmm, that just seems a little too confusing.  It's a lot easier to explain
 that the difference will always be all negative or positive, and I think
 it makes it easier to work with.

What I just said looks confusing? Why? If I add 'one year minus nine days' to 
a particular datetime I know what I want to get back: I want it to be
a year later, less 9 days. That is, using today, 2004-10-03.

Now this is what is confusing:
print DateTime-new(year=2003, month=10, day=12)
-add( years=1, days=-9 )-ymd
2002-10-03

Now why should a single negative in a duration be the deciding factor? 

Basically if a user sets a negative, it's a negative. If they set a positive it's
positive. You can't just make everything negative based on a single value.

Think about the way we talk. If I tell you it was my sister turned 25 a year ago 
tomorrow that would be (years = -1, days = +1); However DateTime::Duration currently 
returns 2002-10-11. But that sould be (years = -1, days = -1) and infact the two
return the same result!

So don't start telling me that my suggestion is a little too confusing.

Cheers!
Rick









Re: More flexibly subtract/difference methods

2003-10-11 Thread Eric Cholet
Matt Sisk wrote:

Dave Rolsky wrote:
Currently, the default when subtracting datetimes is
 to break down the duration into multiple parts, months,
 days, minutes, seconds, and nanoseconds.
From the months piece we can derive years, and from the
 days piece we can derive weeks.

Rick Measham responded:
Except, as Flavio points out, for non-gregorian calendars.
Perhaps the Calendar classes can offer 'unit conversion' methods 
suitable for their particular idiom. Datetime could utilize these 
conversion methods when found, otherwise default to 'Gregorian' style 
calculations.
Yeah, let not the Aztec-Revolutionnary calendar users stop us from
finally having number of a days between two days that us in the
real world need, hopefully in DateTime without the need for an
extra module. (insert appropriate smiley here).
--
Eric Cholet


Re: More flexibly subtract/difference methods

2003-10-11 Thread Dave Rolsky
On Fri, 11 Oct 2003, Rick Measham wrote:

  But some people have indicated that they'd like something a little
  more flexible.  Eugene van der Pijll suggested something like this:
 
   my $dur = $dt1-difference( datetime = $dt2,
   units= [ 'months', 'days' ] );
 
  This would return a duration which only included month and day values,
  without minutes, seconds, or nanoseconds.

 $dt1 = 2003-05-15 19:23:33;
 $dt2 = 2003-04-01 00:00:00;
 my $dur = $dt1-difference( datetime = $dt2,
 units= [ 'months', 'days' ] );

 So do we now have:
 1 month, 15 days
 or:
 1 month, 15 days, 19 hours, 23 minutes, 33 seconds
 or:
 1 month, 15 days, 68400 seconds

 1 month, 15 days

  It seems to me that these 3 cover all the important possibilities, and
  they have a nice simple API.

 Looks good to me ... however for _standard_ subtraction I'd like it
 stored the way I think about it:

 2004-04-11 - 2003-04-20 = 1 year, -9 days.

 I know this breaks some of the internal logic so far as 'if one element
 is negative, it's a negative duration', but I still think of the
 difference in terms of the individual units.

Hmm, that just seems a little too confusing.  It's a lot easier to explain
that the difference will always be all negative or positive, and I think
it makes it easier to work with.

 Also, I said this a while back so skip it if you're bored:

 I'd like a 'normalise' (*normalize = \normalise) function so that:

 (1 year, -9 days)-normalise(2004-04-11) = (1 year, 11 months, 22 days)

 and:
 (45 days)-normalise(2004-04-11) = (1 month, 15 days);
 (45 days)-normalise(2004-05-11) = (1 month, 14 days);

 (45 days)-normalise(2003-02-01) = (1 month, 17 days);
 (45 days)-normalise(2004-02-01) = (1 month, 16 days);

This is certainly doable.  Instead of converting the duration I'd probably
want to return a new one.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/


Re: More flexibly subtract/difference methods

2003-10-11 Thread Dave Rolsky
On Fri, 10 Oct 2003, Flavio S. Glock wrote:

 That's true, because you are talking about a DateTime.pm method.
 (delta_ymd would make sense in other calendars, that don't have
 exactly 12 months.)

 However, if DT::Duration is given 'year' units, it should not
 automatically convert it to months, because I may want to use that
 information in a non-gregorian context.

Well, you might, but you can't ;)

Seriously, I think this idea that DateTime::Duration should work for other
calendars is bogus, and I've said so before.

There's simply too many possible ways for this to break, and while it
would be somewhat flexible, it wouldn't be flexible enough to work with
many odd calendars (like Discordian, Aztec, etc.).

 That is, if you move the year/month semantics to the calendar class,
 then DT::Duration can support (almost) any calendar.

No, it can only support some fraction of calendars, those that are lunar,
solar, or lunisolar.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/


Re: More flexibly subtract/difference methods

2003-10-11 Thread Joshua Hoblitt
  However, if DT::Duration is given 'year' units, it should not
  automatically convert it to months, because I may want to use that
  information in a non-gregorian context.

 Well, you might, but you can't ;)

I agree completely.

 Seriously, I think this idea that DateTime::Duration should work for other
 calendars is bogus, and I've said so before.

Dave++

 There's simply too many possible ways for this to break, and while it
 would be somewhat flexible, it wouldn't be flexible enough to work with
 many odd calendars (like Discordian, Aztec, etc.).

Dave++

  That is, if you move the year/month semantics to the calendar class,
  then DT::Duration can support (almost) any calendar.

 No, it can only support some fraction of calendars, those that are lunar,
 solar, or lunisolar.

Dave++

DateTime::Duration should focus the Gregorian calendar.  There is no possible way to 
make it sufficiently generic to support all possible calendars without giving up 
functionality useful in it's intended context.  The best we should do to support 
alternate calendars is to implement a method that returns an absolute time interval in 
calendar independent units.

There will have to be some fudging here.  For example, how many days should 3 months 
convert to?
--
my $dtd = DateTime::Duration-new( months = 3 );
my( $rd_days, $rd_secs, $rd_nanos ) = $dtd-rd_values;
# or for some interesting compatability...
my( $rd_days, $rd_secs, $rd_nanos ) = $dtd-utc_rd_values;
--
is $rd_days 93, 90, 87, or 84?  I'd vote for 93...

For reference, this is how I handled DT::Durations in DT::C::Mayan:

--
sub add_duration {
my( $self, $duration ) = @_;

my $dt = DateTime-from_object( object = $self );
$dt-add_duration( $duration );

my $new_self = $self-from_object( object = $dt );

# if there is an alternate epoch defined don't touch it
$self-{ rd }   = $new_self-{ rd };
$self-{ rd_secs }  = $new_self-{ rd_secs };

return( $self );
}
--

-J

--


Re: More flexibly subtract/difference methods

2003-10-11 Thread Dave Rolsky
On Sat, 11 Oct 2003, Joshua Hoblitt wrote:

 DateTime::Duration should focus the Gregorian calendar.  There is no
 possible way to make it sufficiently generic to support all possible
 calendars without giving up functionality useful in it's intended
 context.  The best we should do to support alternate calendars is to
 implement a method that returns an absolute time interval in calendar
 independent units.

It did occur to me, however, that we could probably write a duration class
generator really easily.  Basically, durations are composed of base units
and derived units.  For the Gregorian/UTC system, the base units are
nanoseconds, seconds, minutes, days, and months.  The derived units are
hours (minutes * 60) and years (months * 12).

For the Hebrew calendar (which has no leap seconds), the base units are
nanoseconds, seconds, days, months, and years.  The derived units are
minutes and hours.

It'd be easy to have something like this:

 use DateTime::Duration::Generator
 ( base = [ qw( nanoseconds seconds minutes days months ) ],
   derived = { hours = [ 60 = minutes ],
years = [ 12 = months ],
  },
 );

The only thing this doesn't handle is the end of month mode stuff.  But it
could easily generate the delta_* methods, the various unit methods, and
so on.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/


Re: More flexibly subtract/difference methods

2003-10-10 Thread Flavio S. Glock
Dave Rolsky wrote:
 
 Flavio, you'd mentioned something about wanting to get years back as a
 unit, but that didn't make much sense to me.  Years is _always_ equal to
 months * 12, so if we have:

That's true, because you are talking about a DateTime.pm method.
(delta_ymd would make sense in other calendars, that don't have
exactly 12 months.)

However, if DT::Duration is given 'year' units, it should not
automatically convert it to months, because I may want to use that
information in a non-gregorian context.

That is, if you move the year/month semantics to the calendar class,
then DT::Duration can support (almost) any calendar.

- Flavio S. Glock


Re: More flexibly subtract/difference methods

2003-10-10 Thread Matt Sisk
Dave Rolsky wrote:
Currently, the default when subtracting datetimes is 
 to break down the duration into multiple parts, months,
 days, minutes, seconds, and nanoseconds.
From the months piece we can derive years, and from the
 days piece we can derive weeks.

Rick Measham responded:
Except, as Flavio points out, for non-gregorian calendars.
Perhaps the Calendar classes can offer 'unit conversion' methods 
suitable for their particular idiom. Datetime could utilize these 
conversion methods when found, otherwise default to 'Gregorian' style 
calculations.

Matt





More flexibly subtract/difference methods

2003-10-09 Thread Dave Rolsky
So there was some talk about this earlier and I was thinking about how
best to make this information available.

Currently, the default when subtracting datetimes is to break down the
duration into multiple parts, months, days, minutes, seconds, and
nanoseconds.

From the months piece we can derive years, and from the days piece we can
derive weeks.

There's also the subtract_datetime_absolute method, which just returns
seconds and nanoseconds.  I see the primary purpose of this method as
returning an object which can be used to repeatedly add or subtract a very
specific absolute length duration.

But some people have indicated that they'd like something a little more
flexible.  Eugene van der Pijll suggested something like this:

 my $dur = $dt1-difference( datetime = $dt2,
 units= [ 'months', 'days' ] );

This would return a duration which only included month and day values,
without minutes, seconds, or nanoseconds.

This has some obvious uses, as does requesting only days when you'd rather
get back 45 days than 1 month, 14 days.

So this makes sense to me.

_BUT_ ...

Do we really need such a flexible API?  For example, will anyone ever want
to do this:

 my $dur = $dt1-difference( datetime = $dt2,
 units= [ 'months', 'nanoseconds' ] );

My guess is that the answer here is no.

So perhaps rather than providing the above API, we should instead offer
something like this (taking a page from Date::Calc):

 # months  days
 my $dur = $dt-delta_md($dt2);

 # days only
 my $dur = $dt-delta_days($dt2);

 # hours, minutes and seconds only
 my $dur = $dt-delta_hms($dt2);

It seems to me that these 3 cover all the important possibilities, and
they have a nice simple API.

Flavio, you'd mentioned something about wanting to get years back as a
unit, but that didn't make much sense to me.  Years is _always_ equal to
months * 12, so if we have:

 my $dur = $dt-delta_md($dt2);

then $dur-years will give you what you want, right?


Anyway, comments on the above API are welcome.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/