perltutorial
monsterzero
<P>The DateTime suite of modules was created to address a very fundimential
problem with dates in perl. There are several different packages on
CPAN with overlapping functionality, but it was difficult to take dates
in one package and convert them to another which you would often have to
do to get a function from a different package.The primary goal of
DateTime is to solve this problem. The DateTime project also has the
Olson Time Zone database support built in. This database contains code
and data that represent the history of local time for many locations around the globe.
It is updated to reflect changes made by political bodies to UTC offsets
and daylight-saving rules. This database is used by several implementations,
including the GNU C Library used in GNU/Linux.</P>
<P>Currently the project can be divided into several categories.</P>
<P>Core functionality - This contains the core datetime object along with time zone
handling. In addition there are modules that handle various types of datetime
sets, and preforming set math operations on them.
</P>
<PRE>
Parsing and formatting - This set contains the modules that help getting
dates into and out of datetime.</PRE>
<P>Events and sets - This contains various modules that are based on generating
an event or set of events. Events can be any event like easter sunrise/sunset.
</P>
<PRE>
Non-Gregorian calenders - This contains the modules for converting dates to/from other
calenders like Julian, Mayan and others.</PRE>
<P>
<H2><A NAME="using datetime">Using DateTime</A></H2>
<P>Let's take a look at how we can use DateTime to create a date in perl.
Having downloaded it from CPAN and installed it in the normal manner
using it is as simple as:</P>
<CODE>
use strict;
use warnings;
use DateTime;
my $dt1 = DateTime->new( year => 2003,
month => 8,
day => 20,
hour => 0,
minute => 0,
second => 0,
);
</CODE>
<P>Or since you most often want the current date and/or time you can simply do</P>
<CODE>
my $dt2 = DateTime->now(time_zone=>'local');
my $dt3 = DateTime->today(time_zone=>'local');
</CODE>
<P>The difference between the to is that <CODE>DateTime->now</CODE> not only has the
date but also the time. whereas <CODE>DateTime->today</CODE> is truncated to the day.
Both of these will take the time zone offset. On some operating systems
(windows) setting the time_zone param to local will not work unless the TZ
environment variable is set.</P>
<P>Now that I have something in DateTime how can I get it out? DateTime provides some basic output routines. Some examples are</P>
<CODE>
print $dt1->ymd('-'); # produces 2003-08-20
print $dt1->mdy('-'); # produces 08-20-2003
print $dt1->datetime(); # produces 2003-08-20T00:00:00</CODE>
<P>The outputs are self explanatory except for the <CODE>DateTime()</CODE> method. The
output is like <CODE>2003-08-20T00:00:00</CODE>. I mainly use this for debugging and
testing purposes.</P>
<P>Converting between timezones is what makes DateTime shine.</P>
<CODE>
my $dt1 = DateTime->new( year => 2003,
month => 8, day => 26,
hour => 21,
time_zone => 'America/Chicago' );
</CODE>
<P>What time is it in Helsinki, when it is 9pm in Chicago?</P>
<CODE>
$dt2 = $dt1->clone->set_time_zone( 'Europe/Helsinki' );
print $dt2->datetime, "\n";
</CODE>
<P>One of the big problems with handling dates is daylight savings time.
Since DateTime used the Olson database, DateTime can do it all for you.</P>
<CODE>
my $dt1 = DateTime-> new (
year =>'1998',
month =>'4',
day =>'4',
hour =>'21',
time_zone =>'local'
);
$dt1->add(hours =>10);
print $dt1->datetime ,"\n";
</CODE>
<P>This will print <CODE>1998-04-05T08:00:00</CODE>. Notice that the time is 8:00 not
7:00 this is because on April 5 1998 at 2:00 am is when daylight savings
time takes effect here in Los Angeles. DateTime is smart enough to know
the DST rules and makes the correction.</P>
<P>But what if I have a date that is outside of my program (external
source) well there are currently 14 formatting/parsing modules available
to datetime. Chances are one of them will parse the date for you. Here
is an example.</P>
<CODE>
use strict;
use warnings;
use DateTime::Format::HTTP;
my $date = 'Mon, Feb 3 04:00:00 GMT 2003';
my $dt_class = 'DateTime::Format::HTTP';
my $dt = $dt_class->parse_datetime($date);
print $dt_class->format_datetime($dt);
</CODE>
<P>In this example I have chosen to use the DateTime::Format::HTTP module
created by Iain Truskett. Basicly, I have a date (in HTTP format) and I
use the parse_datetime method to convert the string to a datetime
object. Then I output the date in GMT ASCII time format. One thing to
notice is that the formatting modules all have a parse_datetime (for
getting strings into) and format_datetime (for outputting DT objects)
methods. This makes it easy to use all of the formatting modules since
they all have a some what standard interface.</P>
<P>This is all fine and good but what happens when you do not know the
format of the date. Well the other day someone came to comp.lang.perl.misc
and asked a very similer question. He asked:</P>
<P>Hello,
I just came from cpan, after doing some searches and before I get a module,
wanted to ask if any one out there knows of a module that takes an array of
dates and sort them regardless of the date format.</P>
<P>Good question!! lets see if Datetime can help with this. I checked the DateTime
FAQ and came up with something like this.</P>
<CODE>
use strict;
use warnings;
use DateTime;
my @new_dates;
my @dates =(``Sat, 19 Jul 2003 15:53:45 -0500'',
``1996-02-03'',``08-Feb-1998 14:15:29 GMT'',
``19850411'',
``1985-04-12'',
``1985-04'',
``18 Feb 2003 06:54:23 -0000'',
``+001999-04-12'',
``01 Jan 2003 07:03:06 -0000'',
``1982-102'',
``21 Mar 2001 09:15:32 -0800'',
``06 Jan 2002 10:08:00 -0000'',
``09 Jan 2003 11:32:40 -0500'',
);
foreach my $new_date (@dates) {
push(@new_dates,DateTime::Format::Mytest->parse_datetime($new_date) );}
print map {$_->datetime(), ``\n''} sort @new_dates;
package DateTime::Format::Mytest;
use DateTime::Format::HTTP;
use DateTime::Format::Mail;
use DateTime::Format::ISO8601;
use DateTime::Format::Builder (
parsers => { parse_datetime => [
sub { eval { DateTime::Format::HTTP->parse_datetime($_[1] ) } },
sub { eval { DateTime::Format::Mail->parse_datetime($_[1] ) } },
sub { eval {
DateTime::Format::ISO8601->parse_datetime( $_[1]) } },
] }
);
</CODE>
Now the OP did not specify what format his dates were in so I just
had to make some up. In the above example the real workhorse is in
the package DateTime::Format::Mytest, what I have done is chain
together three different DateTime format modules in order to parse the
dates. Once I parsed the dates (and placed them in the new_dates array)
I just sorted the new array using the standard sort function.</P>
<P>Ok, now that I can create a date let's look at how to compare 2
different dates. In DateTime we can use the compare method for this.</P>
<P>Here is an example:</P>
<CODE>
my $dt = DateTime-> new(year => 2002,
month=> 8,
);
my dt2 = DateTime->new(year => 2003,
month=> 2,
);
my $cmp = DateTime->compare($dt, $dt2);
</CODE>
<P>This will set the $cmp variable to either -1,0 or 1. If $dt is less than
$dt2 the value of $cmp will be -1. If $dt is equal to $dt2 the value
will be 0 and if $dt is greater than $dt2 the value will be 1. As you
can see this is using the built in function compare. You can also use
the standard perl function to accomplish the same thing.</P>
<CODE>
if ($dt > $dt2) {do ....;}
elsif($dt == $dt2) {do something else;}
elsif($dt < $dt2) {do still something else...;}
</CODE>
<P>All of these work as expected!</P>
<P>Date math is very easy with DateTime.Here is an example.</P>
<CODE>
my $dt1 = DateTime->now();
my $dt2 = $dt1->clone->subtract( weeks => 1);
</CODE>
<P>This will produce a date one week earler. I can use days, months, years
and all work as expected.</P>
<P>
<HR>
<H1><A NAME="conclusion">Conclusion</A></H1>
<P>The DateTime project is still being developed. However, I have found it
to be extreamly useful. It has made dealing with date and times in perl much
simpler.</P>
<P>
<H2><A NAME="see also">SEE ALSO</A></H2>
<P>For more information about the datetime project please see
the DateTime.perl.org website There is also a mailing list. You can
subscribe by sending a message to datetime-subscribe@perl.org.</P>
<H2><A NAME="credits">Credits</A></H2>
<P>Major thanks goes to Dave Rolsky for writing the DateTime module and to
the rest of the developers at the datetime project.</P>