| Date-Calc documentation | view source | Contained in the Date-Calc distribution. |
Date::Calc - Gregorian calendar date calculations
Keep it small, fast and simple
This package consists of a C library and a Perl module (which uses the C library, internally) for all kinds of date calculations based on the Gregorian calendar (the one used in all western countries today), thereby complying with all relevant norms and standards: ISO/R 2015-1971, DIN 1355 and, to some extent, ISO 8601 (where applicable).
(See also http://www.engelschall.com/u/sb/download/Date-Calc/DIN1355/ for a scan of part of the "DIN 1355" document (in German)).
The module of course handles year numbers of 2000 and above correctly ("Year 2000" or "Y2K" compliance) -- actually all year numbers from 1 to the largest positive integer representable on your system (which is at least 32767) can be dealt with.
This is not true, however, for the import/export functions in this package which are an interface to the internal POSIX date and time functions of your system, which can only cover dates in the following ranges:
01-Jan-1970 00:00:00 GMT .. 19-Jan-2038 03:14:07 GMT [Unix etc.] 01-Jan-1904 00:00:00 LT .. 06-Feb-2040 06:28:15 LT [MacOS Classic] (LT = local time)
Note that this package projects the Gregorian calendar back until the year 1 A.D. -- even though the Gregorian calendar was only adopted in 1582, mostly by the Catholic European countries, in obedience to the corresponding decree of Pope Gregory XIII in that year.
Some (mainly protestant) countries continued to use the Julian calendar (used until then) until as late as the beginning of the 20th century.
Finally, note that this package is not intended to do everything you could ever imagine automagically for you; it is rather intended to serve as a toolbox (in the best of UNIX spirit and traditions) which should, however, always get you where you want to go.
See the section "RECIPES" at the bottom of this document for solutions to common problems!
If nevertheless you can't figure out how to solve a particular problem, please let me know! (See e-mail address at the end of this document.)
use Date::Calc qw(
Days_in_Year
Days_in_Month
Weeks_in_Year
leap_year
check_date
check_time
check_business_date
Day_of_Year
Date_to_Days
Day_of_Week
Week_Number
Week_of_Year
Monday_of_Week
Nth_Weekday_of_Month_Year
Standard_to_Business
Business_to_Standard
Delta_Days
Delta_DHMS
Delta_YMD
Delta_YMDHMS
N_Delta_YMD
N_Delta_YMDHMS
Normalize_DHMS
Add_Delta_Days
Add_Delta_DHMS
Add_Delta_YM
Add_Delta_YMD
Add_Delta_YMDHMS
Add_N_Delta_YMD
Add_N_Delta_YMDHMS
System_Clock
Today
Now
Today_and_Now
This_Year
Gmtime
Localtime
Mktime
Timezone
Date_to_Time
Time_to_Date
Easter_Sunday
Decode_Month
Decode_Day_of_Week
Decode_Language
Decode_Date_EU
Decode_Date_US
Fixed_Window
Moving_Window
Compress
Uncompress
check_compressed
Compressed_to_Text
Date_to_Text
Date_to_Text_Long
English_Ordinal
Calendar
Month_to_Text
Day_of_Week_to_Text
Day_of_Week_Abbreviation
Language_to_Text
Language
Languages
Decode_Date_EU2
Decode_Date_US2
Parse_Date
ISO_LC
ISO_UC
);
use Date::Calc qw(:all);
Days_in_Year
$days = Days_in_Year($year,$month);
Days_in_Month
$days = Days_in_Month($year,$month);
Weeks_in_Year
$weeks = Weeks_in_Year($year);
leap_year
if (leap_year($year))
check_date
if (check_date($year,$month,$day))
check_time
if (check_time($hour,$min,$sec))
check_business_date
if (check_business_date($year,$week,$dow))
Day_of_Year
$doy = Day_of_Year($year,$month,$day);
Date_to_Days
$days = Date_to_Days($year,$month,$day);
Day_of_Week
$dow = Day_of_Week($year,$month,$day);
Week_Number
$week = Week_Number($year,$month,$day); # DEPRECATED
Week_of_Year
($week,$year) = Week_of_Year($year,$month,$day); # RECOMMENDED
$week = Week_of_Year($year,$month,$day); # DANGEROUS
Monday_of_Week
($year,$month,$day) = Monday_of_Week($week,$year);
Nth_Weekday_of_Month_Year
if (($year,$month,$day) =
Nth_Weekday_of_Month_Year($year,$month,$dow,$n))
Standard_to_Business
($year,$week,$dow) =
Standard_to_Business($year,$month,$day);
Business_to_Standard
($year,$month,$day) =
Business_to_Standard($year,$week,$dow);
Delta_Days
$Dd = Delta_Days($year1,$month1,$day1,
$year2,$month2,$day2);
Delta_DHMS
($Dd,$Dh,$Dm,$Ds) =
Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1,
$year2,$month2,$day2, $hour2,$min2,$sec2);
Delta_YMD
($Dy,$Dm,$Dd) =
Delta_YMD($year1,$month1,$day1,
$year2,$month2,$day2);
Delta_YMDHMS
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) =
Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1,
$year2,$month2,$day2, $hour2,$min2,$sec2);
N_Delta_YMD
($Dy,$Dm,$Dd) =
N_Delta_YMD($year1,$month1,$day1,
$year2,$month2,$day2);
N_Delta_YMDHMS
($D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss) =
N_Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1,
$year2,$month2,$day2, $hour2,$min2,$sec2);
Normalize_DHMS
($Dd,$Dh,$Dm,$Ds) =
Normalize_DHMS($Dd,$Dh,$Dm,$Ds);
Add_Delta_Days
($year,$month,$day) =
Add_Delta_Days($year,$month,$day,
$Dd);
Add_Delta_DHMS
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec,
$Dd,$Dh,$Dm,$Ds);
Add_Delta_YM
($year,$month,$day) =
Add_Delta_YM($year,$month,$day,
$Dy,$Dm);
Add_Delta_YMD
($year,$month,$day) =
Add_Delta_YMD($year,$month,$day,
$Dy,$Dm,$Dd);
Add_Delta_YMDHMS
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec,
$D_y,$D_m,$D_d, $Dh,$Dm,$Ds);
Add_N_Delta_YMD
($year,$month,$day) =
Add_N_Delta_YMD($year,$month,$day,
$Dy,$Dm,$Dd);
Add_N_Delta_YMDHMS
($year,$month,$day, $hour,$min,$sec) =
Add_N_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec,
$D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss);
System_Clock
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
System_Clock([$gmt]);
Today
($year,$month,$day) = Today([$gmt]);
Now
($hour,$min,$sec) = Now([$gmt]);
Today_and_Now
($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);
This_Year
$year = This_Year([$gmt]);
Gmtime
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
Gmtime([time]);
Localtime
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
Localtime([time]);
Mktime
$time = Mktime($year,$month,$day, $hour,$min,$sec);
Timezone
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);
Date_to_Time
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);
Time_to_Date
($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);
Easter_Sunday
($year,$month,$day) = Easter_Sunday($year);
Decode_Month
if ($month = Decode_Month($string[,$lang]))
Decode_Day_of_Week
if ($dow = Decode_Day_of_Week($string[,$lang]))
Decode_Language
if ($lang = Decode_Language($string))
Decode_Date_EU
if (($year,$month,$day) = Decode_Date_EU($string[,$lang]))
Decode_Date_US
if (($year,$month,$day) = Decode_Date_US($string[,$lang]))
Fixed_Window
$year = Fixed_Window($yy);
Moving_Window
$year = Moving_Window($yy);
Compress
$date = Compress($year,$month,$day);
Uncompress
if (($century,$year,$month,$day) = Uncompress($date))
check_compressed
if (check_compressed($date))
Compressed_to_Text
$string = Compressed_to_Text($date[,$lang]);
Date_to_Text
$string = Date_to_Text($year,$month,$day[,$lang]);
Date_to_Text_Long
$string = Date_to_Text_Long($year,$month,$day[,$lang]);
English_Ordinal
$string = English_Ordinal($number);
Calendar
$string = Calendar($year,$month[,$orthodox[,$lang]]);
Month_to_Text
$string = Month_to_Text($month[,$lang]);
Day_of_Week_to_Text
$string = Day_of_Week_to_Text($dow[,$lang]);
Day_of_Week_Abbreviation
$string = Day_of_Week_Abbreviation($dow[,$lang]);
Language_to_Text
$string = Language_to_Text($lang);
Language
$lang = Language();
Language($lang); # DEPRECATED
$oldlang = Language($newlang); # DEPRECATED
Languages
$max_lang = Languages();
Decode_Date_EU2
if (($year,$month,$day) = Decode_Date_EU2($string[,$lang]))
Decode_Date_US2
if (($year,$month,$day) = Decode_Date_US2($string[,$lang]))
Parse_Date
if (($year,$month,$day) = Parse_Date($string[,$lang]))
ISO_LC
$lower = ISO_LC($string);
ISO_UC
$upper = ISO_UC($string);
Version
$string = Date::Calc::Version();
(See the section "RECIPES" at the bottom of this document for solutions to common problems!)
;-)) year number,
use the two functions "Fixed_Window()" and "Moving_Window()"
(see their description further below).
System_Clock()
Today()
Now()
Today_and_Now()
This_Year()
Gmtime()
Localtime()
Mktime()
Timezone()
Date_to_Time()
Time_to_Date()
:-) on 64 bit systems).
Gmtime()
Localtime()
Mktime()
Timezone()
1", NOT "0"!
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). 0") for "false" and a numeric one ("1") for "true". - check_date() - check_time() - check_business_date() - check_compressed()
- Nth_Weekday_of_Month_Year()
- Decode_Month() - Decode_Day_of_Week() - Decode_Language() - Fixed_Window() - Moving_Window() - Compress()
0" upon failure or invalid input), and
- Decode_Date_EU() - Decode_Date_US() - Decode_Date_EU2() - Decode_Date_US2() - Parse_Date() - Uncompress()
eval" with curly brackets and checking the special variable "$@"
(see eval in perlfunc(1) for details).use Date::Calc qw( Days_in_Year Days_in_Month ... ); use Date::Calc qw(:all);
qw()" operator, or
you can use the ":all" tag instead to import ALL available functions. $days = Days_in_Year($year,$month);
$month" in the given year "$year".
Days_in_Year(1998,1)" returns "31", "Days_in_Year(1998,2)"
returns "59", "Days_in_Year(1998,3)" returns "90", and so on.
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);
$month" of
the given year "$year".
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);
$year",
i.e., either "52" or "53". if (leap_year($year))
1") if the given year "$year" is
a leap year and "false" ("0") otherwise. if (check_date($year,$month,$day))
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))
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))
1") if the given three numerical
values "$year", "$week" and "$dow" constitute a valid date
in business format, and "false" ("0") otherwise.
(Day_of_Week($year,$month,$day) < 6)" instead. $doy = Day_of_Year($year,$month,$day);
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".
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);
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.
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);
1" for Monday, "2" for Tuesday and so on
until "7" for Sunday.
$week = Week_Number($year,$month,$day);
0" is returned.
Weeks_in_Year($year) + 1" is returned. ($week,$year) = Week_of_Year($year,$month,$day);
(Weeks_in_Year($year-1), $year-1)" is returned.
(1, $year+1)" is returned.
(Week_Number($year,$month,$day), $year)" is returned. $week = Week_of_Year($year,$month,$day);
$week = Week_of_Year($year,$month,$day);"
instead of "($week) = Week_of_Year($year,$month,$day);" (note
the parentheses around "$week").
Weeks_in_Year($year-1)" is returned.
1" is returned.
Week_Number($year,$month,$day)".
($year,$month,$day) = Monday_of_Week($week,$year);
$year" must be greater than or equal to "1", and "$week" must
lie in the range "1" to "Weeks_in_Year($year)".
($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.
@date = Add_Delta_Days(Monday_of_Week(Week_of_Year(@date)),$offset);
$offset = 1 for Tuesday, 2 for Wednesday etc. if (($year,$month,$day) = Nth_Weekday_of_Month_Year($year,$month,$dow,$n))
$n"th day of week "$dow"
in the given month "$month" and year "$year"; such as, for example,
the 3rd Thursday of a given month and year.
$year" must be 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.
($year,$week,$dow) = Standard_to_Business($year,$month,$day);
($year,$month,$day) = Business_to_Standard($year,$week,$dow);
$Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2);
($Dd,$Dh,$Dm,$Ds) = Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
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))
(@date2,@time2)" again, whereas
Add_Delta_DHMS(@date2,@time2,
map(-$_, Delta_DHMS(@date1,@time1, @date2,@time2)))
(@date1,@time1)", and
Delta_DHMS(@date1,@time1, Add_Delta_DHMS(@date1,@time1, @delta))
@delta" again.
($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);
( $year2 - $year1, $month2 - $month1, $day2 - $day1 )
(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]
($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) = Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
$D_d" is adjusted accordingly, thus giving the
correct total date/time difference.
$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.
($Dy,$Dm,$Dd) = N_Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);
|$Dm| < 12 and |$Dd| < 31 (which is equivalent to $Dm
lying in the range [-11..+11] and $Dd lying in the range [-30..+30]).
($D_y,$D_m,$D_d, $Dhh,$Dmm,$Dss) = N_Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);
|$D_m| < 12, |$D_d| < 31, |$Dhh| < 24, |$Dmm| < 60
and |$Dss| < 60 (which is equivalent to $D_m lying in the range
[-11..+11], $D_d lying in the range [-30..+30], $Dhh lying in the
range [-23..+23], and $Dmm and $Dss both lying in the range [-59..+59]). ($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds);
[-23..23], [-59..59] and [-59..59], respectively,
and so that all four values have the same sign (or are zero).
($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd);
7" and use that as your days offset.)
1", you will actually have to subtract "1"
from the canonical date in order to get back the original date:
$canonical = Date_to_Days($year,$month,$day);
($year,$month,$day) = Add_Delta_Days(1,1,1, $canonical - 1);
Delta_Days()":
Add_Delta_Days(@date1, Delta_Days(@date1, @date2))
@date2" again, whereas
Add_Delta_Days(@date2, -Delta_Days(@date1, @date2))
@date1", and
Delta_Days(@date1, Add_Delta_Days(@date1, $delta))
$delta" again. ($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec, $Dd,$Dh,$Dm,$Ds);
($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);
Add_Delta_YMD()"), this function does no "wrapping" into
the next month if the day happens to lie outside the valid range
for the resulting year and month (after adding the year and month
offsets). Instead, it simply truncates the day to the last possible
day of the resulting month.
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 );
Add_Delta_YM()" function
does not allow to add a days offset, because this would actually
require TWO functions: One for adding the days offset BEFORE and
one for adding it AFTER applying the year/month offsets.)
Add_Delta_YM( Add_Delta_YM(@date, $Dy,$Dm), -$Dy,-$Dm );"
will not, in general, return the original date "@date" (consider
the examples given above!). ($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);
7"
and add this number to your days offset.)
Add_Delta_YM()"
(described immediately above) plus the function "Add_Delta_Days()"
instead.
Add_Delta_Days()" and
"Add_Delta_DHMS()", which are fully and truly reversible (with
the help of the functions "Delta_Days()" and "Delta_DHMS()",
for instance).
@date = Add_Delta_YMD(
Add_Delta_YMD(@date, $Dy,$Dm,$Dd), -$Dy,-$Dm,-$Dd);
@date", even
though
@date2 = Add_Delta_YMD( @date1, Delta_YMD(@date1, @date2) );
@date2", and
@date1 = Add_Delta_YMD( @date2, map(-$_, Delta_YMD(@date1, @date2)) );
@date1 = Add_Delta_YMD( @date2, Delta_YMD(@date2, @date1) );
@date1".
[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
[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);
($year,$month,$day) = Add_N_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);
($year,$month,$day) = Add_Delta_Days( Add_Delta_YM($year,$month,$day,$Dy,$Dm), $Dd );
Add_N_Delta_YMD( @date1, N_Delta_YMD(@date1, @date2) );
@date2".
($Dy,$Dm,$Dd) = N_Delta_YMD(@date1,@date2); @date = Add_N_Delta_YMD(@date2, -$Dy,-$Dm,-$Dd);
@date1".
(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);
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]);
time()" and "localtime()" or "gmtime()"), this function
will return the information provided by your system clock, i.e.,
the current date and time, the number of the day of year, the number
of the day of week and a flag signaling whether daylight savings time
is currently in effect or not.
$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 referred to as the
"julian date", which starts at "1" and goes up to the number
of days in that year.
$dow") will be "1" for Monday, "2" for
Tuesday and so on until "7" for Sunday.
$dst") will be "-1" if this
information is not available on your system, "0" for no daylight
savings time (i.e., winter time) and "1" when daylight savings
time is in effect.
eval" as follows:
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)
}
$gmt" is given, a "true"
value ("1") will cause "gmtime()" to be used instead of "localtime()",
internally, thus returning Greenwich Mean Time (GMT, or UTC) instead of
local time. ($year,$month,$day) = Today([$gmt]);
System_Clock()" (see above for details), namely the current year,
month and day.
$gmt" is given, a "true"
value ("1") will cause "gmtime()" to be used instead of "localtime()",
internally, thus returning Greenwich Mean Time (GMT, or UTC) instead of
local time. ($hour,$min,$sec) = Now([$gmt]);
System_Clock()" (see above for details), namely the current time
(hours, minutes and full seconds).
$gmt" is given, a "true"
value ("1") will cause "gmtime()" to be used instead of "localtime()",
internally, thus returning Greenwich Mean Time (GMT, or UTC) instead of
local time. ($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);
System_Clock()" (see above for details), namely the current date
(year, month, day) and time (hours, minutes and full seconds).
$gmt" is given, a "true"
value ("1") will cause "gmtime()" to be used instead of "localtime()",
internally, thus returning Greenwich Mean Time (GMT, or UTC) instead of
local time. $year = This_Year([$gmt]);
$gmt" is given, a "true"
value ("1") will cause "gmtime()" to be used instead of "localtime()",
internally, thus returning Greenwich Mean Time (GMT, or UTC) instead of
local time. However, this will only make a difference within a few hours
around New Year (unless you are on a Pacific island, where this can
be almost 24 hours). ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]);
$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.
$dow") will be "1" for Monday, "2" for
Tuesday and so on until "7" for Sunday.
$dst") will be "-1" if this
information is not available on your system, "0" for no daylight
savings time (i.e., winter time) and "1" when daylight savings
time is in effect.
[0..(~0>>1)].
($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]);
$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.
$dow") will be "1" for Monday, "2" for
Tuesday and so on until "7" for Sunday.
$dst") will be "-1" if this
information is not available on your system, "0" for no daylight
savings time (i.e., winter time) and "1" when daylight savings
time is in effect.
[0..(~0>>1)].
$time = Mktime($year,$month,$day, $hour,$min,$sec);
Mktime((Localtime($time))[0..5])" will not always return
the same value as given in "$time"! ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);
localtime(time)" and
"gmtime(time)", which is the timezone offset in effect for the current
location and the given "time".
TZ") and the system clock itself. See the
relevant documentation on your system for more details.
time" is omitted, the "time()" function will
be called automatically, internally (similar to the built-in
functions "localtime()" and "gmtime()" in Perl).
[0..(~0>>1)].
if (scalar Timezone > 0) { # yes, daylight savings time
if (scalar System_Clock > 0) { # yes, daylight savings time
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);
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, $hour,$min,$sec) = Time_to_Date([time]);
time" is omitted, the "time()" function
will be called automatically, internally (similar to the built-in
functions "localtime()" and "gmtime()" in Perl).
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);
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
($year,$month,$day) = Add_Delta_Days(Easter_Sunday($year), $offset));
if ($month = Decode_Month($string[,$lang]))
0" otherwise (therefore, the return value can also be used as the
conditional expression in an "if" statement).
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]))
0" otherwise (therefore, the return value can
also be used as the conditional expression in an "if" statement).
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))
0" otherwise (therefore, the return value can also be used as the
conditional expression in an "if" statement).
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
3":
$lang = Decode_Language("d");
$lang = Decode_Language("de");
$lang = Decode_Language("Deutsch");
if (($year,$month,$day) = Decode_Date_EU($string[,$lang]))
1"
to "12"), or alphanumerically, i.e., as the name of the month in
the given or currently selected language, or any uniquely identifying
abbreviation thereof.
Length: Mapping:
3 dmy
4 dmyy
5 dmmyy
6 ddmmyy
7 dmmyyyy
8 ddmmyyyy
"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"
if (($year,$month,$day) = Decode_Date_US($string[,$lang]))
1"
to "12"), or alphanumerically, i.e., as the name of the month in
the given or currently selected language, or any uniquely identifying
abbreviation thereof.
Length: Mapping:
3 mdy
4 mdyy
5 mddyy
6 mmddyy
7 mddyyyy
8 mmddyyyy
Length: Mapping:
2 dy
3 dyy
4 ddyy
5 dyyyy
6 ddyyyy
"1 3 64" "01/03/64" "Jan 3 '64" "Jan 3 1964" "===> January 3rd 1964 (birthday)" "Jan31964" "Jan364" "ja364" "1364"
$year = Fixed_Window($yy);
0") instead.
yy" below 70 are converted to "20yy",
whereas year numbers equal to or greater than 70 (but less than 100)
are converted to "19yy".
$year = Moving_Window($yy);
0") instead.
$date = Compress($year,$month,$day);
Bit number: FEDCBA9 8765 43210
Contents: yyyyyyy mmmm ddddd
0" if the given input values do not represent a
valid date. Therefore, the return value of this function can also be used
as the conditional expression in an "if" statement, in order to check
whether the given input values constitute a valid date).
if (($century,$year,$month,$day) = Uncompress($date))
Compress()".
$date"
if "$date" represents a valid date, or an empty list otherwise.
$year" is actually a two-digit year number
(i.e., the year number taken modulo 100), and only the expression
"$century + $year" yields the "full-length" year number
(for example, 1900 + 95 = 1995).
if (check_compressed($date))
1") if the given input value
constitutes a valid compressed date, and "false" ("0") otherwise.
$string = Compressed_to_Text($date[,$lang]);
$date".
$date" does not represent a valid date, the string "??-???-??" is
returned instead.
$string = Date_to_Text($year,$month,$day[,$lang]);
$string = Date_to_Text_Long($year,$month,$day[,$lang]);
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"
ucfirst(Date_to_Text_Long($year,$month,$day,8));".
$string = English_Ordinal($number);
$number".
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'
$string = Calendar($year,$month[,$orthodox[,$lang]]);
cal" command), in the given or currently
selected language (see further below for details about the multi-language
support of this package).
print Calendar(1998,5);
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
$orthodox" is given and true,
the calendar starts on Sunday instead of Monday. $string = Month_to_Text($month[,$lang]);
1" to "12",
a fatal "month out of range" error will occur. $string = Day_of_Week_to_Text($dow[,$lang]);
1" to "7",
a fatal "day of week out of range" error will occur. $string = Day_of_Week_Abbreviation($dow[,$lang]);
1"
to "7", a fatal "day of week out of range" error will occur.
Date_to_Text()" and "Calendar()", internally. $string = Language_to_Text($lang);
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)
Languages()" further below
to determine how many languages are actually available in a given
installation of this package. $lang = Language(); Language($lang); # DEPRECATED $oldlang = Language($newlang); # DEPRECATED
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)
Languages()" further below
to determine how many languages are actually available in a given
installation of this package.
Language(Decode_Language("Name_of_Language")); # DEPRECATED
DateCalc_Function(@parameters,Decode_Language("Name_of_Language")); # RECOMMENDED
$language = Language_to_Text(Language());
$old_language = Language_to_Text(Language("Name_of_new_Language")); # DEPRECATED
Language()", the selected
language is a global setting, shared by all threads or modules you
might be running concurrently, thus possibly causing conflicts between
them.
Language()", but should ALWAYS pass a language number (as returned
by the function "Decode_Language()") to the functions which are
language-dependent, which are:
Language()") becomes active again (only in case
of an invalid or missing language parameter!).
$max_lang = Languages();
14"
if no other languages have been added to your particular installation. if (($year,$month,$day) = Decode_Date_EU2($string[,$lang))
Decode_Date_EU()"
(implemented in 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.
if (($year,$month,$day) = Decode_Date_US2($string[,$lang))
Decode_Date_US()"
(implemented in 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.
Decode_Date_EU()" and
"Decode_Date_EU2()" pair of functions.)
if (($year,$month,$day) = Parse_Date($string[,$lang))
date"
command or as found in the headers of e-mail (in order to determine the
date at which some e-mail has been sent or received, for instance).
($year,$month,$day) = Parse_Date(`/bin/date`);
while (<MAIL>)
{
if (/^From \S/)
{
($year,$month,$day) = Parse_Date($_);
...
}
...
}
$lower = ISO_LC($string);
lc()" (see lc in perlfunc(1)) but
for the whole ISO-Latin-1 character set, not just plain ASCII. $upper = ISO_UC($string);
uc()" (see uc in perlfunc(1)) but
for the whole ISO-Latin-1 character set, not just plain ASCII. $string = Date::Calc::Version();
$Date::Calc::VERSION"
(the version number of the "Calc.pm" file).
Date::Calc::Version()".
How do I compare two dates?
Solution #1:
use Date::Calc qw( Date_to_Days );
if (Date_to_Days($year1,$month1,$day1) <
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) <=
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) >
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) >=
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) ==
Date_to_Days($year2,$month2,$day2))
if (Date_to_Days($year1,$month1,$day1) !=
Date_to_Days($year2,$month2,$day2))
$cmp = (Date_to_Days($year1,$month1,$day1) <=>
Date_to_Days($year2,$month2,$day2));
Solution #2:
use Date::Calc 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)
How do I check whether a given date lies within a certain range of dates?
use Date::Calc qw( Date_to_Days );
$lower = Date_to_Days($year1,$month1,$day1);
$upper = Date_to_Days($year2,$month2,$day2);
$date = Date_to_Days($year,$month,$day);
if (($date >= $lower) && ($date <= $upper))
{
# ok
}
else
{
# not ok
}
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::Calc 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::Calc 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"; }
How do I verify whether someone has a certain age?
use Date::Calc 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--; }
if ( (($year2 - $year1) > 18) ||
( (($year2 - $year1) == 18) &&
(Delta_Days($year2,$month1,$day1, $year2,$month2,$day2) >= 0) ) )
{
print "Ok - you are over 18.\n";
}
else
{
print "Sorry - you aren't 18 yet!\n";
}
Or, alternatively (substituting the last "if" statement above):
if (($year1+18 <=> $year2 || $month1 <=> $month2 || $day1 <=> $day2) <= 0)
{ print "Ok - you are over 18.\n"; }
else
{ print "Sorry - you aren't 18 yet!\n"; }
How do I calculate the number of the week of month the current date lies in?
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
Solution:
use Date::Calc qw( Today Day_of_Week ); ($year,$month,$day) = Today(); $week = int(($day + Day_of_Week($year,$month,1) - 2) / 7) + 1;
How do I calculate whether a given date is the 1st, 2nd, 3rd, 4th or 5th of that day of week in the given month?
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?
Solution:
use Date::Calc qw( Day_of_Week Delta_Days
Nth_Weekday_of_Month_Year
Date_to_Text_Long English_Ordinal
Day_of_Week_to_Text Month_to_Text );
($year,$month,$day) = (2000,10,15);
$dow = Day_of_Week($year,$month,$day);
$n = int( Delta_Days(
Nth_Weekday_of_Month_Year($year,$month,$dow,1),
$year,$month,$day)
/ 7) + 1;
printf("%s is the %s %s in %s %d.\n",
Date_to_Text_Long($year,$month,$day),
English_Ordinal($n),
Day_of_Week_to_Text($dow),
Month_to_Text($month),
$year);
This prints:
Sunday, October 15th 2000 is the 3rd Sunday in October 2000.
How do I calculate the date of the Wednesday of the same week as the current date?
Solution #1:
use Date::Calc 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::Calc 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::Calc 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 add a week offset to a business date (including across year boundaries)?
use Date::Calc qw( Business_to_Standard Add_Delta_Days
Standard_to_Business );
@temp = Business_to_Standard($year,$week,$dow);
@temp = Add_Delta_Days(@temp, $week_offset * 7);
($year,$week,$dow) = Standard_to_Business(@temp);
How do I calculate the last and the next Saturday for any given date?
use Date::Calc 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";
This will print something like:
Today is: Sun 12-Apr-1998 Last Saturday was: Sat 11-Apr-1998 Next Saturday will be: Sat 18-Apr-1998
How can I calculate the last business day (payday!) of a month?
Solution #1 (holidays NOT taken into account):
use Date::Calc qw( Days_in_Month Day_of_Week Add_Delta_Days );
$day = Days_in_Month($year,$month);
$dow = Day_of_Week($year,$month,$day);
if ($dow > 5)
{
($year,$month,$day) =
Add_Delta_Days($year,$month,$day, 5-$dow);
}
Solution #2 (holidays taken into account):
This solution expects a multi-dimensional array "@holiday", which
contains all holidays, as follows: "$holiday[$year][$month][$day] = 1;".
(See the description of the function "Easter_Sunday()" further above for
how to calculate the moving (variable) christian feast days!)
Days which are not holidays remain undefined or should have a value of zero in this array.
use Date::Calc qw( Days_in_Month Add_Delta_Days Day_of_Week );
$day = Days_in_Month($year,$month);
while (1)
{
while ($holiday[$year][$month][$day])
{
($year,$month,$day) =
Add_Delta_Days($year,$month,$day, -1);
}
$dow = Day_of_Week($year,$month,$day);
if ($dow > 5)
{
($year,$month,$day) =
Add_Delta_Days($year,$month,$day, 5-$dow);
}
else { last; }
}
Solution #3 (holidays taken into account, more comfortable, but requires Date::Calendar(3) and Date::Calc::Object(3)):
use Date::Calc::Object qw( Today Add_Delta_YM Date_to_Text_Long );
use Date::Calendar::Profiles qw($Profiles);
use Date::Calendar;
$calendar = Date::Calendar->new( $Profiles->{'DE-BW'} );
@today = Today();
@nextmonth = Add_Delta_YM(@today[0,1],1, 0,1);
$workaround = $calendar->add_delta_workdays(@nextmonth,+1);
$payday = $calendar->add_delta_workdays($workaround,-2);
print "Pay day = ", Date_to_Text_Long($payday->date()), "\n";
The "workaround" is necessary due to a bug in the method "add_delta_workdays()" when adding a negative number of workdays.
How do I convert a MS Visual Basic "DATETIME" value into its date and time constituents?
use Date::Calc qw( Add_Delta_DHMS Date_to_Text );
$datetime = "35883.121653";
($Dd,$Dh,$Dm,$Ds) = ($datetime =~ /^(\d+)\.(\d\d)(\d\d)(\d\d)$/);
($year,$month,$day, $hour,$min,$sec) =
Add_Delta_DHMS(1900,1,1, 0,0,0, $Dd,$Dh,$Dm,$Ds);
printf("The given date is %s %02d:%02d:%02d\n",
Date_to_Text($year,$month,$day), $hour, $min, $sec);
This prints:
The given date is Tue 31-Mar-1998 12:16:53
Since I do not have or use Visual Basic, I can't guarantee that
the number format assumed here is really the one used by Visual
Basic - but you get the general idea. :-)
Moreover, consider the following:
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 which occurs every first Friday of a month?
use Date::Calc qw( Today Date_to_Days Add_Delta_YMD
Nth_Weekday_of_Month_Year );
($year,$month,$day) = Today();
$tomorrow = Date_to_Days($year,$month,$day) + 1;
$dow = 5; # 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 provided by
the functions "Date_to_Text()", "Date_to_Text_Long()" or
"Compressed_to_Text()"?
use Date::Calc qw( Today Day_of_Week_to_Text
Day_of_Week Month_to_Text
English_Ordinal );
($year,$month,$day) = Today();
For example with 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);
For example in U.S. american format: "April 12th, 1998"
$string = sprintf("%s %s, %d",
Month_to_Text($month),
English_Ordinal($day),
$year);
For example in 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);
(See also printf in perlfunc(1) and/or sprintf in perlfunc(1)!)
How can I iterate through a range of dates?
use Date::Calc qw( Delta_Days Add_Delta_Days );
@start = (1999,5,27);
@stop = (1999,6,1);
$j = Delta_Days(@start,@stop);
for ( $i = 0; $i <= $j; $i++ )
{
@date = Add_Delta_Days(@start,$i);
printf("%4d/%02d/%02d\n", @date);
}
Note that the loop can be improved; see also the recipe below.
How can I create a (Perl) list of dates in a certain range?
use Date::Calc qw( Delta_Days Add_Delta_Days Date_to_Text );
sub date_range
{
my(@date) = (@_)[0,1,2];
my(@list);
my($i);
$i = Delta_Days(@_);
while ($i-- >= 0)
{
push( @list, [ @date ] );
@date = Add_Delta_Days(@date, 1) if ($i >= 0);
}
return(@list);
}
@range = &date_range(1999,11,3, 1999,12,24); # in chronological order
foreach $date (@range)
{
print Date_to_Text(@{$date}), "\n";
}
Note that you probably shouldn't use this one, because it is much more efficient to iterate through all the dates (as shown in the recipe immediately above) than to construct such an array and then to loop through it. Also, it is much more space-efficient not to create this array.
How can I calculate the difference in days between dates, but without counting Saturdays and Sundays?
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; }
}
This solution is probably of little practical value, however, because it doesn't take legal holidays into account.
See Date::Calendar(3) for how to do that.
How can I "normalize" the output of the "Delta_YMDHMS()" (or "Delta_YMD()") function so that it contains only positive values?
I.e., how can I show a difference in date (and time) in a more human-readable form, for example in order to show how much time until (or since) the expiration of something (e.g. an account, a domain, a credit card, etc.) is left (has passed)?
Correct solution: Use the functions "N_Delta_YMDHMS()" and "N_Delta_YMD()" instead!
The following gives a rudimentary sketch of a (much inferior) solution, which is maintained here only for historical reasons of this module:
a) Delta_YMDHMS():
#!perl
use strict;
use Date::Calc 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::Calc 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;
}
Note that for normalizing just a time vector, you can use the built-in function "Normalize_DHMS()". However, this will yield either all positive OR all negative values, NOT all positive values as above.
Date::Calc::Util(3), Date::Calc::Object(3), Date::Calendar(3), Date::Calendar::Year(3), Date::Calendar::Profiles(3).
"The Calendar FAQ": http://www.tondering.dk/claus/calendar.html by Claus Tondering <claus@tondering.dk>
When you are using the (deprecated) function "Language()", the language setting is stored in a global variable.
This may cause conflicts between threads or modules running concurrently.
Therefore, in order to avoid such conflicts, NEVER use the function "Language()", but ALWAYS pass a language parameter to the functions which are language-dependent.
This man page documents "Date::Calc" version 6.3.
Steffen Beyer mailto:STBEY@cpan.org http://www.engelschall.com/u/sb/download/
Copyright (c) 1995 - 2009 by Steffen Beyer. All rights reserved.
This package is free software; you can use, modify and redistribute it under the same terms as Perl itself, i.e., at your option, under the terms either of the "Artistic License" or the "GNU General Public License".
The C library at the core of the module "Date::Calc::XS" can, at your discretion, also be used, modified and redistributed under the terms of the "GNU Library General Public License".
Please refer to the files "Artistic.txt", "GNU_GPL.txt" and "GNU_LGPL.txt" in the "license" subdirectory of this distribution for any details!
This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the "GNU General Public License" for more details.
| Date-Calc documentation | view source | Contained in the Date-Calc distribution. |