Re: More flexibly subtract/difference methods
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
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
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
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
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
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
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
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
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 ===*/