DateTime::Precise(3)
π DateTime::Precise(3) π
okay bestie, sit down, hydrate, and get comfy, because today we're reading the manual page for DateTime::Precise from the User Contributed Perl Documentation. yes it's a Perl module. yes it's giving legendary. no we are not skipping anything. π«Ά
β¨ NAME β¨
DateTime::Precise β perform common time and date operations with additional GPS operations. π°οΈ
π SYNOPSIS π
here's the whole vibe, copy-paste ready, no cap:
use DateTime::Precise;
use DateTime::Precise qw(:TimeVars);
# Constructors and ways to set time.
$t1 = DateTime::Precise->new;
$t2 = DateTime::Precise->new('1998. 4. 3 12:13:44.054');
$t3 = DateTime::Precise->new(time() - 100.23456);
$t4 = DateTime::Precise->new('1998.04.24');
$t1->set_localtime_from_epoch_time;
$t1->set_gmtime_from_epoch_time(time + 120.987);
$t1->set_from_datetime('1998.03.23 16:58:14.65');
$t1->set_time('YDHMS', 1998, 177, 9, 15, 26.5);
# This is the same as $d3->set_from_datetime(...)
$t3->dscanf("%^Y.%M.%D %h:%m:%s", "1998.03.25 20:25:23");
if ($msg = $d1->dscanf("%~M", $input)) {
print "error: $msg\n";
print "Must enter a three-letter month abbrev.\n";
}
# Get different parts of the time.
$year = $t3->year;
$month = $t3->month;
$day = $t3->day;
$hours = $t3->hours;
$minutes = $t3->minutes;
$seconds = $t3->seconds;
($year, $day_of_year) = $t3->get_time('Yj');
# Print times and dates.
print $t2->asctime;
print $t2->strftime('%T %C%n');
print $t2->dprintf("%^Y.%M.%D %h:%m:%s"); # datetime
print $t2->dprintf("%~w %~M %-D %h:%m:%s CST %^Y"); # ctime
# Copy times.
my $t4 = $t2->copy;
# Set one time object to the same time as another: set $t3 equal to $t2.
$t3->clone($t2);
# Find the difference between two times.
$secs_from_midnight = $t4 - $t1;
$secs_from_midnight = $t4->diff($t1);
# Add seconds, days, months, etc to time.
$t1 = $t4 + 3600; # $t1 is now an hour after midnight
$t1->inc_month(2); # add two months to $t1
$t1->floor_month; # set $t1 to the first of the month
$t1 -= 0.25; # subtract 1/4 of a second from $t1
# Can compare and sort DateTime::Precise.
print "It's late!!!" if ($t1 > $t4);
@sorted = sort @birthdays; # normal comparisons work fine
# Get the GPS weeks, seconds and day.
$gps_week = $t1->gps_week;
$gps_seconds = $t1->gps_seconds;
$gps_day = $t1->gps_day;
($gps_week, $gps_seconds, $gps_day) = $t1->gps_week_seconds_day;
π¦ DESCRIPTION π¦
so the tea is this: this library exists because the authors were so over depending on Unix epoch time. and honestly? valid. epoch time is stuck in a lil range of roughly 1970 to 2030, which is simply not it when you've got data going all the way back to 1870. π
this date library effectively handles dates from A.D. 1000 to infinity, and it would probably work all the way back to 0 β ignoring, of course, the switch-over to the Gregorian calendar. (iykyk, calendars are messy. π)
the good parts of Unix epoch time are fully preserved: easy date difference calculation, easy date comparison, strict ordering. all of it. slay. and on top of that it adds stuff like human-legibility. iconic behavior. β¨
it also handles fractional seconds and some date/time manipulations used for the Global Positioning Satellite system. π°οΈ
the operators +/-, <=>, cmp, and stringify are overloaded. so like:
- addition handles seconds and fractions of seconds π
- subtraction handles seconds or date differences β
- compares work β
- stringification returns the a representation of the date π
okay now here's the part where the US Geological Survey (USGS) gets quirky. they like midnight to be 24:00:00 of the previous day, not 00:00:00 of the day people expect. so if $DateTime::Precise::USGSMidnight is set, then dprintf will always print midnight as 24:00:00, and the date returned from dprintf will have the previous day's date. π
regardless β and this is the important bit, don't skip it β time is always stored internally as 00:00:00. periodt.
π CONSTRUCTOR π
new
new
new('1998. 4. 3 12:13:44')
new(time() - 100.23456)
new('YDHMS', 1998, 200, 13, 16, 49.5)
this makes you a brand new time object, bestie. π«Ά
if you pass no argument, the time object gets initialized with the time returned from gmtime (time()).
the second form sets the time explicitly. the argument can be in one of three formats:
"YYYY.MM.DD hh:mm:ss.ffff""YYYY.MM.DD"(midnight assumed π)"YYYYMMDDhhmmss.ffff"
here ffff are the fractions of seconds. β±οΈ
the third form sets the time using gmtime() with fractional seconds allowed.
the fourth form sets the time using a format as the first argument, followed by the particular date adjustments as the following arguments. see set_time() for more information. π
if the new fails, then new returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context.
now, the lore behind the second and third forms: because they pass only one argument to new(), there has to be a way to tell them apart. currently the following test is used: if any non-digit characters are found in the argument, or if the string form of the argument is longer than 10 character, then assume it to be a string to parse for the date. otherwise it is the time since the Unix epoch.
and why 10? because the string length of 10 was chosen since when the Unix epoch time flips to 11 digits, it'll be roughly year 2287. future-proofing queen. π
π METHODS π
set_from_datetime datetime
set date/time from the passed date/time string "YYYY.MM.DD hh:mm:ss.fff". βοΈ
if set_from_datetime successfully parses datetime, then the newly set date/time object is returned. otherwise it returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context.
set_localtime_from_epoch_time [epoch]
set from epoch time into the local time zone. π
if epoch is passed, then use that time to set the current time. otherwise use the time as returned from time() or from Time::HiRes::time() if the Time::HiRes module can be loaded.
if the Time::HiRes::time() can be imported, then the resulting loaded time most likely will contain a fractional second component. β±οΈ
the newly set date/time object is returned. the epoch can contain fractional seconds. β¨
set_gmtime_from_epoch_time [epoch]
set from the epoch time into the standard Greenwich time zone. π°οΈ
if epoch is passed, then use that time to set the current time. otherwise use the time as returned from time() or from Time::HiRes::time() if the Time::HiRes module can be loaded.
if the Time::HiRes::time() can be imported, then the resulting loaded time most likely will contain a fractional second component. β±οΈ
the newly set date/time object is returned. the epoch can contain fractional seconds. β¨
set_from_day_of_year year day_of_year
set date/from from the year and the decimal day_of_year. π
midnight January 1st is day 1, noon January 1st is 1.5, etc.
if the date was successfully set, then the newly set date/time object is returned. otherwise it returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context.
set_from_serial_day serial_day_number
set the date/time from the serial day. π’ see also serial_day().
if the date was successfully set, then the newly set date/time object is returned. otherwise is returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context.
set_from_gps_week_seconds gps_week gps_seconds
set the current time using the number of weeks and seconds into the week since the GPS epoch, which is January 6, 1980 UTC. π°οΈπ
if the date was successfully set, then the newly set date/time object is returned. otherwise is returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context.
set_time format [arg, [arg, ...]]
set the time, bestie. π format is a string composed of a select set of characters. some characters may take an optional argument, which are listed following the format argument in the same order as the characters.
the first character must be an absolute time:
N => Set time to now. No argument taken.
G => Set time to GPS time 0 (January 6, 1980). No argument taken.
Y => Set time to beginning of the year. Argument taken.
J => Set time to modified Julian date. Argument taken.
s => Set time to seconds since January 1, 1970. Argument taken.
these characters represent modifiers to the time set using the above characters:
B => Add months to time. Argument taken.
W => Add weeks to time. Argument taken.
D => Add days counted from 1 to time. Argument taken.
d => Add days counted from 0 to time. Argument taken.
H => Add hours to time. Argument taken.
M => Add minutes to time. Argument taken.
S => Add seconds to time. Argument taken.
if the date and time was successfully set, then it returns the newly set date/time object. otherwise set_time() returns an empty list in a list context, an undefined value in a scalar context, or nothing in a void context, and the date and time remain unchanged.
β οΈ note the difference in counting, bestie:Dcounts days from 1 anddcounts days from 0. not the same letter, not the same vibe.
get_time string
return an array, where each element of the array corresponds to the corresponding strftime() value. π
this string should not contain % characters.
this method is a much, much better and faster way of doing:
map {$self->strftime("%$_")} split(//, $string)
year [year]
return the year. ποΈ
if an argument is passed to year, then set the year to the integer part of the argument and then return the newly set year.
month [month]
return the numerical month (1 = January, 12 = December). π
if an argument is passed to month, then set the month to the integer part of the argument and return the newly set month.
day [day]
return the day of the month. π
if an argument is passed to day, then set the day to the integer part of the argument and return the newly set day.
hours [hours]
return the hours in the day. π
if an argument is passed to hours, then set the hours to the integer part of the argument and return the newly set hours.
minutes [minutes]
return the minutes in the hour. β²οΈ
if an argument is passed to minutes, then set the minutes to the integer part of the argument and return the newly set minutes.
seconds [seconds]
return the seconds in the minutes. β±οΈ
if an argument is passed to seconds, then set the seconds to the argument and return the newly set seconds.
this argument accepts fractional seconds and will return the fractional seconds. β¨
serial_day
Returns a serial day number representing the date, plus a fraction representing the time since midnight (so like, noon = 0.5). Bestie, this one's for apps that need a scale index β the docs literally say they use it for positioning a date on a time-series graph axis π
. Also peep set_from_serial_day().
day_of_year
Returns the day of the year, fraction part of the day included. Midnight January 1st is day 1, noon January 1st is 1.5, and so on forever β¨.
julian_day
Returns the day of the year with the fraction part of the day, except time is 0 based here. Midnight January 1st is day 0, noon January 1st is 0.5, noon January 2nd is 1.5, etc. Yes the naming is giving chaos, we move π«Ά.
unix_seconds_since_epoch
Returns the time in seconds between the object and January 1, 1970 UTC.
gps_seconds_since_epoch
Returns the time in seconds between the object and January 6, 1980 UTC.
gps_week_seconds_day
Returns an array of three things: the GPS week 0 filled to four spaces, the number of seconds into the GPS week, and the GPS day β where day 0 is Sunday. An array, bestie, not a string. Act accordingly π.
gps_week
Returns the GPS week of the object. The number that comes back is 0 filled to four digits.
gps_seconds
Returns the number of seconds into the current GPS week for the current object.
gps_day
Returns the GPS day of the week for the current object, where day 0 is Sunday.
copy
Returns an identical copy of the current object. Twins fr fr π―.
clone other_dt
Sets this DateTime::Precise equal to other_dt.
dprintf string
Returns string with substitutions:
%xβ number zero-padded to 2 digits (ie,'02')%C<-x>β number space-padded to 2 digits (ie,' 2')%^xβ unpadded number (ie,'2')%~xβ 3-letter abbrev corresponding to value (%Mand%wonly)%*xβ full name corresponding to value (%Mand%wonly)%%β'%'
where x is one of:
hβ hours (0..23)mβ minutes (0..59)sβ seconds (0..59)Dβ day of the month (1..31)Mβ month (1..12)Yβ years since 1900 (ie, 96)Wβ USGS water year (year+1 for months Oct-Dec)wβ day of the week (0..6, or"Mon", etc.)Eβ internal string (no~^*-)
so, for example, to get a string in datetime format, you would pass a string of '%^Y.%M.%D %h:%m:%s', or, to get a ctime-like string, you would pass: '%~w %~M %-D %h:%m:%s CDT %^Y' (presuming you're in the CDT. Maybe timezone support will show up some day π).
The US Geological Survey (USGS) likes midnight to be24:00:00of the previous day, not00:00:00of the day people expect. If$DateTime::Precise::USGSMidnightis set,dprintfwill always print midnight as24:00:00and the date returned fromdprintfwill have the previous day's date. Regardless, time is always stored internally as00:00:00.
dscanf format string
Takes a format string format, and uses it to read the date and time fields from the supplied string. The current date and time is unchanged if dscanf fails β so no half-updated cursed state, we love a safe fail π.
All format characters recognized by dprintf() are valid here too. Two additional characters are recognized: 'U', which sets the time to the local time/date using the number of seconds since Unix epoch time, and 'u', which sets the time to GMT time/date using the number of seconds since Unix epoch time. Unless exact characters are supplied or format characters are concatenated, it will separate on non-matching characters.
strftime format
Just like the strftime() function call. This version is based on the Solaris manual page. format is a string containing zero or more conversion specifications. A specification character consists of a '%' (percent) character followed by one conversion character that determines the conversion specification's behavior. All ordinary characters are copied unchanged to the return string.
The following GPS specific conversions are supported in this strftime:
%sβ the seconds since UTC January 1, 1970%Gβ the GPS week (4 digits with leading 0's)%gβ the GPS seconds into the GPS week with no leading zeros%fβ the GPS day where 0 = Sunday, 1 = Monday, etc%Fβ the GPS day where 1 = Sunday, 2 = Monday, etc
The following standard conversions are understood:
%%β the same as%%aβ the abbreviated weekday name%Aβ the full weekday name%bβ the abbreviated month name%Bβ the full month name%cβ the appropriate date and time representation%Cβ century number (the year divided by 100 and truncated to an integer as a decimal number [1,99]); single digits are preceded by 0%dβ day of month [1,31]; single digits are preceded by 0%Dβ date as%m/%d/%y%eβ day of month [1,31]; single digits are preceded by a space%hβ locale's abbreviated month name%Hβ hour (24-hour clock) [0,23]; single digits are preceded by 0%Iβ hour (12-hour clock) [1,12]; single digits are preceded by 0%jβ day number of year [1,366]; single digits are preceded by 0%kβ hour (24-hour clock) [0,23]; single digits are preceded by a blank%lβ hour (12-hour clock) [1,12]; single digits are preceded by a blank%mβ month number [1,12]; single digits are preceded by 0%Mβ minute [00,59]; leading zero is permitted but not required%nβ insert a newline%pβ either AM or PM%rβ appropriate time representation in 12-hour clock format with%p%Rβ time as%H:%M%Sβ seconds [00,61]%tβ insert a tab%Tβ time as%H:%M:%S%uβ weekday as a decimal number [1,7], with 1 representing Sunday%Uβ week number of year as a decimal number [00,53], with Sunday as the first day of week 1%Vβ week number of the year as a decimal number [01,53], with Monday as the first day of the week. If the week containing 1 January has four or more days in the new year, then it is considered week 1; otherwise, it is week 53 of the previous year, and the next week is week 1.%wβ weekday as a decimal number [0,6], with 0 representing Sunday%Wβ week number of year as a decimal number [00,53], with Monday as the first day of week 1%xβ locale's appropriate date representation%Xβ locale's appropriate time representation%yβ year within century [00,99]%Yβ year, including the century (for example 1993)%Zβ Always GMT
asctime
Returns a string such as 'Fri Apr 3 12:13:44 GMT 1998'. This is equivalent to strftime('%c'). That's it, that's the whole method, she's short and she's iconic π.
π Incrementing and rounding
There are many subroutines of the format func_unit, where func is one of (inc, dec, floor, ceil, round) and unit is one of (second, minute, hour, day, month, year) β and yes, second and minute can be abbreviated as sec and min respectively, because typing is hard and we respect that π
.
inc_unit(i) increments the date by i units (i defaults to 1 if no parameter is supplied). For days through seconds, fractional increments are allowed. However β listen β for months and years, only the integer part of the increment is used. No .5 months for you, bestie.
dec_unit(i) is identical to inc_unit("-i").
round_unit() rounds the date to the nearest unit. Rounds years down for Jan-Jun, and up for Jul-Dec; months down for 1st-15th and up for 16th and later; days round up on or after 12:00:00; hours on or after xx:30:00, minutes on or after 30 seconds; seconds on or after 0.5 seconds.
floor_unit() rounds the date down to the earliest time for the current unit. For example, floor_month() rounds to midnight of the first day of the current month, floor_day() to midnight of the current day, and floor_hour() to xx:00:00.
ceil_unit() is the complementary function to floor. It rounds the date up, to the earliest time in the next unit. E.g., ceil_month() makes the date midnight of the first day of the next month. β¬οΈ
π₯ Overloaded operators
Addition, subtraction, and comparison operators are overloaded, as well as the string representation of a date object. Look at this little demo, she ate:
# create a new object
$x = DateTime::Precise->new('1996.05.05 05:05:05');
# copy it
$y = $x;
# increment x by one second
$x++;
# decrement by a day
$y = $y - 86400;
# test em
print ($x < $y ? "x is earlier\n" : "y is earlier\n");
# get the difference
print "The difference between x and y is ", $x-$y, " seconds.\n";
If $x is a date object, "$x + $i" is identical to $x->inc_sec($i).
There are two possible results from subtraction, so pay attention bestie:
"$x - $i", where $i is a number, will return a new date, $i seconds before$x."$x - $y", where$yis another date object, is identical to$x->diff($y).
Comparison operators (<,>,==,etc) work as one would expect. No cap π«Ά.
β¨ PUBLIC CONSTANTS β¨
okay bestie so these variables are not imported into your package by default, which is lowkey rude but whatever. if you want them, you gotta say the magic words:
use DateTime::Precise qw(:TimeVars);
in your package. or, alternatively, you can just use the fully qualified package name, like $DateTime::Precise::USGSMidnight β same vibe, more typing π
$USGSMidnightβ set this to1if you want midnight to be represented as24:00:00of the previous day. the default value is0, which does not change the behavior of midnight. to use this variable in your code, load the DateTime::Precise module like this:
use DateTime::Precise qw($USGSMidnight);
β οΈ heads up: setting this only changes the output of dprintf for date and times that are exactly midnight. that's it. that's the whole assignment.
@MonthDaysβ days per month in a non-leap year. this array is 1 indexed, so0is December,1is January, etc. yes it's cursed, no we don't make the rules π«@MonthNameβ month names. also 1 indexed, so0is December,1is January, etc.@MonthAbbrevβ month abbreviated names. 1 indexed too, so0is Dec,1is Jan, etc.@WeekNameβ names of the week, 0 indexed. so0is Sunday,1is Monday, etc.@WeekAbbrevβ abbreviated names of the week, 0 indexed. so0is Sun,1is Mon, etc.&Secs_per_weekβ the number of seconds in one week (604800). iconic number honestly.&Secs_per_dayβ the number of seconds in one day (86400).&Secs_per_hourβ the number of seconds in one hour (3600).&Secs_per_minuteβ the number of seconds in one minute (60).&JANUARY_1_1970β subroutine returning the Unix epoch time January 1, 1970 UTC. the origin story π¬&JANUARY_6_1980β subroutine returning the GPS epoch time January 6, 1980 UTC. not the same birthday as Unix, no cap.
πΈ PUBLIC SUBROUTINES πΈ
IsLeapYear(year)β returns true if the argument is a leap year. give it a year, it tells you if Feb 29 is real that year. slay β¨DaysInMonth(month, year)β returns the number of days in the month. month AND year, because February is a whole drama queen.
π§ IMPLEMENTATION π§
this package is based on the DateTime package written by Greg Fast <gdfast@usgs.gov>. the _week_of_year routine is based on the Date_WeekOfYear routine from the Date::DateManip package written by Sullivan Beck. giving credit where credit is due, periodt π«Ά
instead of using the string representation used in the original DateTime package, this package represents the time internally as a seven element array, where the elements correspond to the year, month, day, hours, minutes, seconds, and fractional seconds. seven elements, seven slays.
π AUTHOR π
contact: Blair Zajac <blair@orcaware.com>. the original version of this module was based on DateTime written by Greg Fast <gdfast@usgs.gov>.
π POD ERRORS π
hey! the above document had some coding errors, which are explained below. not me reading the linter's receipts π
- Around line
2024:=backdoesn't take any parameters, but you said=back 4 - Around line
2330:=backdoesn't take any parameters, but you said=back 4 - Around line
2398:'=item'outside of any'=over' - Around line
2457: You forgot a'=back'before'=head1' - Around line
2469:=backdoesn't take any parameters, but you said=back 4
bestie the pod checker really said "we need to talk" and listed five reasons π
and that's the whole page!! π this was perl v5.42.0, dated 2025-07-25, and it's DateTime::Precise(3) β tysm for reading, mwah π π¦ π β
π¦ where this page comes from
- fedora 43: perl-DateTime-Precise 1.05-53.fc43 Β· LicenseRef-Fedora-Public-Domain
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms