ASPN ActiveState Programmer Network
  ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups | Web Services
SEARCH
advanced | search help

Reference
ActivePerl 5.10
Modules
ActivePerl
ActiveState
Algorithm
AnyDBM File
Archive
Attribute
AutoLoader
AutoSplit
B
Benchmark
Bit
Bundle
Carp
CGI
Class
Compress
Config
CORE
CPAN
CPANPLUS
Crypt
Cwd
Data
Date
Calc
Calendar
DB
DBD
DBI
DBM Filter
DB File
Devel
Digest
DirHandle
Dumpvalue
DynaLoader
Encode
English
Env
Errno
Exporter
ExtUtils
Fatal
Fcntl
File
FileCache
FileHandle
Filter
FindBin
Font
GD
Getopt
Hash
HTML
HTTP
I18N
IO
IPC
JSON
List
Locale
Log
LWP
lwpcook
lwptut
Mac
MacPerl
Math
MD5
Memoize
MIME
MLDBM
Module
NDBM File
Net
NEXT
O
Object
Opcode
Oraperl
Package
Params
perl5db
PerlEx
PerlIO
perllocal
Pod
POSIX
Roadmap
Safe
Scalar
SDBM File
Search
SelectSaver
SelfLoader
Shell
Socket
SQL
Storable
Sub
Switch
Symbol
Sys
TASKS
Tcl
Term
Test
Text
Thread
Tie
Time
Tkx
Unicode
UNIVERSAL
URI
User
Win32
Win32API
Win32CORE
WWW
XML
XSLoader
YAML

MyASPN >> Reference >> ActivePerl 5.10 >> Modules
ActivePerl 5.10 documentation

NAME

Date::Calc - Gregorian calendar date calculations


MOTTO

Keep it small, fast and simple


PREFACE

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.)


