NAME
Date::Easy::Datetime - easy datetime class
VERSION
This document describes version 0.07 of Date::Easy::Datetime.
SYNOPSIS
use Date::Easy::Datetime ':all';
# default timezone is your local zone
my $dt = datetime("3/31/2012 7:38am");
# addition and subtraction work in increments of seconds
my $this_time_yesterday = now - 60*60*24;
my $after_30_minutes = now + 30 * 60;
say "$dt was ", now - $dt, " seconds ago";
# or can add or subtract months
my $next_month = now->add_months(1);
my $last_month = now->add_months(-1);
# if you prefer UTC
my $utc = datetime(UTC => "2016-03-07 01:22:16PST-0800");
# or UTC for all your objects
use Date::Easy::Datetime 'UTC';
say datetime("Jan 1 2000 midnight")->time_zone;
# prints "UTC"
my $yr = $dt->year;
my $mo = $dt->month;
my $da = $dt->day;
my $hr = $dt->hour;
my $mi = $dt->minute;
my $sc = $dt->second;
my $ep = $dt->epoch;
my $zo = $dt->time_zone;
my $qr = $dt->quarter;
my $dw = $dt->day_of_week;
say $dt->strftime("%Y-%m-%dT%H:%M:%S%z");
say $dt->iso8601;
say $dt->as("/Ymd");
my $tp = $dt->as('Time::Piece');
DESCRIPTION
A Date::Easy::Datetime object contains a Time::Piece object and provides a slightly different UI to access it. In typical usage, you will either use the datetime
constructor to convert a human-readable string to a datetime, or the now
function to return the current datetime (i.e. the datetime object corresponding to time()
). Both are exported with the :all
tag; nothing is exported by default.
Arithmetic operators (plus and minus) either add or subtract seconds to or from the datetime object. Accessor methods use the naming conventions of DateTime (rather than those of Time::Piece).
Datetime objects are immutable.
See Date::Easy for more general usage notes.
USAGE
Zone Specifiers
There are three zone specifiers that Date::Easy::Datetime understands:
local
'local' means to use the local timezone, however that is determined (often this is via the $TZ
environment variable, but your system may differ). That is, under 'local' Date::Easy::Datetime will use localtime
and timelocal
(technically, timelocal_modern
, from Time::Local) to deal with epoch seconds.
UTC
'UTC' means to use the UTC timzeone, which essentialy means to ignore timezone altogether. That is, under 'UTC' Date::Easy::Datetime will use gmtime
and timegm
(technically, timegm_local
, from Time::Local) to deal with epcoh seconds.
GMT
As far as Date::Easy::Datetime is concerned, 'GMT' is always exactly equivalent to 'UTC'. It's just an alias for people who prefer that term.
Import Parameters
After the use Date::Easy::Datetime
statement, you can add parameters. These can be one of three things, in any order.
Function names
These are passed on to Exporter to export only certain function names. The only names currently recognized are now
and datetime
.
Exporter tags
These are also passed on to Exporter. The only tag currently recognized is :all
, which means to import all the names above.
Zone specifier
These change the default zone specifier for all datetime objects. If you specify more than one, the last one wins (but don't do that). There is only one default zone specifier, so don't do this in a module.
Possible values are listed under "Zone Specifiers". 'local' is the default, so it's redundant to pass that in, but you may just wish to be explicit. As always, 'UTC' and 'GMT' are equivalent.
Constructors
Date::Easy::Datetime->new
Returns the same as "now".
Date::Easy::Datetime->new($e)
Takes the given epoch seconds and turns it into a datetime using the default zone specifier.
Date::Easy::Datetime->new($zone_spec => $e)
Takes the given epoch seconds and turns it into a datetime using the given zone specifier.
Date::Easy::Datetime->new($y, $m, $d, $hr, $mi, $sc)
Takes the given year, month, day, hours, minutes, and seconds, and turns them into a datetime object, using the default zone specifier. Month and day are human-centric (i.e., 1-based, not 0-based). Year should be a 4-digit year; if you pass in a 2-digit year, you get a year bewteen 1900 and 1999, even if you use the last 2 digits of the current year.
Date::Easy::Datetime->new($zone_spec => $y, $m, $d, $hr, $mi, $sc)
Takes the given year, month, day, hours, minutes, and seconds, and turns them into a datetime object, using the given zone specifier. Month and day are human-centric (i.e., 1-based, not 0-based). Year should be a 4-digit year; if you pass in a 2-digit year, you get a year bewteen 1900 and 1999, even if you use the last 2 digits of the current year.
Date::Easy::Datetime->new($obj)
If the sole argument to new
is a blessed object, attempts to convert that object to a datetime. Currently the only type of object that can be successfully converted is a Time::Piece.
now
Returns the current datetime (using the default zone specifier).
datetime($string)
datetime($zone_spec => $string)
Takes the human-readable string and converts it to a datetime using the given zone specifier, if passed (or the default zone specifier if not), using the following heuristics:
If the string consists of nothing but digits (including an optional leading negative sign), treats it as a number of epoch seconds and passes it to
new
.Otherwise passes it to Date::Parse's
str2time
function. If the zone specifier is 'GMT' or 'UTC', this is passed tostr2time
as its second argument. If the result is defined, pass it as epoch seconds tonew
.Otherwise if the result of calling
str2time
is undefined, passes it to Time::ParseDate'sparsedate
function. If the result is defined, passes the resulting epoch seconds tonew
.If
parsedate
returnsundef
, throws an "Illegal date" exception.
This is designed to be a DWIMmy method which will most of the time just do what you meant so you don't need to think about it.
Accessors
Names of accessors match the DateTime class. Ranges generally match what DateTime uses as well.
is_local
Returns true if the datetime is in the current timezone.
is_utc
Returns true if the datetime is in UTC.
is_gmt
Alias for is_utc
.
year
Returns the year (4-digit).
month
Returns the month as a number (1 - 12).
day
Returns the day as a number (1 - 31).
hour
Returns the hour (0 - 23).
minute
Returns the minute (0 - 59).
second
Returns the second (0 - 59).
epoch
Returns the datetime as a number of epoch seconds.
Other Methods
time_zone
Same as strftime('%Z')
.
day_of_week
Returns the day of the week from 1 (Monday) to 7 (Sunday).
day_of_year
Returns the day of the year from 1 (January 1st) to either 365 (December 31st) for a non-leap year, or 366 for a leap year.
quarter
Returns the quarter of the year, based on the month (1 - 4).
strftime($fmt)
Calls Time::Piece's strftime
. See those docs for full details.
iso8601
Calls Time::Piece's datetime
, which produces an ISO 8601 formatted datetime.
iso
Alias for "iso8601", in case you can never remember the exact digits (like me).
split
Returns a list consisting of the year, month, day, hours, minutes, and seconds, in that order, in the same ranges as returned by the "Accessors". Doesn't return anything useful in scalar context, so don't do that. Calling split
in scalar context may eventually be changed to throw a warning or fatal error.
as($conv_spec)
Tries to convert the datetime according to the supplied conversion specification. There are two possible formats for the spec:
If the spec consists of a non-letter followed by one or more letters (and nothing else),
as
will convert this to a time format to be passed to "strftime". For instance, the spec "-Ymd" is converted to "%Y-%m-%d", and ":HMS" is converted to "%H:%M:%S". This allows conversion to a string using much more compact formats, such as "/mdy" or even " abdYZ".Otherwise, the spec is expected to be a classname, and
as
tries to convert the datetime to the given class. Currently, the only acceptable classname is Time::Piece. (Since a Date::Easy::Datetime is stored internally as a Time::Piece object, this is a trivial lookup.)
Overloaded Operators
Addition
You can add an integer value to a datetime object. It adds that number of seconds and returns a new datetime object. The original datetime is not modified.
Subtraction
You can subtract an integer value from a datetime object. It subtracts that number of seconds and returns a new datetime object. The original datetime is not modified.
You can subtract one datetime from another; the result is the number of seconds you would have to add to the right-hand operand to get the left-hand operand (therefore, the result is positive when the left-hand side is a later datetime, and negative when the left-hand side is earlier). Currently the result of attempting to subtract a date from a datetime is undefined.
Math Methods
add_seconds($num)
Same as adding $num
directly to the datetime.
add_minutes($num)
Same as adding $num * 60
directly to the datetime.
add_hours($num)
Same as adding $num * 60 * 60
directly to the datetime.
add_days($num)
Same as adding $num * 60 * 60 * 24
directly to the datetime.
add_weeks($num)
Same as calling add_days($num * 7)
on the datetime.
add_months($num)
Calls Time::Piece's add_months
to add a given number of months and return a new datetime object. The original datetime is not modified. See the Time::Piece docs for full details, especially as regards what happens when you try to add months to dates at the ends of months.
add_years($num)
Calls Time::Piece's add_years
to add a given number of years and return a new datetime object. The original datetime is not modified. See the Time::Piece docs for full details. (Though the Time::Piece documentation isn't clear on this point, adding a year to Feb 29th of a leap years acts correspondingly to adding a month to Jan 29th of a non-leap year.)
subtract_seconds($num)
subtract_minutes($num)
subtract_hours($num)
subtract_days($num)
subtract_weeks($num)
subtract_months($num)
subtract_years($num)
The same as calling the equivalent add_
method, but with -$num
.
BUGS, CAVEATS and NOTES
If you try to pass a zone specifier to new
along with a Time::Piece object, it is ignored. That means that this code:
use Time::Piece;
use Date::Easy::Datetime;
my $tp = localtime;
my $dt = Date::Easy::Datetime->new(UTC => $tp);
is not going to do what you thought it would do. (Although, honestly, I'm not sure what you thought it was going to do.)
There is a bug in Time::ParseDate which causes epoch seconds to be one hour off in certain specific circumstances. Please note that you will not hit this bug if the string you pass to "datetime" has any of the following characteristicts:
If you use one of the UTC "Zone Specifiers".
If your string never makes it to Time::ParseDate, either because it's a number of epoch seconds, or because it's parseable by Date::Parse.
If your string contains a time zone, in any format.
If your string is a relative time, such as "next week" or "+3 minutes".
If your local timezone doesn't use DST (e.g. Ecuador, Kenya, Nepal, Saudi Arabia, etc).
If the DST flag (i.e. the condition of either being on daylight savings or not) of the time in your string matches the current DST flag, in your local timezone.
Hopefully this means hitting this bug will be rare. An upstream bug has been filed.
If your local timezone contains leap seconds, you will likely get funky results with UTC datetimes, such as this being true:
$dt->second != $dt->strftime("%S")
in all cases except, of course, datetimes from before the first leap second was added (i.e. prior to 30-Jun-1972 23:59:60). Weirdly, this isn't a problem with local datetimes. An upstream bug has been filed, although there is still some ongoing discussion about whether this is a bug or not, and whether it's fixable even if it is.
If you pass a 2-digit year to `datetime`, it will always come back in the 20th century:
say datetime("2/1/17"); # Thu Feb 1 00:00:00 1917
Avoiding this is simple: always use 4-digit dates (which is a good habit to get into anyway). This could be considered a bug, since Time::Local uses a 50-year sliding window, which might be considered to be more correct behavior. However, by suffering this "bug," we avoid a bigger one (see RT/53413 and RT/105031).
See also "Limitations" in Date::Easy.
AUTHOR
Buddy Burden <barefootcoder@gmail.com>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2019 by Buddy Burden.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)