Pcalc(3pm)
β¨ NAME β¨
Date::Pcalc β bestie, it's literally Gregorian calendar date calculations. This is the Pcalc(3pm) manual page, a user-contributed Perl documentation moment. Periodt. π
π MOTTO π
Keep it small, fast and simple
That's the motto. No cap. β¨
πΈ PREFACE πΈ
Okay so first thing: this package is a library written in pure Perl. It does all sorts of date calculations based on the Gregorian calendar β you know, the one all western countries use today. It complies with all the relevant norms and standards: ISO/R 2015-1971, DIN 1355, and to some extent ISO 8601 (where applicable). Iconic. π
Also! There's a link if you want to see a scan of part of the "DIN 1355" document (it's in German): http://www.engelschall.com/u/sb/download/Date-Calc/DIN1355/. π«Ά
This package is meant to be a drop-in replacement for Date::Calc(3). That one is written in C and XS, so it needs a C compiler to build and install β and this one doesn't. Slay. π
The module 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. Big range energy. π
But wait β that is not true for the import/export functions in this package. Those are an interface to the internal POSIX date and time functions of your system, and they can only cover dates in these 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. History lesson, but make it date math. π
Some (mainly protestant) countries continued to use the Julian calendar (used until then) until as late as the beginning of the 20th century. wild. π
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. It's giving reliable bestie. π§°β¨
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.) π
π¦ SYNOPSIS π¦
okay so here's the whole import-and-call situation. This is the menu, bestie β every single one. Don't skip a line, iykyk. π
use Date::Pcalc 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::Pcalc 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::Pcalc::Version();
next up: the DESCRIPTION, where we actually explain all of these β buckle up β¨
π IMPORTANT NOTES π
Okay bestie, before we get into the code, here's the tea. β There's a "RECIPES" section at the bottom of this doc with solutions to common problems β go peep it if you're stuck!
- "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 scalar variable on your system, which is at least 32767, according to the ANSI C standard, on which Perl is based (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.
- POSIX functions
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!)
- 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 returned from functions 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 "eval" in perlfunc(1) for details).
π DESCRIPTION π
use Date::Pcalc qw( Days_in_Year Days_in_Month ... );use Date::Pcalc 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).
Not me about to spill the entire tea on why the week starts on Monday, bestie, sit DOWN. π In medieval times, Catholic Popes decreed the Sunday to be the official day of rest, specifically to dissociate the Christian from the Hebrew belief. It's giving very "let's make it a whole different day so nobody gets confused" energy.
It appears that this actually happened with the Emperor Constantin, who converted to Christianity but still worshipped the Sun god and therefore moved the Christian sabbath to the day of the Sun. βοΈ iconic behavior tbh
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 ISO/R 2015-1971, DIN 1355 and ISO 8601) define the Monday as the first day of the week. Monday girlies stay winning π
$week = Week_Number($year,$month,$day);β 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. yes, zero. lowercase zero. no cap.
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);β this one returns the number of the week the given date lies in, plus the year that week actually belongs to. two-for-one, we love a bundle. π«Ά
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.
Otherwise, (Week_Number($year,$month,$day), $year) is returned. clean, predictable, we stan.
$week = Week_of_Year($year,$month,$day);β in scalar context, this function returns just the week number. β¨ This lets you write$week = Week_of_Year($year,$month,$day);instead of($week) = Week_of_Year($year,$month,$day);(note the parentheses around$week, bestie, they matter).
If the given date lies in the LAST week of the PREVIOUS year, Weeks_in_Year($year-1) is returned.
If the given date lies in the FIRST week of the NEXT year, 1 is returned.
Otherwise the return value is identical with that of Week_Number($year,$month,$day).
π¨ 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! π
If for instance you are iterating through an interval of dates, you might assume that the week always belongs to the same year as the given date, which unfortunately is WRONG in some cases! π
In many years, the 31st of December for instance belongs to week number one of the FOLLOWING year. Assuming that the year is the same as your date (31st of December, in this example), sends you back to the first week of the CURRENT year β the Monday of which, by the way, in case of bad luck, might actually lie in the year BEFORE the current year! π
This actually happens in 2002, for example. not me being personally victimized by a calendar.
So you always need to provide the correct corresponding year number by other means, keeping track of it yourself. she's high-maintenance but she's worth it.
In case you do not understand this, never mind, but then simply DO NOT USE this function in scalar context! periodt. π
($year,$month,$day) = Monday_of_Week($week,$year);β returns the date of the first day of the given week, i.e., the Monday. the main character of weekdays fr fr. π
$year must be greater than or equal to 1, and $week must lie in the range 1 to Weeks_in_Year($year). no funny business.
Note that you can write ($year,$month,$day) = Monday_of_Week(Week_of_Year($year,$month,$day)); in order to calculate the date of the Monday of the same week as the given date. π§
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$nth day of week$dowin the given month$monthand year$year; such as, for example, the 3rd Thursday of a given month and year. ποΈβ¨
This can be used to send a notification mail to the members of a group which meets regularly on every 3rd Thursday of a month, for instance. very "your book club reminder" coded. π¬
(See the section RECIPES near the end of this document for a code snippet to actually do so.)
$year must be greater than or equal to 1, $month must lie in the range 1 to 12, $dow must lie in the range 1 to 7 and $n must lie in the range 1 to 5, or a fatal error (with appropriate error message) occurs. respect the ranges or perish. π
The function returns an empty list when the 5th of a given day of week does not exist in the given month and year. it's giving "no thoughts, empty list."
($year,$week,$dow) = Standard_to_Business($year,$month,$day);β converts a given date from standard notation (year, month, day (of month)) to business notation (year, week, day of week). ππΌ($year,$month,$day) = Business_to_Standard($year,$week,$dow);β converts a given date from business notation (year, week, day of week) to standard notation (year, month, day (of month)). the other direction, bestie, we go both ways. π«Ά$Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2);β returns the difference in days between the two given dates. π
The result is positive if the two dates are in chronological order, i.e., if date #1 comes chronologically BEFORE date #2, and negative if the order of the two dates is reversed. ββ
The result is zero if the two dates are identical. same date, same energy, zero delta.
($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 between the two given dates with times. β° four values, one glow-up.
All four return values will be positive if the two dates are in chronological order, i.e., if date #1 comes chronologically BEFORE date #2, and negative (in all four return values!) if the order of the two dates is reversed. yes, ALL FOUR. they move as a unit. π
This is so that the two functions Delta_DHMS() and Add_Delta_DHMS() (description see further below) are complementary, i.e., mutually inverse: π
Add_Delta_DHMS(@date1,@time1, Delta_DHMS(@date1,@time1, @date2,@time2))
yields (@date2,@time2) again, whereas
Add_Delta_DHMS(@date2,@time2,
map(-$_, Delta_DHMS(@date1,@time1, @date2,@time2)))
yields (@date1,@time1), and
Delta_DHMS(@date1,@time1, Add_Delta_DHMS(@date1,@time1, @delta))
yields @delta again. the way that math justβ¦ works. obsessed. π
The result is zero (in all four return values) if the two dates and times are identical. β¨
($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);β returns the vector
( $year2 - $year1, $month2 - $month1, $day2 - $day1 )
This is called the "one-by-one" semantics. π
Adding the result of this function to the first date always yields the second date again, and adding the negative result (where the signs of all elements of the result vector have been flipped) to the second date gives the first date. See also the description of the function Add_Delta_YMD() further below.
Example: π
(6,2,-30) == Delta_YMD(1996,1,31, 2002,3,1]);
[1996,1,31] + ( 6, 2,-30) = [2002,3, 1]
[2002,3, 1] + (-6,-2, 30) = [1996,1,31]
An error occurs if any of the two given dates is invalid. invalid dates get no sympathy.
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) = Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);β this function is based on the functionDelta_YMD()above but additionally calculates the time difference. β³ When a carry over from the time difference occurs, the value of$D_dis adjusted accordingly, thus giving the correct total date/time difference. she carries. respectfully. π
Arguments are expected to be in chronological order to yield a (usually) positive result.
In any case, adding the result of this function to the first date/time value ($year1,$month1,$day1, $hour1,$min1,$sec1) always gives the second date/time value ($year2,$month2,$day2, $hour2,$min2,$sec2) again, and adding the negative result (with the signs of all elements of the result vector flipped) to the second date/time value gives the first date/time value. ππ
See the function Add_Delta_YMDHMS() further below for adding a date/time value and a date/time difference.
An error occurs if any of the given two date/time values is invalid. π«
($Dy,$Dm,$Dd) = N_Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);β returns the difference between the two given dates in a more intuitive way (as far as possible β more on that see a bit further below) than the functionDelta_YMD()described above. π§ β¨
The N which precedes its name is meant to signify "new" or "normalized". slay.
This function is loosely based on recipe #17 b) (see the section RECIPES below near the end of this document). π
However, the code of recipe #17 b) actually does not treat positive and negative values symmetrically and consistently. yikes.
This new routine does. π she fixed it. she's the moment.
The return values of this function are guaranteed to all have the same sign (or to be zero). This is why this function is called "normalized". π
Moreover, the results are guaranteed to be "minimal", in the sense that |$Dm| < 12 and |$Dd| < 31 (which is equivalent to $Dm lying in the range [-11..+11] and $Dd lying in the range [-30..+30]). small and tidy, we love her. π
When the results are applied (i.e., added) to the first given date in a left-to-right order, the second given date is guaranteed to be obtained, provided that intermediary results are truncated, as done by the function Add_Delta_YM() (see further below), i.e., that invalid intermediate dates such as e.g. [2009,2,31] will automatically be transformed into [2009,2,28] (and not "wrapped" into the next month, e.g. to [2009,3,3]). no wrapping, only truncating. βοΈ
This is called the "left-to-right with truncation" semantics.
Note that reversing the order of the given dates and reversing the sign of each of the result values will not always add up. π it's giving asymmetric breakup.
Consider the dates [2008,2,29] and [2009,2,1]: their difference is (0,11,3) ([2008,2,29] plus 11 months is [2009,1,29], which plus 3 days is [2009,2,1]), but the difference between [2009,2,1] and [2008,2,29] is (0,-11,-1), and not (0,-11,-3) ([2009,2,1] minus 11 months is [2008,3,1], which minus one day is [2008,2,29]). π the math said "trust me bro" and then did NOT trust you bro.
Another example: The difference between [1996,2,29] and [1997,2,28] is (1,0,0) (observe the truncation of the invalid date [1997,2,29] to [1997,2,28] here!), whereas the difference between [1997,2,28] and [1996,2,29] is (0,-11,-28) ([1997,2,28] minus 11 months is [1996,3,28], which minus 28 days is not [1996,3,0] but of course [1996,2,29]). π¦ and THAT'S on leap years, bestie.
βBenignβ cases like the gap between [1964,1,3] and [2009,9,10] are completely symmetrical, bestie β the difference there is (45,8,7), and flipping the order gives you (-45,-8,-7), exactly like your brain expects. And in that one, the answer also matches what Delta_YMD() hands back. π
All of this chaos? It's 100% because months (and, thanks to leap years, years too) are not a fixed number of days. So the meaning of βplus one monthβ or βplus one yearβ is straight-up undefined. There's no correct answer to find, bestie, only definitions to pick. π
So this function is a vibe attempt: define it in a way that feels intuitive most of the time and at least stays internally consistent the rest of the time. Other definitions exist, sure, but most of them end up contradicting themselves (like: the result and the original first date don't add back up to the second date, which is giving broken math). π
Wanna play with this function hands-on? Look at the file datecalc.pl in the examples subdirectory of this distribution, or hit up the online version at http://www.engelschall.com/u/sb/datecalc/. π¦
Errors: one blows up if either of the two dates you gave is invalid, or if any intermediate result along the way lands on an invalid date. (Note: that does not apply to truncation, as we talked about up above.) β οΈ
($D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss) = N_Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);β basically the same deal asN_Delta_YMD()right above, except this one also counts the difference in hours, minutes and seconds. β¨
It's loosely based on recipe #17 a) (peep the βRECIPESβ section near the end of this document). But heads up: the code in recipe #17 a) genuinely doesn't treat positive and negative values symmetrically and consistently. This new routine does. π
Every return value here β time differences included β is guaranteed to have the same sign (or be zero). That's literally why there's an N in front of the name: it stands for βnormalizedβ (or βnewβ). π
Bonus: the results are guaranteed to be minimal, meaning |$D_m| < 12, |$D_d| < 31, |$Dhh| < 24, |$Dmm| < 60 and |$Dss| < 60. Which is the same thing as saying $D_m lives in the range [-11..+11], $D_d lives in [-30..+30], $Dhh lives in [-23..+23], and $Dmm and $Dss both live in [-59..+59]. π
($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds);β you hand this one four whatever values for days, hours, minutes and seconds (they can all have different signs, no judgment π«Ά), and it renormalizes them so that hours, minutes and seconds land in the ranges[-23..23],[-59..59]and[-59..59]respectively, and so that all four values end up with the same sign (or zero). π
The values you passed in are left untouched, i.e., unchanged. No surprise side effects, we love that for you.
($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd);β this one has two main-character uses:
First up: calculate a new date from a starting date plus an offset in days (positive or negative β both welcome), so you can answer stuff like βtoday plus 90 days β which date is that, bestie?β π
(Want a weeks offset instead? Just multiply your weeks by 7 and use that as your days offset. Easy.)
Second: convert the canonical representation of a date β i.e. the number of that day, counting starting at the 1st of January in 1 A.D. β back into a year/month/day date. π°οΈ
Because counting starts at 1, you actually have to subtract 1 from the canonical date to get your original date back:
$canonical = Date_to_Days($year,$month,$day);
($year,$month,$day) = Add_Delta_Days(1,1,1, $canonical - 1);
Also, this function is the inverse of Delta_Days():
Add_Delta_Days(@date1, Delta_Days(@date1, @date2))
hands you @date2 again, whereas
Add_Delta_Days(@date2, -Delta_Days(@date1, @date2))
hands you @date1, and
Delta_Days(@date1, Add_Delta_Days(@date1, $delta))
hands you $delta again. Round trip slay. π
($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 onto a given date and time, for answering questions like βtoday, right now, plus 7 days, but minus 5 hours, and then plus 30 minutes β what date and time is that?β π
($y,$m,$d,$H,$M,$S) = Add_Delta_DHMS(Today_and_Now(), +7,-5,+30,0);
($year,$month,$day) = Add_Delta_YM($year,$month,$day, $Dy,$Dm);β adds a year and/or month offset to a given date. ποΈ
Big difference from the function right below it (Add_Delta_YMD()): this one does no βwrappingβ into the next month if the day happens to land outside the valid range for the resulting year and month (after adding the year/month offsets). Instead, it just truncates the day down to the last possible day of the resulting month. βοΈ
Examples, because vibes aren't enough:
Adding an offset of 0 years, 1 month to the date [1999,1,31] would
result in the (invalid) date [1999,2,31]. The function replaces this
result by the (valid) date [1999,2,28].
Adding an offset of 1 year, 1 month to the same date [1999,1,31] as
above would result in the (still invalid) date [2000,2,31]. The
function replaces this result by the valid date [2000,2,29] (because
2000 is a leap year).
Note that the year and month offsets can be negative, and they can even have different signs. π
Wanna also add a days offset? Then use Add_Delta_Days() before or after calling Add_Delta_YM():
@date2 = Add_Delta_Days( Add_Delta_YM(@date1, $Dy,$Dm), $Dd );
@date2 = Add_Delta_YM( Add_Delta_Days(@date1, $Dd), $Dy,$Dm );
Warning: your result may depend on the order you call those two functions in! π¨
Take the date [1999,2,28] with the offsets 0 years, 1 month and 1 day:
[1999,2,28] plus one month is [1999,3,28], plus one day is
[1999,3,29]. [1999,2,28] plus one day is [1999,3,1], plus one month is
[1999,4,1].
(Which is also why Add_Delta_YM() doesn't let you add a days offset at all β that would genuinely need two functions: one for adding days BEFORE and one for adding them AFTER the year/month offsets are applied.) π
An error occurs if the initial date isn't valid.
And ngl, note that Add_Delta_YM( Add_Delta_YM(@date, $Dy,$Dm), -$Dy,-$Dm ); will not, in general, give you back the original date @date (check the examples above, bestie!). π
($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);β adds a years/months/days offset to a given date. β¨
(Want a weeks offset? Just multiply your weeks by 7 and add that number to your days offset. Same trick as before.)
Note that all three offsets β years, months, days β get applied independently of each other. That's also what lets them have different signs. π
Order of operations, periodt: years and months offsets go first, days offset goes last.
If the resulting date happens to fall on a day past the end of the resulting month β like the 32nd of April or the 30th of February ππ β then the date just gets counted forward into the next month (possibly even into the next year) by however many days are excessive. So e.g. the 32nd of April becomes the 2nd of May. π₯
BEWARE that this behaviour differs from that of previous versions of this module! In previous versions, the day was simply truncated to the maximum number of days in the resulting month. If you want the old behaviour, use the new functionAdd_Delta_YM()(described right above) plus the functionAdd_Delta_Days()instead. β οΈ
BEWARE also that because a year and a month offset is not equivalent to a fixed number of days, the transformation this function performs is NOT ALWAYS REVERSIBLE! π
That's in contrast to Add_Delta_Days() and Add_Delta_DHMS(), which are fully and truly reversible (with a lil help from Delta_Days() and Delta_DHMS(), for instance). π«Ά
For that exact same reason, note:
@date = Add_Delta_YMD(
Add_Delta_YMD(@date, $Dy,$Dm,$Dd), -$Dy,-$Dm,-$Dd);
will in general NOT return the initial date @date, even though
@date2 = Add_Delta_YMD( @date1, Delta_YMD(@date1, @date2) );
will always return the second date @date2, and
@date1 = Add_Delta_YMD( @date2, map(-$_, Delta_YMD(@date1, @date2)) );
which is the same as
@date1 = Add_Delta_YMD( @date2, Delta_YMD(@date2, @date1) );
will always return the first date @date1.
Examples:
[1996,1,31] + ( 6, 1,-2) = [2002,3,1]
[2002,3, 1] + (-6,-1, 2) = [1996,2,3] # EXPECTED: [1996,1,31]
(6,2,-30) == Delta_YMD(1996,1,31, 2002,3,1);
[1996,1,31] + ( 6, 2,-30) = [2002,3, 1]
[2002,3, 1] + (-6,-2, 30) = [1996,1,31] # OK
(6,1,-2) == Delta_YMD(1996,2,3, 2002,3,1);
[1996,2,3] + ( 6, 1,-2) = [2002,3,1]
[2002,3,1] + (-6,-1, 2) = [1996,2,3] # OK
And note that this is NOT a program bug β it is NECESSARILY so, because of the variable lengths of years and months, and therefore because of the ambiguity of the difference between two dates in terms of years, months and days. I.e.: the difference between two dates can be expressed in more than one way. π€―
[1996,1,31] + (6,1, -2) = [2002,3,1]
[1996,1,31] + (6,2,-30) = [2002,3,1]
($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 the function above, except a time offset may be given in addition to the year, month and day offset. π°οΈβ¨($year,$month,$day) = Add_N_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);β this one is actually a shortcut for applyingAdd_Delta_YM()first, followed byAdd_Delta_Days(). So it does exactly the same as:
($year,$month,$day) = Add_Delta_Days( Add_Delta_YM($year,$month,$day,$Dy,$Dm), $Dd );
Beware: if necessary,Add_Delta_YM()truncates the resulting day of the month to the largest allowable value for that month β i.e. the (invalid) result[2009,2,31]is automatically transformed into[2009,2,28]. β οΈ
For more deets on that truncation, see the description of Add_Delta_YM() further up. π
This one's meant to be the bestie of N_Delta_YMD() (she's described further up, go say hi). π
What that means in practice: it's guaranteed that whatever comes out of
Add_N_Delta_YMD( @date1, N_Delta_YMD(@date1, @date2) );
is always gonna be identical to the date @date2 you handed in. No cap.
But heads up, bestie β unlike with Add_Delta_YMD(), the reverse does NOT hold. Like, at all. So:
($Dy,$Dm,$Dd) = N_Delta_YMD(@date1,@date2);
@date = Add_N_Delta_YMD(@date2, -$Dy,-$Dm,-$Dd);
will NOT always give you back the original @date1. It's giving one-way street energy. π
Example, so you can see the chaos with your own eyes:
(0,11,3) == N_Delta_YMD(2008,2,29, 2009,2,1);
[2008,2,29] + (0, 11, 3) = [2009,2, 1]
[2009,2, 1] + (0,-11,-3) = [2008,2,27] # EXPECTED: [2008,2,29]
($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);β okay so this does basically the same thing asAdd_N_Delta_YMD()right above, except it also takes the hours, minutes and seconds difference into account. Glow up fr. β¨($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]);β if your operating system has the relevant system calls (time()andlocaltime(), orgmtime()), this function hands you back whatever your system clock is saying: the current date and time, the number of the day of year, the number of the day of week, and a flag telling you whether daylight savings time is currently happening or not. Iconic.
The ranges of values returned (and what they mean) go like this:
$year : 1970..2038 (or more) [Unix etc.]
$year : 1904..2040 [MacOS Classic]
$month : 1..12
$day : 1..31
$hour : 0..23
$min : 0..59
$sec : 0..59 (0..61 on some systems)
$doy : 1..366
$dow : 1..7
$dst : -1..1
$doy is the day of year β sometimes also called the "julian date" (iykyk) β and it starts at 1 and climbs all the way up to however many days are in that year. π
The day of week ($dow) will be 1 for Monday, 2 for Tuesday, and so on down the line until 7 for Sunday. Slay.
The daylight savings time flag ($dst) will be -1 if your system just doesn't have that info, 0 for no daylight savings time (i.e., winter time, the sad season), and 1 when daylight savings time is in effect. π°οΈ
If your operating system doesn't provide the necessary system calls, calling this function will get you a fatal not available on this system error message. π
And if you wanna catch that exception yourself instead of letting it ruin your whole day, use "eval" like this:
eval { ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
System_Clock(); };
if ($@)
{
# Handle missing system clock
# (For instance, ask user to enter this information manually)
}
Note that curlies ({and}) are what you use here to delimit the statement beingevaled β that's how you catch exceptions in Perl β and not quotes. Quotes are a whole different thing (that's how you evaluate Perl expressions at runtime). Don't mix them up, bestie. π
If the optional (boolean) input parameter $gmt is given, a true value (1) makes gmtime() get used instead of localtime() internally, so you get Greenwich Mean Time back (GMT, or UTC) instead of local time. π
($year,$month,$day) = Today([$gmt]);β gives you a subset of whatSystem_Clock()returns (details up above β¬οΈ), specifically the current year, month and day.
A fatal not available on this system error message will pop up if your current operating system doesn't support the corresponding system calls.
If the optional (boolean) input parameter $gmt is given, a true value (1) makes gmtime() get used instead of localtime() internally, so you get Greenwich Mean Time (GMT, or UTC) instead of local time.
($hour,$min,$sec) = Now([$gmt]);β returns a subset of whatSystem_Clock()returns (again, details above β¬οΈ), namely the current time (hours, minutes and full seconds). β°
A fatal not available on this system error message will pop up if the relevant system calls aren't supported by your operating system.
If the optional (boolean) input parameter $gmt is given, a true value (1) makes gmtime() get used instead of localtime() internally, so you get Greenwich Mean Time (GMT, or UTC) instead of local time.
($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);β the girlies asked for both and she delivered: a subset ofSystem_Clock()'s values (see above for the deets), specifically the current date (year, month, day) and time (hours, minutes and full seconds). π
A fatal not available on this system error message will appear if those system calls aren't supported by your current operating system.
If the optional (boolean) input parameter $gmt is given, a true value (1) makes gmtime() get used instead of localtime() internally, so you get Greenwich Mean Time (GMT, or UTC) instead of local time.
$year = This_Year([$gmt]);β hands you the current year, according to local time. Just the year. Simple. Elegant. β¨
A fatal not available on this system error message will appear if the corresponding system calls aren't supported by your current operating system.
If the optional (boolean) input parameter $gmt is given, a true value (1) makes gmtime() get used instead of localtime() internally, so you get Greenwich Mean Time (GMT, or UTC) instead of local time. However β plot twist β this only makes a difference within a few hours around New Year. Unless you're on a Pacific island, in which case it can be almost 24 hours. ποΈ
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]);β this is Date::Pcalc's version of Perl's built-ingmtime()function. See alsogmtimein perlfunc(1).
With the optional argument time (i.e., seconds since the epoch), this function returns the corresponding values for that particular time instead of the current time (which is what you get when you leave the parameter out).
The ranges of values returned (and what they mean) are:
$year : 1970..2038 (or more) [Unix etc.]
$year : 1904..2040 [MacOS Classic]
$month : 1..12
$day : 1..31
$hour : 0..23
$min : 0..59
$sec : 0..59
$doy : 1..366
$dow : 1..7
$dst : -1..1
$doy is the day of year, sometimes also referred to as the "julian date", starting at 1 and going up to the number of days in that year.
The day of week ($dow) will be 1 for Monday, 2 for Tuesday and so on until 7 for Sunday.
The daylight savings time flag ($dst) will be -1 if this information isn't available on your system, 0 for no daylight savings time (i.e., winter time) and 1 when daylight savings time is in effect.
A fatal time out of range error will occur if the given time value is out of range [0..(~0>>1)].
If the time value is omitted, the time() function gets called instead, internally.
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]);β this is Date::Pcalc's equivalent of Perl's built-inlocaltime()function. See alsolocaltimein perlfunc(1).
The ranges of values returned (and their meanings) are:
$year : 1970..2038 (or more) [Unix etc.]
$year : 1904..2040 [MacOS Classic]
$month : 1..12
$day : 1..31
$hour : 0..23
$min : 0..59
$sec : 0..59
$doy : 1..366
$dow : 1..7
$dst : -1..1
$doy is the day of year, sometimes also referred to as the "julian date", which starts at 1 and goes up to the number of days in that year.
The day of week ($dow) will be 1 for Monday, 2 for Tuesday and so on until 7 for Sunday.
The daylight savings time flag ($dst) will be -1 if this information isn't available on your system, 0 for no daylight savings time (i.e., winter time) and 1 when daylight savings time is in effect.
A fatal time out of range error will occur if the given time value is out of range [0..(~0>>1)].
If the time value is omitted, the time() function gets called instead, internally.
$time = Mktime($year,$month,$day, $hour,$min,$sec);β this one converts a date into a time value, i.e., into the number of seconds since whatever moment your system considers the "epoch". On Unix and most other systems that's the number of seconds since January 1st 1970 at midnight (GMT). On MacOS Classic it's the number of seconds since January 1st 1904 at midnight (local time). β³
She's similar to the POSIX::mktime() function (see mktime in POSIX(1) for more), but plot twist: unlike that one, she expects dates in the usual ranges used all through this module. So the year 2001 stays year 2001, and months are numbered from 1 to 12. Normal. Sane. We love her. π
A fatal date out of range error will occur if the given date can't be expressed in terms of seconds since the epoch. That happens, for instance, when the date lies before the epoch, or if it's later than 19-Jan-2038 03:14:07 GMT on 32 bit Unix systems, or later than 06-Feb-2040 06:28:15 (local time) on a Macintosh running MacOS Classic.
Just like the POSIX::mktime() function, this function uses the mktime() system call internally.
Which means the given date and time is considered to be in local time, and the value that comes back depends on your machine's local settings β the time zone, whether daylight savings time is (or was, at that moment) in effect, and the system clock itself. Basically it's got opinions and they're all environment-dependent. π
BEWARE bestie, this is the important part:mktime()does not always return the same time value you fed intolocaltime(), when you feed the output oflocaltime()back intomktime(). On some systems it just doesn't. π
I.e., "Mktime((Localtime($time))[0..5])" will not always return the same value as given in $time! Round trip? Denied. π
Note that since Perl doesn't provide any access to the internal system call mktime(), in this pure Perl version, Mktime() is calculated like so:
Date_to_Time(Add_Delta_YMDHMS(@_,map(-$_,(Timezone(Date_to_Time(@_)))[0..5])));
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);β okay bestie, this one tells you how far off from Greenwich you are π
It hands back the difference between localtime(time) and gmtime(time) β which is the timezone offset that's actually in effect for where you're sitting and for the "time" you passed in.
This offset is positive if you live east of Greenwich, and it's usually negative if you live west of Greenwich β except during daylight savings time in some locations, where it can flip.
Heads up: this offset is at the mercy of literally every relevant system setting and parameter on your machine β locales, environment variables (like "TZ") and the system clock itself. Go read the relevant docs on your own system for the full tea.
If you leave out the "time", the time() function gets called automatically, internally (same energy as Perl's built-in localtime() and gmtime()).
A fatal time out of range error will occur if the time value you handed over is out of range [0..(~0>>1)]. π
The last item in the returned list is a flag telling you whether daylight savings time is currently in effect. That flag is negative (-1) if your system doesn't have this info at all. It's zero (0) when daylight savings time is off, and positive (+1) when daylight savings time is on.
So you can vibe-check DST real quick by evaluating this function in scalar context (and in scalar context, Perl hands back the last item of a list):
if (scalar Timezone > 0) { # yes, daylight savings time
But a slightly more efficient way would be this:
if (scalar System_Clock > 0) { # yes, daylight savings time
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);β the glow-up replacement for BSD'stimegm()β¨
This function is a replacement for the BSD function timegm() (which, rude, isn't available on all Unix systems). It converts a given date and time into a time value β meaning the number of seconds since whatever moment in time your system considers to be the "epoch". On Unix and most other systems, that's the number of seconds since January 1st 1970 at midnight (GMT). On MacOS Classic it's the number of seconds since January 1st 1904 at midnight (local time).
Under Unix, the date and time are considered to be in UTC ("Universal Time Coordinated"), and so is the resulting time value.
UTC is almost the same as GMT (or "Greenwich Mean Time"), except UTC has leap seconds (to account for small variations in the rotation of the earth, for instance), whereas GMT does not. Lowkey the same, highkey not. π
Under MacOS Classic, though, both input and output are considered to be in local time.
The ranges of year and month follow the same rules as throughout the rest of this module (and not the contorted rules of its Unix equivalent) β i.e., the year 2001 stays 2001 and the month ranges from 1 to 12.
A fatal date out of range error will occur if the given date can't be expressed in terms of seconds since the epoch. This happens for instance when the date lies before the epoch, or if it's later than 19-Jan-2038 03:14:07 GMT on 32 bit Unix systems, or later than 06-Feb-2040 06:28:15 (local time) on a Macintosh with MacOS Classic. π
This function should be very fast, because it's implemented in a very straightforward manner and doesn't use any internal system calls. Periodt.
And on top of that: Date_to_Time() and Time_to_Date() are guaranteed to be complementary, i.e., "Date_to_Time(Time_to_Date($time))" and "Time_to_Date(Date_to_Time($year,$month,$day, $hour,$min,$sec))" will always return the initial values. They're besties fr fr. π«Ά
($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);β the other half of that iconic duo πΈ
This function is an alternative to the POSIX gmtime() function (and its built-in Perl equivalent). It converts a given time value into the corresponding date and time. The time value you give it must be the number of seconds since whatever moment in time your system considers to be the "epoch". On Unix and most other systems that's the number of seconds since January 1st 1970 at midnight (GMT). On MacOS Classic it's the number of seconds since January 1st 1904 at midnight (local time).
Under Unix, the time value you hand in is considered to be in UTC ("Universal Time Coordinated"), and so is the resulting date and time.
UTC is almost the same as GMT (or "Greenwich Mean Time"), except UTC has leap seconds (to account for small variations in the rotation of the earth, for instance), whereas GMT does not.
Under MacOS Classic, however, both input and output are considered to be in local time.
If the input value "time" is omitted, the time() function will be called automatically, internally (similar to the built-in functions localtime() and gmtime() in Perl).
A fatal time out of range error will occur if the given time value is negative. π¨
This function should be very fast, because it's implemented in a very straightforward manner and doesn't use any internal system calls (except for time(), if the input value is omitted).
And yep, same guarantee as before: Date_to_Time() and Time_to_Date() are complementary, i.e., "Date_to_Time(Time_to_Date($time))" and "Time_to_Date(Date_to_Time($year,$month,$day, $hour,$min,$sec))" will always return the initial values. π
($year,$month,$day) = Easter_Sunday($year);β yes bestie, it knows when Easter is π£
This function calculates the date of Easter Sunday for all years in the range from 1583 to 2299 (all other year numbers will result in a fatal year out of range error message) using the method known as the "Gaussian Rule".
Some related christian feast days which depend on the date of Easter Sunday:
Carnival Monday / Rosenmontag / Veille du Mardi Gras = -48 days
Mardi Gras / Karnevalsdienstag / Mardi Gras = -47 days
Ash Wednesday / Aschermittwoch / Mercredi des Cendres = -46 days
Palm Sunday / Palmsonntag / Dimanche des Rameaux = -7 days
Easter Friday / Karfreitag / Vendredi Saint = -2 days
Easter Saturday / Ostersamstag / Samedi de Paques = -1 day
Easter Monday / Ostermontag / Lundi de Paques = +1 day
Ascension of Christ / Christi Himmelfahrt / Ascension = +39 days
Whitsunday / Pfingstsonntag / Dimanche de Pentecote = +49 days
Whitmonday / Pfingstmontag / Lundi de Pentecote = +50 days
Feast of Corpus Christi / Fronleichnam / Fete-Dieu = +60 days
Use the offsets shown above to calculate the date of the corresponding feast day, like this:
($year,$month,$day) = Add_Delta_Days(Easter_Sunday($year), $offset));
if ($month = Decode_Month($string[,$lang]))β turn a month name into a number, no cap ποΈ
This function takes a string as its argument, which should contain the name of a month in the given or currently selected language (see further below for details about the multi-language support of this package), or any uniquely identifying abbreviation of a month's name (i.e., the first few letters). It returns the corresponding number (1..12) upon a successful match, or 0 otherwise β which is why the return value can also be used as the conditional expression in an if statement. Slay.
Note that the input string may not contain any other characters which do not pertain to the month's name β especially no leading or trailing whitespace. Don't do it. π
Note also that matching is performed in a case-insensitive manner (this may depend on the locale setting on your current system, though!).
With 1 ("English") as the given language, the following examples will all return the value 9:
$month = Decode_Month("s",1);
$month = Decode_Month("Sep",1);
$month = Decode_Month("septemb",1);
$month = Decode_Month("September",1);
if ($dow = Decode_Day_of_Week($string[,$lang]))β same energy, but for days π¦
This function takes a string as its argument, which should contain the name of a day of week in the given or currently selected language (see further below for details about the multi-language support of this package), or any uniquely identifying abbreviation of the name of a day of week (i.e., the first few letters). It returns the corresponding number (1..7) upon a successful match, or 0 otherwise β so yes, the return value can also be used as the conditional expression in an if statement.
Note that the input string may not contain any other characters which do not pertain to the name of the day of week β especially no leading or trailing whitespace.
Note also that matching is performed in a case-insensitive manner (this may depend on the locale setting on your current system, though!).
With 1 ("English") as the given language, the following examples will all return the value 3:
$dow = Decode_Day_of_Week("w",1);
$dow = Decode_Day_of_Week("Wed",1);
$dow = Decode_Day_of_Week("wednes",1);
$dow = Decode_Day_of_Week("Wednesday",1);
if ($lang = Decode_Language($string))β name a language, get its internal number π
This function takes a string as its argument, which should contain the name of one of the languages supported by this package (IN THIS VERY LANGUAGE ITSELF), or any uniquely identifying abbreviation of the name of a language (i.e., the first few letters). It returns its corresponding internal number (1..14 in the original distribution) upon a successful match, or 0 otherwise β therefore, the return value can also be used as the conditional expression in an if statement.
Note that the input string may not contain any other characters which do not pertain to the name of a language β especially no leading or trailing whitespace.
Note also that matching is performed in a case-insensitive manner (this may depend on the locale setting on your current system, though!).
The original distribution supports the following fourteen languages:
- the language codes bestie β here's the whole roster, mapped to their number:
English ==> 1 (default)
FranΓ§ais (French) ==> 2
Deutsch (German) ==> 3
EspaΓ±ol (Spanish) ==> 4
PortuguΓͺs (Portuguese) ==> 5
Nederlands (Dutch) ==> 6
Italiano (Italian) ==> 7
Norsk (Norwegian) ==> 8
Svenska (Swedish) ==> 9
Dansk (Danish) ==> 10
suomi (Finnish) ==> 11
Magyar (Hungarian) ==> 12
polski (Polish) ==> 13
Romaneste (Romanian) ==> 14
Wanna add more languages to this package? Go read the section "How to install additional languages" in the file "INSTALL.txt" in this distribution. That's the whole plug. πΈ
So in the original distribution (aka no other languages installed, just the basics), these examples all come back with the value "3":
$lang = Decode_Language("d");
$lang = Decode_Language("de");
$lang = Decode_Language("Deutsch");
Lowkey heads up: on some systems you might not be able to type those special international characters in the language names straight from the keyboard. π
But bestie, this should never be a problem β just type an abbreviation of the language name: the first few letters up to the character right before the first special international character. Easy. β¨
if (($year,$month,$day) = Decode_Date_EU($string[,$lang]))β the European date detective π
This function scans a string you hand it and tries to parse whatever date might be hiding inside it. It's giving treasure hunt.
If it can't successfully extract a valid date from the input string, it returns an empty list. If it can, it returns the date it found.
It accepts pretty much any format, as long as the date is in the european order (hence the name π ) β day-month-year.
So, zero or more NON-NUMERIC characters may PRECEDE the day and FOLLOW the year.
And zero or more NON-ALPHANUMERIC characters are permitted BETWEEN those three items (between day and month, and between month and year).
The month can be numeric (a number from "1" to "12") or alphanumeric β the name of the month in the given or currently selected language, or any uniquely identifying abbreviation of it.
(Scroll down for the tea on this package's multi-language support! π«)
If the year is given as only one or two digits (so the year is less than 100), it gets mapped into a "window" of +/- 50 years around the current year, exactly like the Moving_Window() function describes (more on that further below).
Now, if day, month and year are ALL numeric but there are NO delimiting characters between them, that string of digits gets mapped like this:
Length: Mapping:
3 dmy
4 dmyy
5 dmmyy
6 ddmmyy
7 dmmyyyy
8 ddmmyyyy
(Where d = day, m = month, y = year.)
Every other string made purely of digits (no delimiters in between) is rejected β not recognized, not the vibe. π
Examples:
"3.1.64"
"3 1 64"
"03.01.64"
"03/01/64"
"3. Jan 1964"
"Birthday: 3. Jan '64 in Backnang/Germany"
"03-Jan-64"
"3.Jan1964"
"3Jan64"
"030164"
"3ja64"
"3164"
Experiment! (Check out the corresponding example applications in the "examples" subdirectory of this distribution if you wanna mess around with it. π₯)
if (($year,$month,$day) = Decode_Date_US($string[,$lang]))β the American date detective πΊπΈ
Same deal: it scans a given string and tries to parse any date embedded in it.
It returns an empty list if it can't successfully extract a valid date from its input string, otherwise it returns the date found.
It accepts almost any format, as long as the date is in the U.S. american order (hence the name π ) β month-day-year.
So zero or more NON-ALPHANUMERIC characters may PRECEDE and FOLLOW the month (precede it, and separate it from the day trailing behind).
Plus zero or more NON-NUMERIC characters are permitted BETWEEN the day and the year, and AFTER the year too.
The month may be numeric (a number from "1" to "12"), or alphanumeric β the month's name in the given or currently selected language, or any uniquely identifying abbreviation thereof.
(Yes bestie, more on the multi-language support further below! π)
If the year is only one or two digits (less than 100), it's mapped to a "window" of +/- 50 years around the current year, as described by Moving_Window() (see below).
If month, day and year are all numeric with NO delimiting characters between them, the digit string maps like this:
Length: Mapping:
3 mdy
4 mdyy
5 mddyy
6 mmddyy
7 mddyyyy
8 mmddyyyy
(Where m = month, d = day, y = year.)
All other purely-digit strings (no intervening delimiters) get rejected β not recognized.
And if only the day and the year form a contiguous string of digits, they map like this:
Length: Mapping:
2 dy
3 dyy
4 ddyy
5 dyyyy
6 ddyyyy
(Where d = day and y = year.)
Examples:
"1 3 64"
"01/03/64"
"Jan 3 '64"
"Jan 3 1964"
"===> January 3rd 1964 (birthday)"
"Jan31964"
"Jan364"
"ja364"
"1364"
Experiment! (The corresponding example applications live in the "examples" subdirectory of this distribution. Go be nosy. π¦)
$year = Fixed_Window($yy);
This one applies a "fixed window" strategy to two-digit year numbers, converting them into four-digit year numbers. Iconic behaviour honestly.
All other year numbers pass through unchanged, except negative year numbers β those make the function return zero ("0") instead. π¬
Two-digit year numbers "yy" below 70 get converted to "20yy", while year numbers equal to or greater than 70 (but less than 100) get converted to "19yy".
In the original distribution of this package, the base century is set to "1900" and the base year to "70" (which is a standard on UNIX systems), but these constants (also called the "epoch") can actually be chosen at will. Main character customization energy. π
$year = Moving_Window($yy);
This applies a "moving window" strategy to two-digit year numbers, converting them into four-digit year numbers β provided the necessary system calls (system clock) are available. If they're not, it falls back to the "fixed window" strategy described in the function right above. Backup plan secured. π«Ά
All other year numbers pass through unchanged, except negative year numbers, which cause the function to return zero ("0") instead.
Two-digit year numbers get mapped according to a "window" of 50 years in both directions (past and future) around the current year.
So like: two-digit year numbers are first mapped to the same century as the current year. If the resulting year is smaller than the current year minus 50, then one more century gets added to the result. And if the resulting year is equal to or greater than the current year plus 50, then a century gets subtracted from the result. Math but make it fashion. β¨
$date = Compress($year,$month,$day);
β οΈ WARNING: This function is legacy code, its use is deprecated!
This function encodes a date into 16 bits, which is the value it returns.
The encoding scheme is as follows:
Bit number: FEDCBA9 8765 43210
Contents: yyyyyyy mmmm ddddd
(Where yyyyyyy holds the number of the year, mmmm the number of the month, and ddddd the number of the day.)
The function returns "0" if the given input values don't represent a valid date. Which means the return value can also be used as the conditional expression in an if statement, to check whether the given input values constitute a valid date. Two-for-one deal. π
Through this special encoding scheme, it's possible to COMPARE compressed dates for equality and order (less than/greater than) WITHOUT any previous DECODING!
But bestie, note this: contiguous dates do NOT necessarily have contiguous compressed representations!
Like, incrementing the compressed representation of a date MAY OR MAY NOT yield a valid new date! π
Also note that this function can only handle dates within one century.
That century can be chosen at will (at compile time of this module) by defining a base century and year (also called the "epoch"). In the original distribution of this package, the base century is "1900" and the base year is "70" (which is standard on UNIX systems).
That lets this function handle dates from "1970" up to "2069".
So if the given year is, say, "95", this package automatically assumes you actually meant "1995". But if you specify a year number SMALLER than 70, like "64", then this package assumes you really meant "2064". Vibes based on windowing, no cap.
You're not stuck with two-digit (abbreviated) year numbers though!
The function also accepts "full-length" year numbers, as long as they fall in the supported range (i.e. "1970" to "2069" in this package's original configuration).
And note that this function is maintained mainly for backward compatibility, and its use is not recommended. You've been warned. π
if (($century,$year,$month,$day) = Uncompress($date))
β οΈ WARNING: This function is legacy code, its use is deprecated!
This function decodes dates that were previously encoded using the Compress() function.
okay so this next one is a little four-for-one deal β it hands you back the century, the year, the month and the day, all pulled out of whatever date is encoded in $date. π If $date is actually a valid date you get the whole lil squad; if it's not, you get an empty list instead. nothing. nada. bye. π
and the $year it returns?? bestie it's a two-digit year β literally the year number taken modulo 100. so the only way to get the "full-length" year number is the expression "$century + $year" (like, 1900 + 95 = 1995, math ate that π
).
heads up: this function is maintained mainly for backward compatibility, and its use is not recommended. π
if (check_compressed($date))
β οΈ WARNING: this function is legacy code, its use is deprecated!
this one vibe-checks your input and tells you true (1) if it's a valid compressed date, or false (0) if it is not. that's it, that's the whole function.
note that this function is maintained mainly for backward compatibility, and its use is not recommended. π
$string = Compressed_to_Text($date[,$lang]);
β οΈ WARNING: this function is legacy code, its use is deprecated!
returns a string of fixed length β always 9 characters long, no cap β holding a textual representation of the compressed date encoded in $date.
that string has the form dd-Mmm-yy, where dd is the two-digit number of the day, Mmm is the first three letters of the name of the month in the given or currently selected language (there's a whole multi-language support section further down in this package, we'll get there), and yy is the two-digit year number (i.e., the year number taken modulo 100, bestie).
if $date doesn't represent a valid date, you get the string ??-???-?? instead. iconic fallback honestly.
note that this function is maintained mainly for backward compatibility, and its use is not recommended. π«Ά
$string = Date_to_Text($year,$month,$day[,$lang]);
returns a string with a textual representation of the given date, shaped like www dd-Mmm-yyyy. so: www = the first three letters of the name of the day of week in the given or currently selected language, or a special abbreviation if special abbreviations have been defined for that language (again, see the multi-language support bits further down); dd = the day (one or two digits); Mmm = the first three letters of the month name in the given or currently selected language; and yyyy = the number of the year in full length. β¨
if the given input values do not constitute a valid date, a fatal not a valid date error occurs. π
(peep the RECIPES section near the end of this document for a code snippet on how to print dates in any format you like β obsessed.)
$string = Date_to_Text_Long($year,$month,$day[,$lang]);
returns a string with a textual representation of the given date, roughly of the form Wwwwww, dd Mmmmmm yyyy. Wwwwww = the name of the day of week in the given or currently selected language; dd = the day (one or two digits); Mmmmmm = the name of the month in the given or currently selected language; yyyy = the number of the year in full length. πΈ
the exact format of the output string depends on the given or currently selected language. in the original distribution of this package, the formats are defined like this:
1 English : "Wwwwww, Mmmmmm ddth yyyy"
2 French : "Wwwwww dd mmmmmm yyyy"
3 German : "Wwwwww, den dd. Mmmmmm yyyy"
4 Spanish : "Wwwwww, dd de mmmmmm de yyyy"
5 Portuguese : "Wwwwww, dia dd de mmmmmm de yyyy"
6 Dutch : "Wwwwww, dd mmmmmm yyyy"
7 Italian : "Wwwwww, dd Mmmmmm yyyy"
8 Norwegian : "wwwwww, dd. mmmmmm yyyy"
9 Swedish : "wwwwww, dd mmmmmm yyyy"
10 Danish : "wwwwww, dd. mmmmmm yyyy"
11 Finnish : "wwwwww, dd. mmmmmmta yyyy"
12 Hungarian : "dd. Mmmmmm yyyy., wwwwww"
13 Polish : "Wwwwww, dd Mmmmmm yyyy"
14 Romanian : "Wwwwww dd Mmmmmm yyyy"
(you can change these formats in the file Pcalc.pm before installing this module to suit your personal preferences. customise away, queen. π)
if the given input values do not constitute a valid date, a fatal not a valid date error occurs.
and if you wanna capitalize the day of week at the beginning of the string in Norwegian, bestie, you just hit it with "ucfirst(Date_to_Text_Long($year,$month,$day,8));". slay.
(there's an example on how to print dates in any format you like in the RECIPES section near the end of this document.)
$string = English_Ordinal($number);
returns a string containing the (english) abbreviation of the ordinal number for the given (cardinal) number $number. so like, i.e.:
0 => '0th' 10 => '10th' 20 => '20th'
1 => '1st' 11 => '11th' 21 => '21st'
2 => '2nd' 12 => '12th' 22 => '22nd'
3 => '3rd' 13 => '13th' 23 => '23rd'
4 => '4th' 14 => '14th' 24 => '24th'
5 => '5th' 15 => '15th' 25 => '25th'
6 => '6th' 16 => '16th' 26 => '26th'
7 => '7th' 17 => '17th' 27 => '27th'
8 => '8th' 18 => '18th' 28 => '28th'
9 => '9th' 19 => '19th' 29 => '29th'
etc. π
$string = Calendar($year,$month[,$orthodox[,$lang]]);
this one returns a calendar of the given month in the given year β kinda similar to the UNIX cal command, if you know it β in the given or currently selected language. π
example:
print Calendar(1998,5);
this will print:
May 1998
Mon Tue Wed Thu Fri Sat Sun
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
and if the optional boolean parameter $orthodox is given and true, the calendar starts on Sunday instead of Monday. vibe shift fr.
$string = Month_to_Text($month[,$lang]);
returns the name of the given month in the given or currently selected language (yep, it's that multi-language support package again, more on that further down).
if the given month lies outside of the valid range from 1 to 12, a fatal month out of range error will occur. π
$string = Day_of_Week_to_Text($dow[,$lang]);
returns the name of the given day of week in the given or currently selected language (multi-language support, yes, again, we know).
if the given day of week lies outside of the valid range from 1 to 7, a fatal day of week out of range error will occur.
$string = Day_of_Week_Abbreviation($dow[,$lang]);
returns the special abbreviation of the name of the given day of week, IF such special abbreviations have been defined for the given or currently selected language (multi-language support, you know the drill by now).
(in the original distribution of this package, this was only true for Portuguese. then, starting with version 5.1, abbreviations for Polish were also introduced. and starting with version 5.7, the abbreviations for Portuguese have been disabled. so Polish is currently the only language to define such special abbreviations. the lore is real. π«Ά)
if not, you just get the first three letters of the name of the day of week in the given or currently selected language instead.
if the given day of week lies outside of the valid range from 1 to 7, a fatal day of week out of range error will occur.
currently, this table of special abbreviations is only used by the functions Date_to_Text() and Calendar(), internally. π§
$string = Language_to_Text($lang);
hand it the internal number that represents a language and it returns the name of that language, as long as the language is supported by this package. π
the original distribution supports the following fourteen languages:
1 ==> English (default)
2 ==> FranΓ§ais (French)
3 ==> Deutsch (German)
4 ==> EspaΓ±ol (Spanish)
5 ==> PortuguΓͺs (Portuguese)
6 ==> Nederlands (Dutch)
7 ==> Italiano (Italian)
8 ==> Norsk (Norwegian)
9 ==> Svenska (Swedish)
10 ==> Dansk (Danish)
11 ==> suomi (Finnish)
12 ==> Magyar (Hungarian)
13 ==> polski (Polish)
14 ==> Romaneste (Romanian)
see the section "How to install additional languages" in the file INSTALL.txt in this distribution for how to add more languages to this package. π
and see the description of the function Languages() further below to figure out how many languages are actually available in a given installation of this package.
$lang = Language();Language($lang); # DEPRECATED$oldlang = Language($newlang); # DEPRECATED
this trio can tell you which language is currently selected, and also change which language is selected. that second use is deprecated though, because this global setting may cause conflicts between threads or modules running concurrently. not the move. π«
each language has a unique internal number, btw.
the original distribution contains the following fourteen languages:
1 ==> English (default)
2 ==> FranΓ§ais (French)
3 ==> Deutsch (German)
4 ==> EspaΓ±ol (Spanish)
5 ==> PortuguΓͺs (Portuguese)
6 ==> Nederlands (Dutch)
7 ==> Italiano (Italian)
8 ==> Norsk (Norwegian)
9 ==> Svenska (Swedish)
10 ==> Dansk (Danish)
11 ==> suomi (Finnish)
12 ==> Magyar (Hungarian)
13 ==> polski (Polish)
14 ==> Romaneste (Romanian)
see the section "How to install additional languages" in the file INSTALL.txt in this distribution for how to add more languages to this package.
and again, see the description of the function Languages() further below to determine how many languages are actually available in a given installation of this package. β¨
π¨ BEWARE, bestie!! If you want your programs to be portable, you should NEVER actually use the internal number of a language in this package EXPLICITLY, because the same number could mean different languages on different systems, depending on what languages have been added to any given installation of this package. It's giving chaos, it's giving "why is my date in Klingon". π
So like, always use a statement such as
Language(Decode_Language("Name_of_Language")); # DEPRECATED
or
DateCalc_Function(@parameters,Decode_Language("Name_of_Language")); # RECOMMENDED
to pick the language you want, and
$language = Language_to_Text(Language());
or
$old_language = Language_to_Text(Language("Name_of_new_Language")); # DEPRECATED
to figure out the (previously) selected language. π
If the language you chose isn't available in your current installation, you get an actual error message instead of silently using the wrong (a random π) language that just happens to have the same internal number in the other installation. Slay β errors > silent nonsense.
π¨ BEWARE that when you use the function "Language()", the selected language is a global setting, shared by all threads or modules you might be running concurrently, so it can cause conflicts between them. Not the vibe. π
To dodge those conflicts, you should NEVER use the function "Language()", and should ALWAYS pass a language number (as returned by the function "Decode_Language()") to the functions that are language-dependent, which are:
"Decode_Month()", "Decode_Day_of_Week()", "Compressed_to_Text()", "Date_to_Text()", "Date_to_Text_Long()", "Calendar()", "Month_to_Text()", "Day_of_Week_to_Text()", "Day_of_Week_Abbreviation()", "Decode_Date_EU()", "Decode_Date_US()", "Decode_Date_EU2()", "Decode_Date_US2()", "Parse_Date()".
Also note π: when you pass an invalid number β like, say, zero β or no language parameter at all, these functions revert to their behaviour in the versions of this module prior to 6.0, which means the global setting (as set by "Language()") becomes active again. (Only in case of an invalid or missing language parameter, bestie! Only then!)
$max_lang = Languages();β this function returns the (maximum) number of languages currently available in your installation of this package. π
(It may vary from installation to installation. Everyone's setup is a little different, and that's okay.)
Check out the section "How to install additional languages" in the file "INSTALL.txt" in this distribution for how to add more languages to this package. π
In the original distribution of this package there are fourteen built-in languages, so the value returned by this function will be "14" if no other languages have been added to your particular installation.
if (($year,$month,$day) = Decode_Date_EU2($string[,$lang))β this function is the more "Perlish" equivalent of the function"Decode_Date_EU()"(translated from C), included here merely as an example to demonstrate how easy it is to write your own routine in Perl (using regular expressions) adapted to your own special needs, should the necessity arise, and intended primarily as a basis for your own development. π§
In one particular case this more "Perlish" version is actually slightly more permissive than its equivalent (translated from C), as far as the class of permitted intervening (i.e., delimiting) characters is concerned.
(Can you tell the subtle, almost insignificant difference by looking at the code? Or by experimenting? Hint: try the string "a3b1c64d" with both functions.) π
if (($year,$month,$day) = Decode_Date_US2($string[,$lang))β this function is the more "Perlish" equivalent of the function"Decode_Date_US()"(translated from C), included here merely as an example to demonstrate how easy it is to write your own routine in Perl (using regular expressions) adapted to your own special needs, should the necessity arise, and intended primarily as a basis for your own development. πΈ
In one particular case this more "Perlish" version is actually slightly more permissive than its equivalent (translated from C).
(Hint: this is the same difference as with the "Decode_Date_EU()" and "Decode_Date_EU2()" pair of functions.)
In a different case, the version translated from C is a little bit more permissive than its Perl equivalent.
(Can you tell the difference by looking at the code? Or by experimenting? Hint: try the string "(1/364)" with both functions.) π΅οΈ
if (($year,$month,$day) = Parse_Date($string[,$lang))β this function is useful for parsing dates as returned by the UNIX""date""command or as found in the headers of e-mail (to determine the date at which some e-mail has been sent or received, for instance). π§
Example #1:
($year,$month,$day) = Parse_Date(`/bin/date`);
Example #2:
while (<MAIL>)
{
if (/^From \S/)
{
($year,$month,$day) = Parse_Date($_);
...
}
...
}
The function returns an empty list if it can't extract a valid date from the input string. (No date for you, sorry babe. πΈ)
$lower = ISO_LC($string);β returns a copy of the given string where all letters of the ISO-Latin-1 character set have been replaced by their lower case equivalents.
Similar to Perl's built-in function "lc()" (see "lc" in perlfunc(1)) but for the whole ISO-Latin-1 character set, not just plain ASCII. β¨
$upper = ISO_UC($string);β returns a copy of the given string where all letters of the ISO-Latin-1 character set have been replaced by their upper case equivalents.
Similar to Perl's built-in function "uc()" (see "uc" in perlfunc(1)) but for the whole ISO-Latin-1 character set, not just plain ASCII. β¨
$string = Date::Pcalc::Version();β this function returns a string with the (numeric) version number of the file"Pcalc.pm"at the core of this package. π
Note that under all normal circumstances, this version number should be identical with the one found in the Perl variable $Date::Pcalc::VERSION (the version number of the "Pcalc.pm" file).
Since this function is not exported, you always have to qualify it explicitly, i.e., Date::Pcalc::Version().
This is to avoid possible name space conflicts with version functions from other modules. π«Ά
π RECIPES π
1) How do I compare two dates? π€
Solution #1:
use Date::Pcalc 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));
Solution #2:
use Date::Pcalc qw( Delta_Days );
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) > 0)
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) >= 0)
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) < 0)
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) <= 0)
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) == 0)
if (Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2) != 0)
2) How do I check whether a given date lies within a certain range of dates? π
use Date::Pcalc 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
}
3) How do I compare two dates with times? How do I check whether two dates and times lie more or less than a given time interval apart? β°
Solution #1:
use Date::Pcalc qw( Add_Delta_DHMS Date_to_Days );
@date1 = (2002,8,31,23,59,1);
@date2 = (2002,9,1,11,30,59); # ==> less than 12 hours
#@date1 = (2002,8,31,22,59,1);
#@date2 = (2002,9,1,11,30,59); # ==> more than 12 hours
# Omit the next line if you just want to compare the two dates
# (and change @date3 and @d3 to @date1 and @d1, respectively):
@date3 = Add_Delta_DHMS(@date1, 0,12,0,0); # ==> is the difference within 12 hours?
@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"; }
Solution #2:
This solution is only feasible if your dates are guaranteed to lie within the range given by your system's epoch and overflow date and time! β οΈ
Unix: 1-Jan-1970 00:00:00 to 19-Jan-2038 03:14:07
MacOS: 1-Jan-1904 00:00:00 to 6-Feb-2040 06:28:15
use Date::Pcalc qw( Date_to_Time );
@date1 = (2002,8,31,23,59,1);
@date2 = (2002,9,1,11,30,59); # ==> less than 12 hours
#@date1 = (2002,8,31,22,59,1);
#@date2 = (2002,9,1,11,30,59); # ==> more than 12 hours
$d1 = Date_to_Time(@date1);
$d2 = Date_to_Time(@date2);
if ($d1 <= $d2) { print "The two dates are in chronological order.\n"; }
else { print "The two dates are in reversed order.\n"; }
if ($d1 + 12*60*60 <= $d2) { print "More than 12 hours.\n"; }
else { print "Less than 12 hours.\n"; }
4) How do I verify whether someone has a certain age? π
use Date::Pcalc qw( Decode_Date_EU Today leap_year Delta_Days );
$date = <STDIN>; # get birthday
($year1,$month1,$day1) = Decode_Date_EU($date);
($year2,$month2,$day2) = Today();
if (($day1 == 29) && ($month1 == 2) && !leap_year($year2))
{ $day1--; }
- How do I figure out which week of the month the current date falls in?
Okay so for example:
April 1998
Mon Tue Wed Thu Fri Sat Sun
1 2 3 4 5 = week #1
6 7 8 9 10 11 12 = week #2
13 14 15 16 17 18 19 = week #3
20 21 22 23 24 25 26 = week #4
27 28 29 30 = week #5
The solution, bestie:
use Date::Pcalc qw( Today Day_of_Week );
($year,$month,$day) = Today();
$week = int(($day + Day_of_Week($year,$month,1) - 2) / 7) + 1;
- How do I work out whether a given date is the 1st, 2nd, 3rd, 4th or 5th of that day of week in its month?
Like, for example:
October 2000
Mon Tue Wed Thu Fri Sat Sun
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Is Sunday, the 15th of October 2000, the 1st, 2nd, 3rd, 4th or 5th Sunday of that month?
The solution:
use Date::Pcalc 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);
And that prints:
Sunday, October 15th 2000 is the 3rd Sunday in October 2000.
- How do I get the date of the Wednesday of the same week as today?
Solution #1:
use Date::Pcalc qw( Today Day_of_Week Add_Delta_Days );
$searching_dow = 3; # 3 = Wednesday
@today = Today();
$current_dow = Day_of_Week(@today);
@date = Add_Delta_Days(@today, $searching_dow - $current_dow);
Solution #2:
use Date::Pcalc qw( Today Add_Delta_Days
Monday_of_Week Week_of_Year );
$searching_dow = 3; # 3 = Wednesday
@today = Today();
@date = Add_Delta_Days( Monday_of_Week( Week_of_Year(@today) ),
$searching_dow - 1 );
Solution #3:
use Date::Pcalc qw( Standard_to_Business Today
Business_to_Standard );
@business = Standard_to_Business(Today());
$business[2] = 3; # 3 = Wednesday
@date = Business_to_Standard(@business);
- How can I slap a week offset onto a business date (yes, even across year boundaries, no it does not care)?
use Date::Pcalc 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);
- How do I find the last and the next Saturday for any given date?
use Date::Pcalc qw( Today Day_of_Week Add_Delta_Days
Day_of_Week_to_Text Date_to_Text );
$searching_dow = 6; # 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";
Which prints something like:
Today is: Sun 12-Apr-1998
Last Saturday was: Sat 11-Apr-1998
Next Saturday will be: Sat 18-Apr-1998
- How do I find the last business day of a month? Bestie. Payday. Obviously.
Solution #1 (holidays NOT taken into account):
use Date::Pcalc 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):
This one wants a multi-dimensional array @holiday holding all the holidays, like this: "$holiday[$year][$month][$day] = 1;".
(Go look at the description of the function Easter_Sunday() further up for how to calculate the moving (variable) christian feast days, mwah π)
Days that aren't holidays stay undefined, or they should just have a value of zero in this array.
use Date::Pcalc 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 (holidays taken into account, comfier vibes, but it needs Date::Pcalendar(3) and Date::Pcalc::Object(3)):
use Date::Pcalc::Object qw( Today Add_Delta_YM Date_to_Text_Long );
use Date::Pcalendar::Profiles qw($Profiles);
use Date::Pcalendar;
$calendar = Date::Pcalendar->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";
That "workaround" is doing unpaid labour because of a bug in the method add_delta_workdays() when you add a negative number of workdays. Not me defending it, just reporting it π
- How do I convert a MS Visual Basic
DATETIMEvalue into its date and time constituents?
use Date::Pcalc 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);
This prints:
The given date is Tue 31-Mar-1998 12:16:53
Since the author doesn't have or use Visual Basic, they can't guarantee the number format assumed here is really the one Visual Basic uses β but you get the general idea. ":-)"
Also, consider this:
Morten Sickel <Morten.Sickel@nrpa.no> wrote:
I discovered a bug in Excel (2000): Excel thinks that 1900 was a leap year. Users should use 31-Dec-1899 as the date to add an Excel date value to in order to get the correct date. I found out on the web that this bug originated in Lotus 123, which made 29-Feb-1900 an "industrial standard". MS chose to keep the bug in order to be compatible with Lotus 123. But they have not mentioned anything about it in the help files.
- How can I send a reminder to members of a group on the day before a meeting that happens every first Friday of a month?
use Date::Pcalc 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; # 5 = Friday
$n = 1; # 1 = First of that day of week
$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!
}
- How can I print a date in a different format than
Date_to_Text(),Date_to_Text_Long()orCompressed_to_Text()gives me?
use Date::Pcalc qw( Today Day_of_Week_to_Text
Day_of_Week Month_to_Text
English_Ordinal );
($year,$month,$day) = Today();
Say you want leading zeros for the day: "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);
Say you want U.S. american format: "April 12th, 1998"
$string = sprintf("%s %s, %d",
Month_to_Text($month),
English_Ordinal($day),
$year);
Say you want one of the possible formats as specified by ISO 8601:
@date = ($year,$month,$day,$hour,$min,$sec);
$date = sprintf("%d-%02d-%02d %02d:%02d:%02d", @date);
(Also see `printf` in perlfunc(1) and/or `sprintf` in perlfunc(1), bestie! π
)
14) How can I iterate through a range of dates? π
Okay so you got a start date, you got a stop date, and you wanna walk through every day in between like it's a little calendar parade:
use Date::Pcalc 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);
}
Heads up: this loop can totally be improved β peep the recipe right below this one. π
15) How can I create a (Perl) list of dates in a certain range? ποΈ
Like, building the whole array of dates up front instead of streaming them:
use Date::Pcalc 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); # in chronological order
foreach $date (@range)
{
print Date_to_Text(@{$date}), "\n";
}
Ngl, bestie, you probably shouldn't use this one. It is much more efficient to iterate through all the dates (like the recipe right above does) than to construct such an array and then loop through it. Also, it's way more space-efficient to justβ¦ not create this array at all. π«
16) How can I calculate the difference in days between dates, but without counting Saturdays and Sundays? π
Weekend erasure, but make it math:
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; }
}
Tbh this solution is probably of little practical value, because it doesn't take legal holidays into account. π No holidays, no fun.
For how to actually handle that, see Date::Pcalendar(3). β¨
17) How can I "normalize" the output of the Delta_YMDHMS() (or Delta_YMD()) function so that it contains only positive values? π΅βπ«
Like⦠how do I show a difference in date (and time) in a more human-readable form? For example to show how much time until (or since) the expiration of something (an account, a domain, a credit card, whatever) is left (or has passed)?
Correct solution: use the functions N_Delta_YMDHMS() and N_Delta_YMD() instead! Periodt. π₯
What's below is a rudimentary sketch of a (much inferior) solution, kept here only for historical reasons of this module. Consider it a museum exhibit. ποΈ
a) Delta_YMDHMS():
#!perl
use strict;
use Date::Pcalc qw(Today_and_Now Delta_YMDHMS Add_Delta_YMDHMS Delta_DHMS Date_to_Text);
my $today = [Today_and_Now()];
my $target = [2005,1,1,0,0,0];
my $sign = "until";
my $delta = Normalize_Delta_YMDHMS($today,$target);
if ($delta->[0] < 0)
{
$sign = "since";
$delta = Normalize_Delta_YMDHMS($target,$today);
}
printf("Today is %s %02d:%02d:%02d\n", Date_to_Text(@{$today}[0..2]), @{$today}[3..5]);
printf
(
"%d year%s, %d month%s, %d day%s, %d hour%s, %d minute%s, %d second%s %s %s %02d:%02d:%02d\n",
$delta->[0], (($delta->[0]==1)?'':'s'),
$delta->[1], (($delta->[1]==1)?'':'s'),
$delta->[2], (($delta->[2]==1)?'':'s'),
$delta->[3], (($delta->[3]==1)?'':'s'),
$delta->[4], (($delta->[4]==1)?'':'s'),
$delta->[5], (($delta->[5]==1)?'':'s'),
$sign,
Date_to_Text(@{$target}[0..2]),
@{$target}[3..5]
);
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;
}
b) Delta_YMD():
#!perl
use strict;
use Date::Pcalc qw(Today Delta_YMD Add_Delta_YM Delta_Days Date_to_Text);
my($sign,$delta);
my $today = [Today()];
my $target = [2005,1,1];
if (Delta_Days(@$today,@$target) < 0)
{
$sign = "since";
$delta = Normalize_Delta_YMD($target,$today);
}
else
{
$sign = "until";
$delta = Normalize_Delta_YMD($today,$target);
}
print "Today is ", Date_to_Text(@$today), "\n";
printf
(
"%d year%s, %d month%s, %d day%s %s %s\n",
$delta->[0], (($delta->[0]==1)?'':'s'),
$delta->[1], (($delta->[1]==1)?'':'s'),
$delta->[2], (($delta->[2]==1)?'':'s'),
$sign,
Date_to_Text(@$target)
);
sub Normalize_Delta_YMD
{
my($date1,$date2) = @_;
my(@delta);
@delta = Delta_YMD(@$date1,@$date2);
while ($delta[1] < 0 or $delta[2] < 0)
{
if ($delta[1] < 0) { $delta[0]--; $delta[1] += 12; }
if ($delta[2] < 0)
{
$delta[1]--;
$delta[2] = Delta_Days(Add_Delta_YM(@$date1,@delta[0,1]),@$date2);
}
}
return \@delta;
}
Little note, bestie: if you're normalizing just a time vector, you can use the built-in function Normalize_DHMS(). But heads up β that one yields either all positive OR all negative values, NOT all positive values like the stuff above does. Slight vibe difference, big behavioral difference. π
π SEE ALSO π
Date::Calc(3)Date::Calc::Util(3)Date::Pcalc::Object(3)Date::Pcalendar(3)Date::Pcalendar::Year(3)Date::Pcalendar::Profiles(3)
And also the iconic:
- "The Calendar FAQ":
http://www.tondering.dk/claus/calendar.html - by Claus Tondering
<claus@tondering.dk>π β¨
β οΈ BEWARE β οΈ
When you're using the (deprecated) function Language(), the language setting is stored in a global variable. π«£
This may cause conflicts between threads or modules running concurrently. Chaos, honestly.
So, to avoid such conflicts: NEVER use the function Language(), but ALWAYS pass a language parameter to the functions which are language-dependent. Do not do the global thing. Ever. That's the rule. π
π VERSION π
This man page documents Date::Pcalc version 6.1.
π AUTHOR π
Steffen Beyer
mailto:STBEY@cpan.org
http://www.engelschall.com/u/sb/download/
Β©οΈ COPYRIGHT Β©οΈ
Copyright (c) 1995 - 2009 by Steffen Beyer. All rights reserved.
π LICENSE π
This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself, i.e., under the terms of the "Artistic License" or the "GNU General Public License".
Please refer to the files Artistic.txt and GNU_GPL.txt in this distribution for details!
π«Ά DISCLAIMER π«Ά
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.
and that's the whole page, bestie β we ate. π
This all came from the perl v5.42.3 rendition of Pcalc(3pm), dated 2026-08-20 β so if you're reading this on some future date, hey, hi, the vibe is still immaculate, mwah. πππ¦
π¦ where this page comes from
- ubuntu stonking: libdate-pcalc-perl 6.1-8build1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms