Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Data: Dates, a DateTime replacement to perlfaq4

by BigLug (Chaplain)
on Oct 07, 2005 at 23:51 UTC ( [id://498338]=perlmeditation: print w/replies, xml ) Need Help??

Data: Dates, a DateTime replacement to perlfaq4

This morning I noticed the section in perlfaq4 relating to Dates. While the DateTime project has its own FAQ, I thought I'd take the time to answer the same questions, but restricting myself to the DateTime suite of modules. And in fact, to the core DateTime module where possible.

The true beauty of the DateTime suite comes in two parts: Firstly its completeness and secondly its accuracy.

DateTime has been planned from the start to be expandable. Namespaces were decided early on in the process to allow for alternate calendars (that's not even in this FAQ), formats, time zones, sets, spans and durations, events and utilities.

Accuracy was, likewise, always important. The developers have made certain to be as accurate as possible. This is the only perl module that uses the Olson Time Zone database to accurately represent time zones. Not only for today but back over 30 years. This makes it more accurate than Microsoft Windows who assume that time zones never change and that any rules that apply today must have applied throughout history.

Each of the following questions is taken from the current perlfaq4. This means it is by no means exhaustive, but that's why there's an official DateTime FAQ. The mailing list is also very active and the core developers and many others will be able to answer any other question quickly. If it's an emergency, look for me in IRC on both the Undernet or Freenode masquerading as Woosta.

Enough of a preamble, on with the show.

How do I get the current date and time?

my $dt = DateTime->now(time_zone => 'Local');

Getting the current time in DateTime is as simple as asking for now() however, by default, DateTime will return a an object representing a floating time zone. This floating time zone has no daylight savings time and is offset from all other time zones by 0. That is, if you compare the time-of-day in a floating time zone with the same time-of-day in a fixed time zone, the difference will be 0.

If you do not need daylight-savings, or if your time zone is unknown, then floating time zones are no problem. However, if you want to me more accurate, deadly accurate, then declare your local time zone by either using 'Local' on systems that allow it, or the Olson Time Zone name such as 'Australia/Melbourne'.

How do I find the day or week of the year?

$day_of_year = $dt->doy; $week_of_year = $dt->week_number;

Once you have a DateTime object there are many, many accessors that can return almost any sort of data you require.

Note that the first week of the year is defined by ISO as the one which contains the fourth day of January. Thus the 1st of January might be in the last week of the previous year. The year of the week can be retrieved with the ->week_year() function.

How do I find the current century or millennium?

$century = int($dt->year / 100)+1; $millennium = int($dt->year / 1000)+1;
These are simple math and have not been given their own accessors in DateTime. The century is always one more than the 'hundreds' of years in the date and the millennium one more than the 'thousands' of years in the date as this is the century/millennium the date falls in and not how many have passed.

How can I compare two dates and find the difference?

my $utc_dt = DateTime->now(time_zone => 'UTC'); $difference = $utc_dt - $dt;

The DateTime distribution comes with a module DateTime::Duration which accurately represents real durations. Normally in perl we subtract two epoch times to get a duration in seconds, however this may not be what we want. Due to daylight-savings, leap seconds and inequal month lengths not every unit of the callendar has the same number of seconds.

Consider subtracting August 1st from September 1st. If you do it in your head, the difference is obviously one month. However if we do it using epoch seconds, the difference is 2678400 seconds. Now if we want to use this duration anywhere else, this becomes a problem. Adding 2678400 seconds to September 1st returns October 2nd. September on has 30 days compared to August's 31.

This becomes even worse when there's a daylight-savings change during the period as our epoch will be 'out' from one month by 3600 seconds.

Once we have a duration object there are many things that can be done with it that are beyond the scope of this FAQ. See DateTime::Duration and DateTime::Format::Duration for more information.

How can I take a string and turn it into epoch seconds?

$string = '2005-10-08T08:42'; $parser = DateTime::Format::ISO8601; $parsed_dt = $parser->parse_datetime( $string ); $epoch_seconds = $parsed_dt->epoch;

Unlike other date and time modules, DateTime has no built-in string parser. This is mainly due to the huge number of formats that could possibly be passed in. Thus there are the DateTime::Format:: modules. These modules have been specifically designed to parse and format dates and times in various formats, all using the same API.

The above code uses a string in ISO8601 format, but just by changing the parser, the same code can parse and format in any of a large range of formats. There's even glues to both Date::Manip parsing and Date::Parse parsing for when you really don't know the format.

How can I find the Julian Day?

$julian_day = $dt->jd; $modified_julian_day = $dt->mjd;

DateTime has built in accessors for both the Julian Day and the Modified Julian Day. However, as per the original FAQ, this may not be what you want. Aparently some people refer to the day-of-year as the Julian Day, please see further up this FAQ for that.

How do I find yesterday's date?

$yesterdays_date = $dt->clone(); $yesterdays_date->subtract( days => 1 );

DateTime has full support for date and time math through the ->add(), ->subtract() and ->truncate() methods. Note, however, that that these methods are destructive. If you want to keep your original object, you will need to ->clone() it first.

Does DateTime have a year 2000 problem? Is DateTime Y2K compliant?

More so than perl's cludgy +1900 'hack' .. the year in DateTime can range anywhere from MININT to MAXINT and so depends on your operating system.

Replies are listed 'Best First'.
Re: Data: Dates, a DateTime replacement to perlfaq4 (TZ nit)
by tye (Sage) on Oct 08, 2005 at 03:02 UTC

    To be clear...

    This is the only perl module that uses the Olson Time Zone database to accurately represent time zones. Not only for today but back over 30 years.

    I've seen you make this point several times in the chatterbox, including claiming that this was required for accurately dealing with date-times represented as epoch-seconds.

    So, I'll repeat here that timezone data is irrelevent when dealing only with epoch seconds (no, you didn't claim otherwise here). And that every Unix system for decades has used the Olsen timezone database for their date conversion routines, so Perl on those platforms already uses it, so there is little point in having a module seperately deal with that on those platforms.

    Perhaps you meant to say that it is the only module that you know of that uses such on MS Windows (since you bring up MS Windows next). But that isn't what you said.

    - tye        

      I've seen you make this point several times in the chatterbox, including claiming that this was required for accurately dealing with date-times represented as epoch-seconds.

      Thanks tye, you are right that I have, in the past, made this claim. I'll also point out though that I've been convinced of the error of my ways, and admitted so in the Chatterbox, and so no longer make this claim.

      To reiterate, if all you care about is elapsed seconds (what we've started to call UTC math on the DateTime mailing list) then the time zone is irrelevent, and so is DateTime: two calls to the time() command and you're done.

      However, if you later want to turn that duration into non-second data (eg. days and months, or even minutes), then you need {time zone some form of more complex handling}. I'm sure this can be achieved on some operating systems using the TZ environment variable in some way, please feel free to show other readers how. But basically it is beyond the scope of my article -- answering perlfaq4 with DateTime.

      My claim, however, still remains that this is the only perl module using the Olson Time Zone database - on *nix systems as well as windows.

      Sure the operating system may use the database, and by playing with your TZ environment variable you can probably convert datetimes from one time zone into another. In fact I know you can do all of the above tasks without the DateTime module: read the original perlfaq4.

      The difference is that you cannot interrogate the Olson Time Zone data that is in the operating system. There is no way to ask it when the change-over from standard to summer occurs. All you can do with the OS database is keep firing epochs until you find a 3600 second discrepency.

      Update: You really just need something that understands the human calendar (not clock), like ... DateTime.

        Thank you for pointing out that additional feature that the module provides. But you don't need to know when the change-over happens in order to make accurate calculations with dates and that was your original justification for mentioning this feature. So I stand by my claim that your original statement was misleading.

        However, if you later want to turn that duration into non-second data (eg. days and months, or even minutes), then you need time zone handling.

        No. You could almost make a case for 'days', if you want to claim that a 24-hour duration should not be reported as 'one day' if it crossed a DST transition. But most of the time my preference would be to calculate durations in 'days' as simply 24-hour periods, no matter what the clock might read due to DST transitions or physical movement between timezones. And such calculations would be about comparing two date-times, and are actually impossible if you just have a duration. So a duration based on epoch seconds just plain doesn't involve timezones.

        If you instead convert both epoch second values into date-times in specific timezones and want to compare those instead of calculating the duration between them, then timezones clearly matter.

        But please explain how timezones change 60 seconds from being 1 minute or how timezones make a meaningful difference in something that would be reported in terms of 'months'.

        Surely you aren't claiming that if I start an activity 30 seconds before a DST change and finish 30 seconds after it, that I should report the duration as either 61 minutes or as -59 minutes? Or perhaps you want to make the claim that a leap second during that period means that the duration was 1 minute and 1 second (or is that 1 second less than 1 minute?). That would also be wrong, though not as obviously so.

        - tye        

Re: Data: Dates, a DateTime replacement to perlfaq4
by brian_d_foy (Abbot) on Oct 09, 2005 at 19:10 UTC

    Thanks for the work! This has actually been on my TO DO list for a bit.

    If you send a patch to perlfaq-workers AT perl.org we can get this into the latest version of the docs fairly quickly. If you don't do that, I'll have to wait until I get a bunch of free time to do it myself.

    Just a note: write complete programs for the patch so the users see the use DateTime; line. You can also show the output as a comment or something similar.

    Thanks again. :)

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
Re: Data: Dates, a DateTime replacement to perlfaq4
by hakkr (Chaplain) on Oct 10, 2005 at 16:13 UTC

    Just wondering where this modules stands in respect to Date::Manip and Date::Calc, as I think all these functions can be done with them as well.

    Any advantages/disadvantages, the docs for Date::Manip claim it is slow so does this module provide the same functions faster?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://498338]
Approved by Tanktalus
Front-paged by Tanktalus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2024-04-19 09:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found