The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
NAME

    Date::EzDate - Date and time manipulation made easy

SYNOPSIS

    An EzDate object represents a single point in time and exposes all
    properties of that point. It also makes it easy to change those
    properties to produce a different point in time. EzDate has many
    features, here are a few:

     use Date::EzDate;
     my $mydate = Date::EzDate->new();
    
     # output some date information
     print $mydate, "\n";  # e.g. output:  Wed Apr 11, 2001 09:06:26
    
     # go to next day
     $mydate->{'epochday'}++;
    
     # determine if the date is before some other date
     if ($mydate < 'June 21, 2003')
         {...}
    
     # output some other date and time information
     # e.g. output:  Thursday April 12, 2001 09:06 am
     print
       $mydate->{'weekday long'},        ' ',
       $mydate->{'month long'},          ' ',
       $mydate->{'day of month'},        ', ',
       $mydate->{'year'},                ' ',
       $mydate->{'ampm hour no zero'},   ':',
       $mydate->{'min'},                 ' ',
       $mydate->{'am pm'},               "\n";
    
     # go to Monday of same week, but be lazy and don't spell out
     # the whole day or case it correctly
     $mydate->{'weekday long'} = 'MON';
    
     print $mydate, "\n";  # e.g. output:  Mon Apr 09, 2001 09:06:26
    
     # go to previous year
     $mydate->{'year'}--;
    
     print $mydate, "\n";  # e.g. output:  Sun Apr 09, 2000 09:06:26

INSTALLATION

    Date::EzDate can be installed with the usual routine:

     perl Makefile.PL
     make
     make test
     make install

    You can also just copy EzDate.pm into the Date/ directory of one of
    your library trees.

DESCRIPTION

    Date::EzDate was motivated by the simple fact that I hate dealing with
    date and time calculations, so I put all of them into a single
    easy-to-use object. The main idea of EzDate is that the object
    represents a specific date and time. A variety of properties tell you
    information about that date and time such as hour, minute, day of
    month, weekday, etc.

    The real power of EzDate is that you can assign to (almost) any of
    those properties and EzDate will automatically rework the other
    properties to produce a new valid date with the property you just
    assigned. Properties that can be kept the same with the new value
    aren't changed, while those that logically must change to accomodate
    the new value are recalculated. For example, incrementing epochday by
    one (i.e. moving the date forward one day) does not change the hour or
    minute but does change the day of week.

    So, for example, suppose you want to get information about today, then
    get information about tomorrow. That can be done using the epochday
    property which is used for day-granularity calculations. Let's walk
    through the steps:

    Load the module and instantiate the object

       use Date::EzDate;
       my $mydate = Date::EzDate->new();  # the object defaults to the current date and time

    output all the basic information

       # e.g. outputs:  11:11:40 Wed Apr 11, 2001
       print $mydate->{'full'}, "\n";

    set to tomorrow

      To move the date forward one day we simply increment the epochday
      property (number of days since the epoch). The time (i.e.
      hour:min:sec) of the object does not change.

       $mydate->{'epochday'}++;
      
       # outputs:  11:11:40 Thu Apr 12, 2001
       print $mydate->{'full'}, "\n";

    This demonstrates the basic concept: almost any of the properties can
    be set as well as read and EzDate will take care of resetting all other
    properties as needed.

YESTERDAY and TOMORROW

    In addition to initializing the EzDate object with either nothing (i.e.
    the current day) or with a string representing a date/time, you can
    initialize the object with the strings YESTERDAY or TOMORROW. For
    example, the following code creates an EzDate object with tomorrow's
    date:

     $date = Date::EzDate->new('tomorrow');

STRINGIFICATION

    EzDate objects stringify to a full representation of the date. So, for
    example, the following code outputs a string like Tue Sep 3, 2002
    14:01:02:

     $date = Date::EzDate->new();
     print $date, "\n";

    The object stringifies to its default format, so if you want to change
    how it stringifies simply change the default format. For example, the
    following code outputs a string like September 3, 2002:

     $date->{'default'} = '{month long} {day of month no zero} {year}';
     print $date, "\n";

COMPARISON

    There are two main ways to compare EzDate objects: by comparing the
    object directly using the numeric comparison operators, or by comparing
    their properties.

 Overloaded Numeric Comparison Operators

    EzDate overloads the numeric comparison operators. The epochday
    properties of two EzDate objects can be compared using the ==, >, >=,
    <, <= , and <=>, operators. For example, the following code creates two
    EzDate objects, then determines if the first object is less than the
    second:

     $mybday = Date::EzDate->new();
     $yourbday = Date::EzDate->new('tomorrow');
    
     if ($mybday < $yourbday) {
       ....
     }

    Only one of the two items being compared needs be an EzDate object. The
    other can be a string representation of a date. For example, the
    following code correctly determines if the given EzDate object is
    before June 25, 2003:

     if ($date < 'June 25, 2003') {
        ...
     }

    By default, the comparison is done on the epochday property, so two
    EzDate objects that have the same date but different times will be
    considered the same. If you want to compare based on some other
    property, set $Date::EzDate::overload to the name of the property to
    compare. For example, the following code sets the comparison property
    to epoch hour, meaning that two date/times are considered the same only
    if they are identical down to the hour:

     my ($start, $finish);
     $start = Date::EzDate->new('Oct 18, 2006 4pm');
     $finish = Date::EzDate->new('Oct 18, 2006 6pm');
    
     # outputs false, because both epochdays are the same
     print 'finish is greater than start: ', $finish > $start, "\n";
    
     # change $Date::EzDate::overload to epochhour
     $Date::EzDate::overload = 'epochhour';
    
     # output true, because Oct 18, 2006 6pm is
     # greater than Oct 18, 2006 4pm
     print 'finish is greater than start: ', $finish > $start, "\n";

    PLEASE NOTE: $Date::EzDate::overload used to be named
    $Date::EzDate::compare. I made a non-backwards compatible change to
    "overload" because the same variable for indicating default overload is
    now being used for non-comparison overloads like addition and
    subtraction.

 Comparing Properties

    The other way to compare dates is to compare their properties. For
    example, you can simple determine if two dates are on the same day of
    week by using their day of week properties:

     $date = Date::EzDate->new('January 3, 2001');
     $otherdate = Date::EzDate->new('January 10, 2001');
    
     if ($date->{'day of week'} eq $otherdate->{'day of week'}) {
        ...
     }

OVERLOADED ADDITION AND SUBTRACTION

    You can do basic addition and subtraction on EzDate objects to adjust
    the epoch day property (or whatever property is indicated by the
    $Date::EzDate::overload variable). For example, to increment the day of
    the object, simply increment it with ++ like a number. For example, the
    following code moves the day from Jan 31, 2003 to Feb 1, 2003:

     my $date = Date::EzDate->new('Jan 31, 2003');
     print $date, "\n";  # outputs Fri Jan 31, 2003 16:05:27
     $date++;
     print $date;      # outputs Sat Feb 1, 2003 16:05:27

    You can also move by more than one day with + or +=. These two commands
    do the same thing:

     $date = $date + 3;
     $date += 3;

    Subtraction works the same way. All of these commands move the object
    one day backwards:

     $date = $date - 1;
     $date -= 1;
     $date--;

METHODS

 new([date string])

    Currently, EzDate only accepts a single optional argument when
    instantiated. You may pass in either a Perl time integer or a string
    formatted as DDMMMYYYY. If you don't pass in any argument then the
    returned object represents the time and day at the moment it was
    created.

    The following are valid ways to instantiate an EzDate object:

     # current date and time
     my $date = Date::EzDate->new();
    
     # a specific date and time
     my $date = Date::EzDate->new('Jan 31, 2001');
    
     # a date in DDMMMYYYY format
     my $date = Date::EzDate->new('14JAN2003');
    
     # a little forgiveness is built in (notice oddly place comma)
     my $date = Date::EzDate->new('14 January, 2003');
    
     # epoch second (23:27:39, Tue Apr 10, 2001 if you're curious)
     my $date = Date::EzDate->new(986959659);
    
     # yesterday
     my $date = Date::EzDate->new('yesterday');
    
     # tomorrow
     my $date = Date::EzDate->new('tomorrow');

 $mydate->set_format($name, $format)

    set_format allows you to specify a custom format for use later on. For
    example, suppose you want a format of the form Monday, June 10, 2002.
    You can specify that format using set_format like this:

     $date->set_format('myformat', '{weekday long}, {month long} {day of month}, {year}');
     print $date->{'myformat'}, "\n";

    You can also create a custom format by simply assigning the format to
    its name. If EzDate sees a { in the value being assigned, it knows that
    you are assigning a format, not a date. The set_format line above could
    be written like this:

     $date->{'myformat'} = '{weekday long}, {month long} {day of month}, {year}';

    Note that it's not necessary to store a custom format if you're only
    going to use it once. If you wanted the format above, but just once,
    you could output it like this:

     print $date->{'{weekday long}, {month long} {day of month}, {year}'};

    To delete a custom format, $mydate-del_format($name)>. To get the
    format string itself, use $mydate-get_format($name)>.

    If you use the same custom format in a lot of different places in your
    project, you might find it easier to create your own customer
    super-class of Date::EzDate so that you can set the custom formats in
    one place. See "Super-classing Date::EzDate" below.

 $mydate->clone()

    This method returns an EzDate object exactly like the object it was
    called from. clone is much cheaper than creating a new EzDate object
    and then setting the new object to have the same properties as another
    EzDate object.

 $mydate->set_warnings($warning_level)

    When EzDate receives invalid instructions, by default it outputs a
    warning and continues. For example, if you use a time/date format that
    EzDate doesn't recognize, it outputs a warning to STDERR and ens the
    attempt to set the date/time. There are two other ways that EzDate
    could handle the error: it could ignore the error completely, or it
    could end the entire program.

    You can set which error handling you prefer with the set_warnings
    method. The first and only argument indicates how to handle errors.
    There are three possible values:

     0      Do not handle error in any way
     1      Output error to STDERR (default)
     2      Output to STDERR and exit program

    So, for example, the following code sets the warnings to level 2:

     $date->set_warnings(2);

    You can set the global default warning level by setting
    $Date::EzDate::default_warning. For example, the following code sets
    the global default level to 2:

     $Date::EzDate::default_warning = 2;

 $mydate->next_month([integer])

    EzDate lacks an epochmonth month property (because months aren't all
    the same length) so it needed a way to say "same day, next month".
    Calling next_month w/o any argument moves the object to the same day in
    the next month. If the day doesn't exist in the next month, such as if
    you move from Jan 31 to Feb, then the date is moved back to the last
    day of the next month.

    The only argument, which defaults to 1, allows you to move backward or
    forward any number of months. For example, the following command moves
    the date forward two months:

     $mydate->next_month(2);

    This command moves the date backward three months:

     $mydate->next_month(-3);

    next_month() handles year boundaries without problem. Calling
    next_month() for a date in December moves the date to January of the
    next year.

 $mydate->zero_hour_ampm(1|0)

    In general, EzDate operates on the principal that only date/time
    properties that are explicitly changed are changed. However, this rule
    was confusing people in one manner, so I changed the default behavior.
    If you set the hour using the format hour am|pm (e.g. 4 am without
    specifying the minute or second, then EzDate assumes you meant to set
    the minute and second to 0. So, the following string sets the object to
    exactly 4:00:00 pm:

     $date = Date::EzDate->new('4 pm');

    If you would prefer the old behavior where the time would be set to
    whatever the current minute and second are, then call zero_hour_ampm
    with an argument of zero:

     $date->zero_hour_ampm(0);

    You can also pass zero_hour_ampm as an initial argument for new:

     $date = Date::EzDate->new('January 31, 2002 1 am', zero_hour_ampm=>0);

 after_create

    after_create is intended for use when you are super-classing EzDate. By
    default, after_create does nothing. See "Super-classing Date::EzDate"
    below for more details.

 $start_date->date_range_string($end_date)

    date_range_string outputs a string representing the range of days from
    the EzDate date to some other date. The routine tries to make the
    string as concise as possible, so that months and years are not
    repeated if they are the same in both days. The single argument to
    date_range_string is another EzDate object.

     # same month and year
     # outputs Mar 5-7, 2004
     $start = Date::EzDate->new('Mar 5, 2004');
     $end = Date::EzDate->new('Mar 7, 2004');
     print $start->date_range_string($end);
    
     # same year, different months
     # outputs Feb 20-Mar 3, 2004
     $start = Date::EzDate->new('feb 20, 2004');
     $end = Date::EzDate->new('mar 3, 2004');
     print $start->date_range_string($end);
    
     # different years
     # outputs Dec 23, 2004-Jan 3, 2005
     $start = Date::EzDate->new('Dec 23, 2004');
     $end = Date::EzDate->new('Jan 3, 2005');
     print $start->date_range_string($end);

    It does not matter if the EzDate object is earlier or later than the
    second date. The function will always return them with the earlier date
    first.

    You can pass either an EzDate object or a string. So, for example, the
    following blocks of code output the same thing:

     # outputs Mar 5-7, 2004
     $start = Date::EzDate->new('Mar 5, 2004');
     $end = Date::EzDate->new('Mar 7, 2004');
     print $start->date_range_string($end);
    
     # outputs Mar 5-7, 2004
     $start = Date::EzDate->new('Mar 5, 2004');
     print $start->date_range_string('Mar 7, 2004');

    If both dates are the same day, then just that date will be returned:

     # same day
     # outputs Dec 23, 2004
     $start = Date::EzDate->new('Dec 23, 2004');
     print $start->date_range_string('Dec 23, 2004');

    date_range_string can also be called a static method, i.e., without
    ever explicitly defining an EzDate object:

     # outputs Mar 5-7, 2004
     print Date::EzDate::date_range_string('Mar 5, 2004', 'Mar 7, 2004');

    If you load EzDate using the ':all' param, the function call is even
    simpler:

     # note use of ':all'
     use Date::EzDate ':all';
    
     # outputs Mar 5-7, 2004
     print date_range_string('Mar 5, 2004', 'Mar 7, 2004');

    Array references in the argument list are expanded. So, for example,
    the following two lines of code produce the same thing:

     print date_range_string('May 3, 2005', 'May 5, 2005');
     print date_range_string( ['May 3, 2005', 'May 5, 2005'] );

    This behavior was added to accomodate the output from day_lumps. See
    the documentation of day_lumps for a practical example of this feature.

 $start_time->time_range_string($end_time)

    time_range_string returns a string representation of a range of
    minutes. For example, the following code outputs the range from 10:00
    am to 2:00 pm:

     # outputs 10:00am-2:00pm
     $start = Date::EzDate->new('10:00am');
     $end = Date::EzDate->new('2:00pm');
     print $start->time_range_string($end);

    time_range_string always tries to return the string as concisely as
    possible, so if the two times have the same am/pm designation then
    am/pm is only output once:

     # outputs 10:00-11:00am
     $start = Date::EzDate->new('10:00am');
     $end = Date::EzDate->new('11:00am');
     print $start->time_range_string($end);

    time_range_string can also be called as a static method, i.e. without
    actually creating any EzDate objects:

     # outputs 8:00-9:00pm
     print Date::EzDate::time_range_string('8pm', '9pm');

    If you load EzDate using the ':all' param, the function call is even
    simpler:

     # note use of ':all'
     use Date::EzDate ':all';
    
     # outputs 8:00-9:00pm
     print time_range_string('8pm', '9pm');

    The earlier time is always output first. If you only pass times, not
    dates, then EzDate assumes that both times are on the same day and
    outputs the earlier time first:

     # outputs 8:00-9:00pm
     print time_range_string('8pm', '9pm');

    If the time range crosses over midnight, you should explicitly indicate
    both dates:

     # output jan 21, 2005 8pm
     print time_range_string('jan 21, 2005 9pm', 'jan 22, 2005 5am');

 day_lumps(@dates)

    day_lumps groups an array of dates into "lumps" of contiguous dates.
    For example, consider the following dates:

     Jan 3, 2005
     Jan 4, 2005
     Jan 5, 2005
     Jan 6, 2005
     Jan 10, 2005
     Jan 15, 2005
     Jan 16, 2005
     Jan 17, 2005

    That list of dates could be more concisely expressed like this:

     Jan 3-6, 2005
     Jan 10, 2005
     Jan 15-17, 2005

    day_lumps produces an array of day spans, each span containing the
    start and end date of a single "lump". Here's the code to produce the
    output from the example above:

    # note use of ':all' use Date::EzDate ':all';

     my (@dates, @lumps);
    
     @dates = (
       'Jan 3, 2005',
       'Jan 4, 2005',
       'Jan 5, 2005',
       'Jan 6, 2005',
       'Jan 10, 2005',
       'Jan 15, 2005',
       'Jan 16, 2005',
       'Jan 17, 2005',
     );
    
     @lumps = day_lumps(@dates);
    
     foreach my $lump (@lumps)
        { print date_range_string($lump), "\n" }

PROPERTIES

    This section lists the properties of an EzDate object.

    Properties are case and space insensitive. Properties can be in upper
    or lower case, and you can put spaces anywhere to make them more
    readable. For example, the following properties are all the same:

     weekdaylong
     WEEKDAYLONG
     WeekDay Long
     Wee Kdaylong  # ugly but works

    Also, certain words can always be abbreviated.

     minute  ==  min
     second  ==  sec
     number  ==  num
     ordinal ==  num

    So, for example, the following two properties are the same:

     $mydate->{'minute of day'};
     $mydate->{'min of day'};

 Basic properties

    All of these properties are both readable and writable. Where there
    might be some confusion about what happens if you assign to the
    property more detail is given.

    hour

      Hour in 24 hour clock, 00 to 23. Two digits, with a leading zero
      where necessary.

    ampm hour

      Hour in twelve hour clock, 0 to 12. Two digits, with a leading zero
      where necessary.

    ampm

      am or pm as appropriate. Returns lowercase. If you set this property
      the object will adjust to the same day and same hour but in am or pm
      as you set.

    ampm uc, ampm lc

      ampm uc returns AM or PM uppercased. ampm lc returns am or pm
      lowercased.

    min, minute

      Minute, 00 to 59. Two digits, with a leading zero where necessary.

    sec, second

      Second, 00 to 59. Two digits, with a leading zero where necessary.

    weekday number

      Number of the weekday. This number is zero-based, so Sunday is 0,
      Monday is 1, etc. If you assign to this property the object will
      reset the date to the assigned weekday of the same week. So, for
      example, if the object represents Saturday Apr 14, 2001, and you
      assign 1 (Monday) to weekdaynum:

       $mydate->{'weekday number'} = 1;

      Then the object will adjust to Monday Apr 9, 2001.

    weekday short

      First three letters of the weekday. Sun, Mon, Tue, etc. If you assign
      to this property the object will adjust to that day in the same week.
      When you assign to this property EzDate actually only pays attention
      to the first three letters and ignores case, so SUNDAY would a valid
      assignment.

    weekday long

      Full name of the weekday. If you assign to this property the object
      will adjust to the day in the same week. When you assign to this
      property EzDate actually only pays attention to the first three
      letters and ignores case, so SUN would a valid assignment.

    day of month

      The day of the month. If you assign to this property the object
      adjusts to the day in the same month.

    day of month ordinal word, day of month ordinal number

      The day of month expressed as either an ordinal word (e.g. "Third")
      or as an ordinal number (e.g. "3rd").

    month number

      Zero-based number of the month. January is 0, February is 1, etc. If
      you assign to this property the object will adjust to the same
      month-day in the assigned month. If the current day is greater than
      allowed in the assigned month then the day will adjust to the maximum
      day of the assigned month. So, for example, if the object is set to
      31 Dec 2001 and you assign the month to February (1):

       $mydate->{'month number'} = 1;

      Then day of month will be set to 28.

    month number base 1

      1 based number of the month for those of us who are used to thinking
      of January as 1, February as 2, etc. Can be assigned to.

    month short

      First three letters of the month. Can be assigned to. This property
      is case insensitive, so "jAN" is as valid as "Jan". The assignment
      only looks at the first three letters of the input string, so
      "JANUARY" would be a valid assignment.

    month long

      Full name of the month. Can be assigned to. In the assignment, EzDate
      only pays attention to the first three letters and ignores case.

    year

      Year of the date the object represents.

    year two digits

      The last two digits of the year. If you assign to this property,
      EzDate assumes you mean to use the same first two digits. Therefore,
      if the current date of the object is 1994 and you assign '12' then
      the year will be 1912... quite possibly not what you intended.

    day of year

      Zero-based Number of days into the year of the date. yearday does the
      same thing.

    day of year base1

      One-based number of days into the year of the date. yeardaybase1 does
      the same thing.

    full

      A full string representation of the date, e.g. 04:48:01 pm, Tue Apr
      10, 2001. You can assign just about any common date and/or time
      format to this property.

      Please take the previous statement as a challenge. I've aggressively
      tried to find formats that EzDate can't understand. When I've found
      one, I've modified the code to accomodate it. If you have some
      reasonably unambiguous date format that EzDate is unable to parse
      correctly, please send it to me. -Miko

      When assigning a full date/time string, you can use 'noon' and
      'midnight' to indicate specific times. So, for example, this string
      indicates July 25, 2003 and noon:

       $mydate = Date::EzDate->new('July 23 2003 noon');
       print $mydate->{'full'}; # outputs Wed Jul 23, 2003 12:00:00

    dayandtime

      Outputs the date and the time (to minute granularity).

       $mydate = Date::EzDate->new('December 23 2003 17:45');
       print $mydate->{'dayandtime'}; # outputs Dec 23 2003, 5:45pm

      dayandtime is the default output format.

    dmy

      The day, month and year representation of the date, e.g. 03JUN2004.

    dayparam

      Returns the day of the month, the short month name (lowercased), and
      the full year. dayparam is a convenient string for passing as a
      parameter to scripts. It consists of just alphanumerics (so it need
      not be escaped in any way), it is easily human readable, and is
      completely unambiguous.

      Actually, dayparam looks about the same as dmy, but it lowercased.

       $date = Date::EzDate->new('Dec 1, 2004 12:54:15');
       print $date->{'dayparam'}; # outputs 01dec2004

    military time, miltime

      The time formatted as HHMM on a 24 hour clock. For example, 2:20 PM
      is 1420.

    clocktime

      The time formatted as HH::MM AM/PM.

    minute of day

      How many minutes since midnight. Useful for doing math with times in
      a day.

    iso8601

      Returns the date in the format YYYY-MM-DD HH:MM:SS.

 Epoch properties

    The following properties allow you to do date calculations at different
    granularities. All of these properties are both readable and writable.

    epoch second

      The basic Perl epoch integer.

    epoch hour

      How many hours since the epoch.

    epoch minute

      How many minutes since the epoch.

    epoch day

      How many days since the epoch.

 Read-only properties

    The following properties are read-only and will crash if you try to
    assign to them.

    is leap year

      True if the year is a leap year. The "is" part is optional.

    days in month

      How many days in the month.

CUSTOM FORMATS

    You'll probably often want to retrieve more than one piece of
    information about a date/time at once. You could, of course, do this by
    getting each property individually and concatenating them together. For
    example, you might want to get the date in the format Monday, June 10,
    2002. You could build that string like this:

     $str =
       $date->{'weekday long'} . ', ' .
       $date->{'month long'} . ' ' .
       $date->{'day of month'} . ', ' .
       $date->{'year'};

    That's a lot of typing, however, and it's difficult to tell from the
    code what the final string will look like. To make life EZ, EzDate
    allows you embed several date properties in a single call. Just
    surround each property with braces:

     $str = $date->{'{weekday long}, {month long} {day of month}, {year}'};

 Storing custom formats

    EzDate allows you to store your custom date formats for repeated calls.
    This comes in handy for formats that are needed in several places
    throughout a project. For example, suppose you want all your dates in
    the format Monday, June 10, 2002. Of course, you could output them
    using a format string like in the example above, but even that will get
    tiring if you need to output the same format in several places. Much
    easier would be to set the format once. To do so, just call the
    set_format method with the name of the format and the format itself:

     $date->set_format('myformat', '{weekday long}, {month long} {day of month}, {year}');
     print $date->{'myformat'}, "\n";

    You can also create a custom format by simply assigning the format to
    its name. If EzDate sees a { in the value being assigned, it knows that
    you are assigning a format, not a date. The set_format line above could
    be written like this:

     $date->{'myformat'} = '{weekday long}, {month long} {day of month}, {year}';

 Un*x-style date formatting

    To make the Unix types happy you can format your dates using standard
    Un*x date codes. The format string must contain at least one % or
    EzDate won't know it's a format string. For example, you could output a
    date like this:

     print $mydate->{'%h %d, %Y %k:%M %p'}, "\n";

    which would give you something like this:

     Oct 31, 2001 02:43 pm

    Following is a list of codes. * indicates that the code acts
    differently than standard Unix codes. x indicates that the code does
    not exists in standard Unix codes.

     %a   weekday, short                               Mon
     %A   weekday, long                                Monday
     %b * hour, 12 hour format, no leading zero        2
     %B * hour, 24 hour format, no leading zero        2
     %c   full date                                    Mon Aug 10 14:40:38
     %d   numeric day of the month                     10
     %D   date as month/date/year                      08/10/98
     %e x numeric month, 1 to 12, no leading zero      8
     %f x numeric day of month, no leading zero        3
     %h   short month                                  Aug
     %H   hour 00 to 23                                14
     %j   day of the year, 001 to 366                  222
     %k   hour, 12 hour format                         14
     %m   numeric month, 01 to 12                      08
     %M   minutes                                      40
     %n   newline
     %P x AM/PM                                        PM
     %p * am/pm                                        pm
     %r   hour:minute:second AM/PM                     02:40:38 PM
     %s   number of seconds since start of 1970        902774438
     %S   seconds                                      38
     %t   tab
     %T   hour:minute:second (24 hour format)          14:40:38
     %w   numeric day of the week, 0 to 6, Sun is 0    1
     %y   last two digits of the year                  98
     %Y   four digit year                              1998
     %%   percent sign                                 %

EXTENDING

    If you plan on using the same custom formats in several different
    places in your project, you might find it easier to super-class EzDate
    so that your formats are loaded automatically whenever an object is
    created.

    To super-class EzDate, it is actually necessary to super-class two
    classes: Date::EzDate and Date::EzDate::Tie. For example, suppose you
    want to create a class called MyDateClass. To do that, create a file
    called MyDateClass.pm, store it in the root of one of the directories
    in your @INC path. Then put both MyDateClass and MyDateClass::Tie
    packages in that file. The following code can be used as a working
    template for super-classing EzDate. Notice that we override the
    after_create() method in order to add a custom format. after_create()
    is called by the new method after the new object has been created but
    before it is returned.

     package MyDateClass;
     use strict;
     use Date::EzDate;
     use vars qw(@ISA);
     @ISA = ('Date::EzDate');
    
     # override after_create
     sub after_create {
       my ($self) = @_;
       $self->set_format('myformat', '{weekdaylong}, {monthlong} {dayofmonth}, {year}');
     }
    
     ##############################################################
     package MyDateClass::Tie;
     use strict;
     use vars qw(@ISA);
     @ISA = ('Date::EzDate::Tie');
    
     # return true
     1;

    You can then load your class with code like this:

     use MyDateClass;
     my ($date, $str);
    
     $date = MyDateClass->new();
     print $date->{'myformat'}, "\n";

    EzDate is really two packages in one: the public object, and the
    private tied hash (which is where all the date info is stored). If you
    want to add a public method, add it in the main class (e.g.
    MyDateClass, not MyDateClass::Tie). Usually in those situations you'll
    need to use the private tied hash object (i.e. the object used
    internally by the tying mechanism). To get to that tied object, used
    the tied method, like this:

     sub my_method {
        my ($self) = @_;
        my $ob = tied(%{$self});
    
        # do stuff with $self and $ob
     }

LIMITATIONS, KNOWN/SUSPECTED BUGS

    The routine for setting the year has an off-by-one problem which is
    kludgly fixed but which I haven't been able to properly solve.

    EzDate is entirely based on the localtime() and timelocal() functions,
    so it inherits their limitations. On my computer that means it can't
    handle dates before Jan 1, 1902 or after Dec 31, 2037. Your mileage may
    vary.

TO DO

    The following list itemizes features I'd like to add to EzDate.

    Time zone properties

      The current version does not address time zone issues. Frankly, I
      haven't been able to figure out how best to deal with them. I'd like
      a system where the object knows what time zone it's in and if it's
      daylight savings time. Changing to another time zone changes the
      other properties such that the object is in the same moment in time
      in the new time zone as it was in the old time zone. For example, if
      the object represents 5pm in the Eastern Time Zone (e.g. where New
      York City is) and its time zone is changed to Pacific Time (e.g.
      where Los Angeles is) then the object would have a time of 2pm.

    Assignment based on format

      Right now the formatted string feature is read-only. It might be
      useful if the date could be assigned based on a format. So, for
      example, you could set the date as Nov 1, 2001 like this:

       $mydate->{'%h %d %Y'} = 'Nov 1 2001';

      This would come in handy when dealing with weirdly formatted dates.
      However, EzDate is already quite robust about handling weirdly
      formatted dates, so this feature is not as pressingly needed as it
      might seem.

    Next weekday

      I'd like a function for moving the date forward (or backward) to the
      next (previous) day of a week.

    Time interval object

      An EzDate object represents a point in time. I'd also like to have an
      object that represents an interval of time. For example, an interval
      object could represent "2 days, 3 hours, 18 seconds". An object like
      that could then be used for calculating the difference between two
      dates.

      I'm currently working on this feature.

    Greater range of available dates

      Currently EzDate inherits the limitations of localtime, which
      generally means it can't handle dates before about 1902 or after
      about 2037. I'd like to stretch EzDate so it can handle a greater
      range of dates. Ideally, it should handle dates from the Big Bang to
      the Big Crunch, but let's start with recorded human history.

TERMS AND CONDITIONS

    Copyright (c) 2001-2003 by Miko O'Sullivan. All rights reserved. This
    program is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself. This software comes with NO
    WARRANTY of any kind.

AUTHORS

    Miko O'Sullivan miko@idocs.com

    DST patch submitted by Greg Estep.

VERSION

    Version: 1.16

HISTORY

    Version 0.90 November 1, 2001

      Initial release

    Version 0.91 December 10, 2001

      UI enhancements

    Version 0.92 January 15, 2002

      Fixed some bugs

    Version 0.93 February 11, 2002

      Fixed some more bugs

    Version 1.00 July 5, 2002

      Fixed a bug in next_month.

      Added a lotta functionality:

      - Space insensitive property names

      - Custom formats using braced property names

      - Stored custom formats

      - More supportive of super-classing

      - All that and yet actually decreased the volume of code

      - Decided this sucker's ready for 1.00 release

      Also made a few minor not-so-backward-compatible changes:

      - Got rid of the printabledate and printabletime properties, which
      were just relics from an early project that used EzDate.

      - Changed nextmonth to next_month to stay compatible with other
      methods that were added and will be added.

    Version 1.01 Aug 14, 2002

      - Fixed bug that clones do not return formats

      - Tightened up the code a little

    Version 1.02 Sep 03, 2002

      - Added ability to set a format by just assigning it to a key

      - Added warnings to situations where the IM in DWIM isn't always
      clear.

      - Added stringification of EzDate object

      - Added overloaded comparison operators

      - Made not-backward-compatible change to the full format.

      - Improved efficiency of custom formats

    Version 1.04 Sep 03, 2002

      - Added ordinals

      - Added "noon" and "midnight" keywords.

    Version 1.05 Dec 11, 2002

      - Added format yyyy-mm-dd

      - Added feature that if Date::EzDate->new() is called with an
      unrecognized format, then undef is returned. This allows you to check
      formats for validity.

      - Fixed off-by-one problem that occurred when, for example, moving
      Jan 1, 2003 back one year to 2002

    Version 1.06 Mar 11, 2003

      - Non-backwards compatible change: changed $compare global to
      $overload.

      - Non-backwards compatible change: EzDate objects now stringify to
      the "default" format instead of the "full" format.

      - Added overloading of addition and subtraction.

      - Added recognition of the following time format, which is used by
      PostGreSql: 2003-02-13 12:35:49.480975-05

      - Fixed bug in which days of DST changeover produced off-by-one
      problem when setting hours.

      - Fixed bug in which the epochday value for dates before the epoch
      are off-by-one.

    Version 1.07 May 21, 2003

      - Implemented fix for DST problem. Used patch submitted by Greg
      Estep. Thanks Greg!

    Version 1.08 June 10, 2003

      - Changed test.pl: removed test that incorrectly relied on the host
      having a specific epoch. No change to the module itself.

    Version 1.09

      - Fixed daylight savings time, again. This time I think the fix will
      actually fix it. Sheesh.

      - Added dayparam as built-in format.

      - Fixed bug: system did not recognize "day of week short" in all the
      places it should.

      - Added some default formats: fullday, fulldate, dayandtime

      - changed default format to dayandtime

      - Fixed some bogus documentation.

      - Fixed bug such that new method dies on invalid date format even
      when it is supposed to just give a warning.

      - Added date_range_string, time_range_string, methods

      - Removing MANY tests from test.pl. I discovered that the tests that
      were failing were not proper tests for the module.

      - Fixed monthnum issue. Now you can set monthnum to any integer, and
      it will roll the month forward or backwards that many times. The
      resulting monthnum will still always be from 0..11.

      - Clarified example of using $Date::EzDate::overload

    Version 1.10

      - Removed Debug::ShowStuff call from module. That shouldn't have been
      in the distribution.

    Version 1.11

      This version had been considered the final release of Date::EzDate.
      However, as of verson 1.12 it is active again.

    Version 1.12 June 12, 2012

      In version 1.11 I had stated that Date::EzDate would no longer be
      developed further or supported. Basically, I changed my mind and am
      now developing it again.

      - Added date format "Tue Jun 12 13:03:28 2012".

    Version 1.13

      - Minor tidying up of documentation.

    Version 1.14

      - Minor tidying up of documentation.

      - Fixing some prerequisite issues.

    Version 1.15 January 2, 2015

      Fixed tests so that they use test names.

    Version 1.16 January 4, 2015

      No changes to module itself. Added some debugging information to the
      test names in the tests.