home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-03-23 | 92.7 KB | 1,846 lines |
-
- <HTML>
- <HEAD>
- <TITLE>Date::Manip - date manipulation routines</TITLE>
- <LINK REL="stylesheet" HREF="../../../Active.css" TYPE="text/css">
- <LINK REV="made" HREF="mailto:">
- </HEAD>
-
- <BODY>
- <TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
- <TR><TD CLASS=block VALIGN=MIDDLE WIDTH=100% BGCOLOR="#cccccc">
- <STRONG><P CLASS=block> Date::Manip - date manipulation routines</P></STRONG>
- </TD></TR>
- </TABLE>
-
- <A NAME="__index__"></A>
- <!-- INDEX BEGIN -->
-
- <UL>
-
- <LI><A HREF="#name">NAME</A></LI><LI><A HREF="#supportedplatforms">SUPPORTED PLATFORMS</A></LI>
-
- <LI><A HREF="#synopsis">SYNOPSIS</A></LI>
- <LI><A HREF="#description">DESCRIPTION</A></LI>
- <LI><A HREF="#examples">EXAMPLES</A></LI>
- <LI><A HREF="#should i use date::manip">SHOULD I USE DATE::MANIP</A></LI>
- <LI><A HREF="#routines">ROUTINES</A></LI>
- <LI><A HREF="#timezones">TIMEZONES</A></LI>
- <LI><A HREF="#business mode">BUSINESS MODE</A></LI>
- <LI><A HREF="#customizing date::manip">CUSTOMIZING DATE::MANIP</A></LI>
- <LI><A HREF="#backwards incompatibilities">BACKWARDS INCOMPATIBILITIES</A></LI>
- <LI><A HREF="#known problems">KNOWN PROBLEMS</A></LI>
- <LI><A HREF="#known bugs">KNOWN BUGS</A></LI>
- <LI><A HREF="#bugs and questions">BUGS AND QUESTIONS</A></LI>
- <LI><A HREF="#year 2000">YEAR 2000</A></LI>
- <LI><A HREF="#acknowledgements">ACKNOWLEDGEMENTS</A></LI>
- <LI><A HREF="#author">AUTHOR</A></LI>
- </UL>
- <!-- INDEX END -->
-
- <HR>
- <P>
- <H1><A NAME="name">NAME</A></H1>
- <P>Date::Manip - date manipulation routines</P>
- <P>
- <HR>
- <H1><A NAME="supportedplatforms">SUPPORTED PLATFORMS</A></H1>
- <UL>
- <LI>Linux</LI>
- <LI>Solaris</LI>
- <LI>Windows</LI>
- </UL>
- <HR>
- <H1><A NAME="synopsis">SYNOPSIS</A></H1>
- <PRE>
- use Date::Manip;</PRE>
- <PRE>
- $date=&ParseDate(\@args)
- $date=&ParseDate($string)
- $date=&ParseDate(\$string)</PRE>
- <PRE>
- @date=&UnixDate($date,@format)
- $date=&UnixDate($date,@format)</PRE>
- <PRE>
- $delta=&ParseDateDelta(\@args)
- $delta=&ParseDateDelta($string)
- $delta=&ParseDateDelta(\$string)</PRE>
- <PRE>
- @str=&Delta_Format($delta,$dec,@format)
- $str=&Delta_Format($delta,$dec,@format)</PRE>
- <PRE>
- $recur=&ParseRecur($string,$base,$date0,$date1,$flags)
- @dates=&ParseRecur($string,$base,$date0,$date1,$flags)</PRE>
- <PRE>
- $d=&DateCalc($d1,$d2 [,$errref] [,$del])</PRE>
- <PRE>
- $date=&Date_SetTime($date,$hr,$min,$sec)
- $date=&Date_SetTime($date,$time)</PRE>
- <PRE>
- $date=&Date_SetDateField($date,$field,$val [,$nocheck])</PRE>
- <PRE>
- $date=&Date_GetPrev($date,$dow,$today,$hr,$min,$sec)
- $date=&Date_GetPrev($date,$dow,$today,$time)</PRE>
- <PRE>
- $date=&Date_GetNext($date,$dow,$today,$hr,$min,$sec)
- $date=&Date_GetNext($date,$dow,$today,$time)</PRE>
- <PRE>
- &Date_Init()
- &Date_Init("VAR=VAL",...)</PRE>
- <PRE>
- $version=&DateManipVersion</PRE>
- <PRE>
- $flag=&Date_IsWorkDay($date [,$flag]);</PRE>
- <PRE>
- $date=&Date_NextWorkDay($date,$off [,$time]);
- $date=&Date_PrevWorkDay($date,$off [,$time]);</PRE>
- <P>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).</P>
- <PRE>
- $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_DaysSince999($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)</PRE>
- <P>
- <HR>
- <H1><A NAME="description">DESCRIPTION</A></H1>
- <P>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 operationw we (as people) tend to think of rather than
- those operations used routinely by computers. There are other modules that
- can do a small subset of the operations available in Date::Manip much
- quicker than those presented here, so if speed is a primary issue, you
- should look elsewhere. Check out the CPAN listing of Time and Date
- modules. But for sheer flexibility, I believe that Date::Manip is your
- best bet.</P>
- <P>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 1000 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. Each year is on average 26 seconds too long, which
- means that every 3,323 years, a day should be removed from the calendar.
- No attempt is made to correct for that.</P>
- <P>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.</P>
- <P>Date::Manip has (or will have) functionality to work with several fundamental
- types of data.</P>
- <DL>
- <DT><STRONG><A NAME="item_DATE">DATE</A></STRONG><BR>
- <DD>
- 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.
- <P>NOTE: Much better support for timezones (including Daylight Savings Time)
- is planned for the future.</P>
- <P></P>
- <DT><STRONG><A NAME="item_DELTA">DELTA</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_RECURRENCE">RECURRENCE</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_GRAIN">GRAIN</A></STRONG><BR>
- <DD>
- 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.
- <P>NOTE: Support for this will be added in the future.</P>
- <P></P></DL>
- <P>Among other things, Date::Manip allow you to:</P>
- <P>1. Enter a date and be able to choose any format conveniant</P>
- <P>2. Compare two dates, entered in widely different formats to determine
- which is earlier</P>
- <P>3. Extract any information you want from ANY date using a format string
- similar to the Unix date command</P>
- <P>4. Determine the amount of time between two dates</P>
- <P>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)</P>
- <P>6. Work with dates with dates using international formats (foreign month
- names, 12/10/95 referring to October rather than December, etc.).</P>
- <P>7. To find a list of dates where a recurring event happens.</P>
- <P>Each of these tasks is trivial (one or two lines at most) with this package.</P>
- <P>
- <HR>
- <H1><A NAME="examples">EXAMPLES</A></H1>
- <P>In the documentation below, US formats are used, but in most (if not all)
- cases, a non-English equivalent will work equally well.</P>
- <P>1. Parsing a date from any conveniant format</P>
- <PRE>
- $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
- }</PRE>
- <P>2. Compare two dates</P>
- <PRE>
- $date1=&ParseDate($string1);
- $date2=&ParseDate($string2);
- if ($date1 lt $date2) {
- # date1 is earlier
- } else {
- # date2 is earlier (or the two dates are identical)
- }</PRE>
- <P>3. Extract information from a date.</P>
- <PRE>
- print &UnixDate("today","The time is now %T on %b %e, %Y.");
- => "The time is now 13:24:08 on Feb 3, 1996."</PRE>
- <P>4. The amount of time between two dates.</P>
- <PRE>
- $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</PRE>
- <PRE>
- Read the documentation below for an explanation of the difference.</PRE>
- <P>5. To determine a date a given offset from another.</P>
- <PRE>
- $date=&DateCalc("today","+ 3hours 12minutes 6 seconds",\$err);
- $date=&DateCalc("12 hours ago","12:30 6Jan90",\$err);</PRE>
- <PRE>
- It even works with business days:</PRE>
- <PRE>
- $date=&DateCalc("today","+ 3 business days",\$err);</PRE>
- <P>6. To work with dates in another language.</P>
- <PRE>
- &Date_Init("Language=French","DateFormat=non-US");
- $date=&ParseDate("1er decembre 1990");</PRE>
- <P>7. To find a list of dates where a recurring event happens.</P>
- <PRE>
- # To find the 2nd tuesday of every month
- @date=&ParseRecur("0:1*2:2:0:0:0",$base,$start,$stop);</PRE>
- <P>NOTE: Some date forms do not work as well in languages other than English,
- but this is not because DateManip 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 DateManip.</P>
- <P>
- <HR>
- <H1><A NAME="should i use date::manip">SHOULD I USE DATE::MANIP</A></H1>
- <P>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?</P>
- <P>Date::Manip has several strengths. These include flexibility, a wide
- variety of functions, and it is written entirely in perl.</P>
- <P>It also has several weaknesses. The main one is that it is written
- entirely in perl.</P>
- <P>The fact that it is written in perl is both an advantage and a disadvantage.
- It means that you are not required to have a C compiler around in order to
- install Date::Manip (in fact, Date::Manip has no dependancies on anything
- not included in a standard perl distribution since perl 5.002 or so). On
- Unix platforms, this is not terribly important since they pretty much all have
- a C compiler, but on non-Unix platforms, this can simplify insallation.</P>
- <P>The downside is that Date::Manip is slow, especially when compared to
- several of the other Date/Time modules which are written in C. Although I
- am working on making Date::Manip faster, it will never be as fast as these
- 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.</P>
- <P>If you are going to be using the module in cases where performance is an
- important factor (parsing 10,000 dates from a database or started up in a
- CGI program being run by your web server 5,000 times a second), you might
- check out one of the other Date or Time modules in CPAN. Date::DateCalc,
- Date::TimeDate, or Time::Time-modules might meet your needs. In general,
- you do not need the flexibility offered by Date::Manip in these cases. For
- example, if you are reading a database, all of the dates are written in
- exactly the same format. It should be trivial to write a routine specific
- to this format.</P>
- <P>The biggest strength of Date::Manip is it's flexibility. None of the other
- modules can do everything that Date::Manip can do. I'm trying to build a
- library which can do _EVERY_ conceivable date/time manipulation that you'll
- run into in everyday life. It is definitely intended to use in the terms
- of how you (not the computer) think of dates and times.</P>
- <P>If you are doing operations based more on how people think of dates and
- times, Date::Manip is almost certainly for you. This includes parsing
- dates (including foreign language dates), calendar type operations,
- business dates and holidays, etc.</P>
- <P>
- <HR>
- <H1><A NAME="routines">ROUTINES</A></H1>
- <DL>
- <DT><STRONG><A NAME="item_ParseDate">ParseDate</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&ParseDate(\@args)
- $date=&ParseDate($string)
- $date=&ParseDate(\$string)</PRE>
- <P>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.</P>
- <P>The real work is done in the ParseDateString routine.</P>
- <P>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
- arguement, you can use Date::Manip to make something like the following
- work:</P>
- <PRE>
- mycommand -date Dec 10 1997 -arg -arg2</PRE>
- <P>No more reading man pages to find out what date format is required in a
- man page.</P>
- <P>Historical note: this is originally why the Date::Manip routines were
- written. I was using a bunch of programs 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 could be entered.</P>
- <DT><STRONG><A NAME="item_ParseDateString">ParseDateString</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&ParseDateString($string)</PRE>
- <P>This routine is called by ParseDate, but it may also be called directly
- to save some time.</P>
- <P>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:</P>
- <PRE>
- $secs = ... # seconds since Jan 1, 1970 00:00:00 GMT
- $date = &DateCalc("Jan 1, 1970 00:00:00 GMT",$secs);</PRE>
- <P>Second, you can call it directly as:</P>
- <PRE>
- $date = &ParseDateString("epoch $secs");</PRE>
- <P>To go backwards, just use the ``%s'' format of UnixDate:</P>
- <PRE>
- $secs = &UnixDate($date,"%s");</PRE>
- <P>A 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:</P>
- <PRE>
- [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]</PRE>
- <P>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).</P>
- <P>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).</P>
- <P>Fractional seconds are also supported in parsing but the fractional part is
- discarded.</P>
- <P>Timezones always appear after the time. A number of different forms are
- supported (see the section TIMEZONEs below).</P>
- <P>Spaces (or other separators such as ``/'' or ``-'') in the date are always
- optional when there is absolutely no ambiguity if they are not present. If
- there is ambiguity, the date will either be unparsable, or (as is more
- often the case) get parsed differently than desired.</P>
- <P>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 whenver they are immediately
- adjacent to another part of the date or time.</P>
- <P>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.</P>
- <P>Sections of the date may be separated by spaces or by other valid date
- separators (including ``/'', ``.'', and in some cases ``-''). These separators
- are treated very flexibly (they are converted to spaces), so the following
- dates are all equivalent:</P>
- <PRE>
- 12/10/1965
- 12-10 / 1965
- 12 // 10 -. 1965</PRE>
- <P>In some cases, this may actually be TOO flexible, but no attempt is made
- to trap this.</P>
- <P>Valid date formats include the ISO 8601 formats:</P>
- <PRE>
- YYYYMMDDHHMNSSFFFF
- 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</PRE>
- <P>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.</P>
- <P>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).</P>
- <P>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.</P>
- <P>Additional date formats are available which may or may not be common including:</P>
- <PRE>
- MM/DD **
- MM/DD/YY **
- MM/DD/YYYY **</PRE>
- <PRE>
- mmmDD DDmmm mmmYYYY/DD
- mmmDDYY DDmmmYY DDYYmmm YYYYmmmDD
- mmmDDYYYY DDmmmYYYY DDYYYYmmm YYYY/DDmmm</PRE>
- <P>Where mmm refers to the name of a month. All parts of the date can be
- separated by valid separators (space, ``/'', ``.'', or ``-'' as long as it
- doesn't conflict with an ISO 8601 format), but these are optional except
- for those given as a ``/'' in the list above.</P>
- <P>** Note that with these formats, Americans tend to write month first, but
- many other contries 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).</P>
- <P>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)
- ecpoch SECS seconds since the epoch</P>
- <P>Note that certain words such as ``in'', ``at'', ``of'', etc. which commonly appear
- in a date or time are ignored. Also, the year is alway optional.</P>
- <P>In addition, the following strings are recognized:
- today
- now (synonym for today)
- yesterday (exactly 24 hours ago)
- tomorrow (exactly 24 hours from now)
- noon (12:00:00)
- midnight (00:00:00)
- Other languages have similar (and in some cases additional) strings.</P>
- <P>Some things to note:</P>
- <P>All strings are case insensitive. ``December'' and ``DEceMBer'' both work.</P>
- <P>When a part of the date is not given, defaults are used: year defaults
- to current year; hours, minutes, seconds to 00.</P>
- <P>The year may be entered as 2 or 4 digits. If entered as 2 digits, it must
- first be converted to a 4 digit year. There are a couple of 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], so
- 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.</P>
- <P>Dates are always checked to make sure they are valid.</P>
- <P>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.</P>
- <P>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 otherwords, midnight is the
- beginning of a day rather than the end of one. The time 24:00:00 is NOT
- allowed (even though ISO 8601 allows it).</P>
- <P>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 conveniant. See Date_Init below
- and the config variable Internal.</P>
- <P>NOTE: The format for the date is going to change at some point in the future
- to YYYYMMDDHH:MN:SS+HHMN (i.e. it'll include the timezone). In order to
- maintain compatibility, you should use UnixDate to extract information from
- a date.</P>
- <DT><STRONG><A NAME="item_UnixDate">UnixDate</A></STRONG><BR>
- <DD>
- <PRE>
- @date=&UnixDate($date,@format)
- $date=&UnixDate($date,@format)</PRE>
- <P>This takes a date and a list of strings containing formats roughly
- identical to the format strings used by the UNIX <CODE>date(1)</CODE> command. Each
- format is parsed and an array of strings corresponding to each format is
- returned.</P>
- <P>$date may be any string that can be parsed by ParseDateString.</P>
- <P>The format options are:</P>
- <PRE>
- 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</PRE>
- <PRE>
- %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,%Z timezone (3 characters) - "EDT"
- 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.</PRE>
- <P>If a lone percent is the final character in a format, it is ignored.</P>
- <P>Note that the ls format (%l) applies to date within the past OR future 6
- months!</P>
- <P>The formats %U and %W return a week from 01 to 53. Because days at the
- beginning or end of the year may actually appear in a week in the previous
- or next year, the %L and %G formats were added to handle this case. %L and %G
- give the year of the week for %U and %W respectively. So Jan 1, 1993 is
- written in ISO-8601 format as 1992-W53-5. In this case, %Y is 1993, but %G
- is 1992 and %W is 53. %L and %U are similar for weeks starting with Sunday.
- %J returns the full ISO-8601 format.</P>
- <P>Note that the %s format was introduced in version 5.07. Prior to that,
- %s referred to the seconds since 1/1/70. This was moved to %o in 5.07.</P>
- <P>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 date(1). Also, several have been added which are unique to
- Date::Manip.</P>
- <DT><STRONG><A NAME="item_ParseDateDelta">ParseDateDelta</A></STRONG><BR>
- <DD>
- <PRE>
- $delta=&ParseDateDelta(\@args)
- $delta=&ParseDateDelta($string)
- $delta=&ParseDateDelta(\$string)</PRE>
- <P>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</P>
- <P>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</P>
- <P>Also, the ``s'' string may be omitted. The sign, number, and string may
- all be separated from each other by any number of whitespaces.</P>
- <P>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.</P>
- <P>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.</P>
- <P>The word ``in'' may be prepended to the delta (``in 5 years'') and the word
- ``ago'' may be appended (``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 impled minus sign in front of the 6
- because when no sign is explicitely given, it carries the previously
- entered sign).</P>
- <P>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.</P>
- <P>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''.</P>
- <P>It is possible to include a sign for all elements that is output. See the
- configuration variable DeltaSigns below.</P>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Delta_Format">Delta_Format</A></STRONG><BR>
- <DD>
- <PRE>
- @str=&Delta_Format($delta,$dec,@format)
- $str=&Delta_Format($delta,$dec,@format)</PRE>
- <P>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.</P>
- <P>NOTE: For the time being, Delta_Format only understands the ``exact'' parts
- of a delta (Y/M) and (W/D/H/MN/S). There is currently no ``mixing'' between
- the two parts.</P>
- <P>Formats currently understood are:</P>
- <PRE>
- %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</PRE>
- <PRE>
- X is one of y,M,w,d,h,m,s (case sensitive).</PRE>
- <PRE>
- %% : returns a "%"</PRE>
- <P>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. Similarily, the
- format ``%yd'' means the value (in years) of both the Y and M fields.</P>
- <P>The format ``%hh'' returns the value of W, D, and H expressed in hours.</P>
- <P>If $dec is non-zero, the %Xd and %Xt values are formatted to contain $dec
- decimal places.</P>
- <DT><STRONG><A NAME="item_ParseRecur">ParseRecur</A></STRONG><BR>
- <DD>
- <PRE>
- $recur=&ParseRecur($string [,$base,$date0,$date1,$flags])
- @dates=&ParseRecur($string [,$base,$date0,$date1,$flags])</PRE>
- <P>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 occurences 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. It is written as:</P>
- <PRE>
- recur*flags*base*date0*date1</PRE>
- <P>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.</P>
- <P>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:</P>
- <PRE>
- date0 <= date < date1</PRE>
- <P>The argument $string can contain any of the parts of a full recurrence.
- For example:</P>
- <PRE>
- recur
- recur*flags
- recur**base*date0*date1</PRE>
- <P>The only part which is required is the recur description. Any values
- contained in $string are overridden by values passed in as parameters to
- ParseRecur.</P>
- <P>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 asterix, or an asterix may
- be prepended to the string.</P>
- <P>Any value ``N'' to the left of the asterix refers to the ``Nth'' one. Any
- value to the right of the asterix refers to a value as it appears on a
- calendar. These can be a value or a comma separated list of values or
- ranges. In a few cases, negative values are appropriate.</P>
- <P>This is best illustrated by example.</P>
- <PRE>
- 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</PRE>
- <PRE>
- 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)</PRE>
- <P>Note 1: There is no way to express the following with a single recurrence:</P>
- <PRE>
- every day at 12:30 and 1:00</PRE>
- <P>Note 2: 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 some of the flags below),
- but in common usage, this is so ambiguous that this form should probably
- never be used.</P>
- <P>Note 3: Depending on whether M and W are 0 or nonzero, D means different
- things. This is given in the following table.</P>
- <PRE>
- M W D (when right of an asterix) 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) occurence of Dth (1-7) day of week in month</PRE>
- <P>There are a small handful of English strings which can be parsed in place
- of a numerical recur description. These include:</P>
- <PRE>
- 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 2nd tuesday [in 1997]
- every 2nd tuesday in June [1997]</PRE>
- <P>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).</P>
- <P>Flags are not yet implemented, but will allow even more complex behaviors
- to be easily defined.</P>
- <DT><STRONG><A NAME="item_DateCalc">DateCalc</A></STRONG><BR>
- <DD>
- <PRE>
- $d=&DateCalc($d1,$d2 [,\$err] [,$mode])</PRE>
- <P>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).</P>
- <P>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.</P>
- <P>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.</P>
- <P>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.</P>
- <P>For example, if a config file defines the workday as 08:00 to 18:00, a
- workweek 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
- autmoatically 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).</P>
- <P>See below for some additional comments about business mode calculations.</P>
- <P>Any other non-nil value of $mode is treated as $mode=1 (approximate mode).</P>
- <P>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:</P>
- <PRE>
- $date=&DateCalc("today","+ 2 business days",\$err);
- $date=&DateCalc("today","+ 2 days",\$err,2);</PRE>
- <P>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:</P>
- <PRE>
- $delta=&ParseDateDelta("+ 2 business days");
- $today=&ParseDate("today");
- $date=&DateCalc($today,$delta,\$err);</PRE>
- <P>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.</P>
- <P>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.</P>
- <P>Nothing is returned if an error occurs.</P>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Date_SetTime">Date_SetTime</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_SetTime($date,$hr,$min,$sec)
- $date=&Date_SetTime($date,$time)</PRE>
- <P>This takes a date (any string that may be parsed by ParseDateString) and
- sets the time in that date. For example, to get the time for 7:30
- tomorrow, use the lines:</P>
- <PRE>
- $date=&ParseDate("tomorrow")
- $date=&Date_SetTime($date,"7:30")</PRE>
- <P>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,</P>
- <PRE>
- $date=&Date_SetTime($date,"13:30")</PRE>
- <P>works, but</P>
- <PRE>
- $date=&Date_SetTime($date,"1:30 PM")</PRE>
- <P>doesn't.</P>
- <DT><STRONG><A NAME="item_Date_SetDateField">Date_SetDateField</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_SetDateField($date,$field,$val [,$nocheck])</PRE>
- <P>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.</P>
- <P>If $nocheck is non-zero, no check is made as to the validity of the date.</P>
- <DT><STRONG><A NAME="item_Date_GetPrev">Date_GetPrev</A></STRONG><BR>
- <DD>
- <PRE>
- $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)</PRE>
- <P>This takes a date (any string that may be parsed by ParseDateString) and finds
- the previous occurence of either a day of the week, or a certain time of day.</P>
- <P>If $dow is defined, the previous occurence 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 this day of week, the date returned will be $date (if $curr is
- non-zero) or a week earlier (if $curr is 0). 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:</P>
- <PRE>
- date dow curr time returns
- Fri Nov 22 18:15:00 Thu 0 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 12:30 Fri Nov 22 12:30:00</PRE>
- <P>If $dow is undefined, then a time must be entered, and the date returned is
- the previous occurence 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.</P>
- <PRE>
- 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</PRE>
- <DT><STRONG><A NAME="item_Date_GetNext">Date_GetNext</A></STRONG><BR>
- <DD>
- <PRE>
- $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)</PRE>
- <P>Similar to Date_GetPrev.</P>
- <DT><STRONG><A NAME="item_Date_DayOfWeek">Date_DayOfWeek</A></STRONG><BR>
- <DD>
- <PRE>
- $day=&Date_DayOfWeek($m,$d,$y);</PRE>
- <P>Returns the day of the week (0 for Sunday, 6 for Saturday). Dec 31, 0999
- was Tuesday.</P>
- <P>All arguments must be numeric.</P>
- <DT><STRONG><A NAME="item_Date_SecsSince1970">Date_SecsSince1970</A></STRONG><BR>
- <DD>
- <PRE>
- $secs=&Date_SecsSince1970($m,$d,$y,$h,$mn,$s)</PRE>
- <P>Returns the number of seconds since Jan 1, 1970 00:00 (negative if date is
- earlier).</P>
- <P>All arguments must be numeric.</P>
- <DT><STRONG><A NAME="item_Date_SecsSince1970GMT">Date_SecsSince1970GMT</A></STRONG><BR>
- <DD>
- <PRE>
- $secs=&Date_SecsSince1970GMT($m,$d,$y,$h,$mn,$s)</PRE>
- <P>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).</P>
- <P>All arguments must be numeric.</P>
- <DT><STRONG><A NAME="item_Date_DaysSince999">Date_DaysSince999</A></STRONG><BR>
- <DD>
- <PRE>
- $days=&Date_DaysSince999($m,$d,$y)</PRE>
- <P>Returns the number of days since Dec 31, 0999.</P>
- <P>All arguments must be numeric.</P>
- <DT><STRONG><A NAME="item_Date_DayOfYear">Date_DayOfYear</A></STRONG><BR>
- <DD>
- <PRE>
- $day=&Date_DayOfYear($m,$d,$y);</PRE>
- <P>Returns the day of the year (001 to 366)</P>
- <P>All arguments must be numeric.</P>
- <DT><STRONG><A NAME="item_Date_NthDayOfYear">Date_NthDayOfYear</A></STRONG><BR>
- <DD>
- <PRE>
- ($y,$m,$d,$h,$mn,$s)=&Date_NthDayOfYear($y,$n);</PRE>
- <P>Returns the year, month, day, hour, minutes, and decimal seconds given
- a floating point day of the year.</P>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Date_DaysInYear">Date_DaysInYear</A></STRONG><BR>
- <DD>
- <PRE>
- $days=&Date_DaysInYear($y);</PRE>
- <P>Returns the number of days in the year (365 or 366)</P>
- <DT><STRONG><A NAME="item_Date_DaysInMonth">Date_DaysInMonth</A></STRONG><BR>
- <DD>
- <PRE>
- $days=&Date_DaysInMonth($m,$y);</PRE>
- <P>Returns the number of days in the month.</P>
- <DT><STRONG><A NAME="item_Date_WeekOfYear">Date_WeekOfYear</A></STRONG><BR>
- <DD>
- <PRE>
- $wkno=&Date_WeekOfYear($m,$d,$y,$first);</PRE>
- <P>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.</P>
- <P>All arguments must be numeric.</P>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Date_LeapYear">Date_LeapYear</A></STRONG><BR>
- <DD>
- <PRE>
- $flag=&Date_LeapYear($y);</PRE>
- <P>Returns 1 if the argument is a leap year
- Written by David Muir Sharnoff <<A HREF="mailto:muir@idiom.com">muir@idiom.com</A>></P>
- <DT><STRONG><A NAME="item_Date_DaySuffix">Date_DaySuffix</A></STRONG><BR>
- <DD>
- <PRE>
- $day=&Date_DaySuffix($d);</PRE>
- <P>Add `st', `nd', `rd', `th' to a date (ie 1st, 22nd, 29th). Works for
- international dates.</P>
- <DT><STRONG><A NAME="item_Date_TimeZone">Date_TimeZone</A></STRONG><BR>
- <DD>
- <PRE>
- $tz=&Date_TimeZone</PRE>
- <P>This returns a timezone. It looks in the following places for a timezone
- in the following order:</P>
- <PRE>
- $ENV{TZ}
- $main::TZ
- unix 'date' command
- /etc/TIMEZONE</PRE>
- <P>If it's not found in any of those places, an error occurs:</P>
- <PRE>
- ERROR: Date::Manip unable to determine TimeZone.</PRE>
- <P>Date_TimeZone is able to read zones of the format PST8PDT (see TIMEZONES
- documentation below).</P>
- <DT><STRONG><A NAME="item_Date_ConvTZ">Date_ConvTZ</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_ConvTZ($date)
- $date=&Date_ConvTZ($date,$from)
- $date=&Date_ConvTZ($date,(),$to)
- $date=&Date_ConvTZ($date,$from,$to)</PRE>
- <P>This converts a date (which MUST be in the format returned by ParseDate)
- from one timezone to another.</P>
- <P>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.</P>
- <P>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''.</P>
- <P>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.</P>
- <P>If Date_ConvTZ is called with both $from and $to, the date is converted
- from the timezone $from to $to.</P>
- <P>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).</P>
- <P>Example: To convert 2/2/96 noon PST to CST (regardless of what timezone
- you are in, do the following:</P>
- <PRE>
- $date=&ParseDate("2/2/96 noon");
- $date=&Date_ConvTZ($date,"PST","CST");</PRE>
- <P>Both timezones MUST be in one of the formst listed below in the section
- TIMEZONES.</P>
- <DT><STRONG><A NAME="item_Date_Init">Date_Init</A></STRONG><BR>
- <DD>
- <PRE>
- $flag=&Date_Init();
- $flag=&Date_Init("VAR=VAL","VAR=VAL",...);</PRE>
- <P>Normally, it is not necessary to explicitely 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 reinitizize things.</P>
- <P>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 configuaration 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:</P>
- <PRE>
- &Date_Init("Language=French","DateFormat=nonUS");</PRE>
- <P>Note that the usage of Date_Init changed with version 5.07. The old
- calling convention is allowed but is depreciated.</P>
- <P>If you change timezones in the middle of using Date::Manip, comparing dates
- from before the switch to dates from after the switch will produce incorrect
- results.</P>
- <DT><STRONG><A NAME="item_Date_IsWorkDay">Date_IsWorkDay</A></STRONG><BR>
- <DD>
- <PRE>
- $flag=&Date_IsWorkDay($date [,$flag]);</PRE>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Date_NextWorkDay">Date_NextWorkDay</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_NextWorkDay($date,$off [,$time]);</PRE>
- <P>Finds the day $off work days from now. If $time is passed in, we must also
- take into account the time of day.</P>
- <P>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.</P>
- <P>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.</P>
- <DT><STRONG><A NAME="item_Date_PrevWorkDay">Date_PrevWorkDay</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_PrevWorkDay($date,$off [,$time]);</PRE>
- <P>Similar to Date_NextWorkDay.</P>
- <DT><STRONG><A NAME="item_Date_NearestWorkDay">Date_NearestWorkDay</A></STRONG><BR>
- <DD>
- <PRE>
- $date=&Date_NearestWorkDay($date [,$tomorrowfirst]);</PRE>
- <P>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 otherwords,
- 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.</P>
- <DT><STRONG><A NAME="item_DateManipVersion">DateManipVersion</A></STRONG><BR>
- <DD>
- <PRE>
- $version=&DateManipVersion</PRE>
- <P>Returns the version of Date::Manip.</P>
- </DL>
- <P>
- <HR>
- <H1><A NAME="timezones">TIMEZONES</A></H1>
- <P>The following timezone names are currently understood (and can be used in
- parsing dates). These are zones defined in RFC 822.</P>
- <PRE>
- 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</PRE>
- <P>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 Standare -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 from the Time::Zone module by Graham Barr, David Muir Sharnoff,
- and Paul Foley (with some additions by myself).</P>
- <PRE>
- IDLW -1200 International Date Line West
- NT -1100 Nome
- HST -1000 Hawaii Standard
- CAT -1000 Central Alaska
- AHST -1000 Alaska-Hawaii Standard
- YST -0900 Yukon Standard
- HDT -0900 Hawaii 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
- EDT -0400 Eastern Daylight
- AST -0400 Atlantic Standard
- #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
- ADT -0300 Atlantic Daylight
- NDT -0230 Newfoundland Daylight
- AT -0200 Azores
- WAT -0100 West Africa
- 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
- MEWT +0100 Middle European Winter
- SWT +0100 Swedish Winter
- BST +0100 British Summer bst=Brazil standard -0300
- GB +0100 GMT with daylight savings
- CEST +0200 Central European Summer
- EET +0200 Eastern Europe, USSR Zone 1
- FST +0200 French Summer
- MEST +0200 Middle European Summer
- METDST +0200 An alias for MEST used by HP-UX
- SST +0200 Swedish Summer sst=South Sumatra +0700
- EEST +0300 Eastern Europe Summer
- BT +0300 Baghdad, USSR Zone 2
- IT +0330 Iran
- ZP4 +0400 USSR Zone 3
- ZP5 +0500 USSR Zone 4
- IST +0530 Indian Standard
- ZP6 +0600 USSR Zone 5
- NST +0630 North Sumatra nst=Newfoundland Std -0330
- #SST +0700 South Sumatra, USSR Zone 6 sst=Swedish Summer +0200
- CCT +0800 China Coast, USSR Zone 7
- AWST +0800 West Australian Standard
- WST +0800 West Australian Standard
- JST +0900 Japan Standard, USSR Zone 8
- ROK +0900 Republic of Korea
- CAST +0930 Central Australian Standard
- EAST +1000 Eastern Australian Standard
- GST +1000 Guam Standard, USSR Zone 9 gst=Greenland Std -0300
- CADT +1030 Central Australian 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</PRE>
- <P>Others can be added in the future upon request.</P>
- <P>DateManip needs to be able to determine the local timezone. It can do this
- by certain things such as the TZ environment variable (see Date_TimeZone
- documentation above) or useing the TZ config variable (described below).
- In either case, the timezone can be of the form STD#DST (for example
- EST5EDT). Both the standard and daylight savings time abbreviations must
- be in the table above in order for this to work. Also, this form may NOT
- be used when parsing a date as there is no way to determine whether the
- date is in daylight saving time or not. The following forms are also
- available and are treated similar to the STD#DST forms:</P>
- <PRE>
- US/Pacific
- US/Mountain
- US/Central
- US/Eastern</PRE>
- <P>
- <HR>
- <H1><A NAME="business mode">BUSINESS MODE</A></H1>
- <P>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.</P>
- <P>If you do a business day calculation (with the workday set to 9:00-5:00),
- you will get the following:</P>
- <PRE>
- Saturday at noon + 1 business day = Tuesday at 9:00
- Saturday at noon - 1 business day = Friday at 9:00</PRE>
- <P>What does this mean?</P>
- <P>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 9:00 as being ambiguous (in the
- same way you treat midnight as being ambiguous).</P>
- <P>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.</P>
- <P>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.</P>
- <P>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.</P>
- <P>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.</P>
- <P>
- <HR>
- <H1><A NAME="customizing date::manip">CUSTOMIZING DATE::MANIP</A></H1>
- <P>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.</P>
- <P>At the top of the Manip.pm file, there is a section which contains all
- customization variables. These provide the default values.</P>
- <P>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.</P>
- <P>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.</P>
- <P>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.</P>
- <P>Finally, any variables passed in through Date_Init override all other
- values.</P>
- <P>A config file can be composed of several sections (though only 2 of them
- are currently used). The first section sets configuration varibles. Lines
- in this section are of the form:</P>
- <PRE>
- VARIABLE = VALUE</PRE>
- <P>For example, to make the default language French, include the line:</P>
- <PRE>
- Language = French</PRE>
- <P>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.</P>
- <P>A line which starts with an asterix (*) designates a new section. The only
- section currently used is the Holiday section. All lines are of the form:</P>
- <PRE>
- DATE = HOLIDAY</PRE>
- <P>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).</P>
- <P>DATE is a string which can be parsed to give a valid date in any year. It
- can be of the form</P>
- <PRE>
- Date
- Date + Delta
- Date - Delta</PRE>
- <P>A valid holiday section would be:</P>
- <PRE>
- *Holiday</PRE>
- <PRE>
- 1/1 = New Year's Day
- third Monday in Feb = Presidents' Day
- fourth Thu in Nov = Thanksgiving</PRE>
- <PRE>
- # The Friday after Thanksgiving is an unnamed holiday most places
- fourth Thu in Nov + 1 day =</PRE>
- <P>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:</P>
- <PRE>
- 12/25 - 1 business day =</PRE>
- <P>All Date::Manip variables which can be used are described in the following
- section.</P>
- <DL>
- <DT><STRONG><A NAME="item_IgnoreGlobalCnf">IgnoreGlobalCnf</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_EraseHolidays">EraseHolidays</A></STRONG><BR>
- <DD>
- 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).
- <P></P>
- <DT><STRONG><A NAME="item_PersonalCnf">PersonalCnf</A></STRONG><BR>
- <DD>
- This variable can be passed into Date_Init to read a different personal
- configuration file. It can also be included in the global config file
- to define where personal config files live.
- <P>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 :-).</P>
- <P></P>
- <DT><STRONG><A NAME="item_PersonalCnfPath">PersonalCnfPath</A></STRONG><BR>
- <DD>
- Used in the same way as the PersonalCnf option. You can use tilde (~)
- expansions when defining the path for Unix and VMS platforms.
- <P></P>
- <DT><STRONG><A NAME="item_Language">Language</A></STRONG><BR>
- <DD>
- Date::Manip can be used to parse dates in many different languages.
- Currently, it is configured to read English, Swedish, and French dates,
- but others can be added easily. Language is set to the language used to
- parse dates.
- <P></P>
- <DT><STRONG><A NAME="item_DateFormat">DateFormat</A></STRONG><BR>
- <DD>
- Different countries look at the date 12/10/96 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).
- <P></P>
- <DT><STRONG><A NAME="item_TZ">TZ</A></STRONG><BR>
- <DD>
- Date::Manip is able to understand some timezones (and others will be added
- in the future). At the very least, all zones defined in RFC 822 are
- supported. Currently supported zones are listed in the TIMEZONES section
- above and all timezones should be entered as one of them.
- <P>Date::Manip must be able to determine the timezone the user is in. It does
- this by looking in the following places:</P>
- <PRE>
- the environment variable TZ
- the variable $main::TZ
- the file /etc/TIMEZONE
- the 5th element of the unix "date" command (not available on NT machines)</PRE>
- <P>At least one of these should contain a timezone in one of the supported
- forms. If it doesn't, the TZ variable must be set to contain the local
- timezone in the appropriate form.</P>
- <P>The TZ variable will override the other methods of determining the
- timezone, so it should probably be left blank if any of the other methods
- will work. Otherwise, you will have to modify the variable every time you
- switch to/from daylight savings time.</P>
- <P></P>
- <DT><STRONG><A NAME="item_ConvTZ">ConvTZ</A></STRONG><BR>
- <DD>
- 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.
- <P>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).</P>
- <P></P>
- <DT><STRONG><A NAME="item_Internal">Internal</A></STRONG><BR>
- <DD>
- 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:
- <PRE>
- YYYYMMDDHH:MN:SS</PRE>
- <P>It has been suggested that I remove the colons (:) to shorten this to:</P>
- <PRE>
- YYYYMMDDHHMNSS</PRE>
- <P>The main advantage of this is that some databases are colon delimited which
- makes storing a date from Date::Manip tedious.</P>
- <P>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).</P>
- <P></P>
- <DT><STRONG><A NAME="item_FirstDay">FirstDay</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_WorkWeekBeg%2C_WorkWeekEnd">WorkWeekBeg, WorkWeekEnd</A></STRONG><BR>
- <DD>
- 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 0 (sunday) to 6 (saturday). There is no way to handle an odd
- work week of Thu to Mon for example.
- <P></P>
- <DT><STRONG><A NAME="item_WorkDay24Hr">WorkDay24Hr</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_WorkDayBeg%2C_WorkDayEnd">WorkDayBeg, WorkDayEnd</A></STRONG><BR>
- <DD>
- 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!).
- <P>The time in both can be in any valid time format (including international
- formats), but seconds will be ignored.</P>
- <P></P>
- <DT><STRONG><A NAME="item_TomorrowFirst">TomorrowFirst</A></STRONG><BR>
- <DD>
- 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).
- <P></P>
- <DT><STRONG><A NAME="item_DeltaSigns">DeltaSigns</A></STRONG><BR>
- <DD>
- 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).
- <P></P>
- <DT><STRONG><A NAME="item_Jan1Week1">Jan1Week1</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_YYtoYYYY">YYtoYYYY</A></STRONG><BR>
- <DD>
- 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.
- <P>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.</P>
- <P>It can also be set to the form ``C####'' to force it into a specific 100
- year period. C1950 refers to 1950-2049.</P>
- <P></P>
- <DT><STRONG><A NAME="item_UpdateCurrTZ">UpdateCurrTZ</A></STRONG><BR>
- <DD>
- 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-nill will force timezone checking to be done every
- time a date is parsed... but this will result in a considerable performance
- penalty.
- <P>A better solution would be to restart the process on the two days per year
- where the timezone switch occurs.</P>
- <P></P>
- <DT><STRONG><A NAME="item_IntCharSet">IntCharSet</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_ForceDate">ForceDate</A></STRONG><BR>
- <DD>
- 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.
- <P></P></DL>
- <P>
- <HR>
- <H1><A NAME="backwards incompatibilities">BACKWARDS INCOMPATIBILITIES</A></H1>
- <P>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.</P>
- <DL>
- <DT><STRONG><A NAME="item_VERSION_5%2E32">VERSION 5.32</A></STRONG><BR>
- <DD>
- <DL>
- <DT><STRONG><A NAME="item_Date_Init_arguments">Date_Init arguments</A></STRONG><BR>
- <DD>
- The old style Date_Init arguments that were deprecated in version 5.07
- have been removed.
- <P></P>
- <LI><STRONG><A NAME="item_DateManip%2Ecnf_change">DateManip.cnf change</A></STRONG><BR>
-
- 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.
- <P></P></DL>
- <DT><STRONG><A NAME="item_VERSION_5%2E30">VERSION 5.30</A></STRONG><BR>
- <DD>
- <UL>
- <LI><STRONG><A NAME="item_Delta_format_changed">Delta format changed</A></STRONG><BR>
-
- 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''.
- <P></P></UL>
- <DT><STRONG><A NAME="item_VERSION_5%2E21">VERSION 5.21</A></STRONG><BR>
- <DD>
- <DL>
- <DT><STRONG><A NAME="item_Long_running_processes_may_give_incorrect_timezone">Long running processes may give incorrect timezone</A></STRONG><BR>
- <DD>
- A process that runs during a timezone change (Daylight Saving Time
- specifically) may report the wrong timezone. See the UpdateCurrTZ variable
- for more information.
- <P></P>
- <DT><STRONG><A NAME="item_UnixDate_%22%25J%22%2C_%22%25W%22%2C_and_%22%25U%2">UnixDate ``%J'', ``%W'', and ``%U'' formats fixed</A></STRONG><BR>
- <DD>
- 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.
- <P></P></DL>
- <DT><STRONG><A NAME="item_VERSION_5%2E20">VERSION 5.20</A></STRONG><BR>
- <DD>
- <UL>
- <LI><STRONG><A NAME="item_removed">ParseDate formats removed (ISO 8601 compatibility)</A></STRONG><BR>
-
- 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.
- <P></P>
- <LI><STRONG><A NAME="item_Week_day_numbering">Week day numbering</A></STRONG><BR>
-
- 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).
- <P></P></UL>
- <DT><STRONG><A NAME="item_VERSION_5%2E07">VERSION 5.07</A></STRONG><BR>
- <DD>
- <DL>
- <DT><STRONG><A NAME="item_UnixDate_%22%25s%22_format">UnixDate ``%s'' format</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG><A NAME="item_Internal_format_of_delta">Internal format of delta</A></STRONG><BR>
- <DD>
- 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.
- <P></P>
- <DT><STRONG>Date_Init arguments</STRONG><BR>
- <DD>
- The format of the Date_Init calling arguments changed. The
- old method
- <PRE>
- &Date_Init($language,$format,$tz,$convtz);</PRE>
- <P>is still supported , but this support will likely disappear in the future.
- Use the new calling format instead:</P>
- <PRE>
- &Date_Init("var=val","var=val",...);</PRE>
- <P>NOTE: The old format is no longer supported as of version 5.32 .</P>
- <P></P></DL>
- </DL>
- <P>
- <HR>
- <H1><A NAME="known problems">KNOWN PROBLEMS</A></H1>
- <P>The following are not bugs, but they may give some people problems.</P>
- <DL>
- <DT><STRONG><A NAME="item_Unable_to_determine_TimeZone">Unable to determine TimeZone</A></STRONG><BR>
- <DD>
- Perhaps the most common problem occurs when you get the error:
- <PRE>
- Error: Date::Manip unable to determine TimeZone.</PRE>
- <P>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, or in the
- DateManip.cnf file. 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.</P>
- <P>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.</P>
- <P>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 explicitely 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.</P>
- <P>When running outside the tests, Date::Manip has to rely on it's other
- methods for determining the timezone.</P>
- <P></P>
- <DT><STRONG><A NAME="item_Complaining_about_getpwnam%2Fgetpwuid">Complaining about getpwnam/getpwuid</A></STRONG><BR>
- <DD>
- 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:
- <PRE>
- $ENV{OS} = Windows_NT
- $ENV{OS} = Windows_95</PRE>
- <P>to your script before</P>
- <PRE>
- use Date::Manip</PRE>
- <P></P>
- <DT><STRONG><A NAME="item_Date%3A%3AManip_is_slow">Date::Manip is slow</A></STRONG><BR>
- <DD>
- The reasons for this are covered in the SHOULD I USE DATE::MANIP section
- above.
- <P>Some things that will definitely help:</P>
- <P>Version 5.21 does run noticably 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.</P>
- <P>ISO-8601 dates are parsed first and fastest. Use them whenever possible.</P>
- <P>Avoid parsing dates that are referenced against the current time (in 2
- days, today at noon, etc.). These take a lot longer to parse.</P>
- <PRE>
- 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).</PRE>
- <P>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 :-)</P>
- <P>Never call Date_Init more than once. Unless you're doing something very
- strange, there should never be a reason to anyway.</P>
- <P></P>
- <DT><STRONG><A NAME="item_Sorting_Problems">Sorting Problems</A></STRONG><BR>
- <DD>
- If you use Date::Manip to sort a number of dates, you must call Date_Init
- either explicitely, or by way of some other Date::Manip routine before it
- is used in the sort. For example, the following code fails:
- <PRE>
- use Date::Manip;
- # &Date_Init;
- sub sortDate {
- my($date1, $date2);
- $date1 = &ParseDate($a);
- $date2 = &ParseDate($b);
- return ($date1 cmp $date2);
- }
- @date = ("Fri 16 Aug 96",
- "Mon 19 Aug 96",
- "Thu 15 Aug 96");
- @i=sort sortDate @dates;</PRE>
- <P>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
- (5.004 and earlier) 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 explicitely.</P>
- <P>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.</P>
- <P></P>
- <DT><STRONG><A NAME="item_RCS_Control">RCS Control</A></STRONG><BR>
- <DD>
- 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.
- <P></P></DL>
- <P>
- <HR>
- <H1><A NAME="known bugs">KNOWN BUGS</A></H1>
- <DL>
- <DT><STRONG><A NAME="item_Daylight_Savings_Times">Daylight Savings Times</A></STRONG><BR>
- <DD>
- 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.
- <P>The following examples are run in the winter of the US East coast (i.e.
- in the EST timezone).</P>
- <PRE>
- print UnixDate(ParseDate("6/1/97 noon"),"%u"),"\n";
- => Sun Jun 1 12:00:00 EST 1997</PRE>
- <P>June 1 EST does not exist. June 1st is during EDT. It should print:</P>
- <PRE>
- => Sun Jun 1 00:00:00 EDT 1997</PRE>
- <P>Even explicitely adding the timezone doesn't fix things (if anything, it
- makes them worse):</P>
- <PRE>
- print UnixDate(ParseDate("6/1/97 noon EDT"),"%u"),"\n";
- => Sun Jun 1 11:00:00 EST 1997</PRE>
- <P>Date::Manip converts everything to the current timezone (EST in this case).</P>
- <P>Related problems occur when trying to do date calculations over a timezone
- change. These calculations may be off by an hour.</P>
- <P>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).</P>
- <P>I hope to fix these problems in a future release so that it would convert
- everything to the current zones (EST or EDT).</P>
- <P></P></DL>
- <P>
- <HR>
- <H1><A NAME="bugs and questions">BUGS AND QUESTIONS</A></H1>
- <P>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.).</P>
- <P>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).</P>
- <P>
- <HR>
- <H1><A NAME="year 2000">YEAR 2000</A></H1>
- <P>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.</P>
- <P>Is Date::Manip year 2000 compliant? Yes, but the question is largely
- unmeaningful. Date::Manip is basically a parser. It'll parse dates in any
- of thousands of different formats (including the 2 digit years that are
- going to cause the computer equivalent of doomsday on Dec 31, 1999). But,
- internally, Date::Manip stores years as 4 digits, and all of it's functions
- work with the 4 digit representation, so there is no problem with dates
- after 2000.</P>
- <P>The better question is ``Is Perl year 2000 compliant''? This is such a good
- question, that it's in the perl FAQ. Go read ``Does Perl have a year 2000
- problem'' in section 4.</P>
- <P>The best question is ``For what dates is Date::Manip useful?'' It definitely
- can't handle BC dates, or dates past Dec 31, 9999. Also, one of the basic
- routines I wrote counts the days since Dec 31, 0999. I realize now that I
- should have had it calculate days since Dec 31, 0001 BC, but I didn't. One
- day I may go back and change this, but until I do, dates in the first
- millenium (0001 to 0999) probably won't work. So, I guarantee that
- Date::Manip works during the years 1000 to 9999.</P>
- <P>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 this century. Also, at some point around the
- year 3000, the calendar system is going to have to be modified slightly
- since the current system of leap years will be off by one day every 3200
- years or so. So... in practical terms, Date::Manip is _probably_ useful
- from 1900 to 3000. Approximately.</P>
- <P>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.</P>
- <P>Finally, Date::Manip is flexible. It will allow you to write Year 2000
- NON-compliant code if you really want to.</P>
- <P>
- <HR>
- <H1><A NAME="acknowledgements">ACKNOWLEDGEMENTS</A></H1>
- <P>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. The list is simply too long to appear here, but I appreciate
- their help.</P>
- <P>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 praised in a book written by someone
- else is really great. My thanks to Nate Patwardhan and Clay Irving
- (Programming with Perl Modules -- part of the O'Reilly Perl Resource Kit);
- and Tom Christiansen and Nathan Torkington (for the forthcoming book The
- Perl Cookbook). Also, thanks to any other authors who've written about
- Date::Manip who's books I haven't seen.</P>
- <P>
- <HR>
- <H1><A NAME="author">AUTHOR</A></H1>
- <P>Sullivan Beck (<A HREF="mailto:sbeck@cise.ufl.edu">sbeck@cise.ufl.edu</A>)</P>
- <P>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:</P>
- <P><A HREF="http://www.cise.ufl.edu/~sbeck/">http://www.cise.ufl.edu/~sbeck/</A></P>
- <TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
- <TR><TD CLASS=block VALIGN=MIDDLE WIDTH=100% BGCOLOR="#cccccc">
- <STRONG><P CLASS=block> Date::Manip - date manipulation routines</P></STRONG>
- </TD></TR>
- </TABLE>
-
- </BODY>
-
- </HTML>
-