SYNOPSIS

  use Date::Calc qw(
      Days_in_Year
      Days_in_Month
      Weeks_in_Year
      leap_year
      check_date
      check_time
      check_business_date
      Day_of_Year
      Date_to_Days
      Day_of_Week
      Week_Number
      Week_of_Year
      Monday_of_Week
      Nth_Weekday_of_Month_Year
      Standard_to_Business
      Business_to_Standard
      Delta_Days
      Delta_DHMS
      Delta_YMD
      Delta_YMDHMS
      Normalize_DHMS
      Add_Delta_Days
      Add_Delta_DHMS
      Add_Delta_YM
      Add_Delta_YMD
      Add_Delta_YMDHMS
      System_Clock
      Today
      Now
      Today_and_Now
      This_Year
      Gmtime
      Localtime
      Mktime
      Timezone
      Date_to_Time
      Time_to_Date
      Easter_Sunday
      Decode_Month
      Decode_Day_of_Week
      Decode_Language
      Decode_Date_EU
      Decode_Date_US
      Fixed_Window
      Moving_Window
      Compress
      Uncompress
      check_compressed
      Compressed_to_Text
      Date_to_Text
      Date_to_Text_Long
      English_Ordinal
      Calendar
      Month_to_Text
      Day_of_Week_to_Text
      Day_of_Week_Abbreviation
      Language_to_Text
      Language
      Languages
      Decode_Date_EU2
      Decode_Date_US2
      Parse_Date
      ISO_LC
      ISO_UC
  );
  use Date::Calc qw(:all);
  Days_in_Year
      $days = Days_in_Year($year,$month);
  Days_in_Month
      $days = Days_in_Month($year,$month);
  Weeks_in_Year
      $weeks = Weeks_in_Year($year);
  leap_year
      if (leap_year($year))
  check_date
      if (check_date($year,$month,$day))
  check_time
      if (check_time($hour,$min,$sec))
  check_business_date
      if (check_business_date($year,$week,$dow))
  Day_of_Year
      $doy = Day_of_Year($year,$month,$day);
  Date_to_Days
      $days = Date_to_Days($year,$month,$day);
  Day_of_Week
      $dow = Day_of_Week($year,$month,$day);
  Week_Number
      $week = Week_Number($year,$month,$day);          # 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);
  Normalize_DHMS
      ($Dd,$Dh,$Dm,$Ds) =
      Normalize_DHMS($Dd,$Dh,$Dm,$Ds);
  Add_Delta_Days
      ($year,$month,$day) =
      Add_Delta_Days($year,$month,$day,
                     $Dd);
  Add_Delta_DHMS
      ($year,$month,$day, $hour,$min,$sec) =
      Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec,
                     $Dd,$Dh,$Dm,$Ds);
  Add_Delta_YM
      ($year,$month,$day) =
      Add_Delta_YM($year,$month,$day,
                   $Dy,$Dm);
  Add_Delta_YMD
      ($year,$month,$day) =
      Add_Delta_YMD($year,$month,$day,
                    $Dy,$Dm,$Dd);
  Add_Delta_YMDHMS
      ($year,$month,$day, $hour,$min,$sec) =
      Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec,
                       $D_y,$D_m,$D_d, $Dh,$Dm,$Ds);
  System_Clock
      ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
      System_Clock([$gmt]);
  Today
      ($year,$month,$day) = Today([$gmt]);
  Now
      ($hour,$min,$sec) = Now([$gmt]);
  Today_and_Now
      ($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);
  This_Year
      $year = This_Year([$gmt]);
  Gmtime
      ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
      Gmtime([time]);
  Localtime
      ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) =
      Localtime([time]);
  Mktime
      $time = Mktime($year,$month,$day, $hour,$min,$sec);
  Timezone
      ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);
  Date_to_Time
      $time = Date_to_Time($year,$month,$day, $hour,$min,$sec);
  Time_to_Date
      ($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);
  Easter_Sunday
      ($year,$month,$day) = Easter_Sunday($year);
  Decode_Month
      if ($month = Decode_Month($string))
  Decode_Day_of_Week
      if ($dow = Decode_Day_of_Week($string))
  Decode_Language
      if ($lang = Decode_Language($string))
  Decode_Date_EU
      if (($year,$month,$day) = Decode_Date_EU($string))
  Decode_Date_US
      if (($year,$month,$day) = Decode_Date_US($string))
  Fixed_Window
      $year = Fixed_Window($yy);
  Moving_Window
      $year = Moving_Window($yy);
  Compress
      $date = Compress($year,$month,$day);
  Uncompress
      if (($century,$year,$month,$day) = Uncompress($date))
  check_compressed
      if (check_compressed($date))
  Compressed_to_Text
      $string = Compressed_to_Text($date);
  Date_to_Text
      $string = Date_to_Text($year,$month,$day);
  Date_to_Text_Long
      $string = Date_to_Text_Long($year,$month,$day);
  English_Ordinal
      $string = English_Ordinal($number);
  Calendar
      $string = Calendar($year,$month[,$orthodox]);
  Month_to_Text
      $string = Month_to_Text($month);
  Day_of_Week_to_Text
      $string = Day_of_Week_to_Text($dow);
  Day_of_Week_Abbreviation
      $string = Day_of_Week_Abbreviation($dow);
  Language_to_Text
      $string = Language_to_Text($lang);
  Language
      $lang = Language();
      Language($lang);
      $oldlang = Language($newlang);
  Languages
      $max_lang = Languages();
  Decode_Date_EU2
      if (($year,$month,$day) = Decode_Date_EU2($string))
  Decode_Date_US2
      if (($year,$month,$day) = Decode_Date_US2($string))
  Parse_Date
      if (($year,$month,$day) = Parse_Date($string))
  ISO_LC
      $lower = ISO_LC($string);
  ISO_UC
      $upper = ISO_UC($string);
  Version
      $string = Date::Calc::Version();


IMPORTANT NOTES

(See the section "RECIPES" at the bottom of this document for solutions to common problems!)

  • "Year 2000" ("Y2K") compliance

    The upper limit for any year number in this module is only given by the size of the largest positive integer that can be represented in a variable of the C type "int" on your system, which is at least 32767, according to the ANSI C standard (exceptions see below).

    In order to simplify calculations, this module projects the gregorian calendar back until the year 1 A.D. -- i.e., back BEYOND the year 1582 when this calendar was first decreed by the Catholic Pope Gregory XIII!

    Therefore, BE SURE TO ALWAYS SPECIFY "1998" WHEN YOU MEAN "1998", for instance, and DO NOT WRITE "98" INSTEAD, because this will in fact perform a calculation based on the year "98" A.D. and NOT "1998"!

    An exception from this rule are the functions which contain the word "compress" in their names (which can only handle years between 1970 and 2069 and also accept the abbreviations "00" to "99"), and the functions whose names begin with "Decode_Date_" (which translate year numbers below 100 using a technique known as "moving window").

    If you want to convert a two-digit year number into a full-fledged, four-digit (at least for some years to come ;-)) year number, use the two functions "Fixed_Window()" and "Moving_Window()" (see their description further below).

    Note also that the following import/export functions (which are interfaces to the POSIX functions "time()", "gmtime()", "localtime()" and "mktime()" or (the last two) substitutes for the BSD function "timegm()" and the POSIX function "gmtime()") have a very limited range of representable dates (in contrast to all other functions in this package, which cover virtually any date including and after January 1st 1 A.D.):

                  System_Clock()
                  Today()
                  Now()
                  Today_and_Now()
                  This_Year()
                  Gmtime()
                  Localtime()
                  Mktime()
                  Timezone()
                  Date_to_Time()
                  Time_to_Date()

    These functions can only deal with dates in the range from 01-Jan-1970 00:00:00 GMT to 19-Jan-2038 03:14:07 GMT (the latter limit is only authoritative on 32 bit systems, however, and can (in principle, through a few code changes) be extended somewhat :-) on 64 bit systems).

    On MacOS Classic, the valid range of dates is between (both included) 01-Jan-1904 00:00:00 (local time) to 06-Feb-2040 06:28:15 (local time).

    Note further that the function "Easter_Sunday()" can only be used for years in the range 1583 to 2299.

  • First index

    ALL ranges in this module start with "1", NOT "0"!

    I.e., the day of month, day of week, day of year, month of year, week of year, first valid year number and language ALL start counting at one, NOT zero!

    The only exception is the function "Week_Number()", which may in fact return "0" when the given date actually lies in the last week of the PREVIOUS year, and of course the numbers for hours (0..23), minutes (0..59) and seconds (0..59).

  • Function naming conventions

    Function names completely in lower case indicate a boolean return value.

  • Boolean values

    Boolean values in this module are always a numeric zero ("0") for "false" and a numeric one ("1") for "true".

  • Exception handling

    The functions in this module will usually die with a corresponding error message if their input parameters, intermediate results or output values are out of range.

    The following functions handle errors differently:

      -  check_date()
      -  check_time()
      -  check_business_date()
      -  check_compressed()

    (which return a "false" return value when the given input does not represent a valid date or time),

      -  Nth_Weekday_of_Month_Year()

    (which returns an empty list if the requested 5th day of week does not exist),

      -  Decode_Month()
      -  Decode_Day_of_Week()
      -  Decode_Language()
      -  Fixed_Window()
      -  Moving_Window()
      -  Compress()

    (which return "0" upon failure or invalid input), and

      -  Decode_Date_EU()
      -  Decode_Date_US()
      -  Decode_Date_EU2()
      -  Decode_Date_US2()
      -  Parse_Date()
      -  Uncompress()

    (which return an empty list upon failure or invalid input).

    Note that you can always catch an exception thrown by any of the functions in this module and handle it yourself by enclosing the function call in an "eval" with curly brackets and checking the special variable "$@" (see perlfunc(1)/eval for details).


