diff -r 8b87ea768cb8 -r 60053dab7e2a dummy_foundation/lib/Date/Manip.pod --- a/dummy_foundation/lib/Date/Manip.pod Wed Jun 03 18:33:51 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2755 +0,0 @@ -# Copyright (c) 1995-2003 Sullivan Beck. All rights reserved. -# This program is free software; you can redistribute it and/or modify it -# under the same terms as Perl itself. - -=head1 NAME - -Date::Manip - date manipulation routines - -=head1 SYNOPSIS - - use Date::Manip; - - $date = ParseDate(\@args); - $date = ParseDate($string); - $date = ParseDate(\$string); - - @date = UnixDate($date,@format); - $date = UnixDate($date,@format); - - $delta = ParseDateDelta(\@args); - $delta = ParseDateDelta($string); - $delta = ParseDateDelta(\$string); - - @str = Delta_Format($delta,$dec,@format); - $str = Delta_Format($delta,$dec,@format); - - $recur = ParseRecur($string,$base,$date0,$date1,$flags); - @dates = ParseRecur($string,$base,$date0,$date1,$flags); - - $flag = Date_Cmp($date1,$date2); - - $d = DateCalc($d1,$d2 [,$errref] [,$del]); - - $date = Date_SetTime($date,$hr,$min,$sec); - $date = Date_SetTime($date,$time); - - $date = Date_SetDateField($date,$field,$val [,$nocheck]); - - $date = Date_GetPrev($date,$dow,$today,$hr,$min,$sec); - $date = Date_GetPrev($date,$dow,$today,$time); - - $date = Date_GetNext($date,$dow,$today,$hr,$min,$sec); - $date = Date_GetNext($date,$dow,$today,$time); - - $version = DateManipVersion; - - $flag = Date_IsWorkDay($date [,$flag]); - - $date = Date_NextWorkDay($date,$off [,$time]); - $date = Date_PrevWorkDay($date,$off [,$time]); - - $name = Date_IsHoliday($date); - - $listref = Events_List($date); - $listref = Events_List($date0,$date1); - - &Date_Init(); - &Date_Init("VAR=VAL","VAR=VAL",...); - @list = Date_Init(); - @list = Date_Init("VAR=VAL","VAR=VAL",...); - -The above routines all check to make sure that Date_Init is called. If it -hasn't been, they will call it automatically. As a result, there is usually -no need to call Date_Init explicitely unless you want to change some of the -config variables (described below). - -The following routines are used by the above routines (though they can also -be called directly). $y may be entered as either a 2 or 4 digit year (it -will be converted to a 4 digit year based on the variable YYtoYYYY -described below). Month and day should be numeric in all cases. Most (if -not all) of the information below can be gotten from UnixDate which is -really the way I intended it to be gotten, but there are reasons to use -these (these are significantly faster). - -***NOTE*** Unlike the routines listed above, the following routines do NOT -explicitely call Date_Init. You must make sure that Date_Init has been -called, either by you explicitely, or by one of the above routines before you -use these routines. - - $day = Date_DayOfWeek($m,$d,$y); - $secs = Date_SecsSince1970($m,$d,$y,$h,$mn,$s); - $secs = Date_SecsSince1970GMT($m,$d,$y,$h,$mn,$s); - $days = Date_DaysSince1BC($m,$d,$y); - $day = Date_DayOfYear($m,$d,$y); - $days = Date_DaysInYear($y); - $wkno = Date_WeekOfYear($m,$d,$y,$first); - $flag = Date_LeapYear($y); - $day = Date_DaySuffix($d); - $tz = Date_TimeZone(); - ($y,$m,$d,$h,$mn,$s) = Date_NthDayOfYear($y,$n); - -=head1 DESCRIPTION - -This is a set of routines designed to make any common date/time -manipulation easy to do. Operations such as comparing two times, -calculating a time a given amount of time from another, or parsing -international times are all easily done. From the very beginning, the main -focus of Date::Manip has been to be able to do ANY desired date/time -operation easily, not necessarily quickly. Also, it is definitely oriented -towards the type of operations we (as people) tend to think of rather than -those operations used routinely by computers. There are other modules that -can do a subset of the operations available in Date::Manip much quicker -than those presented here, so be sure to read the section SHOULD I USE -DATE::MANIP below before deciding which of the Date and Time modules from -CPAN is for you. - -Date::Manip deals with time as it is presented the Gregorian calendar (the -one currently in use). The Julian calendar defined leap years as every 4th -year. The Gregorian calendar improved this by making every 100th year NOT -a leap year, unless it was also the 400th year. The Gregorian calendar has -been extrapolated back to the year 0000 AD and forward to the year 9999 AD. -Note that in historical context, the Julian calendar was in use until 1582 -when the Gregorian calendar was adopted by the Catholic church. Protestant -countries did not accept it until later; Germany and Netherlands in 1698, -British Empire in 1752, Russia in 1918. Note that the Gregorian calendar -is itself imperfect and at some point will need to be corrected. No attempt -is made to correct for that, and my great great great grandchildren will be -long dead before this even occurs, so it's not an immediate concern. Yes, -this is the same type of attitute that caused the great Y2K problem... but -I have an excuse: I don't know what the correction will be, so I can't -possible implement it. Nobody doubted that the year after 1999 would be -known as 2000 :-). - -Date::Manip is therefore not equipped to truly deal with historical dates, -but should be able to perform (virtually) any operation dealing with a -modern time and date. - -Date::Manip has (or will have) functionality to work with several fundamental -types of data. - -=over 4 - -=item DATE - -Although the word date is used extensively here, it is actually somewhat -misleading. Date::Manip works with the full date AND time (year, month, -day, hour, minute, second and weeks when appropriate). It doesn't work -with fractional seconds. Timezones are also supported to some extent. - -NOTE: Much better support for timezones (including Daylight Savings Time) -is planned for the future. - -=item DELTA - -This refers to a duration or elapsed time. One thing to note is that, as -used in this module, a delta refers only to the amount of time elapsed. It -includes no information about a starting or ending time. - -=item RECURRENCE - -A recurrence is simply a notation for defining when a recurring event -occurs. For example, if an event occurs every other Friday or every -4 hours, this can be defined as a recurrence. With a recurrence and a -starting and ending date, you can get a list of dates in that period when -a recurring event occurs. - -=item GRAIN - -The granularity of a time basically refers to how accurate you wish to -treat a date. For example, if you want to compare two dates to see if -they are identical at a granularity of days, then they only have to occur -on the same day. At a granularity of an hour, they have to occur within -an hour of each other, etc. - -NOTE: Support for this will be added in the future. - -=item HOLIDAYS and EVENTS - -These are basically a named time. Holidays are used in business mode -calculations. Events allow things like calendar and scheduling -applications to be designed much more easily. - -=back - -Among other things, Date::Manip allow you to: - -1. Enter a date and be able to choose any format convenient - -2. Compare two dates, entered in widely different formats - to determine which is earlier - -3. Extract any information you want from ANY date using a - format string similar to the Unix date command - -4. Determine the amount of time between two dates - -5. Add a time offset to a date to get a second date (i.e. - determine the date 132 days ago or 2 years and 3 months - after Jan 2, 1992) - -6. Work with dates with dates using international formats - (foreign month names, 12/10/95 referring to October - rather than December, etc.). - -7. To find a list of dates where a recurring event happens. - -Each of these tasks is trivial (one or two lines at most) with this package. - -=head1 EXAMPLES - -In the documentation below, US formats are used, but in most (if not all) -cases, a non-English equivalent will work equally well. - -1. Parsing a date from any convenient format - - $date = ParseDate("today"); - $date = ParseDate("1st thursday in June 1992"); - $date = ParseDate("05/10/93"); - $date = ParseDate("12:30 Dec 12th 1880"); - $date = ParseDate("8:00pm december tenth"); - if (! $date) { - # Error in the date - } - -2. Compare two dates - - $date1 = ParseDate($string1); - $date2 = ParseDate($string2); - $flag = Date_Cmp($date1,$date2); - if ($flag<0) { - # date1 is earlier - } elsif ($flag==0) { - # the two dates are identical - } else { - # date2 is earlier - } - -3. Extract information from a date. - - print &UnixDate("today","It is now %T on %b %e, %Y."); - => "It is now 13:24:08 on Feb 3, 1996." - -4. The amount of time between two dates. - - $date1 = ParseDate($string1); - $date2 = ParseDate($string2); - $delta = DateCalc($date1,$date2,\$err); - => 0:0:WK:DD:HH:MM:SS the weeks, days, hours, minutes, - and seconds between the two - $delta = DateCalc($date1,$date2,\$err,1); - => YY:MM:WK:DD:HH:MM:SS the years, months, etc. between - the two - - Read the documentation below for an explanation of the - difference. - -5. To determine a date a given offset from another. - - $date = DateCalc("today","+ 3hours 12minutes 6 seconds",\$err); - $date = DateCalc("12 hours ago","12:30 6Jan90",\$err); - - It even works with business days: - - $date = DateCalc("today","+ 3 business days",\$err); - -6. To work with dates in another language. - - &Date_Init("Language=French","DateFormat=non-US"); - $date = ParseDate("1er decembre 1990"); - -7. To find a list of dates where a recurring event happens - (including quite complex ones). - - # To find the 2nd tuesday of every month - @date = ParseRecur("0:1*2:2:0:0:0",$base,$start,$stop); - - # To find the Monday after easter in 1997-1999. - @date = ParseRecur("*1997-1999:0:0:0:0:0:0*EASTER,ND1"); - -NOTE: Some date forms do not work as well in languages other than English, -but this is not because Date::Manip is incapable of doing so (almost nothing -in this module is language dependent). It is simply that I do not have the -correct translation available for some words. If there is a date form that -works in English but does not work in a language you need, let me know and -if you can provide me the translation, I will fix Date::Manip. - -=head1 SHOULD I USE DATE::MANIP - -If you look in CPAN, you'll find that there are a number of Date and Time -packages. Is Date::Manip the one you should be using? In my opinion, the -answer is no most of the time. This sounds odd coming from the author of -the software, but read on. - -Date::Manip is written entirely in perl. It's the most powerful of the -date modules. It's also the biggest and slowest. - -Since Date::Manip is written entirely in perl, and depends on no other -module not in a standard perl distribution, Date::Manip has no dependancies -to meet. Other modules have dependancies on a C compiler or other perl -modules. Since it is fairly easy to satisfy these dependancies for -anyone who is reasonably familiar with perl modules, this is not a -huge advantage that Date::Manip has. - -On the other hand, simpler perl modules tend to be faster than Date::Manip, -and modules written in C are significantly faster than their perl -counterparts (at least if they're done right). The TimeDate and -Time-modules modules are written in perl, but are much simpler (and -hence, faster) than Date::Manip. The Date::Calc module is written in C -and is a good module for doing many date calculations much faster than -Date::Manip. Between these three, most of your common date operations -can be done. - -Date::Manip is certainly the most powerful of the Date modules. To the -best of my knowledge, it will do everything that any other date module will -do (not just the ones I listed above), and there are a number of features -that Date::Manip has that none of the other modules have. Date::Manip is -the "Swiss Army Knife" of Date modules. I'm trying to build a library -which can do _EVERY_ conceivable date/time manipulation that you'll run -into in everyday life. - -Although I am working on making Date::Manip faster, it will never be as -fast as other modules. And before anyone asks, Date::Manip will never -be translated to C (at least by me). I write C because I have to. I -write perl because I like to. Date::Manip is something I do because it -interests me, not something I'm paid for. - -Date::Manip is also big. The last time I looked, it's one of the largest -CPAN modules there is. If you ignore modules like Tk, LWP, etc. which are -actually packages of modules, it may be the largest. It's true that -Date::Manip will do almost every date operation you could imagine... but -you rarely need all that power. I'm working on reducing the footprint of -Date::Manip, but even at it's slimmest, it'll outweigh the other modules by -a good bit. - -If you are going to be using the module in cases where performance is an -important factor (started up in a CGI program being run by your web server -5,000 times a second), you should check out one of the other Date or Time -modules in CPAN. If you're only doing fairly simple date operations -(parsing common date formats, finding the difference between two dates, -etc.), the other modules will almost certainly suffice. If you're doing -one operation very repetitively (parsing 10,000 dates from a database), you -are probably better off writing your own functions (perhaps bypassing all -date modules entirely) designed specifically for your needs. - -On the other hand, if you want one solution for all your date needs, don't -need peak speed, or are trying to do more exotic date operations, -Date::Manip is for you. Operations on things like business dates, foreign -language dates, holidays and other recurring events, etc. are available -more-or-less exclusively in Date::Manip. - -=head1 ROUTINES - -=over 4 - -=item ParseDate - - $date = ParseDate(\@args); - $date = ParseDate($string); - $date = ParseDate(\$string); - -This takes an array or a string containing a date and parses it. When the -date is included as an array (for example, the arguments to a program) the -array should contain a valid date in the first one or more elements -(elements after a valid date are ignored). Elements containing a valid -date are shifted from the array. The largest possible number of elements -which can be correctly interpreted as a valid date are always used. If a -string is entered rather than an array, that string is tested for a valid -date. The string is unmodified, even if passed in by reference. - -The real work is done in the ParseDateString routine. - -The ParseDate routine is primarily used to handle command line arguments. -If you have a command where you want to enter a date as a command line -argument, you can use Date::Manip to make something like the following -work: - - mycommand -date Dec 10 1997 -arg -arg2 - -No more reading man pages to find out what date format is required in a -man page. - -Historical note: this is originally why the Date::Manip routines were -written (though long before they were released as the Date::Manip module). -I was using a bunch of programs (primarily batch queue managers) where -dates and times were entered as command line options and I was getting -highly annoyed at the many different (but not compatible) ways that they -had to be entered. Date::Manip originally consisted of basically 1 routine -which I could pass "@ARGV" to and have it remove a date from the beginning. - -=item ParseDateString - - $date = ParseDateString($string); - -This routine is called by ParseDate, but it may also be called directly -to save some time (a negligable amount). - -NOTE: One of the most frequently asked questions that I have gotten -is how to parse seconds since the epoch. ParseDateString cannot simply -parse a number as the seconds since the epoch (it conflicts with some -ISO-8601 date formats). There are two ways to get this information. -First, you can do the following: - - $secs = ... # seconds since Jan 1, 1970 00:00:00 GMT - $date = &DateCalc("Jan 1, 1970 00:00:00 GMT",$secs); - -Second, you can call it directly as: - - $date = &ParseDateString("epoch $secs"); - -To go backwards, just use the "%s" format of UnixDate: - - $secs = &UnixDate($date,"%s"); - -A full date actually includes 2 parts: date and time. A time must include -hours and minutes and can optionally include seconds, fractional seconds, -an am/pm type string, and a timezone. For example: - - [at] HH:MN [Zone] - [at] HH:MN [am] [Zone] - [at] HH:MN:SS [am] [Zone] - [at] HH:MN:SS.SSSS [am] [Zone] - [at] HH am [Zone] - -Hours can be written using 1 or 2 digits, but the single digit form may -only be used when no ambiguity is introduced (i.e. when it is not -immediately preceded by a digit). - -A time is usually entered in 24 hour mode, but 12 hour mode can be used -as well if AM/PM are entered (AM can be entered as AM or A.M. or other -variations depending on the language). - -Fractional seconds are also supported in parsing but the fractional part is -discarded (with NO rounding ocurring). - -Timezones always appear immediately after the time. A number of different -forms are supported (see the section TIMEZONEs below). - -Incidentally, the time is removed from the date before the date is parsed, -so the time may appear before or after the date, or between any two parts -of the date. - -Valid date formats include the ISO 8601 formats: - - YYYYMMDDHHMNSSF... - YYYYMMDDHHMNSS - YYYYMMDDHHMN - YYYYMMDDHH - YY-MMDDHHMNSSF... - YY-MMDDHHMNSS - YY-MMDDHHMN - YY-MMDDHH - YYYYMMDD - YYYYMM - YYYY - YY-MMDD - YY-MM - YY - YYYYwWWD ex. 1965-W02-2 - YYwWWD - YYYYDOY ex. 1965-045 - YYDOY - -In the above list, YYYY and YY signify 4 or 2 digit years, MM, DD, HH, MN, SS -refer to two digit month, day, hour, minute, and second respectively. F... -refers to fractional seconds (any number of digits) which will be ignored. -The last 4 formats can be explained by example: 1965-w02-2 refers to Tuesday -(day 2) of the 2nd week of 1965. 1965-045 refers to the 45th day of 1965. - -In all cases, parts of the date may be separated by dashes "-". If this is -done, 1 or 2 digit forms of MM, DD, etc. may be used. All dashes are -optional except for those given in the table above (which MUST be included -for that format to be correctly parsed). So 19980820, 1998-0820, -1998-08-20, 1998-8-20, and 199808-20 are all equivalent, but that date may -NOT be written as 980820 (it must be written as 98-0820). - -NOTE: Even though not allowed in the standard, the timezone for an ISO-8601 -date is flexible and may be any of the timezones understood by Date::Manip. - -Additional date formats are available which may or may not be common including: - - MM/DD ** - MM/DD/YY ** - MM/DD/YYYY ** - - mmmDD DDmmm mmmYYYY/DD mmmYYYY - mmmDD/YY DDmmmYY DD/YYmmm YYYYmmmDD YYYYmmm - mmmDDYYYY DDmmmYYYY DDYYYYmmm YYYY/DDmmm - -Where mmm refers to the name of a month. All parts of the date can be -separated by valid separators (space, "/", or "."). The separator "-" may -be used as long as it doesn't conflict with an ISO 8601 format, but this -is discouraged since it is easy to overlook conflicts. For example, the -format MM/DD/YY is just fine, but MM-DD-YY does not work since it conflicts -with YY-MM-DD. To be safe, if "-" is used as a separator in a non-ISO -format, they should be turned into "/" before calling the Date::Manip -routines. As with ISO 8601 formats, all separators are optional except for -those given as a "/" in the list above. - -** Note that with these formats, Americans tend to write month first, but -many other countries tend to write day first. The latter behavior can be -obtained by setting the config variable DateFormat to something other than -"US" (see CUSTOMIZING DATE::MANIP below). - -Date separators are treated very flexibly (they are converted to spaces), -so the following dates are all equivalent: - - 12/10/1965 - 12-10 / 1965 - 12 // 10 -. 1965 - -In some cases, this may actually be TOO flexible, but no attempt is made to -trap this. - -Years can be entered as 2 or 4 digits, days and months as 1 or 2 digits. -Both days and months must include 2 digits whenever they are immediately -adjacent to another numeric part of the date or time. Date separators -are required if single digit forms of DD or MM are used. If separators -are not used, the date will either be unparsable or will get parsed -incorrectly. - -Miscellaneous other allowed formats are: - which dofw in mmm in YY "first sunday in june 1996 at 14:00" ** - dofw week num YY "sunday week 22 1995" ** - which dofw YY "22nd sunday at noon" ** - dofw which week YY "sunday 22nd week in 1996" ** - next/last dofw "next friday at noon" - next/last week/month "next month" - in num days/weeks/months "in 3 weeks at 12:00" - num days/weeks/months later "3 weeks later" - num days/weeks/months ago "3 weeks ago" - dofw in num week "Friday in 2 weeks" - in num weeks dofw "in 2 weeks on friday" - dofw num week ago "Friday 2 weeks ago" - num week ago dofw "2 weeks ago friday" - last day in mmm in YY "last day of October" - dofw "Friday" (Friday of current week) - Nth "12th", "1st" (day of current month) - epoch SECS seconds since the epoch (negative values - are supported) - -** Note that the formats "sunday week 22" and "22nd sunday" give very -different bahaviors. "sunday week 22" returns the sunday of the 22nd week -of the year based on how week 1 is defined. ISO 8601 defines week one to -contain Jan 4, so "sunday week 1" might be the first or second sunday of -the current year, or the last sunday of the previous year. "22nd sunday" -gives the actual 22nd time sunday occurs in a given year, regardless of the -definition of a week. - -Note that certain words such as "in", "at", "of", etc. which commonly appear -in a date or time are ignored. Also, the year is always optional. - -In addition, the following strings are recognized: - today (exactly now OR today at a given time if a time is specified) - now (synonym for today) - yesterday (exactly 24 hours ago unless a time is specified) - tomorrow (exactly 24 hours from now unless a time is specifed) - noon (12:00:00) - midnight (00:00:00) -Other languages have similar (and in some cases additional) strings. - -Some things to note: - -All strings are case insensitive. "December" and "DEceMBer" both work. - -When a part of the date is not given, defaults are used: year defaults -to current year; hours, minutes, seconds to 00. - -The year may be entered as 2 or 4 digits. If entered as 2 digits, it will -be converted to a 4 digit year. There are several ways to do this based on -the value of the YYtoYYYY variable (described below). The default behavior -it to force the 2 digit year to be in the 100 year period CurrYear-89 to -CurrYear+10. So in 1996, the range is [1907 to 2006], and the 2 digit year -05 would refer to 2005 but 07 would refer to 1907. See CUSTOMIZING -DATE::MANIP below for information on YYtoYYYY for other methods. - -Dates are always checked to make sure they are valid. - -In all of the formats, the day of week ("Friday") can be entered anywhere -in the date and it will be checked for accuracy. In other words, - "Tue Jul 16 1996 13:17:00" -will work but - "Jul 16 1996 Wednesday 13:17:00" -will not (because Jul 16, 1996 is Tuesday, not Wednesday). Note that -depending on where the weekday comes, it may give unexpected results when -used in array context (with ParseDate). For example, the date -("Jun","25","Sun","1990") would return June 25 of the current year since -Jun 25, 1990 is not Sunday. - -The times "12:00 am", "12:00 pm", and "midnight" are not well defined. For -good or bad, I use the following convention in Date::Manip: - midnight = 12:00am = 00:00:00 - noon = 12:00pm = 12:00:00 -and the day goes from 00:00:00 to 23:59:59. In other words, midnight is the -beginning of a day rather than the end of one. The time 24:00:00 is also -allowed (though it is automatically transformed to 00:00:00 of the following -day). - -The format of the date returned is YYYYMMDDHH:MM:SS. The advantage of this -time format is that two times can be compared using simple string comparisons -to find out which is later. Also, it is readily understood by a human. -Alternate forms can be used if that is more convenient. See Date_Init below -and the config variable Internal. - -NOTE: The format for the date is going to change at some point in the future -to YYYYMMDDHH:MN:SS+HHMN*FLAGS. In order to maintain compatibility, you -should use UnixDate to extract information from a date, and Date_Cmp to compare -two dates. The simple string comparison will only work for dates in the same -timezone. - -=item UnixDate - - @date = UnixDate($date,@format); - $date = UnixDate($date,@format); - -This takes a date and a list of strings containing formats roughly -identical to the format strings used by the UNIX date(1) command. Each -format is parsed and an array of strings corresponding to each format is -returned. - -$date may be any string that can be parsed by ParseDateString. - -The format options are: - - Year - %y year - 00 to 99 - %Y year - 0001 to 9999 - %G year - 0001 to 9999 (see below) - %L year - 0001 to 9999 (see below) - Month, Week - %m month of year - 01 to 12 - %f month of year - " 1" to "12" - %b,%h month abbreviation - Jan to Dec - %B month name - January to December - %U week of year, Sunday - as first day of week - 01 to 53 - %W week of year, Monday - as first day of week - 01 to 53 - Day - %j day of the year - 001 to 366 - %d day of month - 01 to 31 - - %e day of month - " 1" to "31" - %v weekday abbreviation - " S"," M"," T"," W","Th"," F","Sa" - %a weekday abbreviation - Sun to Sat - %A weekday name - Sunday to Saturday - %w day of week - 1 (Monday) to 7 (Sunday) - %E day of month with suffix - 1st, 2nd, 3rd... - Hour - %H hour - 00 to 23 - %k hour - " 0" to "23" - %i hour - " 1" to "12" - %I hour - 01 to 12 - %p AM or PM - Minute, Second, Timezone - %M minute - 00 to 59 - %S second - 00 to 59 - %s seconds from 1/1/1970 GMT- negative if before 1/1/1970 - %o seconds from Jan 1, 1970 - in the current time zone - %Z timezone - "EDT" - %z timezone as GMT offset - "+0100" - Date, Time - %c %a %b %e %H:%M:%S %Y - Fri Apr 28 17:23:15 1995 - %C,%u %a %b %e %H:%M:%S %z %Y - Fri Apr 28 17:25:57 EDT 1995 - %g %a, %d %b %Y %H:%M:%S %z - Fri, 28 Apr 1995 17:23:15 EDT - %D,%x %m/%d/%y - 04/28/95 - %l date in ls(1) format - %b %e $H:$M - Apr 28 17:23 (if within 6 months) - %b %e %Y - Apr 28 1993 (otherwise) - %r %I:%M:%S %p - 05:39:55 PM - %R %H:%M - 17:40 - %T,%X %H:%M:%S - 17:40:58 - %V %m%d%H%M%y - 0428174095 - %Q %Y%m%d - 19961025 - %q %Y%m%d%H%M%S - 19961025174058 - %P %Y%m%d%H%M%S - 1996102517:40:58 - %F %A, %B %e, %Y - Sunday, January 1, 1996 - %J %G-W%W-%w - 1997-W02-2 - %K %Y-%j - 1997-045 - Other formats - %n insert a newline character - %t insert a tab character - %% insert a `%' character - %+ insert a `+' character - The following formats are currently unused but may be used in the future: - NO 1234567890 !@#$^&*()_|-=\`[];',./~{}:<>? - They currently insert the character following the %, but may (and probably - will) change in the future as new formats are added. - -If a lone percent is the final character in a format, it is ignored. - -Note that the ls format (%l) applies to date within the past OR future 6 -months! - -The %U, %W, %L, and %G formats are used to support the ISO-8601 format: -YYYY-wWW-D. In this format, a date is written as a year, the week of -the year, and the day of the week. Technically, the week may be considered -to start on any day of the week, but Sunday and Monday are the two most -common choices, so both are supported. - -The %U and %W formats return a week-of-year number from 01 to 53, and -%L and %G return a 4-digit year corresponding to the week. Most of the -time, the %L and %G formats returns the same value as the %Y format, -but there is a problem with days occuring in the first or last week of -the year. - -The ISO-8601 representation of Jan 1, 1993 written in the YYYY-wWWW-D -format is actually 1992-W53-5. In other words, Jan 1 is treates as being -in the last week of the preceding year. Depending on the year, days in -the first week of a year may belong to the previous year, and days in the -final week of a year may belong to the next year. - -The %L and %U formats contains the year and week-of-year values treating -weeks as starting on Sunday. The %G and %W formats are the year and -week-of-year values treating weeks as starting on Monday. - -%J returns the full ISO-8601 format (%G-W%W-%w). - -The formats used in this routine were originally based on date.pl (version -3.2) by Terry McGonigal, as well as a couple taken from different versions -of the Solaris date(1) command. Also, several have been added which are -unique to Date::Manip. - -=item ParseDateDelta - - $delta = ParseDateDelta(\@args); - $delta = ParseDateDelta($string); - $delta = ParseDateDelta(\$string); - -This takes an array and shifts a valid delta date (an amount of time) -from the array. Recognized deltas are of the form: - +Yy +Mm +Ww +Dd +Hh +MNmn +Ss - examples: - +4 hours +3mn -2second - + 4 hr 3 minutes -2 - 4 hour + 3 min -2 s - +Y:+M:+W:+D:+H:+MN:+S - examples: - 0:0:0:0:4:3:-2 - +4:3:-2 - mixed format - examples: - 4 hour 3:-2 - -A field in the format +Yy is a sign, a number, and a string specifying -the type of field. The sign is "+", "-", or absent (defaults to the -next larger element). The valid strings specifying the field type -are: - y: y, yr, year, years - m: m, mon, month, months - w: w, wk, ws, wks, week, weeks - d: d, day, days - h: h, hr, hour, hours - mn: mn, min, minute, minutes - s: s, sec, second, seconds - -Also, the "s" string may be omitted. The sign, number, and string may -all be separated from each other by any number of whitespaces. - -In the date, all fields must be given in the order: Y M W D H MN S. Any -number of them may be omitted provided the rest remain in the correct -order. In the 2nd (colon) format, from 2 to 7 of the fields may be given. -For example +D:+H:+MN:+S may be given to specify only four of the fields. -In any case, both the MN and S field may be present. No spaces may be -present in the colon format. - -Deltas may also be given as a combination of the two formats. For example, -the following is valid: +Yy +D:+H:+MN:+S. Again, all fields must be given -in the correct order. - -The word "in" may be given (prepended in English) to the delta ("in 5 years") -and the word "ago" may be given (appended in English) ("6 months ago"). The -"in" is completely ignored. The "ago" has the affect of reversing all signs -that appear in front of the components of the delta. I.e. "-12 yr 6 mon ago" -is identical to "+12yr +6mon" (don't forget that there is an implied minus -sign in front of the 6 because when no sign is explicitly given, it carries -the previously entered sign). - -One thing is worth noting. The year/month and day/hour/min/sec parts are -returned in a "normalized" form. That is, the signs are adjusted so as to -be all positive or all negative. For example, "+ 2 day - 2hour" does not -return "0:0:0:2:-2:0:0". It returns "+0:0:0:1:22:0:0" (1 day 22 hours -which is equivalent). I find (and I think most others agree) that this is -a more useful form. - -Since the year/month and day/hour/min/sec parts must be normalized -separately there is the possibility that the sign of the two parts will be -different. So, the delta "+ 2years -10 months - 2 days + 2 hours" produces -the delta "+1:2:-0:1:22:0:0". - -It is possible to include a sign for all elements that is output. See the -configuration variable DeltaSigns below. - -NOTE: The internal format of the delta changed in version 5.30 from -Y:M:D:H:MN:S to Y:M:W:D:H:MN:S . Also, it is going to change again at some -point in the future to Y:M:W:D:H:MN:S*FLAGS . Use the routine Delta_Format -to extract information rather than parsing it yourself. - -=item Delta_Format - - @str = Delta_Format($delta,$dec,@format); - $str = Delta_Format($delta,$dec,@format); - -This is similar to the UnixDate routine except that it extracts information -from a delta. Unlike the UnixDate routine, most of the formats are 2 -characters instead of 1. - -Formats currently understood are: - - %Xv : the value of the field named X - %Xd : the value of the field X, and all smaller fields, expressed in - units of X - %Xh : the value of field X, and all larger fields, expressed in units - of X - %Xt : the value of all fields expressed in units of X - - X is one of y,M,w,d,h,m,s (case sensitive). - - %% : returns a "%" - -NOTE: Delta_Format only understands "exact" relationships, so for any delta -that has a month component, there can be no mixing of the Y/M and -W/D/H/MN/S segments. In other words, the delta 1:6:1:1:1:1:1 has a month -component, so asking for the total number of years (using the %yd format) -will return 1.5 (which is what 1 year 6 months is). For deltas which have -NO month component, the relationship between years and days is known -(365.25 is used) and all formats work as expected (except that formats with -X equal to "M" are not allowed). - -So, the format "%hd" means the values of H, MN, and S expressed in hours. -So for the delta "0:0:0:0:2:30:0", this format returns 2.5. Similarly, the -format "%yd" means the value (in years) of both the Y and M fields, or, -if the month component is 0, it uses Y, W, D, H, MN, S. - -The format "%hh" returns the value of W, D, and H expressed in hours if -the month component is non-zero, or Y, W, D, H if the month component is 0. - -If $dec is non-zero, the %Xd and %Xt values are formatted to contain $dec -decimal places. - -=item ParseRecur - - $recur = ParseRecur($string [,$base,$date0,$date1,$flags]); - @dates = ParseRecur($string [,$base,$date0,$date1,$flags]); - -A recurrence refers to a recurring event. A fully specified recurrence -requires (in most cases) 4 items: a recur description (describing the -frequency of the event), a base date (a date when the event occurred and -which other occurrences are based on), and a start and end date. There may -be one or more flags included which modify the behavior of the recur -description. The fully specified recurrence is written as: - - recur*flags*base*date0*date1 - -Here, base, date0, and date1 are any strings (which must not contain any -asterixes) which can be parsed by ParseDate. flags is a comma separated -list of flags (described below), and recur is a string describing a -recurring event. - -If called in scalar context, it returns a string containing a fully -specified recurrence (or as much of it as can be determined with -unspecified fields left blank). In list context, it returns a list of all -dates referred to by a recurrence if enough information is given in the -recurrence. All dates returned are in the range: - - date0 <= date < date1 - -The argument $string can contain any of the parts of a full recurrence. -For example: - - recur - recur*flags - recur**base*date0*date1 - -The only part which is required is the recur description. Any values -contained in $string are overridden or modified by values passed in as -parameters to ParseRecur. - -A recur description is a string of the format Y:M:W:D:H:MN:S . Exactly one -of the colons may optionally be replaced by an asterisk, or an asterisk may -be prepended to the string. - -Any value "N" to the left of the asterisk refers to the "Nth" one. Any -value to the right of the asterisk refers to a value as it appears on a -calendar/clock. Values to the right can be listed a single values, ranges -(2 numbers separated by a dash "-"), or a comma separated list of values -or ranges. In a few cases, negative values are appropriate. - -This is best illustrated by example. - - 0:0:2:1:0:0:0 every 2 weeks and 1 day - 0:0:0:0:5:30:0 every 5 hours and 30 minutes - 0:0:0:2*12:30:0 every 2 days at 12:30 (each day) - 3*1:0:2:12:0:0 every 3 years on Jan 2 at noon - 0:1*0:2:12,14:0:0 2nd of every month at 12:00 and 14:00 - 1:0:0*45:0:0:0 45th day of every year - 0:1*4:2:0:0:0 4th tuesday (day 2) of every month - 0:1*-1:2:0:0:0 last tuesday of every month - 0:1:0*-2:0:0:0 2nd to last day of every month - 0:0:3*2:0:0:0 every 3rd tuesday (every 3 weeks on 2nd day of week) - 1:0*12:2:0:0:0 tuesday of the 12th week of each year - *1990-1995:12:0:1:0:0:0 - Dec 1 in 1990 through 1995 - - 0:1*2:0:0:0:0 the start of the 2nd week of every month (see Note 2) - 1*1:2:0:0:0:0 the start of the 2nd week in January each year (Note 2) - -I realize that this looks a bit cryptic, but after a discussion on the -CALENDAR mailing list, it looked like there was no concise, flexible -notation for handling recurring events. ISO 8601 notations were very bulky -and lacked the flexibility I wanted. As a result, I developed this -notation (based on crontab formats, but with much more flexibility) which -fits in well with this module, and which is able to express every type of -recurring event I could think of. - -NOTE: If a recurrence has a date0 and date1 in it AND a date0 and date1 -are passed in to the function, both sets of criteria apply. If flags are -passed in, they override any flags in the recurrence UNLESS the flags -passed in start with a plus (+) character in which case they are appended -to the flags in the recurrence. - -NOTE: There is no way to express the following with a single recurrence: - - every day at 12:30 and 1:00 - -You have to use two recurrences to do this. - -NOTE: A recurrence specifying the week of a month is NOT clearly defined -in common usage. What is the 1st week in a month? The behavior (with -respect to this module) is well defined (using the FDn and FIn flags -below), but in common usage, this is so ambiguous that this form should -probably never be used. It is included here solely for the sake of -completeness. - -NOTE: Depending on whether M and W are 0 or nonzero, D means different -things. This is given in the following table. - - M W D (when right of an asterisk) refers to - - - ------------------------------------------- - 0 0 day of year (1-366) - M 0 day of month (1-31) - 0 W day of week (1-7), W refers to the week of year - M W the Wth (1-5 or -1 to -5) occurrence of Dth (1-7) day of week in month - -NOTE: Base dates are only used with some types of recurrences. For example, - - 0:0:3*2:0:0:0 every 3rd tuesday - -requires a base date. If a base date is specified which doesn't match the -criteria (for example, if a base date falling on Monday were passed in with -this recurrence), the base date is moved forward to the first relevant date. - -Other dates do not require a base date. For example: - - 0:0*3:2:0:0:0 third tuesday of every month - -A recurrence written in the above format does NOT provide default values -for base, date0, or date1. They must be specified in order to get a list -of dates. - -A base date is not used entirely. It is only used to provide the parts -necessary for the left part of a recurrence. For example, the recurrence: - - 1:3*0:4:0:0:0 every 1 year, 3 months on the 4th day of the month - -would only use the year and month of the base date. - - -There are a small handful of English strings which can be parsed in place -of a numerical recur description. These include: - - every 2nd day [in 1997] - every 2nd day in June [1997] - 2nd day of every month [in 1997] - 2nd tuesday of every month [in 1997] - last tuesday of every month [in 1997] - every tuesday [in 1997] - every 2nd tuesday [in 1997] - every 2nd tuesday in June [1997] - -Each of these set base, date0, and date1 to a default value (the current -year with Jan 1 being the base date is the default if the year and month -are missing). - -The following flags (case insensitive) are understood: - - MWn : n is 1-7. The first week of the month is the week - which contains the first occurrence of day n (1=Monday). - MW2 means that the first week contains the first Tuesday - of the month. - MDn : n is 1-7. The first week of the month contains the - actual date (1st through 7th). MD4 means that the first - week of the month contains the 4th of that month. - - PDn : n is 1-7. Means the previous day n not counting today - PTn : n is 1-7. Means the previous day n counting today - NDn : n is 1-7. Means the next day n not counting today - NTn : n is 1-7. Means the next day n counting today - - FDn : n is any number. Means step forward n days. - BDn : n is any number. Means step backward n days. - FWn : n is any number. Means step forward n workdays. - BWn : n is any number. Means step backward n workdays. - - CWD : the closest work day (using the TomorrowFirst config variable). - CWN : the closest work day (looking forward first). - CWP : the closest work day (looking backward first). - - NWD : next work day counting today - PWD : previous work day counting today - DWD : next/previous work day (TomorrowFirst config) counting today - - EASTER: select easter for this year (the M, W, D fields are ignored - in the recur). - -NOTE: only one of MWn and MDn can be set. If both are set, only the -last one is used. The default is MW7 (i.e. the first week contains -the first Sunday). - -CWD, CWN, and CWP will usually return the same value, but if you are -starting at the middle day of a 3-day weekend (for example), it will return -either the first work day of the following week, or the last work day of -the previous week depending on whether it looks forward or backward first. - -All flags are applied AFTER the recurrence dates are calculated, and they -may move a date outside of the date0 to date1 range. No check is made for -this. - -The workday flags do not act exactly the same as a business mode calculation. -For example, a date that is Saturday with a FW1 steps forward to the first -workday (i.e. Monday). - -=item Date_Cmp - - $flag = Date_Cmp($date1,$date2); - -This takes two dates and compares them. Almost all dates can be compared -using the perl "cmp" command. The only time this will not work is when -comparing dates in different timezones. This routine will take that into -account. - -NOTE: This routine currently does little more than use "cmp", but once -the internal format for storing dates is in place (where timezone information -is kept as part of the date), this routine will become more important. You -should use this routine in prepartation for that version. - -=item DateCalc - - $d = DateCalc($d1,$d2 [,\$err] [,$mode]); - -This takes two dates, deltas, or one of each and performs the appropriate -calculation with them. Dates must be a string that can be parsed by -&ParseDateString. Deltas must be a string that can be parsed by -&ParseDateDelta. Two deltas add together to form a third delta. A date -and a delta returns a 2nd date. Two dates return a delta (the difference -between the two dates). - -Note that in many cases, it is somewhat ambiguous what the delta actually -refers to. Although it is ALWAYS known how many months in a year, hours in -a day, etc., it is NOT known how many days form a month. As a result, the -part of the delta containing month/year and the part with sec/min/hr/day -must be treated separately. For example, "Mar 31, 12:00:00" plus a delta -of 1month 2days would yield "May 2 12:00:00". The year/month is first -handled while keeping the same date. Mar 31 plus one month is Apr 31 (but -since Apr only has 30 days, it becomes Apr 30). Apr 30 + 2 days is May 2. -As a result, in the case where two dates are entered, the resulting delta -can take on two different forms. By default ($mode=0), an absolutely -correct delta (ignoring daylight savings time) is returned in days, hours, -minutes, and seconds. - -If $mode is 1, the math is done using an approximate mode where a delta is -returned using years and months as well. The year and month part is -calculated first followed by the rest. For example, the two dates "Mar 12 -1995" and "Apr 13 1995" would have an exact delta of "31 days" but in the -approximate mode, it would be returned as "1 month 1 day". Also, "Mar 31" -and "Apr 30" would have deltas of "30 days" or "1 month" (since Apr 31 -doesn't exist, it drops down to Apr 30). Approximate mode is a more human -way of looking at things (you'd say 1 month and 2 days more often then 33 -days), but it is less meaningful in terms of absolute time. In approximate -mode $d1 and $d2 must be dates. If either or both is a delta, the -calculation is done in exact mode. - -If $mode is 2, a business mode is used. That is, the calculation is done -using business days, ignoring holidays, weekends, etc. In order to -correctly use this mode, a config file must exist which contains the -section defining holidays (see documentation on the config file below). -The config file can also define the work week and the hours of the work -day, so it is possible to have different config files for different -businesses. - -For example, if a config file defines the workday as 08:00 to 18:00, a -work week consisting of Mon-Sat, and the standard (American) holidays, then -from Tuesday at 12:00 to the following Monday at 14:00 is 5 days and 2 -hours. If the "end" of the day is reached in a calculation, it -automatically switches to the next day. So, Tuesday at 12:00 plus 6 hours -is Wednesday at 08:00 (provided Wed is not a holiday). Also, a date that -is not during a workday automatically becomes the start of the next -workday. So, Sunday 12:00 and Monday at 03:00 both automatically becomes -Monday at 08:00 (provided Monday is not a holiday). In business mode, any -combination of date and delta may be entered, but a delta should not -contain a year or month field (weeks are fine though). - -See below for some additional comments about business mode calculations. - -Note that a business week is treated the same as an exact week (i.e. from -Tuesday to Tuesday, regardless of holidays). Because this means that the -relationship between days and weeks is NOT unambiguous, when a delta is -produced from two dates, it will be in terms of d/h/mn/s (i.e. no week -field). - -If $mode is 3 (which only applies when two dates are passed in), an exact -business mode is used. In this case, it returns a delta as an exact number -of business days/hours/etc. between the two. Weeks, months, and years are -ignored. - -Any other non-nil value of $mode is treated as $mode=1 (approximate mode). - -The mode can be automatically set in the dates/deltas passed by including a -key word somewhere in it. For example, in English, if the word -"approximately" is found in either of the date/delta arguments, approximate -mode is forced. Likewise, if the word "business" or "exactly" appears, -business/exact mode is forced (and $mode is ignored). So, the two -following are equivalent: - - $date = DateCalc("today","+ 2 business days",\$err); - $date = DateCalc("today","+ 2 days",\$err,2); - -Note that if the keyword method is used instead of passing in $mode, it is -important that the keyword actually appear in the argument passed in to -DateCalc. The following will NOT work: - - $delta = ParseDateDelta("+ 2 business days"); - $today = ParseDate("today"); - $date = DateCalc($today,$delta,\$err); - -because the mode keyword is removed from a date/delta by the parse routines, -and the mode is reset each time a parse routine is called. Since DateCalc -parses both of its arguments, whatever mode was previously set is ignored. - -If \$err is passed in, it is set to: - 1 is returned if $d1 is not a delta or date - 2 is returned if $d2 is not a delta or date - 3 is returned if the date is outside the years 1000 to 9999 -This argument is optional, but if included, it must come before $mode. - -Nothing is returned if an error occurs. - -When a delta is returned, the signs such that it is strictly positive or -strictly negative ("1 day - 2 hours" would never be returned for example). -The only time when this cannot be enforced is when two deltas with a -year/month component are entered. In this case, only the signs on the -day/hour/min/sec part are standardized. - -=item Date_SetTime - - $date = Date_SetTime($date,$hr,$min,$sec); - $date = Date_SetTime($date,$time); - -This takes a date (any string that may be parsed by ParseDateString) and -sets the time in that date. For example, one way to get the time for 7:30 -tomorrow would be to use the lines: - - $date = ParseDate("tomorrow"); - $date = Date_SetTime($date,"7:30"); - -Note that in this routine (as well as the other routines below which use -a time argument), no real parsing is done on the times. As a result, - - $date = Date_SetTime($date,"13:30"); - -works, but - - $date = Date_SetTime($date,"1:30 PM"); - -doesn't. - -=item Date_SetDateField - - $date = Date_SetDateField($date,$field,$val [,$nocheck]); - -This takes a date and sets one of it's fields to a new value. $field is -any of the strings "y", "m", "d", "h", "mn", "s" (case insensitive) and -$val is the new value. - -If $nocheck is non-zero, no check is made as to the validity of the date. - -=item Date_GetPrev - - $date = Date_GetPrev($date,$dow, $curr [,$hr,$min,$sec]); - $date = Date_GetPrev($date,$dow, $curr [,$time]); - $date = Date_GetPrev($date,undef,$curr,$hr,$min,$sec); - $date = Date_GetPrev($date,undef,$curr,$time); - -This takes a date (any string that may be parsed by ParseDateString) and finds -the previous occurrence of either a day of the week, or a certain time of day. - -If $dow is defined, the previous occurrence of the day of week is returned. -$dow may either be a string (such as "Fri" or "Friday") or a number -(between 1 and 7). The date of the previous $dow is returned. - -If $date falls on the day of week given by $dow, the date returned depends -on $curr. If $curr is 0, the date returned is a week before $date. If -$curr is 1, the date returned is the same as $date. If $curr is 2, the date -returned (including the time information) is required to be before $date. - -If a time is passed in (either as separate hours, minutes, seconds or as a -time in HH:MM:SS or HH:MM format), the time on this date is set to it. The -following examples should illustrate the use of Date_GetPrev: - - date dow curr time returns - Fri Nov 22 18:15:00 Thu any 12:30 Thu Nov 21 12:30:00 - Fri Nov 22 18:15:00 Fri 0 12:30 Fri Nov 15 12:30:00 - Fri Nov 22 18:15:00 Fri 1/2 12:30 Fri Nov 22 12:30:00 - - Fri Nov 22 18:15:00 Fri 1 18:30 Fri Nov 22 18:30:00 - Fri Nov 22 18:15:00 Fri 2 18:30 Fri Nov 15 18:30:00 - -If $dow is undefined, then a time must be entered, and the date returned is -the previous occurrence of this time. If $curr is non-zero, the current -time is returned if it matches the criteria passed in. In other words, the -time returned is the last time that a digital clock (in 24 hour mode) would -have displayed the time you passed in. If you define hours, minutes and -seconds default to 0 and you might jump back as much as an entire day. If -hours are undefined, you are looking for the last time the minutes/seconds -appeared on the digital clock, so at most, the time will jump back one hour. - - date curr hr min sec returns - Nov 22 18:15:00 0/1 18 undef undef Nov 22 18:00:00 - Nov 22 18:15:00 0/1 18 30 0 Nov 21 18:30:00 - Nov 22 18:15:00 0 18 15 undef Nov 21 18:15:00 - Nov 22 18:15:00 1 18 15 undef Nov 22 18:15:00 - Nov 22 18:15:00 0 undef 15 undef Nov 22 17:15:00 - Nov 22 18:15:00 1 undef 15 undef Nov 22 18:15:00 - -=item Date_GetNext - - $date = Date_GetNext($date,$dow, $curr [,$hr,$min,$sec]); - $date = Date_GetNext($date,$dow, $curr [,$time]); - $date = Date_GetNext($date,undef,$curr,$hr,$min,$sec); - $date = Date_GetNext($date,undef,$curr,$time); - -Similar to Date_GetPrev. - -=item Date_IsHoliday - - $name = Date_IsHoliday($date); - -This returns undef if $date is not a holiday, or a string containing the -name of the holiday otherwise. An empty string is returned for an unnamed -holiday. - -=item Events_List - - $ref = Events_List($date); - $ref = Events_List($date ,0 [,$flag]); - $ref = Events_List($date0,$date1 [,$flag]); - -This returns a list of events. Events are defined in the Events section -of the config file (discussed below). - -In the first form (a single argument), $date is any string containing a -date. A list of events active at that precise time will be returned. -The format is similar to when $flag=0, except only a single time will -be returned. - -In all other cases, a range of times will be used. If the 2nd argument -evaluates to 0, the range of times will be the 24 hour period from -midnight to midnight containing $date. Otherwise, the range is given -by the two dates. - -The value of $flag determines the format of the information that is -returned. - -With $flag=0, the events are returned as a reference to a list of the form: - - [ date, [ list_of_events ], date, [ list_of_events ], ... ] - -For example, if the following events are defined (using the syntax -discussed below in the description of the Event section of the config -file): - - 2000-01-01 ; 2000-03-21 = Winter - 2000-03-22 ; 2000-06-21 = Spring - 2000-02-01 = Event1 - 2000-05-01 = Event2 - 2000-04-01-12:00:00 = Event3 - -might result in the following output: - - &Events_List("2000-04-01") - => [ 2000040100:00:00, [ Spring ] ] - - &Events_List("2000-04-01 12:30"); - => [ 2000040112:30:00, [ Spring, Event3 ] ] - - &Events_List("2000-04-01",0); - => [ 2000040100:00:00, [ Spring ], - 2000040112:00:00, [ Spring, Event3 ], - 2000040113:00:00, [ Spring ] ] - - &Events_List("2000-03-15","2000-04-10"); - => [ 2000031500:00:00, [ Winter ], - 2000032200:00:00, [ Spring ] - 2000040112:00:00, [ Spring, Event3 ] - 2000040113:00:00, [ Spring ] ] - -Much more complicated events can be defined using recurrences. - -When $flag is non-zero, the format of the output is changed. If $flag -is 1, then a tally of the amount of time given to each event is returned. -Time for which two or more events apply is counted for both. - - &Events_List("2000-03-15","2000-04-10",1); - => { Winter => +0:0:1:0:0:0:0, - Spring => +0:0:2:5:0:0:0, - Event3 => +0:0:0:0:1:0:0 } - -When $flag is 2, a more complex tally with no event counted twice is -returned. - - &Events_List("2000-03-15","2000-04-10",2); - => { Winter => +0:0:1:0:0:0:0, - Spring => +0:0:2:4:23:0:0, - Event3+Spring => +0:0:0:0:1:0:0 } - -The hash contains one element for each combination of events. - -=item Date_DayOfWeek - - $day = Date_DayOfWeek($m,$d,$y); - -Returns the day of the week (1 for Monday, 7 for Sunday). - -All arguments must be numeric. - -=item Date_SecsSince1970 - - $secs = Date_SecsSince1970($m,$d,$y,$h,$mn,$s); - -Returns the number of seconds since Jan 1, 1970 00:00 (negative if date is -earlier). - -All arguments must be numeric. - -=item Date_SecsSince1970GMT - - $secs = Date_SecsSince1970GMT($m,$d,$y,$h,$mn,$s); - -Returns the number of seconds since Jan 1, 1970 00:00 GMT (negative if date -is earlier). If CurrTZ is "IGNORE", the number will be identical to -Date_SecsSince1970 (i.e. the date given will be treated as being in GMT). - -All arguments must be numeric. - -=item Date_DaysSince1BC - - $days = Date_DaysSince1BC($m,$d,$y); - -Returns the number of days since Dec 31, 1BC. This includes the year 0000. - -All arguments must be numeric. - -=item Date_DayOfYear - - $day = Date_DayOfYear($m,$d,$y); - -Returns the day of the year (001 to 366) - -All arguments must be numeric. - -=item Date_NthDayOfYear - - ($y,$m,$d,$h,$mn,$s) = Date_NthDayOfYear($y,$n); - -Returns the year, month, day, hour, minutes, and decimal seconds given -a floating point day of the year. - -All arguments must be numeric. $n must be greater than or equal to 1 -and less than 366 on non-leap years and 367 on leap years. - -NOTE: When $n is a decimal number, the results are non-intuitive perhaps. -Day 1 is Jan 01 00:00. Day 2 is Jan 02 00:00. Intuitively, you -might think of day 1.5 as being 1.5 days after Jan 01 00:00, but this -would mean that Day 1.5 was Jan 02 12:00 (which is later than Day 2). -The best way to think of this function is a timeline starting at 1 and -ending at 366 (in a non-leap year). In terms of a delta, think of $n -as the number of days after Dec 31 00:00 of the previous year. - -=item Date_DaysInYear - - $days = Date_DaysInYear($y); - -Returns the number of days in the year (365 or 366) - -=item Date_DaysInMonth - - $days = Date_DaysInMonth($m,$y); - -Returns the number of days in the month. - -=item Date_WeekOfYear - - $wkno = Date_WeekOfYear($m,$d,$y,$first); - -Figure out week number. $first is the first day of the week which is -usually 1 (Monday) or 7 (Sunday), but could be any number between 1 and 7 -in practice. - -All arguments must be numeric. - -NOTE: This routine should only be called in rare cases. Use UnixDate with -the %W, %U, %J, %L formats instead. This routine returns a week between 0 -and 53 which must then be "fixed" to get into the ISO-8601 weeks from 1 to -53. A date which returns a week of 0 actually belongs to the last week of -the previous year. A date which returns a week of 53 may belong to the -first week of the next year. - -=item Date_LeapYear - - $flag = Date_LeapYear($y); - -Returns 1 if the argument is a leap year -Written by David Muir Sharnoff - -=item Date_DaySuffix - - $day = Date_DaySuffix($d); - -Add `st', `nd', `rd', `th' to a date (ie 1st, 22nd, 29th). Works for -international dates. - -=item Date_TimeZone - - $tz = Date_TimeZone; - -This determines and returns the local timezone. If it is unable to determine -the local timezone, the following error occurs: - - ERROR: Date::Manip unable to determine TimeZone. - -See The TIMEZONES section below for more information. - -=item Date_ConvTZ - - $date = Date_ConvTZ($date); - $date = Date_ConvTZ($date,$from); - $date = Date_ConvTZ($date,"",$to); - $date = Date_ConvTZ($date,$from,$to); - -This converts a date (which MUST be in the format returned by ParseDate) -from one timezone to another. - -If it is called with no arguments, the date is converted from the local -timezone to the timezone specified by the config variable ConvTZ (see -documentation on ConvTZ below). If ConvTZ is set to "IGNORE", no -conversion is done. - -If called with $from but no $to, the timezone is converted from the -timezone in $from to ConvTZ (of TZ if ConvTZ is not set). Again, no -conversion is done if ConvTZ is set to "IGNORE". - -If called with $to but no $from, $from defaults to ConvTZ (if set) or the -local timezone otherwise. Although this does not seem immediately obvious, -it actually makes sense. By default, all dates that are parsed are -converted to ConvTZ, so most of the dates being worked with will be stored -in that timezone. - -If Date_ConvTZ is called with both $from and $to, the date is converted -from the timezone $from to $to. - -NOTE: As in all other cases, the $date returned from Date_ConvTZ has no -timezone information included as part of it, so calling UnixDate with the -"%z" format will return the timezone that Date::Manip is working in -(usually the local timezone). - -Example: To convert 2/2/96 noon PST to CST (regardless of what timezone -you are in, do the following: - - $date = ParseDate("2/2/96 noon"); - $date = Date_ConvTZ($date,"PST","CST"); - -Both timezones MUST be in one of the formats listed below in the section -TIMEZONES. - -=item Date_Init - - &Date_Init(); - &Date_Init("VAR=VAL","VAR=VAL",...); - @list = Date_Init(); - @list = Date_Init("VAR=VAL","VAR=VAL",...); - -Normally, it is not necessary to explicitly call Date_Init. The first -time any of the other routines are called, Date_Init will be called to set -everything up. If for some reason you want to change the configuration of -Date::Manip, you can pass the appropriate string or strings into Date_Init -to reinitialize things. - -The strings to pass in are of the form "VAR=VAL". Any number may be -included and they can come in any order. VAR may be any configuration -variable. A list of all configuration variables is given in the section -CUSTOMIZING DATE::MANIP below. VAL is any allowed value for that variable. -For example, to switch from English to French and use non-US format (so -that 12/10 is Oct 12), do the following: - - &Date_Init("Language=French","DateFormat=non-US"); - -If Date_Init is called in list context, it will return a list of all -config variables and their values suitable for passing in to Date_Init -to return Date::Manip to the current state. The only possible problem is -that by default, holidays will not be erased, so you may need to prepend -the "EraseHolidays=1" element to the list. - -=item Date_IsWorkDay - - $flag = Date_IsWorkDay($date [,$flag]); - -This returns 1 if $date is a work day. If $flag is non-zero, the time is -checked to see if it falls within work hours. It returns an empty string -if $date is not valid. - -=item Date_NextWorkDay - - $date = Date_NextWorkDay($date,$off [,$time]); - -Finds the day $off work days from now. If $time is passed in, we must also -take into account the time of day. - -If $time is not passed in, day 0 is today (if today is a workday) or the -next work day if it isn't. In any case, the time of day is unaffected. - -If $time is passed in, day 0 is now (if now is part of a workday) or the -start of the very next work day. - -=item Date_PrevWorkDay - - $date = Date_PrevWorkDay($date,$off [,$time]); - -Similar to Date_NextWorkDay. - -=item Date_NearestWorkDay - - $date = Date_NearestWorkDay($date [,$tomorrowfirst]); - -This looks for the work day nearest to $date. If $date is a work day, it -is returned. Otherwise, it will look forward or backwards in time 1 day -at a time until a work day is found. If $tomorrowfirst is non-zero (or if -it is omitted and the config variable TomorrowFirst is non-zero), we look -to the future first. Otherwise, we look in the past first. In other words, -in a normal week, if $date is Wednesday, $date is returned. If $date is -Saturday, Friday is returned. If $date is Sunday, Monday is returned. If -Wednesday is a holiday, Thursday is returned if $tomorrowfirst is non-nil -or Tuesday otherwise. - -=item DateManipVersion - - $version = DateManipVersion; - -Returns the version of Date::Manip. - -=back - -=head1 TIMEZONES - -The following timezone names are currently understood (and can be used in -parsing dates). These are zones defined in RFC 822. - - Universal: GMT, UT - US zones : EST, EDT, CST, CDT, MST, MDT, PST, PDT - Military : A to Z (except J) - Other : +HHMM or -HHMM - ISO 8601 : +HH:MM, +HH, -HH:MM, -HH - -In addition, the following timezone abbreviations are also accepted. In a -few cases, the same abbreviation is used for two different timezones (for -example, NST stands for Newfoundland Standard -0330 and North Sumatra +0630). -In these cases, only 1 of the two is available. The one preceded by a "#" -sign is NOT available but is documented here for completeness. This list of -zones comes in part from the Time::Zone module by Graham Barr, David Muir -Sharnoff, and Paul Foley (with several additions by myself). - - IDLW -1200 International Date Line West - NT -1100 Nome - HST -1000 Hawaii Standard - CAT -1000 Central Alaska - AHST -1000 Alaska-Hawaii Standard - AKST -0900 Alaska Standard - YST -0900 Yukon Standard - HDT -0900 Hawaii Daylight - AKDT -0800 Alaska Daylight - YDT -0800 Yukon Daylight - PST -0800 Pacific Standard - PDT -0700 Pacific Daylight - MST -0700 Mountain Standard - MDT -0600 Mountain Daylight - CST -0600 Central Standard - CDT -0500 Central Daylight - EST -0500 Eastern Standard - ACT -0500 Brazil, Acre - SAT -0400 Chile - BOT -0400 Bolivia - EDT -0400 Eastern Daylight - AST -0400 Atlantic Standard - AMT -0400 Brazil, Amazon - ACST -0400 Brazil, Acre Daylight - #NST -0330 Newfoundland Standard nst=North Sumatra +0630 - NFT -0330 Newfoundland - #GST -0300 Greenland Standard gst=Guam Standard +1000 - #BST -0300 Brazil Standard bst=British Summer +0100 - BRST -0300 Brazil Standard - BRT -0300 Brazil Standard - AMST -0300 Brazil, Amazon Daylight - ADT -0300 Atlantic Daylight - ART -0300 Argentina - NDT -0230 Newfoundland Daylight - AT -0200 Azores - BRST -0200 Brazil Daylight (official time) - FNT -0200 Brazil, Fernando de Noronha - WAT -0100 West Africa - FNST -0100 Brazil, Fernando de Noronha Daylight - GMT +0000 Greenwich Mean - UT +0000 Universal (Coordinated) - UTC +0000 Universal (Coordinated) - WET +0000 Western European - CET +0100 Central European - FWT +0100 French Winter - MET +0100 Middle European - MEZ +0100 Middle European - MEWT +0100 Middle European Winter - SWT +0100 Swedish Winter - BST +0100 British Summer bst=Brazil standard -0300 - GB +0100 GMT with daylight savings - WEST +0000 Western European Daylight - CEST +0200 Central European Summer - EET +0200 Eastern Europe, USSR Zone 1 - FST +0200 French Summer - MEST +0200 Middle European Summer - MESZ +0200 Middle European Summer - METDST +0200 An alias for MEST used by HP-UX - SAST +0200 South African Standard - SST +0200 Swedish Summer sst=South Sumatra +0700 - EEST +0300 Eastern Europe Summer - BT +0300 Baghdad, USSR Zone 2 - MSK +0300 Moscow - EAT +0300 East Africa - IT +0330 Iran - ZP4 +0400 USSR Zone 3 - MSD +0300 Moscow Daylight - ZP5 +0500 USSR Zone 4 - IST +0530 Indian Standard - ZP6 +0600 USSR Zone 5 - NOVST +0600 Novosibirsk time zone, Russia - NST +0630 North Sumatra nst=Newfoundland Std -0330 - #SST +0700 South Sumatra, USSR Zone 6 sst=Swedish Summer +0200 - JAVT +0700 Java - CCT +0800 China Coast, USSR Zone 7 - AWST +0800 Australian Western Standard - WST +0800 West Australian Standard - PHT +0800 Asia Manila - JST +0900 Japan Standard, USSR Zone 8 - ROK +0900 Republic of Korea - ACST +0930 Australian Central Standard - CAST +0930 Central Australian Standard - AEST +1000 Australian Eastern Standard - EAST +1000 Eastern Australian Standard - GST +1000 Guam Standard, USSR Zone 9 gst=Greenland Std -0300 - ACDT +1030 Australian Central Daylight - CADT +1030 Central Australian Daylight - AEDT +1100 Australian Eastern Daylight - EADT +1100 Eastern Australian Daylight - IDLE +1200 International Date Line East - NZST +1200 New Zealand Standard - NZT +1200 New Zealand - NZDT +1300 New Zealand Daylight - -Others can be added in the future upon request. - -Date::Manip must be able to determine the timezone the user is in. It does -this by looking in the following places: - - $Date::Manip::TZ (set with Date_Init or in Manip.pm) - $ENV{TZ} - the unix `date` command (if available) - $main::TZ - /etc/TIMEZONE - /etc/timezone - -At least one of these should contain a timezone in one of the supported -forms. If none do by default, the TZ variable must be set with Date_Init. - -The timezone may be in the STD#DST format (in which case both abbreviations -must be in the table above) or any of the formats described above. The -STD#DST format is NOT available when parsing a date however. The following -forms are also available and are treated similar to the STD#DST forms: - - US/Pacific - US/Mountain - US/Central - US/Eastern - Canada/Pacific - Canada/Mountain - Canada/Central - Canada/Eastern - -=head1 BUSINESS MODE - -Anyone using business mode is going to notice a few quirks about it which -should be explained. When I designed business mode, I had in mind what UPS -tells me when they say 2 day delivery, or what the local business which -promises 1 business day turnaround really means. - -If you do a business day calculation (with the workday set to 9:00-5:00), -you will get the following: - - Saturday at noon + 1 business day = Tuesday at 9:00 - Saturday at noon - 1 business day = Friday at 9:00 - -What does this mean? - -We have a business that works 9-5 and they have a drop box so I can drop -things off over the weekend and they promise 1 business day turnaround. If -I drop something off Friday night, Saturday, or Sunday, it doesn't matter. -They're going to get started on it Monday morning. It'll be 1 business day -to finish the job, so the earliest I can expect it to be done is around -17:00 Monday or 9:00 Tuesday morning. Unfortunately, there is some -ambiguity as to what day 17:00 really falls on, similar to the ambiguity -that occurs when you ask what day midnight falls on. Although it's not the -only answer, Date::Manip treats midnight as the beginning of a day rather -than the end of one. In the same way, 17:00 is equivalent to 9:00 the next -day and any time the date calculations encounter 17:00, it automatically -switch to 9:00 the next day. Although this introduces some quirks, I think -this is justified. You just have to treat 17:00/9:00 as being ambiguous -(in the same way you treat midnight as being ambiguous). - -Equivalently, if I want a job to be finished on Saturday (despite the fact -that I cannot pick it up since the business is closed), I have to drop it -off no later than Friday at 9:00. That gives them a full business day to -finish it off. Of course, I could just as easily drop it off at 17:00 -Thursday, or any time between then and 9:00 Friday. Again, it's a matter -of treating 9:00 as ambiguous. - -So, in case the business date calculations ever produce results that you -find confusing, I believe the solution is to write a wrapper which, -whenever it sees a date with the time of exactly 9:00, it treats it -specially (depending on what you want. - -So Saturday + 1 business day = Tuesday at 9:00 (which means anything -from Monday 17:00 to Tuesday 9:00), but Monday at 9:01 + 1 business -day = Tuesday at 9:01 which is exact. - -If this is not exactly what you have in mind, don't use the DateCalc -routine. You can probably get whatever behavior you want using the -routines Date_IsWorkDay, Date_NextWorkDay, and Date_PrevWorkDay described -above. - -=head1 CUSTOMIZING DATE::MANIP - -There are a number of variables which can be used to customize the way -Date::Manip behaves. There are also several ways to set these variables. - -At the top of the Manip.pm file, there is a section which contains all -customization variables. These provide the default values. - -These can be overridden in a global config file if one is present (this -file is optional). If the GlobalCnf variable is set in the Manip.pm file, -it contains the full path to a config file. If the file exists, it's -values will override those set in the Manip.pm file. A sample config file -is included with the Date::Manip distribution. Modify it as appropriate -and copy it to some appropriate directory and set the GlobalCnf variable in -the Manip.pm file. - -Each user can have a personal config file which is of the same form as the -global config file. The variables PersonalCnf and PersonalCnfPath set the -name and search path for the personal config file. This file is also -optional. If present, it overrides any values set in the global file. - -NOTE: if you use business mode calculations, you must have a config file -(either global or personal) since this is the only place where you can -define holidays. - -Finally, any variables passed in through Date_Init override all other -values. - -A config file can be composed of several sections. The first section sets -configuration variables. Lines in this section are of the form: - - VARIABLE = VALUE - -For example, to make the default language French, include the line: - - Language = French - -Only variables described below may be used. Blank lines and lines beginning -with a pound sign (#) are ignored. All spaces are optional and strings are -case insensitive. - -A line which starts with an asterisk (*) designates a new section. For -example, the HOLIDAY section starts with a line: - - *Holiday - -The various sections are defined below. - -=head1 DATE::MANIP VARIABLES - -All Date::Manip variables which can be used are described in the following -section. - -=over 4 - -=item IgnoreGlobalCnf - -If this variable is used (any value is ignored), the global config file -is not read. It must be present in the initial call to Date_Init or the -global config file will be read. - -=item EraseHolidays - -If this variable is used (any value is ignored), the current list of -defined holidays is erased. A new set will be set the next time a -config file is read in. This can be set in either the global config file -or as a Date_Init argument (in which case holidays can be read in from -both the global and personal config files) or in the personal config file -(in which case, only holidays in the personal config file are counted). - -=item PathSep - -This is a regular expression used to separate multiple paths. For example, -on Unix, it defaults to a colon (:) so that multiple paths can be written -PATH1:PATH2 . For Win32 platforms, it defaults to a semicolon (;) so that -paths such as "c:\;d:\" will work. - -=item GlobalCnf - -This variable can be passed into Date_Init to point to a global -configuration file. The value must be the complete path to a config file. - -By default, no global config file is read. Any time a global config file -is read, the holidays are erased. - -Paths may have a tilde (~) expansion on platforms where this is supported -(currently Unix and VMS). - -=item PersonalCnf - -This variable can be passed into Date_Init or set in a global config file -to set the name of the personal configuration file. - -The default name for the config file is .DateManip.cnf on all Unix -platforms and Manip.cnf on all non-Unix platforms (because some of them -insist on 8.3 character filenames :-). - -=item PersonalCnfPath - -This is a list of paths separated by the separator specified by the PathSep -variable. These paths are each checked for the PersonalCnf config file. - -Paths may have a tilde (~) expansion on platforms where this is supported -(currently Unix and VMS). - -=item Language - -Date::Manip can be used to parse dates in many different languages. -Currently, it is configured to read the following languages (the version -in which they added is included for historical interest): - - English (default) - French (5.02) - Swedish (5.05) - German (5.31) - Dutch (5.32) aka Nederlands - Polish (5.32) - Spanish (5.33) - Portuguese (5.34) - Romanian (5.35) - Italian (5.35) - Russian (5.41) - Turkish (5.41) - Danish (5.41) - -Others can be added easily. Language is set to the language used to parse -dates. If you are interested in providing a translation for a new -language, email me (see the AUTHOR section below) and I'll send you a list -of things that I need. - -=item DateFormat - -Different countries look at the date 12/10 as Dec 10 or Oct 12. In the -United States, the first is most common, but this certainly doesn't hold -true for other countries. Setting DateFormat to "US" forces the first -behavior (Dec 10). Setting DateFormat to anything else forces the second -behavior (Oct 12). - -=item TZ - -If set, this defines the local timezone. See the TIMEZONES section above -for information on it's format. - -=item ConvTZ - -All date comparisons and calculations must be done in a single time zone in -order for them to work correctly. So, when a date is parsed, it should be -converted to a specific timezone. This allows dates to easily be compared -and manipulated as if they are all in a single timezone. - -The ConvTZ variable determines which timezone should be used to store dates -in. If it is left blank, all dates are converted to the local timezone -(see the TZ variable above). If it is set to one of the timezones listed -above, all dates are converted to this timezone. Finally, if it is set to -the string "IGNORE", all timezone information is ignored as the dates are -read in (in this case, the two dates "1/1/96 12:00 GMT" and "1/1/96 12:00 -EST" would be treated as identical). - -=item Internal - -When a date is parsed using ParseDate, that date is stored in an internal -format which is understood by the Date::Manip routines UnixDate and -DateCalc. Originally, the format used to store the date internally was: - - YYYYMMDDHH:MN:SS - -It has been suggested that I remove the colons (:) to shorten this to: - - YYYYMMDDHHMNSS - -The main advantage of this is that some databases are colon delimited which -makes storing a date from Date::Manip tedious. - -In order to maintain backwards compatibility, the Internal variable was -introduced. Set it to 0 (to use the old format) or 1 (to use the new -format). - -=item FirstDay - -It is sometimes necessary to know what day of week is regarded as first. -By default, this is set to Monday, but many countries and people will -prefer Sunday (and in a few cases, a different day may be desired). Set -the FirstDay variable to be the first day of the week (1=Monday, 7=Sunday) -Monday should be chosen to to comply with ISO 8601. - -=item WorkWeekBeg, WorkWeekEnd - -The first and last days of the work week. By default, Monday and Friday. -WorkWeekBeg must come before WorkWeekEnd numerically. The days are -numbered from 1 (Monday) to 7 (Sunday). - -There is no way to handle an odd work week of Thu to Mon for example or 10 -days on, 4 days off. - -=item WorkDay24Hr - -If this is non-nil, a work day is treated as being 24 hours long. The -WorkDayBeg and WorkDayEnd variables are ignored in this case. - -=item WorkDayBeg, WorkDayEnd - -The times when the work day starts and ends. WorkDayBeg must come before -WorkDayEnd (i.e. there is no way to handle the night shift where the work -day starts one day and ends another). Also, the workday MUST be more than -one hour long (of course, if this isn't the case, let me know... I want a -job there!). - -The time in both can be in any valid time format (including international -formats), but seconds will be ignored. - -=item TomorrowFirst - -Periodically, if a day is not a business day, we need to find the nearest -business day to it. By default, we'll look to "tomorrow" first, but if this -variable is set to 0, we'll look to "yesterday" first. This is only used in -the Date_NearestWorkDay and is easily overridden (see documentation for that -function). - -=item DeltaSigns - -Prior to Date::Manip version 5.07, a negative delta would put negative -signs in front of every component (i.e. "0:0:-1:-3:0:-4"). By default, -5.07 changes this behavior to print only 1 or two signs in front of the -year and day elements (even if these elements might be zero) and the sign -for year/month and day/hour/minute/second are the same. Setting this -variable to non-zero forces deltas to be stored with a sign in front of -every element (including elements equal to 0). - -=item Jan1Week1 - -ISO 8601 states that the first week of the year is the one which contains -Jan 4 (i.e. it is the first week in which most of the days in that week -fall in that year). This means that the first 3 days of the year may -be treated as belonging to the last week of the previous year. If this -is set to non-nil, the ISO 8601 standard will be ignored and the first -week of the year contains Jan 1. - -=item YYtoYYYY - -By default, a 2 digit year is treated as falling in the 100 year period of -CURR-89 to CURR+10. YYtoYYYY may be set to any integer N to force a 2 -digit year into the period CURR-N to CURR+(99-N). A value of 0 forces -the year to be the current year or later. A value of 99 forces the year -to be the current year or earlier. Since I do no checking on the value of -YYtoYYYY, you can actually have it any positive or negative value to force -it into any century you want. - -YYtoYYYY can also be set to "C" to force it into the current century, or -to "C##" to force it into a specific century. So, no (1998), "C" forces -2 digit years to be 1900-1999 and "C18" would force it to be 1800-1899. - -It can also be set to the form "C####" to force it into a specific 100 -year period. C1950 refers to 1950-2049. - -=item UpdateCurrTZ - -If a script is running over a long period of time, the timezone may change -during the course of running it (i.e. when daylight savings time starts or -ends). As a result, parsing dates may start putting them in the wrong time -zone. Since a lot of overhead can be saved if we don't have to check the -current timezone every time a date is parsed, by default checking is turned -off. Setting this to non-nil will force timezone checking to be done every -time a date is parsed... but this will result in a considerable performance -penalty. - -A better solution would be to restart the process on the two days per year -where the timezone switch occurs. - -=item IntCharSet - -If set to 0, use the US character set (7-bit ASCII) to return strings such -as the month name. If set to 1, use the appropriate international character -set. For example, If you want your French representation of Decemeber to -have the accent over the first "e", you'll want to set this to 1. - -=item ForceDate - -This variable can be set to a date in the format: YYYY-MM-DD-HH:MN:SS -to force the current date to be interpreted as this date. Since the current -date is used in parsing, this string will not be parsed and MUST be in the -format given above. - -=back - -=head1 HOLIDAY SECTION - -The holiday section of the config file is used to define holidays. Each -line is of the form: - - DATE = HOLIDAY - -HOLIDAY is the name of the holiday (or it can be blank in which case the -day will still be treated as a holiday... for example the day after -Thanksgiving or Christmas is often a work holiday though neither are -named). - -DATE is a string which can be parsed to give a valid date in any year. It -can be of the form - - Date - Date + Delta - Date - Delta - Recur - -A valid holiday section would be: - - *Holiday - - 1/1 = New Year's Day - third Monday in Feb = Presidents' Day - fourth Thu in Nov = Thanksgiving - - # The Friday after Thanksgiving is an unnamed holiday most places - fourth Thu in Nov + 1 day = - - 1*0:0:0:0:0:0*EASTER = Easter - 1*11:0:11:0:0:0*CWD = Veteran's Day (observed) - 1*0:0:0:0:0:0*EASTER,PD5 = Good Friday - -In a Date + Delta or Date - Delta string, you can use business mode by -including the appropriate string (see documentation on DateCalc) in the -Date or Delta. So (in English), the first workday before Christmas could -be defined as: - - 12/25 - 1 business day = - -The date's may optionally contain the year. For example, the dates - - 1/1 - 1/1/1999 - -refers to Jan 1 in any year or in only 1999 respectively. For dates that -refer to any year, the date must be written such that by simply appending -the year (separated by spaces) it can be correctly interpreted. This -will work for everything except ISO 8601 dates, so ISO 8601 dates may -not be used in this case. - -In cases where you are interested in business type calculations, you'll -want to define most holidays using recurrences, since they can define -when a holiday is celebrated in the financial world. For example, -Christmas chould be defined as: - - 1*12:0:24:0:0:0*FW1 = Christmas - -NOTE: It was pointed out to me that using a similar type recurrence to -define New Years does not work. The recurrence: - - 1*12:0:31:0:0:0*FW1 - -fails (worse, it goes into an infinite loop). The problem is that each -holiday definition is applied to a specific year and it expects to find -the holiday for that year. When this recurrence is applied to the year -1995, it returns the holiday for 1996 and fails. - -Use the recurrence: - - 1*1:0:1:0:0:0*NWD - -instead. - -If you wanted to define both Christmas and Boxing days (Boxing is the -day after Christmas, and is celebrated in some parts of the world), you -could do it in one of the following ways: - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:25:0:0:0*FW1 = Boxing - - 1*12:0:24:0:0:0*FW1 = Christmas - 01*12:0:24:0:0:0*FW1 = Boxing - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:25:0:0:0*FW1,a = Boxing - -The following examples will NOT work: - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:24:0:0:0*FW2 = Boxing - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:24:0:0:0*FW1 = Boxing - -The reasoning behind all this is as follows: - -Holidays go into affect the minute they are parsed. So, in the case of: - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:24:0:0:0*FW2 = Boxing - -the minute the first line is parsed, Christmas is defined as a holiday. -The second line then steps forward 2 work days (skipping Christmas since -that's no longer a work day) and define the work day two days after -Christmas, NOT the day after Christmas. - -An good alternative would appear to be: - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:24:0:0:0*FW1 = Boxing - -This unfortunately fails because the recurrences are currently stored in a -hash. Since these two recurrences are identical, they fail (the first one -is overwritten by the second and in essense, Christmas is never defined). - -To fix this, make them unique with either a fake flag (which is ignored): - - 1*12:0:24:0:0:0*FW1,a = Boxing - -or adding an innocuous 0 somewhere: - - 01*12:0:24:0:0:0*FW1 = Boxing - -The other good alternative would be to make two completely different -recurrences such as: - - 1*12:0:24:0:0:0*FW1 = Christmas - 1*12:0:25:0:0:0*FW1 = Boxing - -At times, you may want to switch back and forth between two holiday files. -This can be done by calling the following: - - &Date_Init("EraseHolidays=1","PersonalCnf=FILE1"); - ... - &Date_Init("EraseHolidays=1","PersonalCnf=FILE2"); - ... - -=head1 EVENTS SECTION - -The Events section of the config file is similar to the Holiday section. -It is used to name certain days or times, but there are a few important -differences: - -=over 4 - -=item Events can be assigned to any time and duration - -All holidays are exactly 1 day long. They are assigned to a period -of time from midnight to midnight. - -Events can be based at any time of the day, and may be of any duration. - -=item Events don't affect business mode calculations - -Unlike holidays, events are completely ignored when doing business -mode calculations. - -=back - -Whereas holidays were added with business mode math in mind, events -were added with calendar and scheduling applications in mind. - -Every line in the events section is of the form: - - EVENT = NAME - -where NAME is the name of the event, and EVENT defines when it occurs -and it's duration. An EVENT can be defined in the following ways: - - Date - Date* - Recur [NYI] - Recur* [NYI] - - Date ; Date - Date ; Delta - Recur ; Delta [NYI] - - Date ; Delta ; Delta [NYI] - Recur ; Delta ; Delta [NYI] - -Here, Date* refers to a string containing a Date with NO TIME fields -(Jan 12, 1/1/2000, 2010-01-01) while Date does contain time fields. -Similarily, Recur* stands for a recurrence with the time fields all -equal to 0) while Recur stands for a recurrence with at least one -non-zero time field. - -Both Date* and Recur* refer to an event very similar to a holiday which -goes from midnight to midnight. - -Date and Recur refer to events which occur at the time given and with -a duration of 1 hour. - -Events given by "Date ; Date", "Date ; Delta", and "Recur ; Delta" -contain both the starting date and either ending date or duration. - -Events given as three elements "Date ; Delta ; Delta" or "Recur ; Delta ; -Delta" take a date and add both deltas to it to give the starting and -ending time of the event. The order and sign of the deltas is -unimportant (and both can be the same sign to give a range of times -which does not contain the base date). - -Items marked with [NYI] are not yet implemented but will be by the -time this is released. - -=head1 BACKWARDS INCOMPATIBILITIES - -For the most part, Date::Manip has remained backward compatible at every -release. There have been a few minor incompatibilities introduced at -various stages. Major differences are marked with bullets. - -=over 4 - -=item VERSION 5.41 - -=item Changed path separator for VMS - -Since ":" is used in some VMS paths, it should not have been used as -the path separator. It has been changed to a newline ("\n") character. - -=item Delta_Format behavior changed - -The entire delta is exact if no month component is present (previously, -no year or month component could be present). - -=item VERSION 5.38 - -=item Removed Date_DaysSince999 - -The Date_DaysSince999 function (deprecated in 5.35) has been removed. - -=item VERSION 5.35 - -=over 4 - -=item Deprected Date_DaysSince999 - -In fixing support for the years 0000-0999, I rewrote Date_DaysSince999 to -be Date_DaysSince1BC. The Date_DaysSince999 function will be removed. - -=item * Added PathSep variable - -In order to better support Win32 platforms, I added the PathSep config -variable. This will allow the use of paths such as "c:\date" on Win32 -platforms. Old config files on Win32 platforms (which were not working -correctly in many cases) may not work if they contain path information to -the personal config file. - -=back - -=item VERSION 5.34 - -=over 4 - -=item * All Date::Manip variables are no longer accessible - -Previously, Date::Manip variables were declared using a full package name. -Now, they are declared with the my() function. This means that internal -variables are no longer accessible outside of the module. - -=item Week interpretation in business mode deltas - -A business mode delta containing a week value used to be treated as 7 days. -A much more likely interpretation of a week is Monday to Monday, regardless -of holidays, so this is now the behavior. - -=item %z UnixDate format - -The %z UnixDate format used to return the Timezone abbreviation. It now -returns it as a GMT offset (i.e. -0500). %Z still returns the Timezone -abbreviation. - -=item Formats "22nd sunday" returns the intuitive value - -The date "22nd sunday" used to return the Sunday of the 22nd week of the -year (which could be the 21st, 22nd, or 23rd Sunday of the year depending -on how weeks were defined). Now, it returns the 22nd Sunday of the year -regardless. - -=item Separator in DD/YYmmm and mmmDD/YY formats no longer optional - -Previously, the date "Dec1065" would return Dec 10, 1965. After adding -the YYYYmmm and mmmYYYY formats, this was no longer possible. The separator -between DD and YY is no longer optional, so - - Dec1065 returns December 1, 1065 - Dec10/65 returns December 10, 1965 - -=item * Date_Cmp added - -This is not a backwards incompatibility... but is added to help prepare for -a future incompatibility. In one of the next versions of Date::Manip, the -internal format of the date will change to include timezone information. -All date comparisons should be made using Date_Cmp (which currently does -nothing more than call the perl "cmp" command, but which will important -when comparing dates that include the timezone). - -=back - -=item VERSION 5.32 - -=over 4 - -=item Date_Init arguments - -The old style Date_Init arguments that were deprecated in version 5.07 -have been removed. - -=item * DateManip.cnf change - -Changed .DateManip.cnf to Manip.cnf (to get rid of problems on OS's -that insist on 8.3 filenames) for all non-Unix platforms (Wintel, VMS, -Mac). For all Unix platforms, it's still .DateManip.cnf . It will only -look in the user's home directory on VMS and Unix. - -=back - -=item VERSION 5.30 - -=over 4 - -=item * Delta format changed - -A week field has been added to the internal format of the delta. It now -reads "Y:M:W:D:H:MN:S" instead of "Y:M:D:H:MN:S". - -=back - -=item VERSION 5.21 - -=over 4 - -=item Long running processes may give incorrect timezone - -A process that runs during a timezone change (Daylight Saving Time -specifically) may report the wrong timezone. See the UpdateCurrTZ variable -for more information. - -=item UnixDate "%J", "%W", and "%U" formats fixed - -The %J, %W, and %U will no longer report a week 0 or a week 53 if it should -really be week 1 of the following year. They now report the correct week -number according to ISO 8601. - -=back - -=item VERSION 5.20 - -=over 4 - -=item * ParseDate formats removed (ISO 8601 compatibility) - -Full support for ISO 8601 formats was added. As a result, some formats -which previously worked may no longer be parsed since they conflict with an -ISO 8601 format. These include MM-DD-YY (conflicts with YY-MM-DD) and -YYMMDD (conflicts with YYYYMM). MM/DD/YY still works, so the first form -can be kept easily by changing "-" to "/". YYMMDD can be changed to -YY-MM-DD before being parsed. Whenever parsing dates using dashes as -separators, they will be treated as ISO 8601 dates. You can get around -this by converting all dashes to slashes. - -=item * Week day numbering - -The day numbering was changed from 0-6 (sun-sat) to 1-7 (mon-sun) to be -ISO 8601 compatible. Weeks start on Monday (though this can be overridden -using the FirstDay config variable) and the 1st week of the year contains -Jan 4 (though it can be forced to contain Jan 1 with the Jan1Week1 config -variable). - -=back - -=item VERSION 5.07 - -=over 4 - -=item UnixDate "%s" format - -Used to return the number of seconds since 1/1/1970 in the current -timezone. It now returns the number of seconds since 1/1/1970 GMT. -The "%o" format was added which returns what "%s" previously did. - -=item Internal format of delta - -The format for the deltas returned by ParseDateDelta changed. Previously, -each element of a delta had a sign attached to it (+1:+2:+3:+4:+5:+6). The -new format removes all unnecessary signs by default (+1:2:3:4:5:6). Also, -because of the way deltas are normalized (see documentation on -ParseDateDelta), at most two signs are included. For backwards -compatibility, the config variable DeltaSigns was added. If set to 1, all -deltas include all 6 signs. - -=item Date_Init arguments - -The format of the Date_Init calling arguments changed. The -old method - - &Date_Init($language,$format,$tz,$convtz); - -is still supported , but this support will likely disappear in the future. -Use the new calling format instead: - - &Date_Init("var=val","var=val",...); - -NOTE: The old format is no longer supported as of version 5.32 . - -=back - -=back - -=head1 KNOWN PROBLEMS - -The following are not bugs in Date::Manip, but they may give some people -problems. - -=over 4 - -=item Unable to determine TimeZone - -Perhaps the most common problem occurs when you get the error: - - Error: Date::Manip unable to determine TimeZone. - -Date::Manip tries hard to determine the local timezone, but on some -machines, it cannot do this (especially non-unix systems). To fix this, -just set the TZ variable, either at the top of the Manip.pm file,, in the -DateManip.cnf file, or in a call to Date_Init. I suggest using the form -"EST5EDT" so you don't have to change it every 6 months when going to or -from daylight savings time. - -Windows NT does not seem to set the TimeZone by default. From the -Perl-Win32-Users mailing list: - - > How do I get the TimeZone on my NT? - > - > $time_zone = $ENV{'TZ'}; - > - You have to set the variable before, WinNT doesn't set it by - default. Open the properties of "My Computer" and set a SYSTEM - variable TZ to your timezone. Jenda@Krynicky.cz - -This might help out some NT users. - -A minor (false) assumption that some users might make is that since -Date::Manip passed all of it's tests at install time, this should not occur -and are surprised when it does. - -Some of the tests are timezone dependent. Since the tests all include -input and expected output, I needed to know in advance what timezone they -would be run in. So, the tests all explicitly set the timezone using the -TZ configuration variable passed into Date_Init. Since this overrides any -other method of determining the timezone, Date::Manip uses this and doesn't -have to look elsewhere for the timezone. - -When running outside the tests, Date::Manip has to rely on it's other -methods for determining the timezone. - -=item Complaining about getpwnam/getpwuid - -Another problem is when running on Micro$oft OS'es. I have added many -tests to catch them, but they still slip through occasionally. If any ever -complain about getpwnam/getpwuid, simply add one of the lines: - - $ENV{OS} = Windows_NT - $ENV{OS} = Windows_95 - -to your script before - - use Date::Manip - -=item Date::Manip is slow - -The reasons for this are covered in the SHOULD I USE DATE::MANIP section -above. - -Some things that will definitely help: - -Version 5.21 does run noticeably faster than earlier versions due to -rethinking some of the initialization, so at the very least, make sure you -are running this version or later. - -ISO-8601 dates are parsed first and fastest. Use them whenever possible. - -Avoid parsing dates that are referenced against the current time (in 2 -days, today at noon, etc.). These take a lot longer to parse. - - Example: parsing 1065 dates with version 5.11 took 48.6 seconds, 36.2 - seconds with version 5.21, and parsing 1065 ISO-8601 dates with version - 5.21 took 29.1 seconds (these were run on a slow, overloaded computer with - little memory... but the ratios should be reliable on a faster computer). - -Business date calculations are extremely slow. You should consider -alternatives if possible (i.e. doing the calculation in exact mode and then -multiplying by 5/7). There will be an approximate business mode in one of -the next versions which will be much faster (though less accurate) which -will do something like this. Whenever possible, use this mode. And who -needs a business date more accurate than "6 to 8 weeks" anyway huh :-) - -Never call Date_Init more than once. Unless you're doing something very -strange, there should never be a reason to anyway. - -=item Sorting Problems - -If you use Date::Manip to sort a number of dates, you must call Date_Init -either explicitly, or by way of some other Date::Manip routine before it -is used in the sort. For example, the following code fails: - - use Date::Manip; - # &Date_Init; - sub sortDate { - my($date1, $date2); - $date1 = &ParseDate($a); - $date2 = &ParseDate($b); - return (&Date_Cmp($date1,$date2)); - } - @dates = ("Fri 16 Aug 96", - "Mon 19 Aug 96", - "Thu 15 Aug 96"); - @i=sort sortDate @dates; - -but if you uncomment the Date_Init line, it works. The reason for this is -that the first time you call Date_Init, it initializes a number of items -used by Date::Manip. Some of these have to be sorted (regular expressions -sorted by length to ensure the longest match). It turns out that perl -has a bug in it which does not allow a sort within a sort. At some point, -this should be fixed, but for now, the best thing to do is to call Date_Init -explicitly. The bug exists in all versions up to 5.005 (I haven't -tested 5.6.0 yet). - -NOTE: This is an EXTREMELY inefficient way to sort data. Instead, you -should parse the dates with ParseDate, sort them using a normal string -comparison, and then convert them back to the format desired using -UnixDate. - -=item RCS Control - -If you try to put Date::Manip under RCS control, you are going to have -problems. Apparently, RCS replaces strings of the form "$Date...$" with -the current date. This form occurs all over in Date::Manip. To prevent the -RCS keyword expansion, checkout files using "co -ko". Since very few people -will ever have a desire to do this (and I don't use RCS), I have not worried -about it. - -=back - -=head1 KNOWN BUGS - -=over 4 - -=item Daylight Savings Times - -Date::Manip does not handle daylight savings time, though it does handle -timezones to a certain extent. Converting from EST to PST works fine. -Going from EST to PDT is unreliable. - -The following examples are run in the winter of the US East coast (i.e. -in the EST timezone). - - print UnixDate(ParseDate("6/1/97 noon"),"%u"),"\n"; - => Sun Jun 1 12:00:00 EST 1997 - -June 1 EST does not exist. June 1st is during EDT. It should print: - - => Sun Jun 1 00:00:00 EDT 1997 - -Even explicitly adding the timezone doesn't fix things (if anything, it -makes them worse): - - print UnixDate(ParseDate("6/1/97 noon EDT"),"%u"),"\n"; - => Sun Jun 1 11:00:00 EST 1997 - -Date::Manip converts everything to the current timezone (EST in this case). - -Related problems occur when trying to do date calculations over a timezone -change. These calculations may be off by an hour. - -Also, if you are running a script which uses Date::Manip over a period of -time which starts in one time zone and ends in another (i.e. it switches -form Daylight Savings Time to Standard Time or vice versa), many things may -be wrong (especially elapsed time). - -I hope to fix these problems in a future release so that it would convert -everything to the current zones (EST or EDT). - -=back - -=head1 BUGS AND QUESTIONS - -If you find a bug in Date::Manip, please send it directly to me (see the -AUTHOR section below) rather than posting it to one of the newsgroups. -Although I try to keep up with the comp.lang.perl.* groups, all too often I -miss news (flaky news server, articles expiring before I caught them, 1200 -articles to wade through and I missed one that I was interested in, etc.). - -When filing a bug report, please include the following information: - - o The version of Date::Manip you are using. You can get this by using - the script: - - use Date::Manip; - print &DateManipVersion(),"\n"; - - o The output from "perl -V" - -If you have a problem using Date::Manip that perhaps isn't a bug (can't -figure out the syntax, etc.), you're in the right place. Go right back to -the top of this man page and start reading. If this still doesn't answer -your question, mail me (again, please mail me rather than post to the -newsgroup). - -=head1 YEAR 2000 - -In hindsight, the fact that I've only been asked once (so far) if Date::Manip -is year 2000 compliant surprises me a bit. Still, as 2000 approaches and -this buzzword starts flying around more and more frantically, other's might -follow suit, so this section answers the question. - -Is Date::Manip year 2000 compliant? - -This question is largely meaningless. Date::Manip is basically just a -parser. You give it a date and it'll manipulate it. Date::Manip does -store the date internally as a 4 digit year, and performs all operations -using this internal representation, so I will state that Date::Manip is -CAPABLE of writing Y2K compliant code. - -But Date::Manip is simply a library. If you use it correctly, your code -can be Y2K compliant. If you don't, your code may not be Y2K compliant. - -The bottom line is this: - - Date::Manip is a library that is capable of being used to write Y2K - compliant code. It may also be used to write non-Y2K compliant code. - - If your code is NOT Y2K compliant, it is NOT due to any deficiency in - Date::Manip. Rather, it is due to poor programming on the part of the - person using Date::Manip. - -For an excellent treatment of the Y2K problem, see the article by Tom -Christiansen at: - - http://language.perl.com/news/y2k.html - -A slightly better question is "Is Perl year 2000 compliant"? This is -covered in the perl FAQ (section 4) and in the article by Tom Crhistiansen. - -The best question is "For what dates is Date::Manip useful?" It definitely -can't handle BC dates, or dates past Dec 31, 9999. So Date::Manip works -during the years 1000 to 9999. - -In practical terms however, Date::Manip deals with the Gregorian calendar, -and is therefore useful in the period that that calendar has been, or will -be, in effect. The Gregorian calendar was first adopted by the Catholic -church in 1582, but some countries were still using the Julian calendar as -late as the early part of the 20th century. Also, at some point (probably -no earlier than the year 3000 and possibly much later), the Gregorian -system is going to have to be modified slightly since the current system of -leap years is off by a few seconds a year. So... in practical terms, -Date::Manip is _probably_ useful from 1900 to 3000. - -One other note is that Date::Manip will NOT handle 3 digit years. So, if -you store the year as an offset from 1900 (which is 2 digits now, but will -become 3 digits in 2000), these will NOT be parsable by Date::Manip. - -=head1 VERSION NUMBERS - -A note about version numbers. - -Prior to version 5.00, Date::Manip was distributed as a perl4 library. -There were no numbering conventions in place, so I used a simple -MAJOR.MINOR numbering scheme. - -With version 5.00, I switched to a perl5 module and at that time switched -to the perl5 numbering convention of a major version followed by a 2 digit -minor version. - -As of 5.41/5.42, all versions released to CPAN will be even numbered. Odd -numbered will be development versions available from my web site. For -example, after 5.40 was released, I started making changes, and called -the development version 5.41. When released to CPAN, it was called 5.42. -I may add a third digit to development versions (i.e. 5.41.9) to keep -track of important changes in the development version. - -=head1 ACKNOWLEDGMENTS - -There are many people who have contributed to Date::Manip over the years -that I'd like to thank. The most important contributions have come in the -form of suggestions and bug reports by users. I have tried to include the -name of every person who first suggested each improvement or first reported -each bug. These are included in the HISTORY file in the Date::Manip -distribution in the order the changes are made. The list is simply too -long to appear here, but I appreciate their help. - -A number of people have made suggestions or reported bugs which are not -mentioned in the HISTORY file. These include suggestions which have not -been implemented and people who have made a suggestion or bug report which -has already been suggested/reported by someone else. For those who's -suggestions have not yet been implemented, they will be added to the -HISTORY file when (if) their suggestions are implemented. For everyone -else, thank you too. I'd much rather have a suggestion made twice than not -at all. - -Thanks to Alan Cezar and Greg Schiedler for paying me to implement the -Events_List routine. They gave me the idea, and were then willing to pay -me for my time to get it implemented quickly. - -I'd also like a couple of authors. Date::Manip has recently been getting -some really good press in a couple of books. Since no one's paying me to -write Date::Manip, seeing my module get a good review in a book written by -someone else really makes my day. My thanks to Nate Padwardhan and Clay -Irving (Programming with Perl Modules -- part of the O'Reilly Perl Resource -Kit); and Tom Christiansen and Nathan Torkington (The Perl Cookbook). -Also, thanks to any other authors who've written about Date::Manip who's -books I haven't seen. - -=head1 AUTHOR - -Sullivan Beck (sbeck@cpan.org) - -You can always get the newest beta version of Date::Manip (which may fix -problems in the current CPAN version... and may add others) from my home -page: - -http://www.cise.ufl.edu/~sbeck/ - -=cut