new fan has questions/comments/suggestions
Hello! I just recently found the DateTime project after spending a good week studying international standards, chapters in various perl books, and the various existing modules in CPAN. I was disastisfied with all existing solutions, and was just about to start coding my own date object when I finally stumbled on Rolsky's perl.com article, which then let me to datetime.perl.org. I'm reading through the FAQ now, and I swear, my eyes are tearing up from the beauty of it all. I'm thrilled to see that someone is finally developing a well-thought-out, well-designed, comprehensive solution to the problem of working with dates and times in software. Of course, I can never leave well-enough alone, so here are a few questions that occurred to me while reading the FAQ. I tried looking up some of this stuff on the mailing list archive without much luck, so I apologize if this has already been discussed before. 1) Why have different 'new' and 'from_epoch' constructors? Couldn't one always use 'new' and have the module figure out what information to initiatlize itself with by seeing if either the 'year' or 'epoch' name parameter was passed? I think it would provide a cleaner and more consistent interface. Instead of: my $date1 = DateTime-new( year = 2003 month = 1, day = 1, ); my $date2 = DateTime-from_epoch( epoch = time() ); You could do this: my $date1 = DateTime-new( year = 2003 month = 1, day = 1, ); my $date2 = DateTime-new( epoch = time() ); 2) However, if you continue to provide different constructors, then when using from_epoch, why require the 'epoch' named paramter? Why not assume a single argument is an epoch value? Instead of: my $date = DateTime-from_epoch( epoch = time() ); You could do this: my $date = DateTime-from_epoch( time() ); 3) I copied the following code from the Strptime example in Section 2.7 of the FAQ: Instead of: # prints '2003-05-04 12:55:10'; print $dt-ymd . ' ' . $dt-hms; You could offer one or more of these: # prints '2003-05-04 12:55:10'; print $dt-ymd_hms; print $dt-ymdhms; # prints '2003-05-04 12:55:10.123456789'; print $dt-ymdhmsn; 4) From section 6.13: How do I find yesterday's Date? Instead of: my $dt = DateTime-now()-subtract( days = 1 ); Why not add the two most popular uses as convenience functions: my $dt = DateTime-yesterday(); my $dt = DateTime-tomorrow(); This would be especially useful in business environments where half of the code that runs daily runs to process the previous day's data (like web logs), and so yesterday's date is often the first thing calculated in a script. Anyway, great job, guys! Also, is anyone working on Sybase support for DateTime::Format::DBI? -ofer
Leap seconds / time zone bug in DateTime.pm
There's a bug somewhere in the interaction between leap seconds and time zones. In timezones with a positive offset, datetimes after local midnight but before UTC midnight already are affected by the leap second: $dt = DateTime-new( year = 1997, month = 7, day = 1, hour = 0, minute = 59, second = 59, time_zone = '+0100' ); print $dt-iso8601, \n; # prints 1997-07-01T00:59:60 In timezones with a negative offset it works the other way for datetimes between UTC midnight and local midnight. And there's something funny going on with time zones with an offset that is not an integer number of minutes... e.g. $dt = DateTime-new( year = 1997, month = 7, day = 1, hour = 0, minute = 0, second = 29, time_zone = '+00:00:30' ); print $dt-iso8601, \n; # prints 1997-07-01T23:59:90 ! I've attached a patch for the test files. I haven't looked into the DateTime.pm code, because both leap second and the time zone handling code are just too scary! Eugene -- Index: t/19leap_second.t === RCS file: /cvsroot/perl-date-time/modules/DateTime.pm/t/19leap_second.t,v retrieving revision 1.22 diff -u -r1.22 19leap_second.t --- t/19leap_second.t 20 Jul 2004 19:22:26 - 1.22 +++ t/19leap_second.t 6 Aug 2004 01:51:18 - @@ -2,7 +2,7 @@ use strict; -use Test::More tests = 74; +use Test::More tests = 78; use DateTime; @@ -106,7 +106,7 @@ is( $t-{utc_rd_secs} , 86400, rd_sec ); } -# test that we can set second to 60 +# test that we can set second to 60 (negative offset) { my $t = DateTime-new( year = 1972, month = 6, day = 30, hour = 20, minute = 59, second = 60, @@ -118,6 +118,43 @@ { my $t = DateTime-new( year = 1972, month = 6, day = 30, + hour = 21, minute = 0, second = 0, + time_zone = 'America/Sao_Paulo', + ); + +is( $t-second, 0, 'datetime just after leap second' ); +} + +# test that we can set second to 60 (positive offset) +{ +my $t = DateTime-new( year = 1972, month = 7, day = 1, + hour = 0, minute = 59, second = 60, + time_zone = '+0100', + ); + +is( $t-second, 60, 'second set to 60 in constructor' ); +} + +{ +my $t = DateTime-new( year = 1972, month = 7, day = 1, + hour = 0, minute = 59, second = 59, + time_zone = '+0100', + ); + +is( $t-second, 59, 'datetime just before leap second' ); +} + +{ +my $t = DateTime-new( year = 1972, month = 7, day = 1, + hour = 0, minute = 0, second = 29, + time_zone = '+00:00:30', + ); + +is( $t-second, 29, 'time zone +00:00:30' ); +} + +{ +my $t = DateTime-new( year = 1972, month = 6, day = 30, hour = 20, minute = 59, second = 60, time_zone = 'America/Sao_Paulo', );
Re: new fan has questions/comments/suggestions
On Thu, 5 Aug 2004, Ofer Nave wrote: 1) Why have different 'new' and 'from_epoch' constructors? Couldn't one always use 'new' and have the module figure out what information to initiatlize itself with by seeing if either the 'year' or 'epoch' name parameter was passed? I think it would provide a cleaner and more consistent interface. Instead of: my $date1 = DateTime-new( year = 2003 month = 1, day = 1, ); my $date2 = DateTime-from_epoch( epoch = time() ); You could do this: my $date1 = DateTime-new( year = 2003 month = 1, day = 1, ); my $date2 = DateTime-new( epoch = time() ); I don't like APIs which can lead to someone confusing themself. With what you suggest, I guarantee someone'd do this: DateTime-new( epoch = time(), year = 2001 ) and either ask why it doesn't work, or get annoyed at the resulting error. Plus then we'd have docs saying you can pass _either_ X and Y, or Y and Z, or X and Z. ETOOCONFUSING! 2) However, if you continue to provide different constructors, then when using from_epoch, why require the 'epoch' named paramter? Why not assume a single argument is an epoch value? Instead of: my $date = DateTime-from_epoch( epoch = time() ); You could do this: my $date = DateTime-from_epoch( time() ); Because you can still pass time_zone and locale parameters to this method. 3) I copied the following code from the Strptime example in Section 2.7 of the FAQ: Instead of: # prints '2003-05-04 12:55:10'; print $dt-ymd . ' ' . $dt-hms; You could offer one or more of these: # prints '2003-05-04 12:55:10'; print $dt-ymd_hms; print $dt-ymdhms; # prints '2003-05-04 12:55:10.123456789'; print $dt-ymdhmsn; There is a datetime method that returns the ISO8601 formatted date. The problem with what you suggest is that we then need to allow up to four separators (date components, date from time, time components, time from nanoseconds), which starts getting a bit hairy. I think $dt-ymd('/') relatively obvious, but $dt-ymdhmsn('/', 'T', ':', ',') is not so clear ;) 4) From section 6.13: How do I find yesterday's Date? Instead of: my $dt = DateTime-now()-subtract( days = 1 ); Why not add the two most popular uses as convenience functions: my $dt = DateTime-yesterday(); my $dt = DateTime-tomorrow(); This would be especially useful in business environments where half of the code that runs daily runs to process the previous day's data (like web logs), and so yesterday's date is often the first thing calculated in a script. That's a possibility, although there are _so_ many methods right now I'm leary of adding more. OTOH, these are super easy to document. -dave /*=== House Absolute Consulting www.houseabsolute.com ===*/
Re: new fan has questions/comments/suggestions
On Fri, 6 Aug 2004, Rick Measham wrote: All parameters are named in DateTime. It's a convention we use and s/All/Almost all/ There are some that take positional params. Those are usually cases where I expect it to never need more than one parameter, _or_ where it takes a list of similar parameters (strftime). But any time it takes more than one dissimilar parameter, it'll be named, and it's also named in cases where it takes one parameter now, but I thought that might change in the future. HOWEVER, that said, I'd like to see some sort of a default format method: $dt-set_default_format($strftime_format); print $dt-default_format; print Stringified with default: $dt; Someone came up to me at OSCON and asked about whether I wanted a patch for this and I said yes. I think it might've been Michael Schwern. again. Maybe these should be in DateTime::Format::Business. $biz = new DateTime::Format::Business( %monday_to_friday_nine_to_five ) $dt2 = $biz-tomorrow( DateTime-now ); Then when you're open M-F and you ask for tomorrow() on a Friday, you get Monday. This is orthogonal to whether or not those constructor end up in DateTime.pm, I think. That said, the functionalityy you're proposing would no doubt be useful for many people. I think it'd belong in DateTime::Fiscal, though. It's not really a format, so much as a way of handling complex sets and doing date math on elements of the set (eerr, does that make sense?). -dave /*=== House Absolute Consulting www.houseabsolute.com ===*/
RE: new fan has questions/comments/suggestions
On Thu, 5 Aug 2004, Ofer Nave wrote: run in epoch mode, and not even pay attention to hour. Just like it wouldn't pay attention to billybob if I passed it ( epoch = time(), billbob = 'thornton' ). Uh, have you tried that? It'll throw an exception. I'm a big believer in dying on bad input, since if the user passes a billybob parameter they probably expect that to have some effect. If you start assuming a single argument is a particular parameter, which do you go with in other cases. If you change one method, you have to be consistent. $dt = DateTime-new( 34 ); Is that 00:00:34 or 00:34:00 or 0034-00-00? Well, since year is the only required argument, you'd probably assume it was year, and therefore the date would be 0034-00-00 00:00:00.0! :) But that's probably a habit to encourage/allow. Nor is it even particularly useful, I'd think. Yes, I know, but the idea is to make it convenient to do the most common things (which is why ymd() and hms() are, in fact, available), and it seems to be like a combined ymd_hms would qualify that list. Especially being the ISO8601 standard time format, and that you often want to print both date and time. Thus the datetime/iso8601 methods (they're the same method internally). -dave /*=== House Absolute Consulting www.houseabsolute.com ===*/