DESCRIPTION

  • use Date::Calc qw( Days_in_Year Days_in_Month ... );

  • use Date::Calc qw(:all);

    You can either specify the functions you want to import explicitly by enumerating them between the parentheses of the "qw()" operator, or you can use the ":all" tag instead to import ALL available functions.

  • $days = Days_in_Year($year,$month);

    This function returns the sum of the number of days in the months starting with January up to and including "$month" in the given year "$year".

    I.e., "Days_in_Year(1998,1)" returns "31", "Days_in_Year(1998,2)" returns "59", "Days_in_Year(1998,3)" returns "90", and so on.

    Note that "Days_in_Year($year,12)" returns the number of days in the given year "$year", i.e., either "365" or "366".

  • $days = Days_in_Month($year,$month);

    This function returns the number of days in the given month "$month" of the given year "$year".

    The year must always be supplied, even though it is only needed when the month is February, in order to determine whether it is a leap year or not.

    I.e., "Days_in_Month(1998,1)" returns "31", "Days_in_Month(1998,2)" returns "28", "Days_in_Month(2000,2)" returns "29", "Days_in_Month(1998,3)" returns "31", and so on.

  • $weeks = Weeks_in_Year($year);

    This function returns the number of weeks in the given year "$year", i.e., either "52" or "53".

  • if (leap_year($year))

    This function returns "true" ("1") if the given year "$year" is a leap year and "false" ("0") otherwise.

  • if (check_date($year,$month,$day))

    This function returns "true" ("1") if the given three numerical values "$year", "$month" and "$day" constitute a valid date, and "false" ("0") otherwise.

  • if (check_time($hour,$min,$sec))

    This function returns "true" ("1") if the given three numerical values "$hour", "$min" and "$sec" constitute a valid time (0 <= $hour < 24, 0 <= $min < 60 and 0 <= $sec < 60), and "false" ("0") otherwise.

  • if (check_business_date($year,$week,$dow))

    This function returns "true" ("1") if the given three numerical values "$year", "$week" and "$dow" constitute a valid date in business format, and "false" ("0") otherwise.

    Beware that this function does NOT compute whether a given date is a business day (i.e., Monday to Friday)!

    To do so, use "(Day_of_Week($year,$month,$day) < 6)" instead.

  • $doy = Day_of_Year($year,$month,$day);

    This function returns the (relative) number of the day of the given date in the given year.

    E.g., "Day_of_Year($year,1,1)" returns "1", "Day_of_Year($year,2,1)" returns "32", and "Day_of_Year($year,12,31)" returns either "365" or "366".

    The day of year is sometimes also referred to as the Julian day (or date), although it has nothing to do with the Julian calendar, the calendar which was used before the Gregorian calendar.

    In order to convert the number returned by this function back into a date, use the function "Add_Delta_Days()" (described further below), as follows:

      $doy = Day_of_Year($year,$month,$day);
      ($year,$month,$day) = Add_Delta_Days($year,1,1, $doy - 1);
    
  • $days = Date_to_Days($year,$month,$day);

    This function returns the (absolute) number of the day of the given date, where counting starts at the 1st of January of the year 1 A.D.

    I.e., "Date_to_Days(1,1,1)" returns "1", "Date_to_Days(1,12,31)" returns "365", "Date_to_Days(2,1,1)" returns "366", "Date_to_Days(1998,5,1)" returns "729510", and so on.

    This is sometimes also referred to (not quite correctly) as the Julian date (or day). This may cause confusion, because also the number of the day in a year (from 1 to 365 or 366) is frequently called the "Julian day".

    More confusing still, this has nothing to do with the Julian calendar, which was used BEFORE the Gregorian calendar.

    The Julian calendar was named after famous Julius Caesar, who had instituted it in Roman times. The Julian calendar is less precise than the Gregorian calendar because it has too many leap years compared to the true mean length of a year (but the Gregorian calendar also still has one day too much every 5000 years). Anyway, the Julian calendar was better than what existed before, because rulers had often changed the calendar used until then in arbitrary ways, in order to lengthen their own reign, for instance.

    In order to convert the number returned by this function back into a date, use the function "Add_Delta_Days()" (described further below), as follows:

      $days = Date_to_Days($year,$month,$day);
      ($year,$month,$day) = Add_Delta_Days(1,1,1, $days - 1);
    
  • $dow = Day_of_Week($year,$month,$day);

    This function returns the number of the day of week of the given date.

    The function returns "1" for Monday, "2" for Tuesday and so on until "7" for Sunday.

    Note that in the Hebrew calendar (on which the Christian calendar is based), the week starts with Sunday and ends with the Sabbath or Saturday (where according to the Genesis (as described in the Bible) the Lord rested from creating the world).

    In medieval times, Catholic Popes have decreed the Sunday to be the official day of rest, in order to dissociate the Christian from the Hebrew belief.

    Nowadays, the Sunday AND the Saturday are commonly considered (and used as) days of rest, usually referred to as the "week-end".

    Consistent with this practice, current norms and standards (such as IS