Date-Manip
view release on metacpan or search on metacpan
lib/Date/Manip/Recur.pod view on Meta::CPAN
the recurring event occurs in this range may NOT be the 0th occurrence
with respect to the base date, and that is allowed.
NOTE: both dates in the range and the base date must all be in the
same time zone, and use the same L<Date::Manip::Base> object.
An alternate definition of the range may also be used to specify that
the recurring events based only on the interval and BEFORE any
modifiers are applied fall in the range.
This definition is described in more detail below.
=back
=head1 FREQUENCY NOTATION
The syntax for specifying a frequency requires some explanation. It is
very concise, but contains the flexibility to express every single
type of recurring event I could think of.
The syntax of the frequency description is a colon separated list of
the format Y:M:W:D:H:MN:S (which stand for year, month, week, etc.).
One (and only one) of the colons may optionally be replaced by an
asterisk, or an asterisk may be prepended to the string. For example,
the following are all valid frequency descriptions:
1:2:3:4:5:6:7
1:2*3:4:5:6:7
*1:2:3:4:5:6:7
But the following are NOT valid because they contain more than one
asterisk:
1:2*3:4:5*6:7
*1:2:3:4:5:6*7
When an asterisk is included, the portion to the left of it is called
the interval, and refers to an approximate time interval between
recurring events. For example, if the interval of the frequency is:
1:2*
it means that the recurring event occurs approximately every 1 year
and 2 months. The interval is approximate because elements to the right of
the asterisk, as well as any modifiers included in the recurrence, will
affect when the events actually occur.
If no asterisks are included, then the entire recurrence is an interval.
For example,
0:0:0:1:12:0:0
refers to an event that occurs every 1 day, 12 hours.
The format of the interval is very simple. It is colon separated digits
only. No other characters are allowed.
The portion of the frequency that occur after an asterisk is called
the recurrence time (or rtime), and refers to a specific value (or
values) for that type of time element (i.e. exactly as it would appear
on a calendar or a clock). For example, if the frequency ends with
the rtime:
*12:0:0
then the recurring event occurs at 12:00:00 (noon).
For example:
0:0:0:2*12:30:0 every 2 days at 12:30 (each day)
Elements in the rtime can be listed as single values, ranges (2
numbers separated by a dash "-"), or a comma separated list of values
or ranges. In some cases, negative values are appropriate for the
week or day values. -1 stands for the last possible value, -2 for the
second to the last, etc.
If multiple values are included in more than one field in the rtime,
every possible combination will be used. For example, if the frequency
ends with the rtime:
*12-13:0,30:0
the event will occur at 12:00, 12:30, 13:00, and 13:30.
Some examples are:
0:0:0:1*2,4,6:0:0 every day at at 02:00, 04:00, and 06:00
0:0:0:2*12-13:0,30:0 every other day at 12:00, 12:30, 13:00,
and 13:30
0:1:0*-1:0:0:0 the last day of every month
*1990-1995:12:0:1:0:0:0
Dec 1 in 1990 through 1995
There is no way to express the following with a single recurrence:
every day at 12:30 and 1:00
You have to use two recurrences to do this.
You can include negative numbers in ranges. For example, including the
range -2--1 means to go from the 2nd to the last to the last
occurrence. Negative values are only supported in the week and
day fields, and only in some cases.
You can even use a range like 2--2 (which means to go from the 2nd to
the 2nd to the last occurrence). However, this is STRONGLY discouraged
since this leads to a date which produces a variable number of events.
As a result, the only way to determine the Nth date is to calculate
every date starting at the base date. If you know that every date
produces exactly 4 recurring events, you can calculate the Nth date
without needing to determine every intermediate date.
When specifying a range, the first value must be less than the second
or else nothing will be returned.
When both the week and day elements are non-zero and the day is right
of the asterisk, the day refers to the day of week. The following
examples illustrate these type of frequencies:
0:1*4:2:0:0:0 4th Tuesday (day 2) of every month
lib/Date/Manip/Recur.pod view on Meta::CPAN
on where the asterisk occurs, and which leading elements (year, month,
week) have non-zero values. It can refer to the day of the week, day
of the month, or day of the year.
When the asterisk occurs before the week element, the week element of
the frequency can also take on multiple meanings as well. When the month
field and day fields are zero, it refers to the week of the year. Since
the week of the year is well defined in the ISO 8601 spec, there is
no ambiguity.
When the month field is zero, but the day field is not, the week field
refers to the nth occurrence of the day of week referred to by the
day field in the year.
When the month field is non-zero, the week field refers to the nth
occurrence of the day of week in the month.
In the tables below only the first 4 elements of the frequency are
shown. The actual frequency will include the hour, minute, and second
elements in addition to the ones shown.
When all elements left of the asterisk are 0, the interval is such
that it occurs the maximum times possible (without changing the type
of elements to the right of the asterisk). Another way of looking at
it is that the last 0 element of the interval is changed to 1. So, the
interval:
0:0*3:0
is equivalent to
0:1*3:0
When the year field is zero, and is right of the asterisk, it
means the current year.
=over 4
=item B<All elements left of the asterisk>
When all of the month, week, and day elements are left of the
asterisk, the simple definitions of the frequency are used:
frequency meaning
1:2:3:4 every 1 year, 2 months, 3 weeks,
4 days
Any, or all of the fields can be zero.
=item B<Non-zero day, non-zero week>
When both the day and week elements are non-zero, the day element
always refers to the day of week. Values must be in the range (1 to 7)
and no negative values are allowed.
The following tables shows all possible variations of the frequency
where this can happen (where day 4 = Thursday).
When the week is left of the asterisk, the interval is used to get the
weeks on the calendar containing a recurring date, and the day is used
to set the day of the week. The following are possible:
frequency meaning
1:2:3*4 every 1 year, 2 months, 3 weeks
on Thur
1:0:3*4 every 1 year, 3 weeks on Thur
0:2:3*4 every 2 months, 3 weeks on Thur
0:0:3*4 every 3 weeks on Thur
When the week is right of the asterisk, and a non-zero month is left of the
asterisk, the recurrence refers to a specific occurrence of a day-of-week
during a month. The following are possible:
frequency meaning
1:2*3:4 every 1 year, 2 months on the
3rd Thursday of the month
0:2*3:4 every 2 months on the 3rd Thur
of the month
When the week and month are both non-zero and right of the asterisk, the
recurrence refers to an occurrence of day-of-week during the given month.
Possibilities are:
frequency meaning
1*2:3:4 every 1 year in February on
the 3rd Thur
0*2:3:4 same as 1*2:3:4
*1:2:3:4 in Feb 0001 on the 3rd Thur
of the month
*0:2:3:4 on the 3rd Thur of Feb in the
current year
When the week is right of the asterisk, and the month is zero, the
recurrence refers to an occurrence of the day-of-week during the
year. The following are possible:
frequency meaning
1:0*3:4 every 1 year on the 3rd Thursday
1*0:3:4 of the year
*1:0:3:4 in 0001 on the 3rd Thur of
the year
0*0:3:4 same as 1*0:3:4
*0:0:3:4 on the 3rd Thur of the current
year
There is one special case:
lib/Date/Manip/Recur.pod view on Meta::CPAN
approximate date-delta calculations, calculations are done with
$subtract = 2.
=item B<next>
=item B<prev>
($date,$err) = $recur->next();
($date,$err) = $recur->prev();
These return the next/previous recurring event.
The first time next/prev is called, one of the recurring events
will be selected and returned (using the rules discussed below).
Subsequent calls to next/prev will return the next or previous
event.
Unlike the B<nth> method which will return a specific event (or
undef if the Nth even is not defined), the next and prev methods
will only work with defined events.
So, for the recurrence:
the 31st of every month
next might return the following sequence of events:
Jan 31 2000
Mar 31 2000
May 31 2000
The rules for determining what event to return the first time one
of these is called are as follows:
1) If there is a range, next will return the first event that occurs
after the start of the range. prev will return the last event that
occurs before the end of the range.
2) If there is no range, next will return the first event on or after
the base date. prev will return the last event before the base date.
The error codes are the same as for the nth method.
=back
=head1 HISTORY OF THE FREQUENCY NOTATION
I realize that the frequency notation described above looks quite
complicated at first glance, but it is (IMO) the best notation for
expressing recurring events in existence. I actually consider it the
single most important contribution to date/time handling in
Date::Manip.
When I first decided to add recurring events to Date::Manip, I first
came up with a list of common ways of specifying recurring events, and
then went looking for a notation that could be used to define them. I
was hoping for a notation that would be similar to cron notation, but
more powerful.
After looking in several specifications (including ISO 8601) and after
a discussion on a mailing list of calendar related topics, it appeared
that there was no concise, flexible notation for handling recurring
events that would handle all of the common forms I'd come up with.
So, as a matter of necessity, I set about inventing my own notation.
As I was looking at my list, it struck me that all of the parts which
specified a frequency were higher level (i.e. referred to a larger
unit of time) than those parts which specified a specific value (what
I've called the rtime). In other words, when the terms were laid out
from year down to seconds, the frequency part was always left of
specific values.
That led immediately to the notation described above, so I started analyzing
it to figure out if it could express all of the recurring events I'd
come up with. It succeeded on 100% of them. Not only that, but by playing
with different values (especially different combinations of m/w/d values), I
found that it would define recurring events that I hadn't even thought of,
but which seemed perfectly reasonable in hindsight.
After a very short period, I realized just how powerful this notation was,
and set about implementing it, and as I said above, of all the contributions
that Date::Manip has made, I consider this to be the most important.
=head1 KNOWN BUGS
If you specify a recurrence which cannot be satisfied for the base date,
or for any time after the base date, the recurrence will crash. This
can only happen if you specify a recurrence that always occurs in the
spring DST transition using the current timezone rules.
For example, in a US timezone, the current timezone rules state that a
DST transition occurs at 02:00:00 on the 2nd Sunday in March and the
clock jumps to 03:00. This started in 2006. As a result, the recurrence
1*3:2:7:2:0:0
with a base date of 2006 or later cannot be satisfied.
=head1 BUGS AND QUESTIONS
Please refer to the L<Date::Manip::Problems> documentation for
information on submitting bug reports or questions to the author.
=head1 SEE ALSO
L<Date::Manip> - main module documentation
=head1 LICENSE
This script is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
Sullivan Beck (sbeck@cpan.org)
=cut
( run in 0.813 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )