From jay at mlug.missouri.edu Tue Dec 20 21:27:31 2005 From: jay at mlug.missouri.edu (Jay Buffington) Date: Tue, 20 Dec 2005 21:27:31 -0800 Subject: [PBP-pm] Working with dates Message-ID: Hi Everyone. I'd like some feedback on best practices for working with dates in perl. Here's what I came up with: Date Calculations Use CPAN's Date::Calc to do any math or comparisons of dates. See Date::Calc's recipes (http://search.cpan.org/dist/Date-Calc/Calc.pod#RECIPES) section for more examples. Example: Determine if today date is between Dec. 12th, 2005 and Dec. 19th, 2005 (inclusive): use Date::Calc qw( Date_to_Days Today ); my $lower = Date_to_Days(2005, 12, 12); my $upper = Date_to_Days(2005, 12, 19); my $date = Date_to_Days(Today()); if (($date >= $lower) && ($date <= $upper)) { print "Today is between Dec. 12th and Dec. 19th!\n"; } Returning Dates from Functions Functions or methods that need to return a date should return them in a hash reference using the same format the DateTime module takes as input. Example: Return a date that represents Tue Dec 15 19:23:45 PST 2005 return { year => 2005, month => 12, day => 15, hour => 19, minute => 23, second => 45, time_zone => '+0800', }; Displaying Dates Use CPAN's DateTime to format dates for display. Example: Print the date a file was uploaded as a RFC822-conformant date use DateTime; my $date = $file->get_upload_date(); my $dt = new DateTime( %{ $date } ); # `perldoc DateTime` for all format specifiers print $dt->strftime('%a, %d %b %Y %H:%M:%S %z'); From david at kineticode.com Wed Dec 21 10:45:59 2005 From: david at kineticode.com (David Wheeler) Date: Wed, 21 Dec 2005 10:45:59 -0800 Subject: [PBP-pm] Working with dates In-Reply-To: References: Message-ID: On Dec 20, 2005, at 9:27 PM, Jay Buffington wrote: > I'd like some feedback on best practices for working with dates in > perl. Here's what I came up with: One word: DateTime: http://search.cpan.org/dist/DateTime/ It's not the fastest, but it is by far the most accurate date and time module you can find. > Date Calculations > Use CPAN's Date::Calc to do any math or comparisons of dates. See > Date::Calc's recipes > (http://search.cpan.org/dist/Date-Calc/Calc.pod#RECIPES) section for > more examples. > > Example: > Determine if today date is between Dec. 12th, 2005 and Dec. 19th, 2005 > (inclusive): > > use Date::Calc qw( Date_to_Days Today ); > > my $lower = Date_to_Days(2005, 12, 12); > my $upper = Date_to_Days(2005, 12, 19); > > my $date = Date_to_Days(Today()); > > if (($date >= $lower) && ($date <= $upper)) { > print "Today is between Dec. 12th and Dec. 19th!\n"; > } my $lower = DateTime->new( year => 2005, month => 12, day => 12, ); my $upper = DateTime->new( year => 2005, month => 12, day => 19, ); my date = DateTime->now; if ($date > $lower && $date <= $upper) { print "Today is between Dec. 12th and Dec. 19th!\n"; } > Returning Dates from Functions > Functions or methods that need to return a date should return them in > a hash reference using the same format the DateTime module takes as > input. > > Example: > Return a date that represents Tue Dec 15 19:23:45 PST 2005 > > return { > year => 2005, > month => 12, > day => 15, > hour => 19, > minute => 23, > second => 45, > time_zone => '+0800', > }; Why not just return a DateTime object? Also, avoid offsets, as time zones with the same offsets can actually have a great deal of variation. > Displaying Dates > Use CPAN's DateTime to format dates for display. > > Example: > Print the date a file was uploaded as a RFC822-conformant date > > use DateTime; > > my $date = $file->get_upload_date(); > my $dt = new DateTime( %{ $date } ); > # `perldoc DateTime` for all format specifiers > print $dt->strftime('%a, %d %b %Y %H:%M:%S %z'); Yep! Best, David From bet at rahul.net Wed Dec 21 10:54:28 2005 From: bet at rahul.net (Bennett Todd) Date: Wed, 21 Dec 2005 18:54:28 +0000 Subject: [PBP-pm] Working with dates In-Reply-To: References: Message-ID: <20051221185428.GF26160@rahul.net> I'm not sure there's a one-size-fits-all best practice here. For external representations, I really like ISO 8601 / RFC 3339, like 2005-12-21T18:50:14Z. For many sorts of interval calculations, I'm quite happy using time_t (integer seconds since 1970-01-01T00:00:00Z in a POSIX fantasy world where leap seconds don't exist), converting printable => time_t with Date::Parse (from TimeDate), and back with Date::Format (likewise) if I need Date::Parse, POSIX::strftime if not. For quick one-offs, or anything where performance isn't that critical (i.e. I'm not doing a zillion date calculations) Date::Manip is comforting to have around. -Bennett -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051221/37109057/attachment.bin From jay at mlug.missouri.edu Wed Dec 21 13:24:29 2005 From: jay at mlug.missouri.edu (Jay Buffington) Date: Wed, 21 Dec 2005 13:24:29 -0800 Subject: [PBP-pm] Working with dates In-Reply-To: <20051221185428.GF26160@rahul.net> References: <20051221185428.GF26160@rahul.net> Message-ID: > Why not just return a DateTime object? It sounds like the general consense is to use DateTime for most things, and I agree. But, for a module that returns a date, I don't want to lock the user into using DateTime, since its not a standard module. If they want to, great, but some uses may not need that power (or overhead). > Also, avoid offsets, as time zones with the same offsets can actually have a > great deal of variation. So time_zone should always be something like 'America/Los-Angeles'. That seems strange to me, but it makes sense. > You can return the same hash from a function (though I'd personally > return a hash rather than a hashref) and feed it straight into > DateTime's constructor DateTime breaks the "Named Arguments" best practice from the PBP book (chapter 9, page 182). It seems intuitive to me that the opposite should be true and that returning hashes is bad for similiar reasons. i.e. what if the users does something like this: my @date = get_date(); Thanks, Jay On 12/21/05, Bennett Todd wrote: > I'm not sure there's a one-size-fits-all best practice here. > > For external representations, I really like ISO 8601 / RFC 3339, > like 2005-12-21T18:50:14Z. > > For many sorts of interval calculations, I'm quite happy using > time_t (integer seconds since 1970-01-01T00:00:00Z in a POSIX > fantasy world where leap seconds don't exist), converting printable > => time_t with Date::Parse (from TimeDate), and back with > Date::Format (likewise) if I need Date::Parse, POSIX::strftime if > not. > > For quick one-offs, or anything where performance isn't that > critical (i.e. I'm not doing a zillion date calculations) > Date::Manip is comforting to have around. > > -Bennett > > > _______________________________________________ > PBP-pm mailing list > PBP-pm at pm.org > http://mail.pm.org/mailman/listinfo/pbp-pm > > > > From bet at rahul.net Wed Dec 21 13:56:39 2005 From: bet at rahul.net (Bennett Todd) Date: Wed, 21 Dec 2005 21:56:39 +0000 Subject: [PBP-pm] Working with dates In-Reply-To: References: <20051221185428.GF26160@rahul.net> Message-ID: <20051221215639.GA4228@rahul.net> 2005-12-21T21:24:29 Jay Buffington: > > Also, avoid offsets, as time zones with the same offsets can > > actually have a great deal of variation. > So time_zone should always be something like 'America/Los-Angeles'. There are two different use cases. When you are doing timezone conversions, or specifying a timezone for any use over a range of times, zoneinfo database refs, mostly Continent/City, are the very best way to go; this stuff mutates many times a year, but a large team of people are keeping the ado database up to date. However, when you want to have an external representation of a single time object (or a whole file full of 'em), specifying the zoneinfo database ref requires a large, variable-length field, and a whack of a lot of extra computation to robustly process it. ISO 8601 / RFC 3339 timestamps allow you to specify numerical offsets, which robustly describe a single time entry. The key difference is that a timestamp doesn't have weirdly mutating summer time shifts changing the conversion rules. -Bennett -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051221/816bb07d/attachment.bin From david at kineticode.com Wed Dec 21 14:40:36 2005 From: david at kineticode.com (David Wheeler) Date: Wed, 21 Dec 2005 14:40:36 -0800 Subject: [PBP-pm] Working with dates In-Reply-To: References: <20051221185428.GF26160@rahul.net> Message-ID: <57F05D68-1439-43A0-8220-0F5F011C56C2@kineticode.com> On Dec 21, 2005, at 1:24 PM, Jay Buffington wrote: >> Why not just return a DateTime object? > It sounds like the general consense is to use DateTime for most > things, and I agree. But, for a module that returns a date, I don't > want to lock the user into using DateTime, since its not a standard > module. If they want to, great, but some uses may not need that power > (or overhead). You're going to find a *lot* of useful modules you'll want to use that aren't included with Perl. DBI is the first that comes to mind. > So time_zone should always be something like 'America/Los-Angeles'. > That seems strange to me, but it makes sense. Yes, although it's "America/Los_Angeles". It may seem strange, but think of it this way: If you set it to +0800, what time zone is that? Daylight savings or standard time? These things have an effect, even within an offset. Offsets should be considered, at best, a rough approximation. The Olson database is considered the standard, IIRC. > DateTime breaks the "Named Arguments" best practice from the PBP book > (chapter 9, page 182). It seems intuitive to me that the opposite > should be true and that returning hashes is bad for similiar reasons. > i.e. what if the users does something like this: > my @date = get_date(); Just because a module does not adhere to the best practices laid out in the book (if for no other reason than that it pre-dates the book by several years), that does not make it a bad module. Indeed, there are very good reasons to argue that a list is a better practice than a hash, and I believe that Dave Rolsky holds to those reasons. But from your POV, it just makes the use of the module a bit different than the use of other modules you write yourself. It's more important to use a module as a best practice than to not use it because it does not adhere to some defined set of best practices. Best, David (Theory) From bruce at 2MinuteExplainer.com Wed Dec 21 15:16:41 2005 From: bruce at 2MinuteExplainer.com (Bruce McKenzie) Date: Wed, 21 Dec 2005 18:16:41 -0500 Subject: [PBP-pm] Working with dates In-Reply-To: <57F05D68-1439-43A0-8220-0F5F011C56C2@kineticode.com> References: <20051221185428.GF26160@rahul.net> <57F05D68-1439-43A0-8220-0F5F011C56C2@kineticode.com> Message-ID: <43A9E259.2050205@2MinuteExplainer.com> I'm certainly no expert -- but some of the people who use your code won't be, either. Until I started using the DateTime module, I always had to review the documentation and scratch my head a lot to read or write any code involving dates. Now, I only have to to look in the DateTime dox every so often, and, occasionally, look up a timezone. I strongly advise standardizing on DateTime, and use other modules only when the need for speed or imprecision (Date::Manip understands "last Wednesday") is paramount. I *hadn't* thought about whys and wherefores of the "America/LosAngeles" method before -- so I found the comment below interesting. > > Yes, although it's "America/Los_Angeles". It may seem strange, but > think of it this way: If you set it to +0800, what time zone is that? > Daylight savings or standard time? These things have an effect, even > within an offset. Offsets should be considered, at best, a rough > approximation. The Olson database is considered the standard, IIRC. > > Cheers Bruce From jhoblitt at ifa.hawaii.edu Wed Dec 21 15:48:27 2005 From: jhoblitt at ifa.hawaii.edu (Joshua Hoblitt) Date: Wed, 21 Dec 2005 13:48:27 -1000 Subject: [PBP-pm] Working with dates In-Reply-To: <20051221185428.GF26160@rahul.net> References: <20051221185428.GF26160@rahul.net> Message-ID: <20051221234827.GB14652@ifa.hawaii.edu> On Wed, Dec 21, 2005 at 06:54:28PM +0000, Bennett Todd wrote: > For external representations, I really like ISO 8601 / RFC 3339, > like 2005-12-21T18:50:14Z. > > For many sorts of interval calculations, I'm quite happy using > time_t (integer seconds since 1970-01-01T00:00:00Z in a POSIX > fantasy world where leap seconds don't exist), converting printable > => time_t with Date::Parse (from TimeDate), and back with > Date::Format (likewise) if I need Date::Parse, POSIX::strftime if > not. I'd be hesitant to suggest using POSIX.pm is a 'Best Practice' as it sucks up 900K-1500K of memory depending on the platform. I'd also like to point out that DateTime natively support an ISO8601 compliant format. e.g. my $dt = DateTime->now; print $dt->iso8601; There is also a module called DateTime::Format::IS08601 that parses a wide range of IS08601:2000(E) formats. my $dt = DateTime::Format::ISO8601->parse_datetime( $string ); (Note: I am the author of DateTIme::Format::ISO8601) It's not that I have anything against using 'Duct Tape' solutions, it's just that in this particular instance using one is no longer required. Cheers, -J -- -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051221/6b9bd0c3/attachment.bin From jhoblitt at ifa.hawaii.edu Wed Dec 21 15:52:53 2005 From: jhoblitt at ifa.hawaii.edu (Joshua Hoblitt) Date: Wed, 21 Dec 2005 13:52:53 -1000 Subject: [PBP-pm] Working with dates In-Reply-To: References: <20051221185428.GF26160@rahul.net> Message-ID: <20051221235253.GC14652@ifa.hawaii.edu> On Wed, Dec 21, 2005 at 01:24:29PM -0800, Jay Buffington wrote: > DateTime breaks the "Named Arguments" best practice from the PBP book > (chapter 9, page 182). It seems intuitive to me that the opposite > should be true and that returning hashes is bad for similiar reasons. > i.e. what if the users does something like this: > my @date = get_date(); Huh? What DateTime method returns a hash (the constructors and mutators return blessed hash reference but that's hardly the same thing)? Does POSIX.pm follow PBP or Date::Parse or Date::Manip? Cheers, -J -- -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051221/1a17eb6b/attachment.bin From jerry.wilcox at gmail.com Wed Dec 21 16:07:19 2005 From: jerry.wilcox at gmail.com (Jerry Wilcox) Date: Wed, 21 Dec 2005 16:07:19 -0800 Subject: [PBP-pm] Working with dates Message-ID: > I'd like some feedback on best practices for working with dates in > perl. Here's what I came up with: > [snip] > Use CPAN's Date::Calc to do any math or comparisons of dates. See > Date::Calc's recipes I like to use only ISO date representations and I almost exclusively use Sullivan Beck's excellent Date::Manip routines for manipulating, converting, and calculating dates. There are faster routines around which might be worth looking into if I were doing millions of such calculations, but I seldom encounter situations where those are required. Date::Manip also supports Holiday and Event descriptions, which I use extensively along with calculations of business days. -- Jerry Wilcox (jerry.wilcox at gmail.com) After silence, that which comes nearest to expressing the inexpressible is music. - Aldous Huxley From bet at rahul.net Thu Dec 22 04:44:31 2005 From: bet at rahul.net (Bennett Todd) Date: Thu, 22 Dec 2005 12:44:31 +0000 Subject: [PBP-pm] Working with dates In-Reply-To: <20051221234827.GB14652@ifa.hawaii.edu> References: <20051221185428.GF26160@rahul.net> <20051221234827.GB14652@ifa.hawaii.edu> Message-ID: <20051222124430.GA5033@rahul.net> 2005-12-21T23:48:27 Joshua Hoblitt: > I'd be hesitant to suggest using POSIX.pm is a 'Best Practice' as > it sucks up 900K-1500K of memory depending on the platform. POSIX is in the core. If I need Date::Parse I'll use Date::Format, but if I only need POSIX::strftime I lose one external dependency. I don't think I'll write programs that depend on the complex chain of DateTime modules when I could just use a core module. And that reminds me, another thing I like about Date::Manip is its stand-alone flavour. -Bennett -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051222/fee2e97e/attachment.bin From david at kineticode.com Thu Dec 22 09:44:27 2005 From: david at kineticode.com (David Wheeler) Date: Thu, 22 Dec 2005 09:44:27 -0800 Subject: [PBP-pm] Working with dates In-Reply-To: <20051222124430.GA5033@rahul.net> References: <20051221185428.GF26160@rahul.net> <20051221234827.GB14652@ifa.hawaii.edu> <20051222124430.GA5033@rahul.net> Message-ID: On Dec 22, 2005, at 4:44 AM, Bennett Todd wrote: > I don't think I'll write programs that depend on the complex chain > of DateTime modules when I could just use a core module. Sure. You can make an argument for best practice vs. convenience. Me, I'll generally go with the best practice and figure out how to make it more convenient as necessary. Best, David From jhoblitt at ifa.hawaii.edu Thu Dec 22 15:55:02 2005 From: jhoblitt at ifa.hawaii.edu (Joshua Hoblitt) Date: Thu, 22 Dec 2005 13:55:02 -1000 Subject: [PBP-pm] Working with dates In-Reply-To: <20051222124430.GA5033@rahul.net> References: <20051221185428.GF26160@rahul.net> <20051221234827.GB14652@ifa.hawaii.edu> <20051222124430.GA5033@rahul.net> Message-ID: <20051222235502.GA3709@ifa.hawaii.edu> On Thu, Dec 22, 2005 at 12:44:31PM +0000, Bennett Todd wrote: > POSIX is in the core. > > If I need Date::Parse I'll use Date::Format, but if I only need > POSIX::strftime I lose one external dependency. > > I don't think I'll write programs that depend on the complex chain > of DateTime modules when I could just use a core module. > > And that reminds me, another thing I like about Date::Manip is its > stand-alone flavour. Is the point of this thread to discuss which date and time handling modules have superior syntax, semantics, and implementation? If so, then the argument "that modules not included in the p5 core" isn't relevant to the discussion. That's like saying you think it's a bad practice to use [n]curses because it's not included in libc. -J -- -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mail.pm.org/pipermail/pbp-pm/attachments/20051222/000971e5/attachment.bin From Steve.Tolkin at FMR.COM Fri Dec 23 13:20:55 2005 From: Steve.Tolkin at FMR.COM (Tolkin, Steve) Date: Fri, 23 Dec 2005 16:20:55 -0500 Subject: [PBP-pm] Handling fractions of seconds Message-ID: <493A37523A8D17448240DA1DDDE924B40686CD92@MSGBOSCLD2WIN.DMN1.FMR.COM> One problem with Time::Local is that it does not handle fractions of seconds. When I discovered this the hard way (error message) I looked for the "use integer;" line I expected at the top of the module and removed it. Then if failed when the number of seconds was > 59 e.g. 59.7. So I fixed that check to allow up to 60. But then I discovered that it produced wrong results! (I tested that by using "scalar localtime(...)" to convert its output number back to a string format, and the output was very different from the input.) So I put the "use integer;" back and now I manually add the number of seconds since this epoch like this: my $end_seconds = timelocal(0,$min,$hour,$mday,$mon,$year)+$sec; I am using this to compute elapsed time between two events that can be less than 1 second apart. They can cross a time boundary at any grain (e.g. minute, hour, day). I also looked at Date::Manip but the POD seems to suggest it also does not handle fractions of seconds, saying: 4. The amount of time between two dates. ... $delta=&DateCalc($date1,$date2,\$err); => 0:0:WK:DD:HH:MM:SS the weeks, days, hours, minutes, and seconds between the two Since it does not show SS.nnn I guess it does not support fractions of seconds. Two questions: 1. What date module supports fractional seconds. Ideally it would be in the perl 5 core. 2. I thought use integer was supposed to be purely an performance optimization, If this is true there is a bug in Time::Local and I will try to create a small reproducible test case later/ Thanks, Steve --- Steven Tolkin There is nothing so practical as a good theory. Comments are by me, not Fidelity Investments, its subsidiaries or affiliates. From david at kineticode.com Fri Dec 23 13:57:16 2005 From: david at kineticode.com (David Wheeler) Date: Fri, 23 Dec 2005 13:57:16 -0800 Subject: [PBP-pm] Handling fractions of seconds In-Reply-To: <493A37523A8D17448240DA1DDDE924B40686CD92@MSGBOSCLD2WIN.DMN1.FMR.COM> References: <493A37523A8D17448240DA1DDDE924B40686CD92@MSGBOSCLD2WIN.DMN1.FMR.COM> Message-ID: <0CD8E444-CA5E-45E9-9943-DDC3EEFBDE0B@kineticode.com> On Dec 23, 2005, at 1:20 PM, Tolkin, Steve wrote: > Two questions: > 1. What date module supports fractional seconds. > Ideally it would be in the perl 5 core. DateTime supports nanoseconds, and of course all multiples of nanoseconds. The relevant methods include: fractional_second() millisecond() microsecond() nanosecond() It's not in the core, of course. Perhaps someone can convince P5P to add it for Perl 5.10. Best, David From autarch at urth.org Fri Dec 23 14:59:16 2005 From: autarch at urth.org (Dave Rolsky) Date: Fri, 23 Dec 2005 16:59:16 -0600 (CST) Subject: [PBP-pm] Handling fractions of seconds In-Reply-To: <0CD8E444-CA5E-45E9-9943-DDC3EEFBDE0B@kineticode.com> References: <493A37523A8D17448240DA1DDDE924B40686CD92@MSGBOSCLD2WIN.DMN1.FMR.COM> <0CD8E444-CA5E-45E9-9943-DDC3EEFBDE0B@kineticode.com> Message-ID: On Fri, 23 Dec 2005, David Wheeler wrote: > On Dec 23, 2005, at 1:20 PM, Tolkin, Steve wrote: > >> Two questions: >> 1. What date module supports fractional seconds. >> Ideally it would be in the perl 5 core. > > DateTime supports nanoseconds, and of course all multiples of > nanoseconds. The relevant methods include: > > fractional_second() > millisecond() > microsecond() > nanosecond() > > It's not in the core, of course. Perhaps someone can convince P5P to > add it for Perl 5.10. Only if someone else besides me wants to maintain it _in_ the core. They still use Perforce for Perl source control, which makes dealing with it a PITA, and I have plenty of work to do without adding more work to sync things up every time I make a release. It's got a buttload of dependencies, too. Personally, I'd just as soon see _nothing_ in the core so folks who complain about "it's not core" would have nothing to complain about ;) -dave /*=================================================== VegGuide.Org www.BookIRead.com Your guide to all that's veg. My book blog ===================================================*/ From rick at measham.id.au Wed Dec 21 04:36:18 2005 From: rick at measham.id.au (Rick Measham) Date: Wed, 21 Dec 2005 23:36:18 +1100 Subject: [PBP-pm] Fwd: Working with dates In-Reply-To: <20051221053555.GB17070@ifa.hawaii.edu> References: <20051221053555.GB17070@ifa.hawaii.edu> Message-ID: <43A94C42.6000102@measham.id.au> ----- Forwarded message from Jay Buffington ----- > > Hi Everyone. > > I'd like some feedback on best practices for working with dates in > perl. Here's what I came up with: --- >8 --- > Displaying Dates > Use CPAN's DateTime to format dates for display. If you're going to be using DateTime, then stick with DateTime. It probably does everything you need*. my $lower = new DateTime(year => 2005, month => 12, day => 12 ); my $upper = new DateTime(year => 2005, month => 12, day => 19 ); my $date = DateTime->today(); if (($date >= $lower) && ($date <= $upper)) { print "Today is between Dec. 12th and Dec. 19th!\n"; } Plus, each of those three DateTimes can be in a different time zone and the result will still return the truth. You can return the same hash from a function (though I'd personally return a hash rather than a hashref) and feed it straight into DateTime's constructor: my $date1 = DateTime->new( %{ yourFunction() } ); my $date2 = DateTime->new( myFunction() ); Cheers! Rick Measham * If it doesn't do everything you need, then let the datetime list know so we can consider it! -- "War is God's way of teaching Americans geography." -- Ambrose Bierce