|
Date::Calc - Gregorian calendar date calculations
Keep it small, fast and simple
This package consists of a C library and a Perl module (which uses
the C library, internally) for all kinds of date calculations based
on the Gregorian calendar (the one used in all western countries today),
thereby complying with all relevant norms and standards: ISO/R 2015-1971,
DIN 1355 and, to some extent, ISO 8601 (where applicable).
(See also http://www.engelschall.com/u/sb/download/Date-Calc/DIN1355/
for a scan of part of the "DIN 1355" document (in German)).
The module of course handles year numbers of 2000 and above correctly
("Year 2000" or "Y2K" compliance) -- actually all year numbers from 1
to the largest positive integer representable on your system (which
is at least 32767) can be dealt with.
This is not true, however, for the import/export functions in this
package which are an interface to the internal POSIX date and time
functions of your system, which can only cover dates in the following
ranges:
01-Jan-1970 00:00:00 GMT .. 19-Jan-2038 03:14:07 GMT [Unix etc.]
01-Jan-1904 00:00:00 LT .. 06-Feb-2040 06:28:15 LT [MacOS Classic]
(LT = local time)
Note that this package projects the Gregorian calendar back until the
year 1 A.D. -- even though the Gregorian calendar was only adopted
in 1582, mostly by the Catholic European countries, in obedience to the
corresponding decree of Pope Gregory XIII in that year.
Some (mainly protestant) countries continued to use the Julian calendar
(used until then) until as late as the beginning of the 20th century.
Finally, note that this package is not intended to do everything you could
ever imagine automagically for you; it is rather intended to serve as a
toolbox (in the best of UNIX spirit and traditions) which should, however,
always get you where you want to go.
See the section "RECIPES" at the bottom of this document for solutions
to common problems!
If nevertheless you can't figure out how to solve a particular problem,
please let me know! (See e-mail address at the end of this document.)
use Date::Calc qw(
Days_in_Year
Days_in_Month
Weeks_in_Year
leap_year
check_date
check_time
check_business_date
Day_of_Year
Date_to_Days
Day_of_Week
Week_Number
Week_of_Year
Monday_of_Week
Nth_Weekday_of_Month_Year
Standard_to_Business
Business_to_Standard
Delta_Days
Delta_DHMS
Delta_YMD
Delta_YMDHMS
Normalize_DHMS
Add_Delta_Days
Add_Delta_DHMS
Add_Delta_YM
Add_Delta_YMD
Add_Delta_YMDHMS
System_Clock
Today
Now
Today_and_Now
This_Year
Gmtime
Localtime
Mktime
Timezone
Date_to_Time
Time_to_Date
Easter_Sunday
Decode_Month
Decode_Day_of_Week
Decode_Language
Decode_Date_EU
Decode_Date_US
Fixed_Window
Moving_Window
Compress
Uncompress
check_compressed
Compressed_to_Text
Date_to_Text
Date_to_Text_Long
English_Ordinal
Calendar
Month_to_Text
Day_of_Week_to_Text
Day_of_Week_Abbreviation
Language_to_Text
Language
Languages
Decode_Date_EU2
Decode_Date_US2
Parse_Date
ISO_LC
ISO_UC
);
use Date::Calc qw(:all);
Days_in_Year
$days = Days_in_Year($year,$month);
Days_in_Month
$days = Days_in_Month($year,$month);
Weeks_in_Year
$weeks = Weeks_in_Year($year);
leap_year
if (leap_year($year))
check_date
if (check_date($year,$month,$day))
check_time
if (check_time($hour,$min,$sec))
check_business_date
if (check_business_date($year,$week,$dow))
Day_of_Year
$doy = Day_of_Year($year,$month,$day);
Date_to_Days
$days = Date_to_Days($year,$month,$day);
Day_of_Week
$dow = Day_of_Week($year,$month,$day);
Week_Number
$week = Week_Number($year,$month,$day);
Week_of_Year
($week,$year) = Week_of_Year($year,$month,$day);
$week = Week_of_Year($year,$month,$day);
Monday_of_Week
($year,$month,$day) = Monday_of_Week($week,$year);
Nth_Weekday_of_Month_Year
if (($year,$month,$day) =
Nth_Weekday_of_Month_Year($year,$month,$dow,$n))
Standard_to_Business
($year,$week,$dow) =
Standard_to_Business($year,$month,$day);
Business_to_Standard
($year,$month,$day) =
Business_to_Standard($year,$week,$dow);
Delta_Days
$Dd = Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2);
Delta_DHMS
($Dd,$Dh,$Dm,$Ds) =
Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1,
$year2,$month2,$day2, $hour2,$min2,$sec2);
Delta_YMD
($Dy,$Dm,$Dd) =
Delta_YMD($year1,$month1,$day1,
$year2,$month2,$day2);
Delta_YMDHMS
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) =
Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1,
$year2,$month2,$day2, $hour2,$min2,$sec2);
Normalize_DHMS
($Dd,$Dh,$Dm,$Ds) =
Normalize_DHMS($Dd,$Dh,$Dm,$Ds);
Add_Delta_Days
($year,$month,$day) =
Add_Delta_Days($year,$month,$day,
$Dd);
Add_Delta_DHMS
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec,
$Dd,$Dh,$Dm,$Ds);
Add_Delta_YM
($year,$month,$day) =
Add_Delta_YM($year,$month,$day,
$Dy,$Dm);
Add_Delta_YMD
($year,$month,$day) =
Add_Delta_YMD($year,$month,$day,
$Dy,$Dm,$Dd);
Add_Delta_YMDHMS
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec,
$D_y,$D_m,$D_d, $Dh,$Dm,$Ds);
System_Clock
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
System_Clock([$gmt]);
Today
($year,$month,$day) = Today([$gmt]);
Now
($hour,$min,$sec) = Now([$gmt]);
Today_and_Now
($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);
This_Year
$year = This_Year([$gmt]);
Gmtime
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
Gmtime([time]);
Localtime
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
Localtime([time]);
Mktime
$time = Mktime($year,$month,$day, $hour,$min,$sec);
Timezone
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);
Date_to_Time
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);
Time_to_Date
($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);
Easter_Sunday
($year,$month,$day) = Easter_Sunday($year);
Decode_Month
if ($month = Decode_Month($string))
Decode_Day_of_Week
if ($dow = Decode_Day_of_Week($string))
Decode_Language
if ($lang = Decode_Language($string))
Decode_Date_EU
if (($year,$month,$day) = Decode_Date_EU($string))
Decode_Date_US
if (($year,$month,$day) = Decode_Date_US($string))
Fixed_Window
$year = Fixed_Window($yy);
Moving_Window
$year = Moving_Window($yy);
Compress
$date = Compress($year,$month,$day);
Uncompress
if (($century,$year,$month,$day) = Uncompress($date))
check_compressed
if (check_compressed($date))
Compressed_to_Text
$string = Compressed_to_Text($date);
Date_to_Text
$string = Date_to_Text($year,$month,$day);
Date_to_Text_Long
$string = Date_to_Text_Long($year,$month,$day);
English_Ordinal
$string = English_Ordinal($number);
Calendar
$string = Calendar($year,$month[,$orthodox]);
Month_to_Text
$string = Month_to_Text($month);
Day_of_Week_to_Text
$string = Day_of_Week_to_Text($dow);
Day_of_Week_Abbreviation
$string = Day_of_Week_Abbreviation($dow);
Language_to_Text
$string = Language_to_Text($lang);
Language
$lang = Language();
Language($lang);
$oldlang = Language($newlang);
Languages
$max_lang = Languages();
Decode_Date_EU2
if (($year,$month,$day) = Decode_Date_EU2($string))
Decode_Date_US2
if (($year,$month,$day) = Decode_Date_US2($string))
Parse_Date
if (($year,$month,$day) = Parse_Date($string))
ISO_LC
$lower = ISO_LC($string);
ISO_UC
$upper = ISO_UC($string);
Version
$string = Date::Calc::Version();
(See the section "RECIPES" at the bottom of this document for
solutions to common problems!)
-
"Year 2000" ("Y2K") compliance
The upper limit for any year number in this module is only given
by the size of the largest positive integer that can be represented
in a variable of the C type "int" on your system, which is at least
32767, according to the ANSI C standard (exceptions see below).
In order to simplify calculations, this module projects the gregorian
calendar back until the year 1 A.D. -- i.e., back BEYOND the
year 1582 when this calendar was first decreed by the Catholic Pope
Gregory XIII!
Therefore, BE SURE TO ALWAYS SPECIFY "1998" WHEN YOU MEAN "1998",
for instance, and DO NOT WRITE "98" INSTEAD, because this will
in fact perform a calculation based on the year "98" A.D. and
NOT "1998"!
An exception from this rule are the functions which contain the
word "compress" in their names (which can only handle years between
1970 and 2069 and also accept the abbreviations "00" to "99"), and
the functions whose names begin with "Decode_Date_" (which translate
year numbers below 100 using a technique known as "moving window").
If you want to convert a two-digit year number into a full-fledged,
four-digit (at least for some years to come ;-)) year number,
use the two functions "Fixed_Window()" and "Moving_Window()"
(see their description further below).
Note also that the following import/export functions (which are
interfaces to the POSIX functions "time()", "gmtime()", "localtime()"
and "mktime()" or (the last two) substitutes for the BSD function
"timegm()" and the POSIX function "gmtime()") have a very limited
range of representable dates (in contrast to all other functions
in this package, which cover virtually any date including and
after January 1st 1 A.D.):
System_Clock()
Today()
Now()
Today_and_Now()
This_Year()
Gmtime()
Localtime()
Mktime()
Timezone()
Date_to_Time()
Time_to_Date()
These functions can only deal with dates in the range from
01-Jan-1970 00:00:00 GMT to 19-Jan-2038 03:14:07 GMT
(the latter limit is only authoritative on 32 bit systems,
however, and can (in principle, through a few code changes)
be extended somewhat :-) on 64 bit systems).
On MacOS Classic, the valid range of dates is between
(both included) 01-Jan-1904 00:00:00 (local time)
to 06-Feb-2040 06:28:15 (local time).
Note further that the function "Easter_Sunday()" can only
be used for years in the range 1583 to 2299.
-
First index
ALL ranges in this module start with "1", NOT "0"!
I.e., the day of month, day of week, day of year, month of year,
week of year, first valid year number and language ALL start
counting at one, NOT zero!
The only exception is the function "Week_Number()", which may
in fact return "0" when the given date actually lies in the
last week of the PREVIOUS year, and of course the numbers for
hours (0..23), minutes (0..59) and seconds (0..59).
-
Function naming conventions
Function names completely in lower case indicate a boolean return value.
-
Boolean values
Boolean values in this module are always a numeric zero ("0") for
"false" and a numeric one ("1") for "true".
-
Exception handling
The functions in this module will usually die with a corresponding error
message if their input parameters, intermediate results or output values
are out of range.
The following functions handle errors differently:
- check_date()
- check_time()
- check_business_date()
- check_compressed()
(which return a "false" return value when the given input does not represent
a valid date or time),
- Nth_Weekday_of_Month_Year()
(which returns an empty list if the requested 5th day of week does not exist),
- Decode_Month()
- Decode_Day_of_Week()
- Decode_Language()
- Fixed_Window()
- Moving_Window()
- Compress()
(which return "0" upon failure or invalid input), and
- Decode_Date_EU()
- Decode_Date_US()
- Decode_Date_EU2()
- Decode_Date_US2()
- Parse_Date()
- Uncompress()
(which return an empty list upon failure or invalid input).
Note that you can always catch an exception thrown by any of the functions
in this module and handle it yourself by enclosing the function call in an
"eval" with curly brackets and checking the special variable "$@"
(see perlfunc(1)/eval for details).
-
use Date::Calc qw( Days_in_Year Days_in_Month ... );
-
use Date::Calc qw(:all);
You can either specify the functions you want to import explicitly by
enumerating them between the parentheses of the "qw()" operator, or
you can use the ":all" tag instead to import ALL available functions.
-
$days = Days_in_Year($year,$month);
This function returns the sum of the number of days in the months starting
with January up to and including "$month" in the given year "$year".
I.e., "Days_in_Year(1998,1)" returns "31", "Days_in_Year(1998,2)"
returns "59", "Days_in_Year(1998,3)" returns "90", and so on.
Note that "Days_in_Year($year,12)" returns the number of days in the
given year "$year", i.e., either "365" or "366".
-
$days = Days_in_Month($year,$month);
This function returns the number of days in the given month "$month" of
the given year "$year".
The year must always be supplied, even though it is only needed when the
month is February, in order to determine whether it is a leap year or not.
I.e., "Days_in_Month(1998,1)" returns "31", "Days_in_Month(1998,2)"
returns "28", "Days_in_Month(2000,2)" returns "29",
"Days_in_Month(1998,3)" returns "31", and so on.
-
$weeks = Weeks_in_Year($year);
This function returns the number of weeks in the given year "$year",
i.e., either "52" or "53".
-
if (leap_year($year))
This function returns "true" ("1") if the given year "$year" is
a leap year and "false" ("0") otherwise.
-
if (check_date($year,$month,$day))
This function returns "true" ("1") if the given three numerical
values "$year", "$month" and "$day" constitute a valid date,
and "false" ("0") otherwise.
-
if (check_time($hour,$min,$sec))
This function returns "true" ("1") if the given three numerical
values "$hour", "$min" and "$sec" constitute a valid time
(0 <= $hour < 24, 0 <= $min < 60 and
0 <= $sec < 60), and "false" ("0") otherwise.
-
if (check_business_date($year,$week,$dow))
This function returns "true" ("1") if the given three numerical
values "$year", "$week" and "$dow" constitute a valid date
in business format, and "false" ("0") otherwise.
Beware that this function does NOT compute whether a given date
is a business day (i.e., Monday to Friday)!
To do so, use "(Day_of_Week($year,$month,$day) < 6)" instead.
-
$doy = Day_of_Year($year,$month,$day);
This function returns the (relative) number of the day of the given date
in the given year.
E.g., "Day_of_Year($year,1,1)" returns "1",
"Day_of_Year($year,2,1)" returns "32", and
"Day_of_Year($year,12,31)" returns either "365" or "366".
The day of year is sometimes also referred to as the Julian day (or date),
although it has nothing to do with the Julian calendar, the calendar which
was used before the Gregorian calendar.
In order to convert the number returned by this function back into a
date, use the function "Add_Delta_Days()" (described further below),
as follows:
$doy = Day_of_Year($year,$month,$day);
($year,$month,$day) = Add_Delta_Days($year,1,1, $doy - 1);
-
$days = Date_to_Days($year,$month,$day);
This function returns the (absolute) number of the day of the given date,
where counting starts at the 1st of January of the year 1 A.D.
I.e., "Date_to_Days(1,1,1)" returns "1", "Date_to_Days(1,12,31)"
returns "365", "Date_to_Days(2,1,1)" returns "366",
"Date_to_Days(1998,5,1)" returns "729510", and so on.
This is sometimes also referred to (not quite correctly) as the Julian
date (or day). This may cause confusion, because also the number of the
day in a year (from 1 to 365 or 366) is frequently called the "Julian day".
More confusing still, this has nothing to do with the Julian calendar,
which was used BEFORE the Gregorian calendar.
The Julian calendar was named after famous Julius Caesar, who had
instituted it in Roman times. The Julian calendar is less precise than
the Gregorian calendar because it has too many leap years compared to
the true mean length of a year (but the Gregorian calendar also still
has one day too much every 5000 years). Anyway, the Julian calendar was
better than what existed before, because rulers had often changed the
calendar used until then in arbitrary ways, in order to lengthen their
own reign, for instance.
In order to convert the number returned by this function back into
a date, use the function "Add_Delta_Days()" (described further
below), as follows:
$days = Date_to_Days($year,$month,$day);
($year,$month,$day) = Add_Delta_Days(1,1,1, $days - 1);
-
$dow = Day_of_Week($year,$month,$day);
This function returns the number of the day of week of the given date.
The function returns "1" for Monday, "2" for Tuesday and so on
until "7" for Sunday.
Note that in the Hebrew calendar (on which the Christian calendar is based),
the week starts with Sunday and ends with the Sabbath or Saturday (where
according to the Genesis (as described in the Bible) the Lord rested from
creating the world).
In medieval times, Catholic Popes have decreed the Sunday to be the official
day of rest, in order to dissociate the Christian from the Hebrew belief.
Nowadays, the Sunday AND the Saturday are commonly considered (and
used as) days of rest, usually referred to as the "week-end".
Consistent with this practice, current norms and standards (such as
IS |