DateTime
view release on metacpan or search on metacpan
If you do not care about time zones or leap seconds, use the "floating"
timezone:
my $dt = DateTime->now( time_zone => 'floating' );
Math done on two objects in the floating time zone produces very predictable
results.
Note that in most cases you will want to start by creating an object in a
specific zone and _then_ convert it to the floating time zone. When an object
goes from a real zone to the floating zone, the time for the object remains the
same.
This means that passing the floating zone to a constructor may not do what you
want.
my $dt = DateTime->now( time_zone => 'floating' );
is equivalent to
my $dt = DateTime->now( time_zone => 'UTC' )->set_time_zone('floating');
This might not be what you wanted. Instead, you may prefer to do this:
my $dt = DateTime->now( time_zone => 'local' )->set_time_zone('floating');
- use UTC for all calculations
If you do care about time zones (particularly DST) or leap seconds, try to use
non-UTC time zones for presentation and user input only. Convert to UTC
immediately and convert back to the local time zone for presentation:
my $dt = DateTime->new( %user_input, time_zone => $user_tz );
$dt->set_time_zone('UTC');
# do various operations - store it, retrieve it, add, subtract, etc.
$dt->set_time_zone($user_tz);
print $dt->datetime;
- math on non-UTC time zones
If you need to do date math on objects with non-UTC time zones, please read the
caveats below carefully. The results `DateTime` produces are predictable,
correct, and mostly intuitive, but datetime math gets very ugly when time zones
are involved, and there are a few strange corner cases involving subtraction of
two datetimes across a DST change.
If you can always use the floating or UTC time zones, you can skip ahead to
["Leap Seconds and Date Math"](#leap-seconds-and-date-math)
- date vs datetime math
If you only care about the date (calendar) portion of a datetime, you should
use either `$dt->delta_md` or `$dt->delta_days`, not `$dt->subtract_datetime`. This will give predictable, unsurprising results,
free from DST-related complications.
- $dt->subtract\_datetime and $dt->add\_duration
You must convert your datetime objects to the UTC time zone before doing date
math if you want to make sure that the following formulas are always true:
$dt2 - $dt1 = $dur
$dt1 + $dur = $dt2
$dt2 - $dur = $dt1
Note that using `$dt->delta_days` ensures that this formula always works,
regardless of the time zones of the objects involved, as does using `$dt->subtract_datetime_absolute`. Other methods of subtraction are not always
reversible.
- never do math on two objects where only one is in the floating time zone
The date math code accounts for leap seconds whenever the `DateTime` object is
not in the floating time zone. If you try to do math where one object is in the
floating zone and the other isn't, the results will be confusing and wrong.
### Adding a Duration to a DateTime
The parts of a duration can be broken down into five parts. These are months,
days, minutes, seconds, and nanoseconds. Adding one month to a date is
different than adding 4 weeks or 28, 29, 30, or 31 days. Similarly, due to DST
and leap seconds, adding a day can be different than adding 86,400 seconds, and
adding a minute is not exactly the same as 60 seconds.
We cannot convert between these units, except for seconds and nanoseconds,
because there is no fixed conversion between most pairs of units. That is
because of things like leap seconds, DST changes, etc.
`DateTime` always adds (or subtracts) days, then months, minutes, and then
seconds and nanoseconds. If there are any boundary overflows, these are
normalized at each step. For the days and months the local (not UTC) values are
used. For minutes and seconds, the local values are used. This generally just
works.
This means that adding one month and one day to February 28, 2003 will produce
the date April 1, 2003, not March 29, 2003.
my $dt = DateTime->new( year => 2003, month => 2, day => 28 );
$dt->add( months => 1, days => 1 );
# 2003-04-01 - the result
On the other hand, if we add months first, and then separately add days, we end
up with March 29, 2003:
$dt->add( months => 1 )->add( days => 1 );
# 2003-03-29
We see similar strangeness when math crosses a DST boundary:
my $dt = DateTime->new(
year => 2003,
month => 4,
day => 5,
hour => 1,
minute => 58,
time_zone => "America/Chicago",
);
$dt->add( days => 1, minutes => 3 );
# 2003-04-06 02:01:00
$dt->add( minutes => 3 )->add( days => 1 );
# 2003-04-06 03:01:00
( run in 2.198 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )