summaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
authorniemeyer <>2003-10-09 03:11:46 +0000
committerniemeyer <>2003-10-09 03:11:46 +0000
commita8102477a48fe0a5ccfebbfbb99c08c7c8157cb3 (patch)
treea27a3ebf365f457d6a519df8a834c09176f42574 /README
parentcc77d438c8f634fe250f89372f9dccdb6974f125 (diff)
downloaddateutil-a8102477a48fe0a5ccfebbfbb99c08c7c8157cb3.tar.gz
- Renamed dateutil.moin to README.
- Other packaging ajustments.
Diffstat (limited to 'README')
-rw-r--r--README1765
1 files changed, 1765 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..54b2148
--- /dev/null
+++ b/README
@@ -0,0 +1,1765 @@
+## This file is in the moin format. The latest version is found
+## at https://moin.conectiva.com.br/DateUtil
+
+== Contents ==
+[[TableOfContents]]
+
+== Description ==
+The '''dateutil''' module provides powerful extensions to
+the standard '''datetime''' module, available in Python 2.3+.
+
+== Features ==
+
+ * Computing of relative deltas (next month, next year,
+ next monday, last week of month, etc);
+
+ * Computing of relative deltas between two given
+ date and/or datetime objects;
+
+ * Computing of dates based on very flexible recurrence rules,
+ using a superset of the
+ [ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar]
+ specification. Parsing of RFC strings is supported as well.
+
+ * Generic parsing of dates in almost any string format;
+
+ * Timezone (tzinfo) implementations for tzfile(5) format
+ files (/etc/localtime, /usr/share/zoneinfo, etc), TZ
+ environment string (in all known formats), iCalendar
+ format files, given ranges (with help from relative deltas),
+ local machine timezone, fixed offset timezone, and UTC timezone.
+
+ * Computing of Easter Sunday dates for any given year,
+ using Western, Orthodox or Julian algorithms;
+
+ * More than 400 test cases.
+
+== Download ==
+ * attachment:python-dateutil-0.1.tar.bz2
+
+== Author ==
+GustavoNiemeyer <niemeyer@conectiva.com>
+
+== Documentation ==
+The following modules are available.
+
+=== relativedelta ===
+This module offers the '''relativedelta''' type, which is based
+on the specification of the excelent work done by M.-A. Lemburg in his
+[http://www.egenix.com/files/python/mxDateTime.html mxDateTime]
+extension. However, notice that this type '''does not''' implement the
+same algorithm as his work. Do not expect it to behave like
+{{{mxDateTime}}}'s counterpart.
+
+==== relativedelta type ====
+
+There's two different ways to build a relativedelta instance. The
+first one is passing it two {{{date}}}/{{{datetime}}} instances:
+{{{
+relativedelta(datetime1, datetime2)
+}}}
+
+This will build the relative difference between {{{datetime1}}} and
+{{{datetime2}}}, so that the following constraint is always true:
+{{{
+datetime2+relativedelta(datetime1, datetime2) == datetime1
+}}}
+
+Notice that instead of {{{datetime}}} instances, you may use
+{{{date}}} instances, or a mix of both.
+
+And the other way is to use any of the following keyword arguments:
+
+ year, month, day, hour, minute, seconds, microseconds::
+ Absolute information.
+
+ years, months, weeks, days, hours, minutes, seconds, microseconds::
+ Relative information, may be negative.
+
+ weekday::
+ One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These
+ instances may receive a parameter {{{n}}}, specifying the {{{n}}}th
+ weekday, which could be positive or negative (like {{{MO(+2)}}} or
+ {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}.
+ You can also use an integer, where {{{0=MO}}}. Notice that,
+ for example, if the calculated date is already Monday, using
+ {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context),
+ won't change the day.
+
+ leapdays::
+ Will add given days to the date found, but only if the computed
+ year is a leap year and the computed date is post 28 of february.
+
+ yearday, nlyearday::
+ Set the yearday or the non-leap year day (jump leap days).
+ These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}}
+ information.
+
+==== Behavior of operations ====
+If you're curious about exactly how the relative delta will act
+on operations, here is a description of its behavior.
+
+ 1. Calculate the absolute year, using the {{{year}}} argument, or the
+ original datetime year, if the argument is not present.
+ 1. Add the relative {{{years}}} argument to the absolute year.
+ 1. Do steps 1 and 2 for {{{month}}}/{{{months}}}.
+ 1. Calculate the absolute day, using the {{{day}}} argument, or the
+ original datetime day, if the argument is not present. Then, subtract
+ from the day until it fits in the year and month found after their
+ operations.
+ 1. Add the relative {{{days}}} argument to the absolute day. Notice
+ that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}.
+ 1. If {{{leapdays}}} is present, the computed year is a leap year, and
+ the computed month is after february, remove one day from the found date.
+ 1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}},
+ {{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}.
+ 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th
+ occurrence of the given weekday.
+
+==== Examples ====
+
+Let's begin our trip.
+{{{
+>>> from datetime import *; from dateutil.relativedelta import *
+>>> import calendar
+}}}
+
+Store some values.
+{{{
+>>> NOW = datetime.now()
+>>> TODAY = date.today()
+>>> NOW
+datetime.datetime(2003, 9, 17, 20, 54, 47, 282310)
+>>> TODAY
+datetime.date(2003, 9, 17)
+}}}
+
+Next month.
+{{{
+>>> NOW+relativedelta(months=+1)
+datetime.datetime(2003, 10, 17, 20, 54, 47, 282310)
+}}}
+
+Next month, plus one week.
+{{{
+>>> NOW+relativedelta(months=+1, weeks=+1)
+datetime.datetime(2003, 10, 24, 20, 54, 47, 282310)
+}}}
+
+Next month, plus one week, at 10am.
+{{{
+>>> TODAY+relativedelta(months=+1, weeks=+1, hour=10)
+datetime.datetime(2003, 10, 24, 10, 0)
+}}}
+
+Let's try the other way around. Notice that the
+hour setting we get in the relativedelta is relative,
+since it's a difference, and the weeks parameter
+has gone.
+{{{
+>>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY)
+relativedelta(months=+1, days=+7, hours=+10)
+}}}
+
+One month before one year.
+{{{
+>>> NOW+relativedelta(years=+1, months=-1)
+datetime.datetime(2004, 8, 17, 20, 54, 47, 282310)
+}}}
+
+How does it handle months with different numbers of days?
+Notice that adding one month will never cross the month
+boundary.
+{{{
+>>> date(2003,1,27)+relativedelta(months=+1)
+datetime.date(2003, 2, 27)
+>>> date(2003,1,31)+relativedelta(months=+1)
+datetime.date(2003, 2, 28)
+>>> date(2003,1,31)+relativedelta(months=+2)
+datetime.date(2003, 3, 31)
+}}}
+
+The logic for years is the same, even on leap years.
+{{{
+>>> date(2000,2,28)+relativedelta(years=+1)
+datetime.date(2001, 2, 28)
+>>> date(2000,2,29)+relativedelta(years=+1)
+datetime.date(2001, 2, 28)
+
+>>> date(1999,2,28)+relativedelta(years=+1)
+datetime.date(2000, 2, 28)
+>>> date(1999,3,1)+relativedelta(years=+1)
+datetime.date(2000, 3, 1)
+
+>>> date(2001,2,28)+relativedelta(years=-1)
+datetime.date(2000, 2, 28)
+>>> date(2001,3,1)+relativedelta(years=-1)
+datetime.date(2000, 3, 1)
+}}}
+
+Next friday.
+{{{
+>>> TODAY+relativedelta(weekday=FR)
+datetime.date(2003, 9, 19)
+
+>>> TODAY+relativedelta(weekday=calendar.FRIDAY)
+datetime.date(2003, 9, 19)
+}}}
+
+Last friday in this month.
+{{{
+>>> TODAY+relativedelta(day=31, weekday=FR(-1))
+datetime.date(2003, 9, 26)
+}}}
+
+Next wednesday (it's today!).
+{{{
+>>> TODAY+relativedelta(weekday=WE(+1))
+datetime.date(2003, 9, 17)
+}}}
+
+Next wednesday, but not today.
+{{{
+>>> TODAY+relativedelta(days=+1, weekday=WE(+1))
+datetime.date(2003, 9, 24)
+}}}
+
+Following
+[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation]
+find the first day of the 15th week of 1997.
+{{{
+>>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14)
+datetime.datetime(1997, 4, 7, 0, 0)
+}}}
+
+How long ago has the millennium changed?
+{{{
+>>> relativedelta(NOW, date(2001,1,1))
+relativedelta(years=+2, months=+8, days=+16, hours=+20, minutes=+54, seconds=+47, microseconds=+282310)
+}}}
+
+How old is John?
+{{{
+>>> johnbirthday = datetime(1978, 4, 5, 12, 0)
+>>> relativedelta(NOW, johnbirthday)
+relativedelta(years=+25, months=+5, days=+12, hours=+8, minutes=+54, seconds=+47, microseconds=+282310)
+}}}
+
+It works with dates too.
+{{{
+>>> relativedelta(TODAY, johnbirthday)
+relativedelta(years=+25, months=+5, days=+11, hours=+12)
+}}}
+
+Obtain today's date using the yearday:
+{{{
+>>> date(2003, 1, 1)+relativedelta(yearday=260)
+datetime.date(2003, 9, 17)
+}}}
+
+We can use today's date, since yearday should be absolute
+in the given year:
+{{{
+>>> TODAY+relativedelta(yearday=260)
+datetime.date(2003, 9, 17)
+}}}
+
+Last year it should be in the same day:
+{{{
+>>> date(2002, 1, 1)+relativedelta(yearday=260)
+datetime.date(2002, 9, 17)
+}}}
+
+But not in a leap year:
+{{{
+>>> date(2000, 1, 1)+relativedelta(yearday=260)
+datetime.date(2000, 9, 16)
+}}}
+
+We can use the non-leap year day to ignore this:
+{{{
+>>> date(2000, 1, 1)+relativedelta(nlyearday=260)
+datetime.date(2000, 9, 17)
+}}}
+
+=== rrule ===
+The rrule module offers a small, complete, and very fast, implementation
+of the recurrence rules documented in the
+[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including
+support for caching of results.
+
+==== rrule type ====
+That's the base of the rrule operation. It accepts all the keywords
+defined in the RFC as its constructor parameters (except {{{byday}}},
+which was renamed to {{{byweekday}}}) and more. The constructor
+prototype is:
+{{{
+rrule(freq)
+}}}
+
+Where {{{freq}}} must be one of {{{FREQ_YEARLY}}}, {{{FREQ_MONTHLY}}},
+{{{FREQ_WEEKLY}}}, {{{FREQ_DAILY}}}, {{{FREQ_HOURLY}}}, {{{FREQ_MINUTELY}}},
+or {{{FREQ_SECONDLY}}}.
+
+Additionally, it supports the following keyword arguments:
+
+ cache::
+ If given, it must be a boolean value specifying to enable
+ or disable caching of results. If you will use the same
+ {{{rrule}}} instance multiple times, enabling caching will
+ improve the performance considerably.
+
+ dtstart::
+ The recurrence start. Besides being the base for the
+ recurrence, missing parameters in the final recurrence
+ instances will also be extracted from this date. If not
+ given, {{{datetime.now()}}} will be used instead.
+
+ interval::
+ The interval between each {{{freq}}} iteration. For example,
+ when using {{{FREQ_YEARLY}}}, an interval of {{{2}}} means
+ once every two years, but with {{{FREQ_HOURLY}}}, it means
+ once every two hours. The default interval is {{{1}}}.
+
+ wkst::
+ The week start day. Must be one of the {{{MO}}}, {{{TU}}},
+ {{{WE}}} constants, or an integer, specifying the first day
+ of the week. This will affect recurrences based on weekly
+ periods. The default week start is got from
+ {{{calendar.firstweekday()}}}, and may be modified by
+ {{{calendar.setfirstweekday()}}}.
+
+ count::
+ How many occurrences will be generated.
+
+ until::
+ If given, this must be a {{{datetime}}} instance, that will
+ specify the limit of the recurrence. If a recurrence instance
+ happens to be the same as the {{{datetime}}} instance given
+ in the {{{until}}} keyword, this will be the last occurrence.
+
+ bysetpos::
+ If given, it must be either an integer, or a sequence of
+ integers, positive or negative. Each given integer will
+ specify an occurrence number, corresponding to the nth
+ occurrence of the rule inside the frequency period. For
+ example, a {{{bysetpos}}} of {{{-1}}} if combined with a
+ {{{FREQ_MONTHLY}}} frequency, and a {{{byweekday}}} of
+ {{{(MO, TU, WE, TH, FR)}}}, will result in the last work
+ day of every month.
+
+ bymonth::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the months to apply the recurrence to.
+
+ bymonthday::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the month days to apply the recurrence to.
+
+ byyearday::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the year days to apply the recurrence to.
+
+ byweekno::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the week numbers to apply the recurrence
+ to. Week numbers have the meaning described in ISO8601,
+ that is, the first week of the year is that containing at
+ least four days of the new year.
+
+ byweekday::
+ If given, it must be either an integer ({{{0 == MO}}}), a
+ sequence of integers, one of the weekday constants
+ ({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants.
+ When given, these variables will define the weekdays where
+ the recurrence will be applied. It's also possible to use
+ an argument {{{n}}} for the weekday instances, which will
+ mean the {{{n}}}''th'' occurrence of this weekday in the
+ period. For example, with {{{FREQ_MONTHLY}}}, or with
+ {{{FREQ_YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}}
+ in {{{byweekday}}} will specify the first friday of the
+ month where the recurrence happens. Notice that in the RFC
+ documentation, this is specified as {{{BYDAY}}}, but was
+ renamed to avoid the ambiguity of that keyword.
+
+ byhour::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the hours to apply the recurrence to.
+
+ byminute::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the minutes to apply the recurrence to.
+
+ bysecond::
+ If given, it must be either an integer, or a sequence of
+ integers, meaning the seconds to apply the recurrence to.
+
+ byeaster::
+ If given, it must be either an integer, or a sequence of
+ integers, positive or negative. Each integer will define
+ an offset from the Easter Sunday. Passing the offset
+ {{{0}}} to {{{byeaster}}} will yield the Easter Sunday
+ itself. This is an extension to the RFC specification.
+
+==== rrule methods ====
+The following methods are available in {{{rrule}}} instances:
+
+ rrule.before(dt, inc=False)::
+ Returns the last recurrence before the given {{{datetime}}}
+ instance. The {{{inc}}} keyword defines what happens if
+ {{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
+ if {{{dt}}} itself is an occurrence, it will be returned.
+
+ rrule.after(dt, inc=False)::
+ Returns the first recurrence after the given {{{datetime}}}
+ instance. The {{{inc}}} keyword defines what happens if
+ {{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
+ if {{{dt}}} itself is an occurrence, it will be returned.
+
+ rrule.between(after, before, inc=False)::
+ Returns all the occurrences of the rrule between {{{after}}}
+ and {{{before}}}. The {{{inc}}} keyword defines what happens
+ if {{{after}}} and/or {{{before}}} are themselves occurrences.
+ With {{{inc == True}}}, they will be included in the list,
+ if they are found in the recurrence set.
+
+
+==== Notes ====
+
+ * The rrule type has no {{{byday}}} keyword. The equivalent keyword
+ has been replaced by the {{{byweekday}}} keyword, to remove the
+ ambiguity present in the original keyword.
+
+ * Unlike documented in the RFC, the starting datetime ({{{dtstart}}})
+ is not the first recurrence instance, unless it does fit in the
+ specified rules. In a python module context, this behavior makes more
+ sense than otherwise. Notice that you can easily get the original
+ behavior by using a rruleset and adding the {{{dtstart}}} as an
+ {{{rdate}}} recurrence.
+
+ * Unlike documented in the RFC, every keyword is valid on every
+ frequency (the RFC documents that {{{byweekno}}} is only valid
+ on yearly frequencies, for example).
+
+ * In addition to the documented keywords, a {{{byeaster}}} keyword
+ was introduced, making it easy to compute recurrent events relative
+ to the Easter Sunday.
+
+==== rrule examples ====
+These examples were converted from the RFC.
+
+Prepare the environment.
+{{{
+>>> from dateutil.rrule import *
+>>> from dateutil.parser import *
+>>> from datetime import *
+
+>>> import pprint
+>>> import sys
+>>> sys.displayhook = pprint.pprint
+}}}
+
+Daily, for 10 occurrences.
+{{{
+>>> list(rrule(FREQ_DAILY, count=10, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 3, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 9, 5, 9, 0),
+ datetime.datetime(1997, 9, 6, 9, 0),
+ datetime.datetime(1997, 9, 7, 9, 0),
+ datetime.datetime(1997, 9, 8, 9, 0),
+ datetime.datetime(1997, 9, 9, 9, 0),
+ datetime.datetime(1997, 9, 10, 9, 0),
+ datetime.datetime(1997, 9, 11, 9, 0)]
+}}}
+
+Daily until December 24, 1997
+{{{
+>>> list(rrule(FREQ_DAILY, dtstart=parse("19970902T090000"), until=parse("19971224T000000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 3, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ (...)
+ datetime.datetime(1997, 12, 21, 9, 0),
+ datetime.datetime(1997, 12, 22, 9, 0),
+ datetime.datetime(1997, 12, 23, 9, 0)]
+}}}
+
+Every other day, 5 occurrences.
+{{{
+>>> list(rrule(FREQ_DAILY, interval=2, count=5, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 9, 6, 9, 0),
+ datetime.datetime(1997, 9, 8, 9, 0),
+ datetime.datetime(1997, 9, 10, 9, 0)]
+}}}
+
+Every 10 days, 5 occurrences.
+{{{
+>>> list(rrule(FREQ_DAILY, interval=10, count=5, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 12, 9, 0),
+ datetime.datetime(1997, 9, 22, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0),
+ datetime.datetime(1997, 10, 12, 9, 0)]
+}}}
+
+Everyday in January, for 3 years.
+{{{
+>>> list(rrule(FREQ_YEARLY, bymonth=1, byweekday=range(7), dtstart=parse("19980101T090000"), until=parse("20000131T090000")))
+[datetime.datetime(1998, 1, 1, 9, 0),
+ datetime.datetime(1998, 1, 2, 9, 0),
+ (...)
+ datetime.datetime(1998, 1, 30, 9, 0),
+ datetime.datetime(1998, 1, 31, 9, 0),
+ datetime.datetime(1999, 1, 1, 9, 0),
+ datetime.datetime(1999, 1, 2, 9, 0),
+ (...)
+ datetime.datetime(1999, 1, 30, 9, 0),
+ datetime.datetime(1999, 1, 31, 9, 0),
+ datetime.datetime(2000, 1, 1, 9, 0),
+ datetime.datetime(2000, 1, 2, 9, 0),
+ (...)
+ datetime.datetime(2000, 1, 29, 9, 0),
+ datetime.datetime(2000, 1, 31, 9, 0)]
+}}}
+
+Same thing, in another way.
+{{{
+>>> list(rrule(FREQ_DAILY, bymonth=1, dtstart=parse("19980101T090000"), until=parse("20000131T090000")))
+(...)
+}}}
+
+Weekly for 10 occurrences.
+{{{
+>>> list(rrule(FREQ_WEEKLY, count=10, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 9, 9, 0),
+ datetime.datetime(1997, 9, 16, 9, 0),
+ datetime.datetime(1997, 9, 23, 9, 0),
+ datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 10, 7, 9, 0),
+ datetime.datetime(1997, 10, 14, 9, 0),
+ datetime.datetime(1997, 10, 21, 9, 0),
+ datetime.datetime(1997, 10, 28, 9, 0),
+ datetime.datetime(1997, 11, 4, 9, 0)]
+}}}
+
+Every other week, 6 occurrences.
+{{{
+>>> list(rrule(FREQ_WEEKLY, interval=2, count=6, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 16, 9, 0),
+ datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 10, 14, 9, 0),
+ datetime.datetime(1997, 10, 28, 9, 0),
+ datetime.datetime(1997, 11, 11, 9, 0)]
+}}}
+
+Weekly on Tuesday and Thursday for 5 weeks.
+{{{
+>>> list(rrule(FREQ_WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), dtstart=parse(
+"19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 9, 9, 9, 0),
+ datetime.datetime(1997, 9, 11, 9, 0),
+ datetime.datetime(1997, 9, 16, 9, 0),
+ datetime.datetime(1997, 9, 18, 9, 0),
+ datetime.datetime(1997, 9, 23, 9, 0),
+ datetime.datetime(1997, 9, 25, 9, 0),
+ datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0)]
+}}}
+
+Every other week on Tuesday and Thursday, for 8 occurrences.
+{{{
+>>> list(rrule(FREQ_WEEKLY, interval=2, count=8, wkst=SU, byweekday=(TU,TH), dts
+tart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 9, 16, 9, 0),
+ datetime.datetime(1997, 9, 18, 9, 0),
+ datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0),
+ datetime.datetime(1997, 10, 14, 9, 0),
+ datetime.datetime(1997, 10, 16, 9, 0)]
+}}}
+
+Monthly on the 1st Friday for ten occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=10, byweekday=FR(1), dtstart=parse("19970905T090000")))
+[datetime.datetime(1997, 9, 5, 9, 0),
+ datetime.datetime(1997, 10, 3, 9, 0),
+ datetime.datetime(1997, 11, 7, 9, 0),
+ datetime.datetime(1997, 12, 5, 9, 0),
+ datetime.datetime(1998, 1, 2, 9, 0),
+ datetime.datetime(1998, 2, 6, 9, 0),
+ datetime.datetime(1998, 3, 6, 9, 0),
+ datetime.datetime(1998, 4, 3, 9, 0),
+ datetime.datetime(1998, 5, 1, 9, 0),
+ datetime.datetime(1998, 6, 5, 9, 0)]
+}}}
+
+Every other month on the 1st and last Sunday of the month for 10 occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, interval=2, count=10, byweekday=(SU(1), SU(-1)), dtstart=parse("19970907T090000")))
+[datetime.datetime(1997, 9, 7, 9, 0),
+ datetime.datetime(1997, 9, 28, 9, 0),
+ datetime.datetime(1997, 11, 2, 9, 0),
+ datetime.datetime(1997, 11, 30, 9, 0),
+ datetime.datetime(1998, 1, 4, 9, 0),
+ datetime.datetime(1998, 1, 25, 9, 0),
+ datetime.datetime(1998, 3, 1, 9, 0),
+ datetime.datetime(1998, 3, 29, 9, 0),
+ datetime.datetime(1998, 5, 3, 9, 0),
+ datetime.datetime(1998, 5, 31, 9, 0)]
+}}}
+
+Monthly on the second to last Monday of the month for 6 months.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=6, byweekday=MO(-2), dtstart=parse("19970922T090000")))
+[datetime.datetime(1997, 9, 22, 9, 0),
+ datetime.datetime(1997, 10, 20, 9, 0),
+ datetime.datetime(1997, 11, 17, 9, 0),
+ datetime.datetime(1997, 12, 22, 9, 0),
+ datetime.datetime(1998, 1, 19, 9, 0),
+ datetime.datetime(1998, 2, 16, 9, 0)]
+}}}
+
+Monthly on the third to the last day of the month, for 6 months.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=6, bymonthday=-3, dtstart=parse("19970928T090000")))
+[datetime.datetime(1997, 9, 28, 9, 0),
+ datetime.datetime(1997, 10, 29, 9, 0),
+ datetime.datetime(1997, 11, 28, 9, 0),
+ datetime.datetime(1997, 12, 29, 9, 0),
+ datetime.datetime(1998, 1, 29, 9, 0),
+ datetime.datetime(1998, 2, 26, 9, 0)]
+}}}
+
+Monthly on the 2nd and 15th of the month for 5 occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=5, bymonthday=(2,15), dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 15, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0),
+ datetime.datetime(1997, 10, 15, 9, 0),
+ datetime.datetime(1997, 11, 2, 9, 0)]
+}}}
+
+Monthly on the first and last day of the month for 3 occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=5, bymonthday=(-1,1,), dtstart=parse("1997090
+2T090000")))
+[datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 10, 1, 9, 0),
+ datetime.datetime(1997, 10, 31, 9, 0),
+ datetime.datetime(1997, 11, 1, 9, 0),
+ datetime.datetime(1997, 11, 30, 9, 0)]
+}}}
+
+Every 18 months on the 10th thru 15th of the month for 10 occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, interval=18, count=10, bymonthday=range(10,16), dtstart=parse("19970910T090000")))
+[datetime.datetime(1997, 9, 10, 9, 0),
+ datetime.datetime(1997, 9, 11, 9, 0),
+ datetime.datetime(1997, 9, 12, 9, 0),
+ datetime.datetime(1997, 9, 13, 9, 0),
+ datetime.datetime(1997, 9, 14, 9, 0),
+ datetime.datetime(1997, 9, 15, 9, 0),
+ datetime.datetime(1999, 3, 10, 9, 0),
+ datetime.datetime(1999, 3, 11, 9, 0),
+ datetime.datetime(1999, 3, 12, 9, 0),
+ datetime.datetime(1999, 3, 13, 9, 0)]
+}}}
+
+Every Tuesday, every other month, 6 occurences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, interval=2, count=6, byweekday=TU, dtstart=parse("1
+9970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 9, 9, 0),
+ datetime.datetime(1997, 9, 16, 9, 0),
+ datetime.datetime(1997, 9, 23, 9, 0),
+ datetime.datetime(1997, 9, 30, 9, 0),
+ datetime.datetime(1997, 11, 4, 9, 0)]
+}}}
+
+Yearly in June and July for 10 occurrences.
+{{{
+>>> list(rrule(FREQ_YEARLY, count=4, bymonth=(6,7), dtstart=parse("19970610T0900
+00")))
+[datetime.datetime(1997, 6, 10, 9, 0),
+ datetime.datetime(1997, 7, 10, 9, 0),
+ datetime.datetime(1998, 6, 10, 9, 0),
+ datetime.datetime(1998, 7, 10, 9, 0)]
+}}}
+
+Every 3rd year on the 1st, 100th and 200th day for 4 occurrences.
+{{{
+>>> list(rrule(FREQ_YEARLY, count=4, interval=3, byyearday=(1,100,200), dtstart=parse("19970101T090000")))
+[datetime.datetime(1997, 1, 1, 9, 0),
+ datetime.datetime(1997, 4, 10, 9, 0),
+ datetime.datetime(1997, 7, 19, 9, 0),
+ datetime.datetime(2000, 1, 1, 9, 0)]
+}}}
+
+Every 20th Monday of the year, 3 occurrences.
+{{{
+>>> list(rrule(FREQ_YEARLY, count=3, byweekday=MO(20), dtstart=parse("19970519T090000")))
+[datetime.datetime(1997, 5, 19, 9, 0),
+ datetime.datetime(1998, 5, 18, 9, 0),
+ datetime.datetime(1999, 5, 17, 9, 0)]
+}}}
+
+Monday of week number 20 (where the default start of the week is Monday),
+3 occurrences.
+{{{
+>>> list(rrule(FREQ_YEARLY, count=3, byweekno=20, byweekday=MO, dtstart=parse("19970512T090000")))
+[datetime.datetime(1997, 5, 12, 9, 0),
+ datetime.datetime(1998, 5, 11, 9, 0),
+ datetime.datetime(1999, 5, 17, 9, 0)]
+}}}
+
+The week number 1 may be in the last year.
+{{{
+>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=1, byweekday=MO, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 12, 29, 9, 0),
+ datetime.datetime(1999, 1, 4, 9, 0),
+ datetime.datetime(2000, 1, 3, 9, 0)]
+}}}
+
+And the week numbers greater than 51 may be in the next year.
+{{{
+>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=52, byweekday=SU, dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 12, 28, 9, 0),
+ datetime.datetime(1998, 12, 27, 9, 0),
+ datetime.datetime(2000, 1, 2, 9, 0)]
+}}}
+
+Only some years have week number 53:
+{{{
+>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=53, byweekday=MO, dtstart=parse("19970902T090000")))
+[datetime.datetime(1998, 12, 28, 9, 0),
+ datetime.datetime(2004, 12, 27, 9, 0),
+ datetime.datetime(2009, 12, 28, 9, 0)]
+}}}
+
+Every Friday the 13th, 4 occurrences.
+{{{
+>>> list(rrule(FREQ_YEARLY, count=4, byweekday=FR, bymonthday=13, dtstart=parse(
+"19970902T090000")))
+[datetime.datetime(1998, 2, 13, 9, 0),
+ datetime.datetime(1998, 3, 13, 9, 0),
+ datetime.datetime(1998, 11, 13, 9, 0),
+ datetime.datetime(1999, 8, 13, 9, 0)]
+}}}
+
+Every four years, the first Tuesday after a Monday in November,
+3 occurrences (U.S. Presidential Election day):
+{{{
+>>> list(rrule(FREQ_YEARLY, interval=4, count=3, bymonth=11, byweekday=TU, bymonthday=(2,3,4,5,6,7,8), dtstart=parse("19961105T090000")))
+[datetime.datetime(1996, 11, 5, 9, 0),
+ datetime.datetime(2000, 11, 7, 9, 0),
+ datetime.datetime(2004, 11, 2, 9, 0)]
+}}}
+
+The 3rd instance into the month of one of Tuesday, Wednesday or
+Thursday, for the next 3 months:
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=3, byweekday=(TU,WE,TH), bysetpos=3, dtstart=parse("19970904T090000")))
+[datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 10, 7, 9, 0),
+ datetime.datetime(1997, 11, 6, 9, 0)]
+}}}
+
+The 2nd to last weekday of the month, 3 occurrences.
+{{{
+>>> list(rrule(FREQ_MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), bysetpos=-2, d
+tstart=parse("19970929T090000")))
+[datetime.datetime(1997, 9, 29, 9, 0),
+ datetime.datetime(1997, 10, 30, 9, 0),
+ datetime.datetime(1997, 11, 27, 9, 0)]
+}}}
+
+Every 3 hours from 9:00 AM to 5:00 PM on a specific day.
+{{{
+>>> list(rrule(FREQ_HOURLY, interval=3, dtstart=parse("19970902T090000"), until=parse("19970902T170000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 2, 12, 0),
+ datetime.datetime(1997, 9, 2, 15, 0)]
+}}}
+
+Every 15 minutes for 6 occurrences.
+{{{
+>>> list(rrule(FREQ_MINUTELY, interval=15, count=6, dtstart=parse("19970902T0900
+00")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 2, 9, 15),
+ datetime.datetime(1997, 9, 2, 9, 30),
+ datetime.datetime(1997, 9, 2, 9, 45),
+ datetime.datetime(1997, 9, 2, 10, 0),
+ datetime.datetime(1997, 9, 2, 10, 15)]
+}}}
+
+Every hour and a half for 4 occurrences.
+{{{
+>>> list(rrule(FREQ_MINUTELY, interval=90, count=4, dtstart=parse("19970902T0900
+00")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 2, 10, 30),
+ datetime.datetime(1997, 9, 2, 12, 0),
+ datetime.datetime(1997, 9, 2, 13, 30)]
+}}}
+
+Every 20 minutes from 9:00 AM to 4:40 PM for two days.
+{{{
+>>> list(rrule(FREQ_MINUTELY, interval=20, count=48, byhour=range(9,17), byminut
+e=(0,20,40), dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 2, 9, 20),
+ (...)
+ datetime.datetime(1997, 9, 2, 16, 20),
+ datetime.datetime(1997, 9, 2, 16, 40),
+ datetime.datetime(1997, 9, 3, 9, 0),
+ datetime.datetime(1997, 9, 3, 9, 20),
+ (...)
+ datetime.datetime(1997, 9, 3, 16, 20),
+ datetime.datetime(1997, 9, 3, 16, 40)]
+}}}
+
+An example where the days generated makes a difference because of {{{wkst}}}.
+{{{
+>>> list(rrule(FREQ_WEEKLY, interval=2, count=4, byweekday=(TU,SU), wkst=MO, dtstart=parse("19970805T090000")))
+[datetime.datetime(1997, 8, 5, 9, 0),
+ datetime.datetime(1997, 8, 10, 9, 0),
+ datetime.datetime(1997, 8, 19, 9, 0),
+ datetime.datetime(1997, 8, 24, 9, 0)]
+
+>>> list(rrule(FREQ_WEEKLY, interval=2, count=4, byweekday=(TU,SU), wkst=SU, dts
+tart=parse("19970805T090000")))
+[datetime.datetime(1997, 8, 5, 9, 0),
+ datetime.datetime(1997, 8, 17, 9, 0),
+ datetime.datetime(1997, 8, 19, 9, 0),
+ datetime.datetime(1997, 8, 31, 9, 0)]
+}}}
+
+==== rruleset type ====
+The {{{rruleset}}} type allows more complex recurrence setups, mixing
+multiple rules, dates, exclusion rules, and exclusion dates.
+The type constructor takes the following keyword arguments:
+
+ cache::
+ If True, caching of results will be enabled, improving performance
+ of multiple queries considerably.
+
+==== rruleset methods ====
+The following methods are available:
+
+ rruleset.rrule(rrule)::
+ Include the given {{{rrule}}} instance in the recurrence set
+ generation.
+
+ rruleset.rdate(dt)::
+ Include the given {{{datetime}}} instance in the recurrence
+ set generation.
+
+ rruleset.exrule(rrule)::
+ Include the given {{{rrule}}} instance in the recurrence set
+ exclusion list. Dates which are part of the given recurrence
+ rules will not be generated, even if some inclusive {{{rrule}}}
+ or {{{rdate}}} matches them.
+
+ rruleset.exdate(dt)::
+ Include the given {{{datetime}}} instance in the recurrence set
+ exclusion list. Dates included that way will not be generated,
+ even if some inclusive {{{rrule}}} or {{{rdate}}} matches them.
+
+ rruleset.before(dt, inc=False)::
+ Returns the last recurrence before the given {{{datetime}}}
+ instance. The {{{inc}}} keyword defines what happens if
+ {{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
+ if {{{dt}}} itself is an occurrence, it will be returned.
+
+ rruleset.after(dt, inc=False)::
+ Returns the first recurrence after the given {{{datetime}}}
+ instance. The {{{inc}}} keyword defines what happens if
+ {{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
+ if {{{dt}}} itself is an occurrence, it will be returned.
+
+ rruleset.between(after, before, inc=False)::
+ Returns all the occurrences of the rrule between {{{after}}}
+ and {{{before}}}. The {{{inc}}} keyword defines what happens
+ if {{{after}}} and/or {{{before}}} are themselves occurrences.
+ With {{{inc == True}}}, they will be included in the list,
+ if they are found in the recurrence set.
+
+==== rruleset examples ====
+Daily, for 7 days, jumping Saturday and Sunday occurrences.
+{{{
+>>> set = rruleset()
+>>> set.rrule(rrule(FREQ_DAILY, count=7, dtstart=parse("19970902T090000")))
+>>> set.exrule(rrule(FREQ_YEARLY, byweekday=(SA,SU), dtstart=parse("19970902T090000")))
+>>> list(set)
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 3, 9, 0),
+ datetime.datetime(1997, 9, 4, 9, 0),
+ datetime.datetime(1997, 9, 5, 9, 0),
+ datetime.datetime(1997, 9, 8, 9, 0)]
+}}}
+
+Weekly, for 4 weeks, plus one time on day 7, and not on day 16.
+{{{
+>>> set = rruleset()
+>>> set.rrule(rrule(FREQ_WEEKLY, count=4, dtstart=parse("19970902T090000")))
+>>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0))
+>>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0))
+>>> list(set)
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 7, 9, 0),
+ datetime.datetime(1997, 9, 9, 9, 0),
+ datetime.datetime(1997, 9, 23, 9, 0)]
+}}}
+
+==== rrulestr() function ====
+The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes.
+The function prototype is:
+{{{
+rrulestr(str)
+}}}
+
+The string passed as parameter may be a multiple line string, a
+single line string, or just the {{{RRULE}}} property value.
+
+Additionally, it accepts the following keyword arguments:
+
+ cache::
+ If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance
+ will cache its results. Default is not to cache.
+
+ dtstart::
+ If given, it must be a {{{datetime}}} instance that will be used
+ when no {{{DTSTART}}} property is found in the parsed string. If
+ it is not given, and the property is not found, {{{datetime.now()}}}
+ will be used instead.
+
+ unfold::
+ If set to {{{True}}}, lines will be unfolded following the RFC
+ specification. It defaults to {{{False}}}, meaning that spaces
+ before every line will be stripped.
+
+ forceset::
+ If set to {{{True}}} a {{{rruleset}}} instance will be returned,
+ even if only a single rule is found. The default is to return an
+ {{{rrule}}} if possible, and an {{{rruleset}}} if necessary.
+
+ compatible::
+ If set to {{{True}}}, the parser will operate in RFC-compatible
+ mode. Right now it means that {{{unfold}}} will be turned on,
+ and if a {{{DTSTART}}} is found, it will be considered the first
+ recurrence instance, as documented in the RFC.
+
+ ignoretz::
+ If set to {{{True}}}, the date parser will ignore timezone
+ information available in the {{{DTSTART}}} property, or the
+ {{{UNTIL}}} attribute.
+
+ tzinfos::
+ If set, it will be passed to the datetime string parser to
+ resolve unknown timezone settings. For more information about
+ what could be used here, check the parser documentation.
+
+==== rrulestr() examples ====
+
+Every 10 days, 5 occurrences.
+{{{
+>>> list(rrulestr("""
+... DTSTART:19970902T090000
+... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+... """))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 12, 9, 0),
+ datetime.datetime(1997, 9, 22, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0),
+ datetime.datetime(1997, 10, 12, 9, 0)]
+}}}
+
+Same thing, but passing only the {{{RRULE}}} value.
+{{{
+>>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", dtstart=parse("19970902T090000")))
+[datetime.datetime(1997, 9, 2, 9, 0),
+ datetime.datetime(1997, 9, 12, 9, 0),
+ datetime.datetime(1997, 9, 22, 9, 0),
+ datetime.datetime(1997, 10, 2, 9, 0),
+ datetime.datetime(1997, 10, 12, 9, 0)]
+}}}
+
+Notice that when using a single rule, it returns an
+{{{rrule}}} instance, unless {{{forceset}}} was used.
+{{{
+>>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5")
+<dateutil.rrule.rrule instance at 0x30269f08>
+
+>>> rrulestr("""
+... DTSTART:19970902T090000
+... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+... """)
+<dateutil.rrule.rrule instance at 0x302699e0>
+
+>>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True)
+<dateutil.rrule.rruleset instance at 0x30269f08>
+}}}
+
+But when an {{{rruleset}}} is needed, it is automatically used.
+{{{
+>>> rrulestr("""
+... DTSTART:19970902T090000
+... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3
+... """)
+<dateutil.rrule.rruleset instance at 0x302699e0>
+}}}
+
+=== parser ===
+This module offers a generic date/time string parser which is
+able to parse most known formats to represent a date and/or
+time.
+
+==== parse() function ====
+That's probably the only function you'll need from this module.
+It offers you an interface to access the parser functionality and
+extract a {{{datetime}}} type out of a string.
+
+The prototype of this function is:
+{{{
+parse(timestr)
+}}}
+
+Additionally, the following keyword arguments are available:
+
+ default::
+ If given, this must be a {{{datetime}}} instance. Any fields
+ missing in the parsed date will be copied from this instance.
+ The default value is the current date, at 00:00:00am.
+
+ ignoretz::
+ If this is true, even if a timezone is found in the string,
+ the parser will not use it.
+
+ tzinfos::
+ Using this keyword argument you may provide custom timezones
+ to the parser. If given, it must be either a dictionary with
+ the timezone abbreviation as key, or a function accepting a
+ timezone abbreviation and offset as argument. The dictionary
+ values and the function return must be a timezone offset
+ in seconds, a tzinfo subclass, or a string defining the
+ timezone (in the TZ environment variable format).
+
+ dayfirst::
+ This option allow one to change the precedence in which
+ days are parsed in date strings. The default is given in the
+ parserinfo instance (the default parserinfo has it set to
+ False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}}
+ format will have precedence over {{{DD-MM-YYYY}}} in an
+ ambiguous date.
+
+ yearfirst::
+ This option allow one to change the precedence in which
+ years are parsed in date strings. The default is given in
+ the parserinfo instance (the default parserinfo has it set
+ to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}}
+ format will have precedence over {{{YY-MM-DD}}} in an
+ ambiguous date.
+
+ fuzzy::
+ If {{{fuzzy}}} is set to True, unknown tokens in the string
+ will be ignored.
+
+ parserinfo::
+ This parameter allows one to change how the string is parsed,
+ by using a different parserinfo class instance. Using it you
+ may, for example, intenationalize the parser strings, or make
+ it ignore additional words.
+
+==== Format precedence ====
+Whenever an ambiguous date is found, the {{{dayfirst}}} and
+{{{yearfirst}}} parameters will control how the information
+is processed. Here is the precedence in each case:
+
+If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}},
+(default, if no parameter is given):
+
+ * {{{MM-DD-YY}}}
+ * {{{DD-MM-YY}}}
+ * {{{YY-MM-DD}}}
+
+If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}:
+
+ * {{{DD-MM-YY}}}
+ * {{{MM-DD-YY}}}
+ * {{{YY-MM-DD}}}
+
+If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}:
+
+ * {{{YY-MM-DD}}}
+ * {{{MM-DD-YY}}}
+ * {{{DD-MM-YY}}}
+
+If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}:
+
+ * {{{YY-MM-DD}}}
+ * {{{DD-MM-YY}}}
+ * {{{MM-DD-YY}}}
+
+==== Converting two digit years ====
+When a two digit year is found, it is processed considering
+the current year, so that the computed year is never more
+than 49 years after then current year, nor 50 years before the
+current year. In other words, if we are in year 2003, and the
+year 30 is found, it will be considered as 2030, but if the
+year 60 is found, it will be considered 1960.
+
+==== Examples ====
+The following code will prepare the environment:
+{{{
+>>> from dateutil.parser import *
+>>> from dateutil.tz import *
+>>> from datetime import *
+>>> TZOFFSETS = {"BRST": -10800}
+>>> BRSTTZ = tzoffset(-10800, "BRST")
+>>> DEFAULT = datetime(2003, 9, 25)
+}}}
+
+Some simple examples based on the {{{date}}} command, using the
+{{{TZOFFSET}}} dictionary to provide the BRST timezone offset.
+{{{
+>>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS)
+datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzoffset('BRST', -10800))
+
+>>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS)
+datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzoffset('BRST', -10800))
+}}}
+
+Notice that since BRST is my local timezone, parsing it without
+further timezone settings will yield a {{{tzlocal}}} timezone.
+{{{
+>>> parse("Thu Sep 25 10:36:28 BRST 2003")
+datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal())
+}}}
+
+We can also ask to ignore the timezone explicitly:
+{{{
+>>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True)
+datetime.datetime(2003, 9, 25, 10, 36, 28)
+}}}
+
+That's the same as processing a string without timezone:
+{{{
+>>> parse("Thu Sep 25 10:36:28 2003")
+datetime.datetime(2003, 9, 25, 10, 36, 28)
+}}}
+
+Without the year, but passing our {{{DEFAULT}}} datetime to return
+the same year, no mattering what year we currently are in:
+{{{
+>>> parse("Thu Sep 25 10:36:28", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36, 28)
+}}}
+
+Strip it further:
+{{{
+>>> parse("Thu Sep 10:36:28", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36, 28)
+
+>>> parse("Thu 10:36:28", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36, 28)
+
+>>> parse("Thu 10:36", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36)
+
+>>> parse("10:36", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36)
+>>>
+}}}
+
+Strip in a different way:
+{{{
+>>> parse("Thu Sep 25 2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("Sep 25 2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("Sep 2003", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("Sep", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("2003", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Another format, based on {{{date -R}}} (RFC822):
+{{{
+>>> parse("Thu, 25 Sep 2003 10:49:41 -0300")
+datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
+}}}
+
+ISO format:
+{{{
+>>> parse("2003-09-25T10:49:41.5-03:00")
+datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, tzinfo=tzoffset(None, -10800))
+}}}
+
+Some variations:
+{{{
+>>> parse("2003-09-25T10:49:41")
+datetime.datetime(2003, 9, 25, 10, 49, 41)
+
+>>> parse("2003-09-25T10:49")
+datetime.datetime(2003, 9, 25, 10, 49)
+
+>>> parse("2003-09-25T10")
+datetime.datetime(2003, 9, 25, 10, 0)
+
+>>> parse("2003-09-25")
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+ISO format, without separators:
+{{{
+>>> parse("20030925T104941.5-0300")
+datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, tzinfo=tzinfo=tzoffset(None, -10800))
+
+>>> parse("20030925T104941-0300")
+datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
+
+>>> parse("20030925T104941")
+datetime.datetime(2003, 9, 25, 10, 49, 41)
+
+>>> parse("20030925T1049")
+datetime.datetime(2003, 9, 25, 10, 49)
+
+>>> parse("20030925T10")
+datetime.datetime(2003, 9, 25, 10, 0)
+
+>>> parse("20030925")
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Everything together.
+{{{
+>>> parse("199709020900")
+datetime.datetime(1997, 9, 2, 9, 0)
+>>> parse("19970902090059")
+datetime.datetime(1997, 9, 2, 9, 0, 59)
+}}}
+
+Different date orderings:
+{{{
+>>> parse("2003-09-25")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("2003-Sep-25")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("25-Sep-2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("Sep-25-2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("09-25-2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("25-09-2003")
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Check some ambiguous dates:
+{{{
+>>> parse("10-09-2003")
+datetime.datetime(2003, 10, 9, 0, 0)
+
+>>> parse("10-09-2003", dayfirst=True)
+datetime.datetime(2003, 9, 10, 0, 0)
+
+>>> parse("10-09-03")
+datetime.datetime(2003, 10, 9, 0, 0)
+
+>>> parse("10-09-03", yearfirst=True)
+datetime.datetime(2010, 9, 3, 0, 0)
+}}}
+
+Other date separators are allowed:
+{{{
+>>> parse("2003.Sep.25")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("2003/09/25")
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Even with spaces:
+{{{
+>>> parse("2003 Sep 25")
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("2003 09 25")
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Hours with letters work:
+{{{
+>>> parse("10h36m28.5s", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 36, 28, 500000)
+
+>>> parse("01s02h03m", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 2, 3, 1)
+
+>>> parse("01h02m03", default=DEFAULT)
+datetime.datetime(2003, 9, 3, 1, 2)
+
+>>> parse("01h02", default=DEFAULT)
+datetime.datetime(2003, 9, 2, 1, 0)
+
+>>> parse("01h02s", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 1, 0, 2)
+}}}
+
+With AM/PM:
+{{{
+>>> parse("10h am", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 10, 0)
+
+>>> parse("10pm", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 22, 0)
+
+>>> parse("12:00am", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 0, 0)
+
+>>> parse("12pm", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 12, 0)
+}}}
+
+Some special treating for ''pertain'' relations:
+{{{
+>>> parse("Sep 03", default=DEFAULT)
+datetime.datetime(2003, 9, 3, 0, 0)
+
+>>> parse("Sep of 03", default=DEFAULT)
+datetime.datetime(2003, 9, 25, 0, 0)
+}}}
+
+Fuzzy parsing:
+{{{
+>>> s = "Today is 25 of September of 2003, exactly " \
+... "at 10:49:41 with timezone -03:00."
+>>> parse(s, fuzzy=True)
+datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
+}}}
+
+Other random formats:
+{{{
+>>> parse("Wed, July 10, '96")
+datetime.datetime(1996, 7, 10, 0, 0)
+
+>>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True)
+datetime.datetime(1996, 7, 10, 15, 8, 56)
+
+>>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True)
+datetime.datetime(1952, 4, 12, 15, 30, 42)
+
+>>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True)
+datetime.datetime(1994, 11, 5, 8, 15, 30)
+
+>>> parse("3rd of May 2001")
+datetime.datetime(2001, 5, 3, 0, 0)
+
+>>> parse("5:50 A.M. on June 13, 1990")
+datetime.datetime(1990, 6, 13, 5, 50)
+}}}
+
+=== easter ===
+This module offers a generic easter computing method for
+any given year, using Western, Orthodox or Julian algorithms.
+
+==== easter() function ====
+This method was ported from the work done by
+[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts],
+on top of the algorithm by
+[http://www.tondering.dk/claus/calendar.html Claus Tondering],
+which was based in part on the algorithm of Ouding (1940),
+as quoted in "Explanatory Supplement to the Astronomical
+Almanac", P. Kenneth Seidelmann, editor.
+
+This algorithm implements three different easter
+calculation methods:
+
+ 1. Original calculation in Julian calendar, valid in
+ dates after 326 AD
+ 1. Original method, with date converted to Gregorian
+ calendar, valid in years 1583 to 4099
+ 1. Revised method, in Gregorian calendar, valid in
+ years 1583 to 4099 as well
+
+These methods are represented by the constants:
+{{{
+EASTER_JULIAN = 1
+EASTER_ORTHODOX = 2
+EASTER_WESTERN = 3
+}}}
+
+The default method is method 3.
+
+=== tz ===
+This module offers timezone implementations subclassing
+the abstract {{{datetime.tzinfo}}} type. There are
+classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile]
+format files (usually are in /etc/localtime,
+/usr/share/zoneinfo, etc), TZ environment string (in all
+known formats), given ranges (with help from relative
+deltas), local machine timezone, fixed offset timezone,
+and UTC timezone.
+
+==== tzutc type ====
+This type implements a basic UTC timezone. The constructor of this
+type accepts no parameters.
+
+==== tzutc examples ====
+{{{
+>>> from datetime import *
+>>> from dateutil.tz import *
+
+>>> datetime.now()
+datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
+
+>>> datetime.now(tzutc())
+datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
+
+>>> datetime.now(tzutc()).tzname()
+'UTC'
+}}}
+
+==== tzoffset type ====
+This type implements a fixed offset timezone, with no
+support to daylight saving times. Here is the prototype of the
+type constructor:
+{{{
+tzoffset(name, offset)
+}}}
+
+The {{{name}}} parameter may be optionally set to {{{None}}}, and
+{{{offset}}} must be given in seconds.
+
+==== tzoffset examples ====
+{{{
+>>> from datetime import *
+>>> from dateutil.tz import *
+
+>>> datetime.now(tzoffset("BRST", -10800))
+datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, tzinfo=tzinfo=tzoffset('BRST', -10800))
+
+>>> datetime.now(tzoffset("BRST", -10800)).tzname()
+'BRST'
+
+>>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc())
+datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, tzinfo=tzutc())
+}}}
+
+==== tzlocal type ====
+This type implements timezone settings as known by the
+operating system. The constructor of this type accepts no
+parameters.
+
+==== tzlocal examples ====
+{{{
+>>> from datetime import *
+>>> from dateutil.tz import *
+
+>>> datetime.now(tzlocal())
+datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, tzinfo=tzlocal())
+
+>>> datetime.now(tzlocal()).tzname()
+'BRST'
+
+>>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0))
+datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, tzinfo=tzoffset(None, 0))
+}}}
+
+==== tzstr type ====
+This type implements timezone settings extracted from a
+string in known TZ environment variable formats. Here is the prototype
+of the constructor:
+{{{
+tzstr(str)
+}}}
+
+==== tzstr examples ====
+Here are examples of the recognized formats:
+
+ * {{{EST5EDT}}}
+ * {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}}
+ * {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}}
+ * {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}}
+ * {{{EST5EDT4,95/02:00:00,298/02:00}}}
+ * {{{EST5EDT4,J96/02:00:00,J299/02:00}}}
+
+Notice that if daylight information is not present, but a
+daylight abbreviation was provided, {{{tzstr}}} will follow the
+convention of using the first sunday of April to start daylight
+saving, and the last sunday of October to end it. If start or
+end time is not present, 2AM will be used, and if the daylight
+offset is not present, the standard offset plus one hour will
+be used. This convention is the same as used in the GNU libc.
+
+This also means that some of the above examples are exactly
+equivalent, and all of these examples are equivalent
+in the year of 2003.
+
+Here is the example mentioned in the
+[http://www.python.org/doc/current/lib/module-time.html time module documentation].
+{{{
+>>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0'
+>>> time.tzset()
+>>> time.strftime('%X %x %Z')
+'02:07:36 05/08/03 EDT'
+>>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0'
+>>> time.tzset()
+>>> time.strftime('%X %x %Z')
+'16:08:12 05/08/03 AEST'
+}}}
+
+And here is an example showing the same information using {{{tzstr}}},
+without touching system settings.
+{{{
+>>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0')
+>>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0')
+>>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1)
+>>> dt.strftime('%X %x %Z')
+'02:07:36 05/08/03 EDT'
+>>> dt.astimezone(tz2).strftime('%X %x %Z')
+'16:07:36 05/08/03 AEST'
+}}}
+
+Are these really equivalent?
+{{{
+>>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600')
+True
+}}}
+
+Check the daylight limit.
+{{{
+>>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname()
+'EST'
+>>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname()
+'EDT'
+>>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname()
+'EDT'
+>>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname()
+'EST'
+}}}
+
+==== tzrange type ====
+This type offers the same functionality as the {{{tzstr}}} type, but
+instead of timezone strings, information is passed using
+{{{relativedelta}}}s which are applied to a datetime set to the first
+day of the year. Here is the prototype of this type's constructor:
+{{{
+tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, start=None, end=None):
+}}}
+
+Offsets must be given in seconds. Information not provided will be
+set to the defaults, as explained in the {{{tzstr}}} section above.
+
+==== tzrange examples ====
+{{{
+>>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
+True
+
+>>> from dateutil.relativedelta import *
+>>> range1 = tzrange("EST", -18000, "EDT")
+>>> range2 = tzrange("EST", -18000, "EDT", -14400,
+... relativedelta(hours=+2, month=4, day=1, weekday=SU(+1)),
+... relativedelta(hours=+1, month=10, day=31, weekday=SU(-1)))>>> tzstr('EST5EDT') == range1 == range2
+>>> tzstr('EST5EDT') == range1 == range2
+True
+}}}
+
+Notice a minor detail in the last example: while the DST should end
+at 2AM, the delta will catch 1AM. That's because the daylight saving
+time should end at 2AM standard time (the difference between STD and
+DST is 1h in the given example) instead of the DST time. That's how
+the {{{tzinfo}}} subtypes should deal with the extra hour that happens
+when going back to the standard time. Check
+[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation]
+for more information.
+
+==== tzfile type ====
+This type allows one to use tzfile(5) format timezone files to extract
+current and historical zone information. Here is the type constructor
+prototype:
+{{{
+tzfile(fileobj)
+}}}
+
+Where {{{fileobj}}} is either a filename or a file-like object with
+a {{{read()}}} method.
+
+==== tzfile examples ====
+{{{
+>>> tz = tzfile("/etc/localtime")
+>>> datetime.now(tz)
+datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, tzinfo=tzfile('/etc/localtime'))
+
+>>> datetime.now(tz).astimezone(tzutc())
+datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, tzinfo=tzutc())
+
+>>> datetime.now(tz).tzname()
+'BRST'
+>>> datetime(2003, 1, 1, tzinfo=tz).tzname()
+'BRDT'
+}}}
+
+Check the daylight limit.
+{{{
+>>> tz = tzfile('/usr/share/zoneinfo/EST5EDT')
+>>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname()
+'EST'
+>>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname()
+'EDT'
+>>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname()
+'EDT'
+>>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname()
+'EST'
+}}}
+
+==== tzical type ====
+This type is able to parse
+[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar]
+style {{{VTIMEZONE}}} sessions into a Python timezone object.
+The constuctor prototype is:
+{{{
+tzical(fileobj)
+}}}
+
+Where {{{fileobj}}} is either a filename or a file-like object with
+a {{{read()}}} method.
+
+==== tzical methods ====
+
+ tzical.get(tzid=None)::
+ Since a single iCalendar file may contain more than one timezone,
+ you must ask for the timezone you want with this method. If there's
+ more than one timezone in the parsed file, you'll need to pass the
+ {{{tzid}}} parameter. Otherwise, leaving it empty will yield the only
+ available timezone.
+
+==== tzical examples ====
+Here is a sample file extracted from the RFC. This file defines
+the {{{EST5EDT}}} timezone, and will be used in the following example.
+{{{
+BEGIN:VTIMEZONE
+TZID:US-Eastern
+LAST-MODIFIED:19870101T000000Z
+TZURL:http://zones.stds_r_us.net/tz/US-Eastern
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+}}}
+
+And here is an example exploring a {{{tzical}}} type:
+{{{
+>>> from dateutil.tz import *; from datetime import *
+
+>>> tz = tzical('EST5EDT.ics')
+>>> tz.keys()
+['US-Eastern']
+
+>>> est = tz.get('US-Eastern')
+>>> est
+<tzicalvtz 'US-Eastern'>
+
+>>> datetime.now(est)
+datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, tzinfo=<tzicalvtz 'US-Eastern'>)
+
+>>> est == tz.get()
+True
+}}}
+
+Let's check the daylight ranges, as usual:
+{{{
+>>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname()
+'EST'
+>>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname()
+'EDT'
+
+>>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname()
+'EDT'
+>>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname()
+'EST'
+}}}
+
+==== gettz() function ====
+This function is a helper that will try its best to get the right
+timezone for your environment, or for the given string. The prototype
+is as follows:
+{{{
+gettz(name=None)
+}}}
+
+If given, the parameter may be a filename, a path relative to the base
+of the timezone information path (the base could be
+{{{/usr/share/zoneinfo}}}, for example), a string timezone
+specification, or a timezone abbreviation. If {{{name}}} is not given,
+and the {{{TZ}}} environment variable is set, it's used instead. If the
+parameter is not given, and {{{TZ}}} is not set, the default tzfile
+paths will be tried.
+
+Example:
+{{{
+>>> from dateutil.tz import *
+>>> gettz()
+tzfile('/etc/localtime')
+
+>>> gettz("America/Sao Paulo")
+tzfile('/usr/share/zoneinfo/America/Sao_Paulo')
+
+>>> gettz("EST5EDT")
+tzfile('/usr/share/zoneinfo/EST5EDT')
+
+>>> gettz("EST5")
+tzstr('EST5')
+
+>>> gettz('BRST')
+tzlocal()
+
+>>> os.environ["TZ"] = "America/Sao Paulo"
+>>> gettz()
+tzfile('/usr/share/zoneinfo/America/Sao_Paulo')
+
+>>> os.environ["TZ"] = "BRST"
+>>> gettz()
+tzlocal()
+
+>>> gettz("Unavailable")
+>>>
+}}}
+
+## vim:ft=moin