Data: Dates
The day of the year is in the array returned by localtime() (see perlfunc/"localtime"):
$day_of_year = (localtime(time()))[7];
|
|
Use the following simple functions:
sub get_century {
return int((((localtime(shift || time))[5] + 1999))/100);
}
sub get_millennium {
return 1+int((((localtime(shift || time))[5] + 1899))/1000);
}
|
|
On some systems, you'll find that the POSIX module's strftime() function has been extended in
a non-standard way to use a %C format, which they sometimes claim is the
"century". It isn't, because on most such systems, this is only the first two digits
of the four-digit year, and thus cannot be used to reliably determine the current century or
millennium.
If you're storing your dates as epoch seconds then simply subtract one from the other. If
you've got a structured date (distinct year, day, month, hour, minute, seconds values), then for
reasons of accessibility, simplicity, and efficiency, merely use either timelocal or timegm
(from the Time::Local module in the standard distribution) to reduce structured dates to epoch
seconds. However, if you don't know the precise format of your dates, then you should probably
use either of the Date::Manip and Date::Calc modules from CPAN before you go hacking up your own
parsing routine to handle arbitrary date formats.
If it's a regular enough string that it always has the same format, you can split it up and
pass the parts to timelocal in the standard Time::Local module. Otherwise, you
should look into the Date::Calc and Date::Manip modules from CPAN.
Use the Time::JulianDay module (part of the Time-modules bundle available from CPAN.)
Before you immerse yourself too deeply in this, be sure to verify that it is the Julian
Day you really want. Are you interested in a way of getting serial days so that you just can
tell how many days they are apart or so that you can do also other date arithmetic? If you are
interested in performing date arithmetic, this can be done using modules Date::Manip or
Date::Calc.
There is too many details and much confusion on this issue to cover in this FAQ, but the term
is applied (correctly) to a calendar now supplanted by the Gregorian Calendar, with the Julian
Calendar failing to adjust properly for leap years on centennial years (among other annoyances).
The term is also used (incorrectly) to mean: [1] days in the Gregorian Calendar; and [2] days
since a particular starting time or `epoch', usually 1970 in the Unix world and 1980 in the
MS-DOS/Windows world. If you find that it is not the first meaning that you really want, then
check out the Date::Manip and Date::Calc modules. (Thanks to David Cassell for most of this
text.)
The time() function returns the current time in seconds since the epoch. Take
twenty-four hours off that:
$yesterday = time() - ( 24 * 60 * 60 );
|
|
Then you can pass this to localtime() and get the individual year, month, day,
hour, minute, seconds values.
Note very carefully that the code above assumes that your days are twenty-four hours each.
For most people, there are two days a year when they aren't: the switch to and from summer time
throws this off. A solution to this issue is offered by Russ Allbery.
sub yesterday {
my $now = defined $_[0] ? $_[0] : time;
my $then = $now - 60 * 60 * 24;
my $ndst = (localtime $now)[8] > 0;
my $tdst = (localtime $then)[8] > 0;
$then - ($tdst - $ndst) * 60 * 60;
}
# Should give you "this time yesterday" in seconds since epoch relative to
# the first argument or the current time if no argument is given and
# suitable for passing to localtime or whatever else you need to do with
# it. $ndst is whether we're currently in daylight savings time; $tdst is
# whether the point 24 hours ago was in daylight savings time. If $tdst
# and $ndst are the same, a boundary wasn't crossed, and the correction
# will subtract 0. If $tdst is 1 and $ndst is 0, subtract an hour more
# from yesterday's time since we gained an extra hour while going off
# daylight savings time. If $tdst is 0 and $ndst is 1, subtract a
# negative hour (add an hour) to yesterday's time since we lost an hour.
#
# All of this is because during those days when one switches off or onto
# DST, a "day" isn't 24 hours long; it's either 23 or 25.
#
# The explicit settings of $ndst and $tdst are necessary because localtime
# only says it returns the system tm struct, and the system tm struct at
# least on Solaris doesn't guarantee any particular positive value (like,
# say, 1) for isdst, just a positive value. And that value can
# potentially be negative, if DST information isn't available (this sub
# just treats those cases like no DST).
#
# Note that between 2am and 3am on the day after the time zone switches
# off daylight savings time, the exact hour of "yesterday" corresponding
# to the current hour is not clearly defined. Note also that if used
# between 2am and 3am the day after the change to daylight savings time,
# the result will be between 3am and 4am of the previous day; it's
# arguable whether this is correct.
#
# This sub does not attempt to deal with leap seconds (most things don't).
#
# Copyright relinquished 1999 by Russ Allbery <rra@stanford.edu>
# This code is in the public domain
|
|
Short answer: No, Perl does not have a Year 2000 problem. Yes, Perl is Y2K compliant
(whatever that means). The programmers you've hired to use it, however, probably are not.
Long answer: The question belies a true understanding of the issue. Perl is just as Y2K
compliant as your pencil--no more, and no less. Can you use your pencil to write a
non-Y2K-compliant memo? Of course you can. Is that the pencil's fault? Of course it isn't.
The date and time functions supplied with Perl (gmtime and localtime) supply adequate
information to determine the year well beyond 2000 (2038 is when trouble strikes for 32-bit
machines). The year returned by these functions when used in a list context is the year minus
1900. For years between 1910 and 1999 this happens to be a 2-digit decimal number. To
avoid the year 2000 problem simply do not treat the year as a 2-digit number. It isn't.
When gmtime() and localtime() are used in scalar context they return a timestamp string that
contains a fully-expanded year. For example, $timestamp = gmtime(1005613200) sets
$timestamp to "Tue Nov 13 01:00:00 2001". There's no year 2000 problem here.
That doesn't mean that Perl can't be used to create non-Y2K compliant programs. It can. But
so can your pencil. It's the fault of the user, not the language. At the risk of inflaming the
NRA: ``Perl doesn't break Y2K, people do.'' See http://language.perl.com/news/y2k.html for a
longer exposition.
|
|