Date::Calc — Gregorian calendar date calculations
| Use Case | Command | Description |
|---|---|---|
| 📅 Get today's date | ($y,$m,$d) = Today(); | Returns current year, month, day |
| ⏰ Get current time | ($h,$m,$s) = Now(); | Returns current hour, min, sec |
| 📆 Get day of week | $dow = Day_of_Week($y,$m,$d); | 1=Mon … 7=Sun |
| ➕ Add days to date | ($y,$m,$d) = Add_Delta_Days($y,$m,$d, $n); | Add +/– n days |
| ➖ Difference in days | $dd = Delta_Days($y1,$m1,$d1, $y2,$m2,$d2); | Chronological diff |
| 📦 Check if valid date | if (check_date($y,$m,$d)) | Returns true if valid |
| 📆 Week number of date | ($wk,$yr) = Week_of_Year($y,$m,$d); | Returns (week, year) |
| 📅 Monday of week | ($y,$m,$d) = Monday_of_Week($wk,$yr); | First day of given week |
| 📅 Nth weekday of month | ($y,$m,$d) = Nth_Weekday_of_Month_Year($y,$m,$dow,$n); | e.g., 3rd Thursday |
| 📅 Easter Sunday | ($y,$m,$d) = Easter_Sunday($y); | 1583–2299 |
| 🌐 Date to text | $str = Date_to_Text($y,$m,$d); | e.g., "Wed 31-Mar-1998" |
| 🌐 Decode date (EU) | ($y,$m,$d) = Decode_Date_EU($str); | Parses "3.1.64" etc. |
| 🌐 Decode date (US) | ($y,$m,$d) = Decode_Date_US($str); | Parses "1/3/64" etc. |
| 📅 Business format | ($yr,$wk,$dow) = Standard_to_Business($y,$m,$d); | Convert to (year,week,dow) |
| 📅 Delta YMD (normalized) | ($Dy,$Dm,$Dd) = N_Delta_YMD($y1,$m1,$d1, $y2,$m2,$d2); | Human-readable difference |
| 📅 Delta YMDHMS (normalized) | ($Dy,$Dm,$Dd,$Dh,$Dm,$Ds) = N_Delta_YMDHMS(...); | With time |
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
N_Delta_YMD
N_Delta_YMDHMS
Normalize_DHMS
Add_Delta_Days
Add_Delta_DHMS
Add_Delta_YM
Add_Delta_YMD
Add_Delta_YMDHMS
Add_N_Delta_YMD
Add_N_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); # DEPRECATED
Week_of_Year
($week,$year) = Week_of_Year($year,$month,$day); # RECOMMENDED
$week = Week_of_Year($year,$month,$day); # DANGEROUS
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);
N_Delta_YMD
($Dy,$Dm,$Dd) =
N_Delta_YMD($year1,$month1,$day1,
$year2,$month2,$day2);
N_Delta_YMDHMS
($D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss) =
N_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);
Add_N_Delta_YMD
($year,$month,$day) =
Add_N_Delta_YMD($year,$month,$day,
$Dy,$Dm,$Dd);
Add_N_Delta_YMDHMS
($year,$month,$day, $hour,$min,$sec) =
Add_N_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec,
$D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss);
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[,$lang]))
Decode_Day_of_Week
if ($dow = Decode_Day_of_Week($string[,$lang]))
Decode_Language
if ($lang = Decode_Language($string))
Decode_Date_EU
if (($year,$month,$day) = Decode_Date_EU($string[,$lang]))
Decode_Date_US
if (($year,$month,$day) = Decode_Date_US($string[,$lang]))
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[,$lang]);
Date_to_Text
$string = Date_to_Text($year,$month,$day[,$lang]);
Date_to_Text_Long
$string = Date_to_Text_Long($year,$month,$day[,$lang]);
English_Ordinal
$string = English_Ordinal($number);
Calendar
$string = Calendar($year,$month[,$orthodox[,$lang]]);
Month_to_Text
$string = Month_to_Text($month[,$lang]);
Day_of_Week_to_Text
$string = Day_of_Week_to_Text($dow[,$lang]);
Day_of_Week_Abbreviation
$string = Day_of_Week_Abbreviation($dow[,$lang]);
Language_to_Text
$string = Language_to_Text($lang);
Language
$lang = Language();
Language($lang); # DEPRECATED
$oldlang = Language($newlang); # DEPRECATED
Languages
$max_lang = Languages();
Decode_Date_EU2
if (($year,$month,$day) = Decode_Date_EU2($string[,$lang]))
Decode_Date_US2
if (($year,$month,$day) = Decode_Date_US2($string[,$lang]))
Parse_Date
if (($year,$month,$day) = Parse_Date($string[,$lang]))
ISO_LC
$lower = ISO_LC($string);
ISO_UC
$upper = ISO_UC($string);
Version
$string = Date::Calc::Version();
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.
Note that the following functions
Gmtime()
Localtime()
Mktime()
Timezone()
are actually wrappers around or based upon the corresponding POSIX functions "time()", "gmtime()", "localtime()" and "mktime()".
As such, they depend on local settings of the underlying machine such as e.g. the system clock, the time zone and the locale.
Their results can therefore sometimes be unexpected or counter-intuitive.
Therefore, no support can be provided for these functions.
They are supplied "as is", purely for the sake of interoperability.
Use at your own risk. (You have been warned!)
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).
Boolean values returned from functions in this module are always a numeric zero ("0") for "false" and a numeric one ("1") for "true".
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)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 "eval" in perlfunc(1) for details).
$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".
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.
Consistent with current practice, current norms and standards (such as ISO/R 2015-1971, DIN 1355 and ISO 8601) define the Monday as the first day of the week.
$week = Week_Number($year,$month,$day);
This function returns the number of the week the given date lies in.
If the given date lies in the LAST week of the PREVIOUS year, "0" is returned.
If the given date lies in the FIRST week of the NEXT year, ""Weeks_in_Year($year) + 1"" is returned.
($week,$year) = Week_of_Year($year,$month,$day); — returns (week, year)
This function returns the number of the week the given date lies in, as well as the year that week belongs to.
I.e., if the given date lies in the LAST week of the PREVIOUS year, ""(Weeks_in_Year($year-1), $year-1)"" is returned.
If the given date lies in the FIRST week of the NEXT year, ""(1, $year+1)"" is returned.
In scalar context, this function returns just the week number. BEWARE that using this function in scalar context is a DANGEROUS feature, because without knowing which year the week belongs to, you might inadvertently assume the wrong one!
($year,$month,$day) = Monday_of_Week($week,$year);
This function returns the date of the first day of the given week, i.e., the Monday.
"$year" must be greater than or equal to "1", and "$week" must lie in the range "1" to ""Weeks_in_Year($year)"".
If you want to calculate any other day of week in the same week as a given date, use
@date = Add_Delta_Days(Monday_of_Week(Week_of_Year(@date)),$offset);
where "$offset = 1" for Tuesday, 2 for Wednesday etc.
if (($year,$month,$day) = Nth_Weekday_of_Month_Year($year,$month,$dow,$n))
This function calculates the date of the "$n"th day of week "$dow" in the given month "$month" and year "$year"; such as, for example, the 3rd Thursday of a given month and year.
"$year" must be ≥ 1, "$month" in 1..12, "$dow" in 1..7, "$n" in 1..5, or a fatal error occurs.
The function returns an empty list when the 5th of a given day of week does not exist in the given month and year.
($year,$week,$dow) = Standard_to_Business($year,$month,$day);
($year,$month,$day) = Business_to_Standard($year,$week,$dow);
These functions convert between standard notation (year, month, day) and business notation (year, week, day of week).
$Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2);
Returns the difference in days between the two given dates. Positive if date1 is chronologically BEFORE date2, negative if reversed, zero if identical.
($Dd,$Dh,$Dm,$Ds) = Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
Returns the difference in days, hours, minutes and seconds. All four values are positive if chronological, negative if reversed. Complementary with Add_Delta_DHMS.
($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);
Returns the vector ($year2 - $year1, $month2 - $month1, $day2 - $day1). This is the "one-by-one" semantics.
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) = Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
Based on Delta_YMD but additionally calculates the time difference, adjusting $D_d accordingly.
($Dy,$Dm,$Dd) = N_Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);
Returns the difference in a more intuitive "normalized" way: all signs are the same (or zero), and results are minimal (|$Dm| < 12, |$Dd| < 31). Uses "left-to-right with truncation" semantics.
($D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss) = N_Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
Same as N_Delta_YMD but also includes time difference. All values have the same sign and are minimal.
($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds);
Renormalizes four arbitrary values for days, hours, minutes, seconds so that hours, minutes, seconds lie in [-23..23], [-59..59], [-59..59] respectively, and all have the same sign.
($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd);
Calculates a new date given an initial date and an offset in days (positive or negative). Also used to convert canonical day numbers back to dates.
($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec, $Dd,$Dh,$Dm,$Ds);
Adds a days, hours, minutes, seconds offset to a given date and time.
($year,$month,$day) = Add_Delta_YM($year,$month,$day, $Dy,$Dm);
Adds a year and/or month offset. If the resulting day is out of range for the new month, it truncates to the last valid day (e.g., Jan 31 + 1 month → Feb 28).
($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);
Adds years, months, and days offsets independently. Years/months applied first, days last. If the resulting date falls past the end of the month, days are counted forward into the next month.
($year,$month,$day, $hour,$min,$sec) = Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec, $D_y,$D_m,$D_d, $Dh,$Dm,$Ds);
Same as Add_Delta_YMD but also includes a time offset.
($year,$month,$day) = Add_N_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);
Shortcut for applying Add_Delta_YM first, then Add_Delta_Days. Complementary with N_Delta_YMD.
($year,$month,$day, $hour,$min,$sec) = Add_N_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec, $D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss);
Same as Add_N_Delta_YMD but includes time difference.
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]);
Returns current date, time, day of year (1..366), day of week (1=Mon..7=Sun), and daylight savings flag (-1 unknown, 0 no, 1 yes). Optional $gmt=true returns GMT instead of local time.
($year,$month,$day) = Today([$gmt]);
Returns current year, month, day.
($hour,$min,$sec) = Now([$gmt]);
Returns current hour, minute, second.
($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);
Returns current date and time.
$year = This_Year([$gmt]);
Returns current year.
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]);
Date::Calc's equivalent of Perl's built-in gmtime(). Optional parameter: seconds since epoch.
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]);
Date::Calc's equivalent of Perl's built-in localtime().
$time = Mktime($year,$month,$day, $hour,$min,$sec);
Converts a date/time into seconds since epoch (like POSIX::mktime but with normal year/month ranges).
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);
Returns the difference between localtime and gmtime (timezone offset) plus dst flag.
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);
Converts a date/time (UTC) to seconds since epoch. Fast implementation, no system calls. Complementary with Time_to_Date.
($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);
Converts seconds since epoch (UTC) to date/time. Fast, no system calls. Complementary with Date_to_Time.
($year,$month,$day) = Easter_Sunday($year);
Calculates Easter Sunday for years 1583–2299 using the "Gaussian Rule". Related Christian feast days can be computed with offsets:
if ($month = Decode_Month($string[,$lang]))
Takes a string (month name or abbreviation) and returns the month number (1..12) or 0 if not found. Case-insensitive.
if ($dow = Decode_Day_of_Week($string[,$lang]))
Takes a string (day name or abbreviation) and returns the day number (1..7) or 0 if not found.
if ($lang = Decode_Language($string))
Takes a string (language name in that language itself) and returns the internal language number (1..14 in original distribution) or 0.
if (($year,$month,$day) = Decode_Date_EU($string[,$lang]))
Parses a date string in European order (day-month-year). Accepts many formats, including numeric, alphanumeric months, and delimiters. Two-digit years use moving window.
if (($year,$month,$day) = Decode_Date_US($string[,$lang]))
Parses a date string in US order (month-day-year). Accepts many formats.
$year = Fixed_Window($yy);
Converts two-digit years: yy < 70 → 20yy, yy ≥ 70 → 19yy.
$year = Moving_Window($yy);
Converts two-digit years using a +/-50 year window around the current year.
$date = Compress($year,$month,$day);
Encodes a date in 16 bits (yyyyyyy mmmm ddddd). Can only handle dates within one century (1970–2069 in default config).
if (($century,$year,$month,$day) = Uncompress($date))
Decodes a compressed date, returning century, year (two-digit), month, day.
if (check_compressed($date))
Returns true if the given value is a valid compressed date.
$string = Compressed_to_Text($date[,$lang]);
Returns a 9-character string "dd-Mmm-yy" for a compressed date, or "??-???-??" if invalid.
$string = Date_to_Text($year,$month,$day[,$lang]);
Returns a string of the form "www dd-Mmm-yyyy" (e.g., "Wed 31-Mar-1998").
$string = Date_to_Text_Long($year,$month,$day[,$lang]);
Returns a longer textual representation like "Wwwwww, dd Mmmmmm yyyy" (format depends on language).
$string = English_Ordinal($number);
Returns the English ordinal abbreviation: 1 → "1st", 2 → "2nd", 3 → "3rd", 4 → "4th", etc.
$string = Calendar($year,$month[,$orthodox[,$lang]]);
Returns a calendar for the given month (like Unix cal). Optional $orthodox=true starts week on Sunday.
$string = Month_to_Text($month[,$lang]);
Returns the name of the month (language-dependent).
$string = Day_of_Week_to_Text($dow[,$lang]);
Returns the name of the day of week (language-dependent).
$string = Day_of_Week_Abbreviation($dow[,$lang]);
Returns a special abbreviation if defined for the language, otherwise the first three letters of the day name.
$string = Language_to_Text($lang);
Returns the name of a language given its internal number.
$lang = Language(); — returns current language number
Language($lang); — sets global language (deprecated — use per-function language parameter instead)
$max_lang = Languages();
Returns the number of languages available in the current installation.
if (($year,$month,$day) = Decode_Date_EU2($string[,$lang]))
if (($year,$month,$day) = Decode_Date_US2($string[,$lang]))
Perl equivalents of the C functions Decode_Date_EU and Decode_Date_US, included as examples for customization.
if (($year,$month,$day) = Parse_Date($string[,$lang))
Useful for parsing dates from Unix date command or email headers.
$lower = ISO_LC($string);
$upper = ISO_UC($string);
Returns a copy of the string with all ISO-Latin-1 letters converted to lower/upper case.
$string = Date::Calc::Version();
Returns the version number of the C library (not exported).
use Date::Calc qw( Date_to_Days );
if (Date_to_Days($year1,$month1,$day1) <
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) <=
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) >
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) >=
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) ==
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) !=
Date_to_Days($year2,$month2,$day2))
$cmp = (Date_to_Days($year1,$month1,$day1) <=>
Date_to_Days($year2,$month2,$day2));
Alternative using Delta_Days:
use Date::Calc qw( Delta_Days );
if (Delta_Days($year1,$month1,$day1, $year2,$month2,$day2) > 0) # date1 before date2
if (Delta_Days($year1,$month1,$day1, $year2,$month2,$day2) == 0) # equal
if (Delta_Days($year1,$month1,$day1, $year2,$month2,$day2) < 0) # date1 after date2
use Date::Calc qw( Date_to_Days );
$lower = Date_to_Days($year1,$month1,$day1);
$upper = Date_to_Days($year2,$month2,$day2);
$date = Date_to_Days($year,$month,$day);
if (($date >= $lower) && ($date <= $upper)) {
# ok
} else {
# not ok
}
use Date::Calc qw( Add_Delta_DHMS Date_to_Days );
@date1 = (2002,8,31,23,59,1);
@date2 = (2002,9,1,11,30,59);
@date3 = Add_Delta_DHMS(@date1, 0,12,0,0); # 12 hours later
@d2 = ( Date_to_Days(@date2[0..2]), ($date2[3]*60+$date2[4])*60+$date2[5] );
@d3 = ( Date_to_Days(@date3[0..2]), ($date3[3]*60+$date3[4])*60+$date3[5] );
@diff = ( $d2[0]-$d3[0], $d2[1]-$d3[1] );
if ($diff[0] > 0 and $diff[1] < 0) { $diff[0]--; $diff[1] += 86400; }
if ($diff[0] < 0 and $diff[1] > 0) { $diff[0]++; $diff[1] -= 86400; }
if (($diff[0] || $diff[1]) >= 0) { print "More than 12 hours.\n"; }
else { print "Less than 12 hours.\n"; }
Alternative using Date_to_Time (if dates are within epoch range):
use Date::Calc qw( Date_to_Time );
$d1 = Date_to_Time(@date1);
$d2 = Date_to_Time(@date2);
if ($d1 + 12*60*60 <= $d2) { print "More than 12 hours.\n"; }
else { print "Less than 12 hours.\n"; }
use Date::Calc qw( Decode_Date_EU Today leap_year Delta_Days );
$date = <STDIN>;
($year1,$month1,$day1) = Decode_Date_EU($date);
($year2,$month2,$day2) = Today();
if (($day1 == 29) && ($month1 == 2) && !leap_year($year2)) { $day1--; }
if ( (($year2 - $year1) > 18) ||
( (($year2 - $year1) == 18) &&
(Delta_Days($year2,$month1,$day1, $year2,$month2,$day2) >= 0) ) )
{
print "Ok - you are over 18.\n";
} else {
print "Sorry - you aren't 18 yet!\n";
}
use Date::Calc qw( Today Day_of_Week );
($year,$month,$day) = Today();
$week = int(($day + Day_of_Week($year,$month,1) - 2) / 7) + 1;
use Date::Calc qw( Day_of_Week Delta_Days
Nth_Weekday_of_Month_Year
Date_to_Text_Long English_Ordinal
Day_of_Week_to_Text Month_to_Text );
($year,$month,$day) = (2000,10,15);
$dow = Day_of_Week($year,$month,$day);
$n = int( Delta_Days(
Nth_Weekday_of_Month_Year($year,$month,$dow,1),
$year,$month,$day)
/ 7) + 1;
printf("%s is the %s %s in %s %d.\n",
Date_to_Text_Long($year,$month,$day),
English_Ordinal($n),
Day_of_Week_to_Text($dow),
Month_to_Text($month),
$year);
Prints: "Sunday, October 15th 2000 is the 3rd Sunday in October 2000."
use Date::Calc qw( Today Day_of_Week Add_Delta_Days );
$searching_dow = 3; # Wednesday
@today = Today();
$current_dow = Day_of_Week(@today);
@date = Add_Delta_Days(@today, $searching_dow - $current_dow);
Alternative using Monday_of_Week:
use Date::Calc qw( Today Add_Delta_Days Monday_of_Week Week_of_Year );
@date = Add_Delta_Days( Monday_of_Week( Week_of_Year(@today) ),
$searching_dow - 1 );
Alternative using business format:
use Date::Calc qw( Standard_to_Business Today Business_to_Standard );
@business = Standard_to_Business(Today());
$business[2] = 3; # Wednesday
@date = Business_to_Standard(@business);
use Date::Calc qw( Business_to_Standard Add_Delta_Days Standard_to_Business );
@temp = Business_to_Standard($year,$week,$dow);
@temp = Add_Delta_Days(@temp, $week_offset * 7);
($year,$week,$dow) = Standard_to_Business(@temp);
use Date::Calc qw( Today Day_of_Week Add_Delta_Days
Day_of_Week_to_Text Date_to_Text );
$searching_dow = 6; # Saturday
@today = Today();
$current_dow = Day_of_Week(@today);
if ($searching_dow == $current_dow) {
@prev = Add_Delta_Days(@today,-7);
@next = Add_Delta_Days(@today,+7);
} else {
if ($searching_dow > $current_dow) {
@next = Add_Delta_Days(@today, $searching_dow - $current_dow);
@prev = Add_Delta_Days(@next,-7);
} else {
@prev = Add_Delta_Days(@today, $searching_dow - $current_dow);
@next = Add_Delta_Days(@prev,+7);
}
}
$dow = Day_of_Week_to_Text($searching_dow);
print "Today is: ", ' ' x length($dow), Date_to_Text(@today), "\n";
print "Last $dow was: ", Date_to_Text(@prev), "\n";
print "Next $dow will be: ", Date_to_Text(@next), "\n";
Solution #1 (holidays NOT taken into account):
use Date::Calc qw( Days_in_Month Day_of_Week Add_Delta_Days );
$day = Days_in_Month($year,$month);
$dow = Day_of_Week($year,$month,$day);
if ($dow > 5) {
($year,$month,$day) = Add_Delta_Days($year,$month,$day, 5-$dow);
}
Solution #2 (holidays taken into account using a holiday array):
use Date::Calc qw( Days_in_Month Add_Delta_Days Day_of_Week );
$day = Days_in_Month($year,$month);
while (1) {
while ($holiday[$year][$month][$day]) {
($year,$month,$day) = Add_Delta_Days($year,$month,$day, -1);
}
$dow = Day_of_Week($year,$month,$day);
if ($dow > 5) {
($year,$month,$day) = Add_Delta_Days($year,$month,$day, 5-$dow);
} else { last; }
}
Solution #3 (using Date::Calendar):
use Date::Calc::Object qw( Today Add_Delta_YM Date_to_Text_Long );
use Date::Calendar::Profiles qw($Profiles);
use Date::Calendar;
$calendar = Date::Calendar->new( $Profiles->{'DE-BW'} );
@today = Today();
@nextmonth = Add_Delta_YM(@today[0,1],1, 0,1);
$workaround = $calendar->add_delta_workdays(@nextmonth,+1);
$payday = $calendar->add_delta_workdays($workaround,-2);
print "Pay day = ", Date_to_Text_Long($payday->date()), "\n";
use Date::Calc qw( Add_Delta_DHMS Date_to_Text );
$datetime = "35883.121653";
($Dd,$Dh,$Dm,$Ds) = ($datetime =~ /^(\d+)\.(\d\d)(\d\d)(\d\d)$/);
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_DHMS(1900,1,1, 0,0,0, $Dd,$Dh,$Dm,$Ds);
printf("The given date is %s %02d:%02d:%02d\n",
Date_to_Text($year,$month,$day), $hour, $min, $sec);
Note: Excel has a bug where it thinks 1900 was a leap year. Use 31-Dec-1899 as base date instead.
use Date::Calc qw( Today Date_to_Days Add_Delta_YMD
Nth_Weekday_of_Month_Year );
($year,$month,$day) = Today();
$tomorrow = Date_to_Days($year,$month,$day) + 1;
$dow = 5; # Friday
$n = 1; # First
$meeting_this_month = Date_to_Days(
Nth_Weekday_of_Month_Year($year,$month,$dow,$n) );
($year,$month,$day) = Add_Delta_YMD($year,$month,$day, 0,1,0);
$meeting_next_month = Date_to_Days(
Nth_Weekday_of_Month_Year($year,$month,$dow,$n) );
if (($tomorrow == $meeting_this_month) ||
($tomorrow == $meeting_next_month)) {
# Send reminder e-mail!
}
use Date::Calc qw( Today Day_of_Week_to_Text
Day_of_Week Month_to_Text English_Ordinal );
($year,$month,$day) = Today();
# With leading zeros: "Fri 03-Jan-1964"
printf("%.3s %02d-%.3s-%d\n",
Day_of_Week_to_Text(Day_of_Week($year,$month,$day)),
$day, Month_to_Text($month), $year);
# US format: "April 12th, 1998"
$string = sprintf("%s %s, %d",
Month_to_Text($month), English_Ordinal($day), $year);
# ISO 8601: "1998-04-12 15:30:00"
@date = ($year,$month,$day,$hour,$min,$sec);
$date = sprintf("%d-%02d-%02d %02d:%02d:%02d", @date);
use Date::Calc qw( Delta_Days Add_Delta_Days );
@start = (1999,5,27);
@stop = (1999,6,1);
$j = Delta_Days(@start,@stop);
for ( $i = 0; $i <= $j; $i++ ) {
@date = Add_Delta_Days(@start,$i);
printf("%4d/%02d/%02d\n", @date);
}
use Date::Calc qw( Delta_Days Add_Delta_Days Date_to_Text );
sub date_range {
my(@date) = (@_)[0,1,2];
my(@list);
my($i);
$i = Delta_Days(@_);
while ($i-- >= 0) {
push( @list, [ @date ] );
@date = Add_Delta_Days(@date, 1) if ($i >= 0);
}
return(@list);
}
@range = &date_range(1999,11,3, 1999,12,24);
foreach $date (@range) {
print Date_to_Text(@{$date}), "\n";
}
sub Delta_Business_Days {
my(@date1) = (@_)[0,1,2];
my(@date2) = (@_)[3,4,5];
my($minus,$result,$dow1,$dow2,$diff,$temp);
$minus = 0;
$result = Delta_Days(@date1,@date2);
if ($result != 0) {
if ($result < 0) {
$minus = 1;
$result = -$result;
$dow1 = Day_of_Week(@date2);
$dow2 = Day_of_Week(@date1);
} else {
$dow1 = Day_of_Week(@date1);
$dow2 = Day_of_Week(@date2);
}
$diff = $dow2 - $dow1;
$temp = $result;
if ($diff != 0) {
if ($diff < 0) { $diff += 7; }
$temp -= $diff;
$dow1 += $diff;
if ($dow1 > 6) { $result--;
if ($dow1 > 7) { $result--; }
}
}
if ($temp != 0) {
$temp /= 7;
$result -= ($temp << 1);
}
}
if ($minus) { return -$result; }
else { return $result; }
}
Note: This doesn't take legal holidays into account. See Date::Calendar for that.
Use the built-in functions N_Delta_YMDHMS and N_Delta_YMD instead. The following is a historical sketch:
sub Normalize_Delta_YMDHMS {
my($date1,$date2) = @_;
my(@delta);
@delta = Delta_YMDHMS(@$date1,@$date2);
while ($delta[1] < 0 or $delta[2] < 0 or $delta[3] < 0 or $delta[4] < 0 or $delta[5] < 0) {
if ($delta[1] < 0) { $delta[0]--; $delta[1] += 12; }
if ($delta[2] < 0) {
$delta[1]--;
@delta[2..5] = (0,0,0,0);
@delta[2..5] = Delta_DHMS(Add_Delta_YMDHMS(@$date1,@delta),@$date2);
}
if ($delta[3] < 0) { $delta[2]--; $delta[3] += 24; }
if ($delta[4] < 0) { $delta[3]--; $delta[4] += 60; }
if ($delta[5] < 0) { $delta[4]--; $delta[5] += 60; }
}
return \@delta;
}
Date::Calc::Util(3), Date::Calc::Object(3), Date::Calendar(3), Date::Calendar::Year(3), Date::Calendar::Profiles(3).
"The Calendar FAQ": http://www.tondering.dk/claus/calendar.html by Claus Tondering <claus@tondering.dk>
When you are using the (deprecated) function "Language()", the language setting is stored in a global variable. This may cause conflicts between threads or modules running concurrently. Therefore, in order to avoid such conflicts, NEVER use the function "Language()", but ALWAYS pass a language parameter to the functions which are language-dependent.
This man page documents "Date::Calc" version 6.4.
Steffen Beyer
mailto:STBEY@cpan.org
http://www.engelschall.com/u/sb/download/
Copyright (c) 1995 - 2015 by Steffen Beyer. All rights reserved.
This package is free software; you can use, modify and redistribute it under the same terms as Perl itself, i.e., at your option, under the terms either of the "Artistic License" or the "GNU General Public License".
The C library at the core of the module "Date::Calc::XS" can, at your discretion, also be used, modified and redistributed under the terms of the "GNU Library General Public License".
Please refer to the files "Artistic.txt", "GNU_GPL.txt" and "GNU_LGPL.txt" in the "license" subdirectory of this distribution for any details!
This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the "GNU General Public License" for more details.
Generated by phpman v4.9.26-5-g7740029 · Markdown · JSON · MCP Author: Che Dong Under GNU General Public License
2026-08-22 01:52 @216.73.216.206
CrawledBy Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)