1
## This file is in the moin format. The latest version is found
2
## at https://moin.conectiva.com.br/DateUtil
8
The '''dateutil''' module provides powerful extensions to
9
the standard '''datetime''' module, available in Python 2.3+.
13
* Computing of relative deltas (next month, next year,
14
next monday, last week of month, etc);
16
* Computing of relative deltas between two given
17
date and/or datetime objects;
19
* Computing of dates based on very flexible recurrence rules,
20
using a superset of the
21
[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar]
22
specification. Parsing of RFC strings is supported as well.
24
* Generic parsing of dates in almost any string format;
26
* Timezone (tzinfo) implementations for tzfile(5) format
27
files (/etc/localtime, /usr/share/zoneinfo, etc), TZ
28
environment string (in all known formats), iCalendar
29
format files, given ranges (with help from relative deltas),
30
local machine timezone, fixed offset timezone, and UTC timezone.
32
* Computing of Easter Sunday dates for any given year,
33
using Western, Orthodox or Julian algorithms;
35
* More than 400 test cases.
38
Here's a snapshot, just to give an idea about the power of the
39
package. For more examples, look at the documentation below.
41
Suppose you want to know how much time is left, in
42
years/months/days/etc, before the next easter happening on a
43
year with a Friday 13th in August, and you want to get today's
44
date out of the "date" unix system command. Here is the code:
46
from dateutil.relativedelta import *
47
from dateutil.easter import *
48
from dateutil.rrule import *
49
from dateutil.parser import *
50
from datetime import *
53
now = parse(commands.getoutput("date"))
55
year = rrule(FREQ_YEARLY,bymonth=8,bymonthday=13,byweekday=FR)[0].year
56
rdelta = relativedelta(easter(year), today)
57
print "Today is:", today
58
print "Year with next Aug 13th on a Friday is:", year
59
print "How far is the Easter of that year:", rdelta
60
print "And the Easter of that year is:", today+rdelta
63
And here's the output:
66
Year with next Aug 13th on a Friday is: 2004
67
How far is the Easter of that year: relativedelta(months=+6)
68
And the Easter of that year is: 2004-04-11
71
{i} It was '''really''' a coincidence :)
74
The following files are available.
75
* attachment:python-dateutil-0.3.tar.bz2
76
* attachment:python-dateutil-0.3-1cl.noarch.rpm
79
The dateutil module was written by GustavoNiemeyer <niemeyer@conectiva.com>.
82
The following modules are available.
85
This module offers the '''relativedelta''' type, which is based
86
on the specification of the excelent work done by M.-A. Lemburg in his
87
[http://www.egenix.com/files/python/mxDateTime.html mxDateTime]
88
extension. However, notice that this type '''does not''' implement the
89
same algorithm as his work. Do not expect it to behave like
90
{{{mxDateTime}}}'s counterpart.
92
==== relativedelta type ====
94
There's two different ways to build a relativedelta instance. The
95
first one is passing it two {{{date}}}/{{{datetime}}} instances:
97
relativedelta(datetime1, datetime2)
100
This will build the relative difference between {{{datetime1}}} and
101
{{{datetime2}}}, so that the following constraint is always true:
103
datetime2+relativedelta(datetime1, datetime2) == datetime1
106
Notice that instead of {{{datetime}}} instances, you may use
107
{{{date}}} instances, or a mix of both.
109
And the other way is to use any of the following keyword arguments:
111
year, month, day, hour, minute, seconds, microseconds::
112
Absolute information.
114
years, months, weeks, days, hours, minutes, seconds, microseconds::
115
Relative information, may be negative.
118
One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These
119
instances may receive a parameter {{{n}}}, specifying the {{{n}}}th
120
weekday, which could be positive or negative (like {{{MO(+2)}}} or
121
{{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}.
122
You can also use an integer, where {{{0=MO}}}. Notice that,
123
for example, if the calculated date is already Monday, using
124
{{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context),
125
won't change the day.
128
Will add given days to the date found, but only if the computed
129
year is a leap year and the computed date is post 28 of february.
132
Set the yearday or the non-leap year day (jump leap days).
133
These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}}
136
==== Behavior of operations ====
137
If you're curious about exactly how the relative delta will act
138
on operations, here is a description of its behavior.
140
1. Calculate the absolute year, using the {{{year}}} argument, or the
141
original datetime year, if the argument is not present.
142
1. Add the relative {{{years}}} argument to the absolute year.
143
1. Do steps 1 and 2 for {{{month}}}/{{{months}}}.
144
1. Calculate the absolute day, using the {{{day}}} argument, or the
145
original datetime day, if the argument is not present. Then, subtract
146
from the day until it fits in the year and month found after their
148
1. Add the relative {{{days}}} argument to the absolute day. Notice
149
that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}.
150
1. If {{{leapdays}}} is present, the computed year is a leap year, and
151
the computed month is after february, remove one day from the found date.
152
1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}},
153
{{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}.
154
1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th
155
occurrence of the given weekday.
159
Let's begin our trip.
161
>>> from datetime import *; from dateutil.relativedelta import *
167
>>> NOW = datetime.now()
168
>>> TODAY = date.today()
170
datetime.datetime(2003, 9, 17, 20, 54, 47, 282310)
172
datetime.date(2003, 9, 17)
177
>>> NOW+relativedelta(months=+1)
178
datetime.datetime(2003, 10, 17, 20, 54, 47, 282310)
181
Next month, plus one week.
183
>>> NOW+relativedelta(months=+1, weeks=+1)
184
datetime.datetime(2003, 10, 24, 20, 54, 47, 282310)
187
Next month, plus one week, at 10am.
189
>>> TODAY+relativedelta(months=+1, weeks=+1, hour=10)
190
datetime.datetime(2003, 10, 24, 10, 0)
193
Let's try the other way around. Notice that the
194
hour setting we get in the relativedelta is relative,
195
since it's a difference, and the weeks parameter
198
>>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY)
199
relativedelta(months=+1, days=+7, hours=+10)
202
One month before one year.
204
>>> NOW+relativedelta(years=+1, months=-1)
205
datetime.datetime(2004, 8, 17, 20, 54, 47, 282310)
208
How does it handle months with different numbers of days?
209
Notice that adding one month will never cross the month
212
>>> date(2003,1,27)+relativedelta(months=+1)
213
datetime.date(2003, 2, 27)
214
>>> date(2003,1,31)+relativedelta(months=+1)
215
datetime.date(2003, 2, 28)
216
>>> date(2003,1,31)+relativedelta(months=+2)
217
datetime.date(2003, 3, 31)
220
The logic for years is the same, even on leap years.
222
>>> date(2000,2,28)+relativedelta(years=+1)
223
datetime.date(2001, 2, 28)
224
>>> date(2000,2,29)+relativedelta(years=+1)
225
datetime.date(2001, 2, 28)
227
>>> date(1999,2,28)+relativedelta(years=+1)
228
datetime.date(2000, 2, 28)
229
>>> date(1999,3,1)+relativedelta(years=+1)
230
datetime.date(2000, 3, 1)
232
>>> date(2001,2,28)+relativedelta(years=-1)
233
datetime.date(2000, 2, 28)
234
>>> date(2001,3,1)+relativedelta(years=-1)
235
datetime.date(2000, 3, 1)
240
>>> TODAY+relativedelta(weekday=FR)
241
datetime.date(2003, 9, 19)
243
>>> TODAY+relativedelta(weekday=calendar.FRIDAY)
244
datetime.date(2003, 9, 19)
247
Last friday in this month.
249
>>> TODAY+relativedelta(day=31, weekday=FR(-1))
250
datetime.date(2003, 9, 26)
253
Next wednesday (it's today!).
255
>>> TODAY+relativedelta(weekday=WE(+1))
256
datetime.date(2003, 9, 17)
259
Next wednesday, but not today.
261
>>> TODAY+relativedelta(days=+1, weekday=WE(+1))
262
datetime.date(2003, 9, 24)
266
[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation]
267
find the first day of the 15th week of 1997.
269
>>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14)
270
datetime.datetime(1997, 4, 7, 0, 0)
273
How long ago has the millennium changed?
275
>>> relativedelta(NOW, date(2001,1,1))
276
relativedelta(years=+2, months=+8, days=+16, hours=+20, minutes=+54, seconds=+47, microseconds=+282310)
281
>>> johnbirthday = datetime(1978, 4, 5, 12, 0)
282
>>> relativedelta(NOW, johnbirthday)
283
relativedelta(years=+25, months=+5, days=+12, hours=+8, minutes=+54, seconds=+47, microseconds=+282310)
286
It works with dates too.
288
>>> relativedelta(TODAY, johnbirthday)
289
relativedelta(years=+25, months=+5, days=+11, hours=+12)
292
Obtain today's date using the yearday:
294
>>> date(2003, 1, 1)+relativedelta(yearday=260)
295
datetime.date(2003, 9, 17)
298
We can use today's date, since yearday should be absolute
301
>>> TODAY+relativedelta(yearday=260)
302
datetime.date(2003, 9, 17)
305
Last year it should be in the same day:
307
>>> date(2002, 1, 1)+relativedelta(yearday=260)
308
datetime.date(2002, 9, 17)
311
But not in a leap year:
313
>>> date(2000, 1, 1)+relativedelta(yearday=260)
314
datetime.date(2000, 9, 16)
317
We can use the non-leap year day to ignore this:
319
>>> date(2000, 1, 1)+relativedelta(nlyearday=260)
320
datetime.date(2000, 9, 17)
324
The rrule module offers a small, complete, and very fast, implementation
325
of the recurrence rules documented in the
326
[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including
327
support for caching of results.
330
That's the base of the rrule operation. It accepts all the keywords
331
defined in the RFC as its constructor parameters (except {{{byday}}},
332
which was renamed to {{{byweekday}}}) and more. The constructor
338
Where {{{freq}}} must be one of {{{FREQ_YEARLY}}}, {{{FREQ_MONTHLY}}},
339
{{{FREQ_WEEKLY}}}, {{{FREQ_DAILY}}}, {{{FREQ_HOURLY}}}, {{{FREQ_MINUTELY}}},
340
or {{{FREQ_SECONDLY}}}.
342
Additionally, it supports the following keyword arguments:
345
If given, it must be a boolean value specifying to enable
346
or disable caching of results. If you will use the same
347
{{{rrule}}} instance multiple times, enabling caching will
348
improve the performance considerably.
351
The recurrence start. Besides being the base for the
352
recurrence, missing parameters in the final recurrence
353
instances will also be extracted from this date. If not
354
given, {{{datetime.now()}}} will be used instead.
357
The interval between each {{{freq}}} iteration. For example,
358
when using {{{FREQ_YEARLY}}}, an interval of {{{2}}} means
359
once every two years, but with {{{FREQ_HOURLY}}}, it means
360
once every two hours. The default interval is {{{1}}}.
363
The week start day. Must be one of the {{{MO}}}, {{{TU}}},
364
{{{WE}}} constants, or an integer, specifying the first day
365
of the week. This will affect recurrences based on weekly
366
periods. The default week start is got from
367
{{{calendar.firstweekday()}}}, and may be modified by
368
{{{calendar.setfirstweekday()}}}.
371
How many occurrences will be generated.
374
If given, this must be a {{{datetime}}} instance, that will
375
specify the limit of the recurrence. If a recurrence instance
376
happens to be the same as the {{{datetime}}} instance given
377
in the {{{until}}} keyword, this will be the last occurrence.
380
If given, it must be either an integer, or a sequence of
381
integers, positive or negative. Each given integer will
382
specify an occurrence number, corresponding to the nth
383
occurrence of the rule inside the frequency period. For
384
example, a {{{bysetpos}}} of {{{-1}}} if combined with a
385
{{{FREQ_MONTHLY}}} frequency, and a {{{byweekday}}} of
386
{{{(MO, TU, WE, TH, FR)}}}, will result in the last work
390
If given, it must be either an integer, or a sequence of
391
integers, meaning the months to apply the recurrence to.
394
If given, it must be either an integer, or a sequence of
395
integers, meaning the month days to apply the recurrence to.
398
If given, it must be either an integer, or a sequence of
399
integers, meaning the year days to apply the recurrence to.
402
If given, it must be either an integer, or a sequence of
403
integers, meaning the week numbers to apply the recurrence
404
to. Week numbers have the meaning described in ISO8601,
405
that is, the first week of the year is that containing at
406
least four days of the new year.
409
If given, it must be either an integer ({{{0 == MO}}}), a
410
sequence of integers, one of the weekday constants
411
({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants.
412
When given, these variables will define the weekdays where
413
the recurrence will be applied. It's also possible to use
414
an argument {{{n}}} for the weekday instances, which will
415
mean the {{{n}}}''th'' occurrence of this weekday in the
416
period. For example, with {{{FREQ_MONTHLY}}}, or with
417
{{{FREQ_YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}}
418
in {{{byweekday}}} will specify the first friday of the
419
month where the recurrence happens. Notice that in the RFC
420
documentation, this is specified as {{{BYDAY}}}, but was
421
renamed to avoid the ambiguity of that keyword.
424
If given, it must be either an integer, or a sequence of
425
integers, meaning the hours to apply the recurrence to.
428
If given, it must be either an integer, or a sequence of
429
integers, meaning the minutes to apply the recurrence to.
432
If given, it must be either an integer, or a sequence of
433
integers, meaning the seconds to apply the recurrence to.
436
If given, it must be either an integer, or a sequence of
437
integers, positive or negative. Each integer will define
438
an offset from the Easter Sunday. Passing the offset
439
{{{0}}} to {{{byeaster}}} will yield the Easter Sunday
440
itself. This is an extension to the RFC specification.
442
==== rrule methods ====
443
The following methods are available in {{{rrule}}} instances:
445
rrule.before(dt, inc=False)::
446
Returns the last recurrence before the given {{{datetime}}}
447
instance. The {{{inc}}} keyword defines what happens if
448
{{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
449
if {{{dt}}} itself is an occurrence, it will be returned.
451
rrule.after(dt, inc=False)::
452
Returns the first recurrence after the given {{{datetime}}}
453
instance. The {{{inc}}} keyword defines what happens if
454
{{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
455
if {{{dt}}} itself is an occurrence, it will be returned.
457
rrule.between(after, before, inc=False)::
458
Returns all the occurrences of the rrule between {{{after}}}
459
and {{{before}}}. The {{{inc}}} keyword defines what happens
460
if {{{after}}} and/or {{{before}}} are themselves occurrences.
461
With {{{inc == True}}}, they will be included in the list,
462
if they are found in the recurrence set.
465
Returns the number of recurrences in this set. It will have
466
go trough the whole recurrence, if this hasn't been done
469
Besides these methods, {{{rrule}}} instances also support
470
the {{{__getitem__()}}} and {{{__contains__()}}} special methods,
471
meaning that these are valid expressions:
474
if datetime(...) in rr:
482
The getitem/slicing mechanism is smart enough to avoid getting the whole
483
recurrence set, if possible.
487
* The rrule type has no {{{byday}}} keyword. The equivalent keyword
488
has been replaced by the {{{byweekday}}} keyword, to remove the
489
ambiguity present in the original keyword.
491
* Unlike documented in the RFC, the starting datetime ({{{dtstart}}})
492
is not the first recurrence instance, unless it does fit in the
493
specified rules. In a python module context, this behavior makes more
494
sense than otherwise. Notice that you can easily get the original
495
behavior by using a rruleset and adding the {{{dtstart}}} as an
496
{{{rdate}}} recurrence.
498
* Unlike documented in the RFC, every keyword is valid on every
499
frequency (the RFC documents that {{{byweekno}}} is only valid
500
on yearly frequencies, for example).
502
* In addition to the documented keywords, a {{{byeaster}}} keyword
503
was introduced, making it easy to compute recurrent events relative
504
to the Easter Sunday.
506
==== rrule examples ====
507
These examples were converted from the RFC.
509
Prepare the environment.
511
>>> from dateutil.rrule import *
512
>>> from dateutil.parser import *
513
>>> from datetime import *
517
>>> sys.displayhook = pprint.pprint
520
Daily, for 10 occurrences.
522
>>> list(rrule(FREQ_DAILY, count=10, dtstart=parse("19970902T090000")))
523
[datetime.datetime(1997, 9, 2, 9, 0),
524
datetime.datetime(1997, 9, 3, 9, 0),
525
datetime.datetime(1997, 9, 4, 9, 0),
526
datetime.datetime(1997, 9, 5, 9, 0),
527
datetime.datetime(1997, 9, 6, 9, 0),
528
datetime.datetime(1997, 9, 7, 9, 0),
529
datetime.datetime(1997, 9, 8, 9, 0),
530
datetime.datetime(1997, 9, 9, 9, 0),
531
datetime.datetime(1997, 9, 10, 9, 0),
532
datetime.datetime(1997, 9, 11, 9, 0)]
535
Daily until December 24, 1997
537
>>> list(rrule(FREQ_DAILY, dtstart=parse("19970902T090000"), until=parse("19971224T000000")))
538
[datetime.datetime(1997, 9, 2, 9, 0),
539
datetime.datetime(1997, 9, 3, 9, 0),
540
datetime.datetime(1997, 9, 4, 9, 0),
542
datetime.datetime(1997, 12, 21, 9, 0),
543
datetime.datetime(1997, 12, 22, 9, 0),
544
datetime.datetime(1997, 12, 23, 9, 0)]
547
Every other day, 5 occurrences.
549
>>> list(rrule(FREQ_DAILY, interval=2, count=5, dtstart=parse("19970902T090000")))
550
[datetime.datetime(1997, 9, 2, 9, 0),
551
datetime.datetime(1997, 9, 4, 9, 0),
552
datetime.datetime(1997, 9, 6, 9, 0),
553
datetime.datetime(1997, 9, 8, 9, 0),
554
datetime.datetime(1997, 9, 10, 9, 0)]
557
Every 10 days, 5 occurrences.
559
>>> list(rrule(FREQ_DAILY, interval=10, count=5, dtstart=parse("19970902T090000")))
560
[datetime.datetime(1997, 9, 2, 9, 0),
561
datetime.datetime(1997, 9, 12, 9, 0),
562
datetime.datetime(1997, 9, 22, 9, 0),
563
datetime.datetime(1997, 10, 2, 9, 0),
564
datetime.datetime(1997, 10, 12, 9, 0)]
567
Everyday in January, for 3 years.
569
>>> list(rrule(FREQ_YEARLY, bymonth=1, byweekday=range(7), dtstart=parse("19980101T090000"), until=parse("20000131T090000")))
570
[datetime.datetime(1998, 1, 1, 9, 0),
571
datetime.datetime(1998, 1, 2, 9, 0),
573
datetime.datetime(1998, 1, 30, 9, 0),
574
datetime.datetime(1998, 1, 31, 9, 0),
575
datetime.datetime(1999, 1, 1, 9, 0),
576
datetime.datetime(1999, 1, 2, 9, 0),
578
datetime.datetime(1999, 1, 30, 9, 0),
579
datetime.datetime(1999, 1, 31, 9, 0),
580
datetime.datetime(2000, 1, 1, 9, 0),
581
datetime.datetime(2000, 1, 2, 9, 0),
583
datetime.datetime(2000, 1, 29, 9, 0),
584
datetime.datetime(2000, 1, 31, 9, 0)]
587
Same thing, in another way.
589
>>> list(rrule(FREQ_DAILY, bymonth=1, dtstart=parse("19980101T090000"), until=parse("20000131T090000")))
593
Weekly for 10 occurrences.
595
>>> list(rrule(FREQ_WEEKLY, count=10, dtstart=parse("19970902T090000")))
596
[datetime.datetime(1997, 9, 2, 9, 0),
597
datetime.datetime(1997, 9, 9, 9, 0),
598
datetime.datetime(1997, 9, 16, 9, 0),
599
datetime.datetime(1997, 9, 23, 9, 0),
600
datetime.datetime(1997, 9, 30, 9, 0),
601
datetime.datetime(1997, 10, 7, 9, 0),
602
datetime.datetime(1997, 10, 14, 9, 0),
603
datetime.datetime(1997, 10, 21, 9, 0),
604
datetime.datetime(1997, 10, 28, 9, 0),
605
datetime.datetime(1997, 11, 4, 9, 0)]
608
Every other week, 6 occurrences.
610
>>> list(rrule(FREQ_WEEKLY, interval=2, count=6, dtstart=parse("19970902T090000")))
611
[datetime.datetime(1997, 9, 2, 9, 0),
612
datetime.datetime(1997, 9, 16, 9, 0),
613
datetime.datetime(1997, 9, 30, 9, 0),
614
datetime.datetime(1997, 10, 14, 9, 0),
615
datetime.datetime(1997, 10, 28, 9, 0),
616
datetime.datetime(1997, 11, 11, 9, 0)]
619
Weekly on Tuesday and Thursday for 5 weeks.
621
>>> list(rrule(FREQ_WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), dtstart=parse(
623
[datetime.datetime(1997, 9, 2, 9, 0),
624
datetime.datetime(1997, 9, 4, 9, 0),
625
datetime.datetime(1997, 9, 9, 9, 0),
626
datetime.datetime(1997, 9, 11, 9, 0),
627
datetime.datetime(1997, 9, 16, 9, 0),
628
datetime.datetime(1997, 9, 18, 9, 0),
629
datetime.datetime(1997, 9, 23, 9, 0),
630
datetime.datetime(1997, 9, 25, 9, 0),
631
datetime.datetime(1997, 9, 30, 9, 0),
632
datetime.datetime(1997, 10, 2, 9, 0)]
635
Every other week on Tuesday and Thursday, for 8 occurrences.
637
>>> list(rrule(FREQ_WEEKLY, interval=2, count=8, wkst=SU, byweekday=(TU,TH), dts
638
tart=parse("19970902T090000")))
639
[datetime.datetime(1997, 9, 2, 9, 0),
640
datetime.datetime(1997, 9, 4, 9, 0),
641
datetime.datetime(1997, 9, 16, 9, 0),
642
datetime.datetime(1997, 9, 18, 9, 0),
643
datetime.datetime(1997, 9, 30, 9, 0),
644
datetime.datetime(1997, 10, 2, 9, 0),
645
datetime.datetime(1997, 10, 14, 9, 0),
646
datetime.datetime(1997, 10, 16, 9, 0)]
649
Monthly on the 1st Friday for ten occurrences.
651
>>> list(rrule(FREQ_MONTHLY, count=10, byweekday=FR(1), dtstart=parse("19970905T090000")))
652
[datetime.datetime(1997, 9, 5, 9, 0),
653
datetime.datetime(1997, 10, 3, 9, 0),
654
datetime.datetime(1997, 11, 7, 9, 0),
655
datetime.datetime(1997, 12, 5, 9, 0),
656
datetime.datetime(1998, 1, 2, 9, 0),
657
datetime.datetime(1998, 2, 6, 9, 0),
658
datetime.datetime(1998, 3, 6, 9, 0),
659
datetime.datetime(1998, 4, 3, 9, 0),
660
datetime.datetime(1998, 5, 1, 9, 0),
661
datetime.datetime(1998, 6, 5, 9, 0)]
664
Every other month on the 1st and last Sunday of the month for 10 occurrences.
666
>>> list(rrule(FREQ_MONTHLY, interval=2, count=10, byweekday=(SU(1), SU(-1)), dtstart=parse("19970907T090000")))
667
[datetime.datetime(1997, 9, 7, 9, 0),
668
datetime.datetime(1997, 9, 28, 9, 0),
669
datetime.datetime(1997, 11, 2, 9, 0),
670
datetime.datetime(1997, 11, 30, 9, 0),
671
datetime.datetime(1998, 1, 4, 9, 0),
672
datetime.datetime(1998, 1, 25, 9, 0),
673
datetime.datetime(1998, 3, 1, 9, 0),
674
datetime.datetime(1998, 3, 29, 9, 0),
675
datetime.datetime(1998, 5, 3, 9, 0),
676
datetime.datetime(1998, 5, 31, 9, 0)]
679
Monthly on the second to last Monday of the month for 6 months.
681
>>> list(rrule(FREQ_MONTHLY, count=6, byweekday=MO(-2), dtstart=parse("19970922T090000")))
682
[datetime.datetime(1997, 9, 22, 9, 0),
683
datetime.datetime(1997, 10, 20, 9, 0),
684
datetime.datetime(1997, 11, 17, 9, 0),
685
datetime.datetime(1997, 12, 22, 9, 0),
686
datetime.datetime(1998, 1, 19, 9, 0),
687
datetime.datetime(1998, 2, 16, 9, 0)]
690
Monthly on the third to the last day of the month, for 6 months.
692
>>> list(rrule(FREQ_MONTHLY, count=6, bymonthday=-3, dtstart=parse("19970928T090000")))
693
[datetime.datetime(1997, 9, 28, 9, 0),
694
datetime.datetime(1997, 10, 29, 9, 0),
695
datetime.datetime(1997, 11, 28, 9, 0),
696
datetime.datetime(1997, 12, 29, 9, 0),
697
datetime.datetime(1998, 1, 29, 9, 0),
698
datetime.datetime(1998, 2, 26, 9, 0)]
701
Monthly on the 2nd and 15th of the month for 5 occurrences.
703
>>> list(rrule(FREQ_MONTHLY, count=5, bymonthday=(2,15), dtstart=parse("19970902T090000")))
704
[datetime.datetime(1997, 9, 2, 9, 0),
705
datetime.datetime(1997, 9, 15, 9, 0),
706
datetime.datetime(1997, 10, 2, 9, 0),
707
datetime.datetime(1997, 10, 15, 9, 0),
708
datetime.datetime(1997, 11, 2, 9, 0)]
711
Monthly on the first and last day of the month for 3 occurrences.
713
>>> list(rrule(FREQ_MONTHLY, count=5, bymonthday=(-1,1,), dtstart=parse("1997090
715
[datetime.datetime(1997, 9, 30, 9, 0),
716
datetime.datetime(1997, 10, 1, 9, 0),
717
datetime.datetime(1997, 10, 31, 9, 0),
718
datetime.datetime(1997, 11, 1, 9, 0),
719
datetime.datetime(1997, 11, 30, 9, 0)]
722
Every 18 months on the 10th thru 15th of the month for 10 occurrences.
724
>>> list(rrule(FREQ_MONTHLY, interval=18, count=10, bymonthday=range(10,16), dtstart=parse("19970910T090000")))
725
[datetime.datetime(1997, 9, 10, 9, 0),
726
datetime.datetime(1997, 9, 11, 9, 0),
727
datetime.datetime(1997, 9, 12, 9, 0),
728
datetime.datetime(1997, 9, 13, 9, 0),
729
datetime.datetime(1997, 9, 14, 9, 0),
730
datetime.datetime(1997, 9, 15, 9, 0),
731
datetime.datetime(1999, 3, 10, 9, 0),
732
datetime.datetime(1999, 3, 11, 9, 0),
733
datetime.datetime(1999, 3, 12, 9, 0),
734
datetime.datetime(1999, 3, 13, 9, 0)]
737
Every Tuesday, every other month, 6 occurences.
739
>>> list(rrule(FREQ_MONTHLY, interval=2, count=6, byweekday=TU, dtstart=parse("1
741
[datetime.datetime(1997, 9, 2, 9, 0),
742
datetime.datetime(1997, 9, 9, 9, 0),
743
datetime.datetime(1997, 9, 16, 9, 0),
744
datetime.datetime(1997, 9, 23, 9, 0),
745
datetime.datetime(1997, 9, 30, 9, 0),
746
datetime.datetime(1997, 11, 4, 9, 0)]
749
Yearly in June and July for 10 occurrences.
751
>>> list(rrule(FREQ_YEARLY, count=4, bymonth=(6,7), dtstart=parse("19970610T0900
753
[datetime.datetime(1997, 6, 10, 9, 0),
754
datetime.datetime(1997, 7, 10, 9, 0),
755
datetime.datetime(1998, 6, 10, 9, 0),
756
datetime.datetime(1998, 7, 10, 9, 0)]
759
Every 3rd year on the 1st, 100th and 200th day for 4 occurrences.
761
>>> list(rrule(FREQ_YEARLY, count=4, interval=3, byyearday=(1,100,200), dtstart=parse("19970101T090000")))
762
[datetime.datetime(1997, 1, 1, 9, 0),
763
datetime.datetime(1997, 4, 10, 9, 0),
764
datetime.datetime(1997, 7, 19, 9, 0),
765
datetime.datetime(2000, 1, 1, 9, 0)]
768
Every 20th Monday of the year, 3 occurrences.
770
>>> list(rrule(FREQ_YEARLY, count=3, byweekday=MO(20), dtstart=parse("19970519T090000")))
771
[datetime.datetime(1997, 5, 19, 9, 0),
772
datetime.datetime(1998, 5, 18, 9, 0),
773
datetime.datetime(1999, 5, 17, 9, 0)]
776
Monday of week number 20 (where the default start of the week is Monday),
779
>>> list(rrule(FREQ_YEARLY, count=3, byweekno=20, byweekday=MO, dtstart=parse("19970512T090000")))
780
[datetime.datetime(1997, 5, 12, 9, 0),
781
datetime.datetime(1998, 5, 11, 9, 0),
782
datetime.datetime(1999, 5, 17, 9, 0)]
785
The week number 1 may be in the last year.
787
>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=1, byweekday=MO, dtstart=parse("19970902T090000")))
788
[datetime.datetime(1997, 12, 29, 9, 0),
789
datetime.datetime(1999, 1, 4, 9, 0),
790
datetime.datetime(2000, 1, 3, 9, 0)]
793
And the week numbers greater than 51 may be in the next year.
795
>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=52, byweekday=SU, dtstart=parse("19970902T090000")))
796
[datetime.datetime(1997, 12, 28, 9, 0),
797
datetime.datetime(1998, 12, 27, 9, 0),
798
datetime.datetime(2000, 1, 2, 9, 0)]
801
Only some years have week number 53:
803
>>> list(rrule(FREQ_WEEKLY, count=3, byweekno=53, byweekday=MO, dtstart=parse("19970902T090000")))
804
[datetime.datetime(1998, 12, 28, 9, 0),
805
datetime.datetime(2004, 12, 27, 9, 0),
806
datetime.datetime(2009, 12, 28, 9, 0)]
809
Every Friday the 13th, 4 occurrences.
811
>>> list(rrule(FREQ_YEARLY, count=4, byweekday=FR, bymonthday=13, dtstart=parse(
813
[datetime.datetime(1998, 2, 13, 9, 0),
814
datetime.datetime(1998, 3, 13, 9, 0),
815
datetime.datetime(1998, 11, 13, 9, 0),
816
datetime.datetime(1999, 8, 13, 9, 0)]
819
Every four years, the first Tuesday after a Monday in November,
820
3 occurrences (U.S. Presidential Election day):
822
>>> list(rrule(FREQ_YEARLY, interval=4, count=3, bymonth=11, byweekday=TU, bymonthday=(2,3,4,5,6,7,8), dtstart=parse("19961105T090000")))
823
[datetime.datetime(1996, 11, 5, 9, 0),
824
datetime.datetime(2000, 11, 7, 9, 0),
825
datetime.datetime(2004, 11, 2, 9, 0)]
828
The 3rd instance into the month of one of Tuesday, Wednesday or
829
Thursday, for the next 3 months:
831
>>> list(rrule(FREQ_MONTHLY, count=3, byweekday=(TU,WE,TH), bysetpos=3, dtstart=parse("19970904T090000")))
832
[datetime.datetime(1997, 9, 4, 9, 0),
833
datetime.datetime(1997, 10, 7, 9, 0),
834
datetime.datetime(1997, 11, 6, 9, 0)]
837
The 2nd to last weekday of the month, 3 occurrences.
839
>>> list(rrule(FREQ_MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), bysetpos=-2, d
840
tstart=parse("19970929T090000")))
841
[datetime.datetime(1997, 9, 29, 9, 0),
842
datetime.datetime(1997, 10, 30, 9, 0),
843
datetime.datetime(1997, 11, 27, 9, 0)]
846
Every 3 hours from 9:00 AM to 5:00 PM on a specific day.
848
>>> list(rrule(FREQ_HOURLY, interval=3, dtstart=parse("19970902T090000"), until=parse("19970902T170000")))
849
[datetime.datetime(1997, 9, 2, 9, 0),
850
datetime.datetime(1997, 9, 2, 12, 0),
851
datetime.datetime(1997, 9, 2, 15, 0)]
854
Every 15 minutes for 6 occurrences.
856
>>> list(rrule(FREQ_MINUTELY, interval=15, count=6, dtstart=parse("19970902T0900
858
[datetime.datetime(1997, 9, 2, 9, 0),
859
datetime.datetime(1997, 9, 2, 9, 15),
860
datetime.datetime(1997, 9, 2, 9, 30),
861
datetime.datetime(1997, 9, 2, 9, 45),
862
datetime.datetime(1997, 9, 2, 10, 0),
863
datetime.datetime(1997, 9, 2, 10, 15)]
866
Every hour and a half for 4 occurrences.
868
>>> list(rrule(FREQ_MINUTELY, interval=90, count=4, dtstart=parse("19970902T0900
870
[datetime.datetime(1997, 9, 2, 9, 0),
871
datetime.datetime(1997, 9, 2, 10, 30),
872
datetime.datetime(1997, 9, 2, 12, 0),
873
datetime.datetime(1997, 9, 2, 13, 30)]
876
Every 20 minutes from 9:00 AM to 4:40 PM for two days.
878
>>> list(rrule(FREQ_MINUTELY, interval=20, count=48, byhour=range(9,17), byminut
879
e=(0,20,40), dtstart=parse("19970902T090000")))
880
[datetime.datetime(1997, 9, 2, 9, 0),
881
datetime.datetime(1997, 9, 2, 9, 20),
883
datetime.datetime(1997, 9, 2, 16, 20),
884
datetime.datetime(1997, 9, 2, 16, 40),
885
datetime.datetime(1997, 9, 3, 9, 0),
886
datetime.datetime(1997, 9, 3, 9, 20),
888
datetime.datetime(1997, 9, 3, 16, 20),
889
datetime.datetime(1997, 9, 3, 16, 40)]
892
An example where the days generated makes a difference because of {{{wkst}}}.
894
>>> list(rrule(FREQ_WEEKLY, interval=2, count=4, byweekday=(TU,SU), wkst=MO, dtstart=parse("19970805T090000")))
895
[datetime.datetime(1997, 8, 5, 9, 0),
896
datetime.datetime(1997, 8, 10, 9, 0),
897
datetime.datetime(1997, 8, 19, 9, 0),
898
datetime.datetime(1997, 8, 24, 9, 0)]
900
>>> list(rrule(FREQ_WEEKLY, interval=2, count=4, byweekday=(TU,SU), wkst=SU, dts
901
tart=parse("19970805T090000")))
902
[datetime.datetime(1997, 8, 5, 9, 0),
903
datetime.datetime(1997, 8, 17, 9, 0),
904
datetime.datetime(1997, 8, 19, 9, 0),
905
datetime.datetime(1997, 8, 31, 9, 0)]
908
==== rruleset type ====
909
The {{{rruleset}}} type allows more complex recurrence setups, mixing
910
multiple rules, dates, exclusion rules, and exclusion dates.
911
The type constructor takes the following keyword arguments:
914
If True, caching of results will be enabled, improving performance
915
of multiple queries considerably.
917
==== rruleset methods ====
918
The following methods are available:
920
rruleset.rrule(rrule)::
921
Include the given {{{rrule}}} instance in the recurrence set
925
Include the given {{{datetime}}} instance in the recurrence
928
rruleset.exrule(rrule)::
929
Include the given {{{rrule}}} instance in the recurrence set
930
exclusion list. Dates which are part of the given recurrence
931
rules will not be generated, even if some inclusive {{{rrule}}}
932
or {{{rdate}}} matches them.
934
rruleset.exdate(dt)::
935
Include the given {{{datetime}}} instance in the recurrence set
936
exclusion list. Dates included that way will not be generated,
937
even if some inclusive {{{rrule}}} or {{{rdate}}} matches them.
939
rruleset.before(dt, inc=False)::
940
Returns the last recurrence before the given {{{datetime}}}
941
instance. The {{{inc}}} keyword defines what happens if
942
{{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
943
if {{{dt}}} itself is an occurrence, it will be returned.
945
rruleset.after(dt, inc=False)::
946
Returns the first recurrence after the given {{{datetime}}}
947
instance. The {{{inc}}} keyword defines what happens if
948
{{{dt}}} '''is''' an occurrence. With {{{inc == True}}},
949
if {{{dt}}} itself is an occurrence, it will be returned.
951
rruleset.between(after, before, inc=False)::
952
Returns all the occurrences of the rrule between {{{after}}}
953
and {{{before}}}. The {{{inc}}} keyword defines what happens
954
if {{{after}}} and/or {{{before}}} are themselves occurrences.
955
With {{{inc == True}}}, they will be included in the list,
956
if they are found in the recurrence set.
959
Returns the number of recurrences in this set. It will have
960
go trough the whole recurrence, if this hasn't been done
963
Besides these methods, {{{rruleset}}} instances also support
964
the {{{__getitem__()}}} and {{{__contains__()}}} special methods,
965
meaning that these are valid expressions:
968
if datetime(...) in set:
976
The getitem/slicing mechanism is smart enough to avoid getting the whole
977
recurrence set, if possible.
979
==== rruleset examples ====
980
Daily, for 7 days, jumping Saturday and Sunday occurrences.
983
>>> set.rrule(rrule(FREQ_DAILY, count=7, dtstart=parse("19970902T090000")))
984
>>> set.exrule(rrule(FREQ_YEARLY, byweekday=(SA,SU), dtstart=parse("19970902T090000")))
986
[datetime.datetime(1997, 9, 2, 9, 0),
987
datetime.datetime(1997, 9, 3, 9, 0),
988
datetime.datetime(1997, 9, 4, 9, 0),
989
datetime.datetime(1997, 9, 5, 9, 0),
990
datetime.datetime(1997, 9, 8, 9, 0)]
993
Weekly, for 4 weeks, plus one time on day 7, and not on day 16.
996
>>> set.rrule(rrule(FREQ_WEEKLY, count=4, dtstart=parse("19970902T090000")))
997
>>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0))
998
>>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0))
1000
[datetime.datetime(1997, 9, 2, 9, 0),
1001
datetime.datetime(1997, 9, 7, 9, 0),
1002
datetime.datetime(1997, 9, 9, 9, 0),
1003
datetime.datetime(1997, 9, 23, 9, 0)]
1006
==== rrulestr() function ====
1007
The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes.
1008
The function prototype is:
1013
The string passed as parameter may be a multiple line string, a
1014
single line string, or just the {{{RRULE}}} property value.
1016
Additionally, it accepts the following keyword arguments:
1019
If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance
1020
will cache its results. Default is not to cache.
1023
If given, it must be a {{{datetime}}} instance that will be used
1024
when no {{{DTSTART}}} property is found in the parsed string. If
1025
it is not given, and the property is not found, {{{datetime.now()}}}
1026
will be used instead.
1029
If set to {{{True}}}, lines will be unfolded following the RFC
1030
specification. It defaults to {{{False}}}, meaning that spaces
1031
before every line will be stripped.
1034
If set to {{{True}}} a {{{rruleset}}} instance will be returned,
1035
even if only a single rule is found. The default is to return an
1036
{{{rrule}}} if possible, and an {{{rruleset}}} if necessary.
1039
If set to {{{True}}}, the parser will operate in RFC-compatible
1040
mode. Right now it means that {{{unfold}}} will be turned on,
1041
and if a {{{DTSTART}}} is found, it will be considered the first
1042
recurrence instance, as documented in the RFC.
1045
If set to {{{True}}}, the date parser will ignore timezone
1046
information available in the {{{DTSTART}}} property, or the
1047
{{{UNTIL}}} attribute.
1050
If set, it will be passed to the datetime string parser to
1051
resolve unknown timezone settings. For more information about
1052
what could be used here, check the parser documentation.
1054
==== rrulestr() examples ====
1056
Every 10 days, 5 occurrences.
1058
>>> list(rrulestr("""
1059
... DTSTART:19970902T090000
1060
... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
1062
[datetime.datetime(1997, 9, 2, 9, 0),
1063
datetime.datetime(1997, 9, 12, 9, 0),
1064
datetime.datetime(1997, 9, 22, 9, 0),
1065
datetime.datetime(1997, 10, 2, 9, 0),
1066
datetime.datetime(1997, 10, 12, 9, 0)]
1069
Same thing, but passing only the {{{RRULE}}} value.
1071
>>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", dtstart=parse("19970902T090000")))
1072
[datetime.datetime(1997, 9, 2, 9, 0),
1073
datetime.datetime(1997, 9, 12, 9, 0),
1074
datetime.datetime(1997, 9, 22, 9, 0),
1075
datetime.datetime(1997, 10, 2, 9, 0),
1076
datetime.datetime(1997, 10, 12, 9, 0)]
1079
Notice that when using a single rule, it returns an
1080
{{{rrule}}} instance, unless {{{forceset}}} was used.
1082
>>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5")
1083
<dateutil.rrule.rrule instance at 0x30269f08>
1086
... DTSTART:19970902T090000
1087
... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
1089
<dateutil.rrule.rrule instance at 0x302699e0>
1091
>>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True)
1092
<dateutil.rrule.rruleset instance at 0x30269f08>
1095
But when an {{{rruleset}}} is needed, it is automatically used.
1098
... DTSTART:19970902T090000
1099
... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
1100
... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3
1102
<dateutil.rrule.rruleset instance at 0x302699e0>
1106
This module offers a generic date/time string parser which is
1107
able to parse most known formats to represent a date and/or
1110
==== parse() function ====
1111
That's probably the only function you'll need from this module.
1112
It offers you an interface to access the parser functionality and
1113
extract a {{{datetime}}} type out of a string.
1115
The prototype of this function is:
1120
Additionally, the following keyword arguments are available:
1123
If given, this must be a {{{datetime}}} instance. Any fields
1124
missing in the parsed date will be copied from this instance.
1125
The default value is the current date, at 00:00:00am.
1128
If this is true, even if a timezone is found in the string,
1129
the parser will not use it.
1132
Using this keyword argument you may provide custom timezones
1133
to the parser. If given, it must be either a dictionary with
1134
the timezone abbreviation as key, or a function accepting a
1135
timezone abbreviation and offset as argument. The dictionary
1136
values and the function return must be a timezone offset
1137
in seconds, a tzinfo subclass, or a string defining the
1138
timezone (in the TZ environment variable format).
1141
This option allow one to change the precedence in which
1142
days are parsed in date strings. The default is given in the
1143
parserinfo instance (the default parserinfo has it set to
1144
False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}}
1145
format will have precedence over {{{DD-MM-YYYY}}} in an
1149
This option allow one to change the precedence in which
1150
years are parsed in date strings. The default is given in
1151
the parserinfo instance (the default parserinfo has it set
1152
to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}}
1153
format will have precedence over {{{YY-MM-DD}}} in an
1157
If {{{fuzzy}}} is set to True, unknown tokens in the string
1161
This parameter allows one to change how the string is parsed,
1162
by using a different parserinfo class instance. Using it you
1163
may, for example, intenationalize the parser strings, or make
1164
it ignore additional words.
1166
==== Format precedence ====
1167
Whenever an ambiguous date is found, the {{{dayfirst}}} and
1168
{{{yearfirst}}} parameters will control how the information
1169
is processed. Here is the precedence in each case:
1171
If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}},
1172
(default, if no parameter is given):
1178
If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}:
1184
If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}:
1190
If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}:
1196
==== Converting two digit years ====
1197
When a two digit year is found, it is processed considering
1198
the current year, so that the computed year is never more
1199
than 49 years after then current year, nor 50 years before the
1200
current year. In other words, if we are in year 2003, and the
1201
year 30 is found, it will be considered as 2030, but if the
1202
year 60 is found, it will be considered 1960.
1205
The following code will prepare the environment:
1207
>>> from dateutil.parser import *
1208
>>> from dateutil.tz import *
1209
>>> from datetime import *
1210
>>> TZOFFSETS = {"BRST": -10800}
1211
>>> BRSTTZ = tzoffset(-10800, "BRST")
1212
>>> DEFAULT = datetime(2003, 9, 25)
1215
Some simple examples based on the {{{date}}} command, using the
1216
{{{TZOFFSET}}} dictionary to provide the BRST timezone offset.
1218
>>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS)
1219
datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzoffset('BRST', -10800))
1221
>>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS)
1222
datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzoffset('BRST', -10800))
1225
Notice that since BRST is my local timezone, parsing it without
1226
further timezone settings will yield a {{{tzlocal}}} timezone.
1228
>>> parse("Thu Sep 25 10:36:28 BRST 2003")
1229
datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal())
1232
We can also ask to ignore the timezone explicitly:
1234
>>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True)
1235
datetime.datetime(2003, 9, 25, 10, 36, 28)
1238
That's the same as processing a string without timezone:
1240
>>> parse("Thu Sep 25 10:36:28 2003")
1241
datetime.datetime(2003, 9, 25, 10, 36, 28)
1244
Without the year, but passing our {{{DEFAULT}}} datetime to return
1245
the same year, no mattering what year we currently are in:
1247
>>> parse("Thu Sep 25 10:36:28", default=DEFAULT)
1248
datetime.datetime(2003, 9, 25, 10, 36, 28)
1253
>>> parse("Thu Sep 10:36:28", default=DEFAULT)
1254
datetime.datetime(2003, 9, 25, 10, 36, 28)
1256
>>> parse("Thu 10:36:28", default=DEFAULT)
1257
datetime.datetime(2003, 9, 25, 10, 36, 28)
1259
>>> parse("Thu 10:36", default=DEFAULT)
1260
datetime.datetime(2003, 9, 25, 10, 36)
1262
>>> parse("10:36", default=DEFAULT)
1263
datetime.datetime(2003, 9, 25, 10, 36)
1267
Strip in a different way:
1269
>>> parse("Thu Sep 25 2003")
1270
datetime.datetime(2003, 9, 25, 0, 0)
1272
>>> parse("Sep 25 2003")
1273
datetime.datetime(2003, 9, 25, 0, 0)
1275
>>> parse("Sep 2003", default=DEFAULT)
1276
datetime.datetime(2003, 9, 25, 0, 0)
1278
>>> parse("Sep", default=DEFAULT)
1279
datetime.datetime(2003, 9, 25, 0, 0)
1281
>>> parse("2003", default=DEFAULT)
1282
datetime.datetime(2003, 9, 25, 0, 0)
1285
Another format, based on {{{date -R}}} (RFC822):
1287
>>> parse("Thu, 25 Sep 2003 10:49:41 -0300")
1288
datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
1293
>>> parse("2003-09-25T10:49:41.5-03:00")
1294
datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, tzinfo=tzoffset(None, -10800))
1299
>>> parse("2003-09-25T10:49:41")
1300
datetime.datetime(2003, 9, 25, 10, 49, 41)
1302
>>> parse("2003-09-25T10:49")
1303
datetime.datetime(2003, 9, 25, 10, 49)
1305
>>> parse("2003-09-25T10")
1306
datetime.datetime(2003, 9, 25, 10, 0)
1308
>>> parse("2003-09-25")
1309
datetime.datetime(2003, 9, 25, 0, 0)
1312
ISO format, without separators:
1314
>>> parse("20030925T104941.5-0300")
1315
datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, tzinfo=tzinfo=tzoffset(None, -10800))
1317
>>> parse("20030925T104941-0300")
1318
datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
1320
>>> parse("20030925T104941")
1321
datetime.datetime(2003, 9, 25, 10, 49, 41)
1323
>>> parse("20030925T1049")
1324
datetime.datetime(2003, 9, 25, 10, 49)
1326
>>> parse("20030925T10")
1327
datetime.datetime(2003, 9, 25, 10, 0)
1329
>>> parse("20030925")
1330
datetime.datetime(2003, 9, 25, 0, 0)
1333
Everything together.
1335
>>> parse("199709020900")
1336
datetime.datetime(1997, 9, 2, 9, 0)
1337
>>> parse("19970902090059")
1338
datetime.datetime(1997, 9, 2, 9, 0, 59)
1341
Different date orderings:
1343
>>> parse("2003-09-25")
1344
datetime.datetime(2003, 9, 25, 0, 0)
1346
>>> parse("2003-Sep-25")
1347
datetime.datetime(2003, 9, 25, 0, 0)
1349
>>> parse("25-Sep-2003")
1350
datetime.datetime(2003, 9, 25, 0, 0)
1352
>>> parse("Sep-25-2003")
1353
datetime.datetime(2003, 9, 25, 0, 0)
1355
>>> parse("09-25-2003")
1356
datetime.datetime(2003, 9, 25, 0, 0)
1358
>>> parse("25-09-2003")
1359
datetime.datetime(2003, 9, 25, 0, 0)
1362
Check some ambiguous dates:
1364
>>> parse("10-09-2003")
1365
datetime.datetime(2003, 10, 9, 0, 0)
1367
>>> parse("10-09-2003", dayfirst=True)
1368
datetime.datetime(2003, 9, 10, 0, 0)
1370
>>> parse("10-09-03")
1371
datetime.datetime(2003, 10, 9, 0, 0)
1373
>>> parse("10-09-03", yearfirst=True)
1374
datetime.datetime(2010, 9, 3, 0, 0)
1377
Other date separators are allowed:
1379
>>> parse("2003.Sep.25")
1380
datetime.datetime(2003, 9, 25, 0, 0)
1382
>>> parse("2003/09/25")
1383
datetime.datetime(2003, 9, 25, 0, 0)
1388
>>> parse("2003 Sep 25")
1389
datetime.datetime(2003, 9, 25, 0, 0)
1391
>>> parse("2003 09 25")
1392
datetime.datetime(2003, 9, 25, 0, 0)
1395
Hours with letters work:
1397
>>> parse("10h36m28.5s", default=DEFAULT)
1398
datetime.datetime(2003, 9, 25, 10, 36, 28, 500000)
1400
>>> parse("01s02h03m", default=DEFAULT)
1401
datetime.datetime(2003, 9, 25, 2, 3, 1)
1403
>>> parse("01h02m03", default=DEFAULT)
1404
datetime.datetime(2003, 9, 3, 1, 2)
1406
>>> parse("01h02", default=DEFAULT)
1407
datetime.datetime(2003, 9, 2, 1, 0)
1409
>>> parse("01h02s", default=DEFAULT)
1410
datetime.datetime(2003, 9, 25, 1, 0, 2)
1415
>>> parse("10h am", default=DEFAULT)
1416
datetime.datetime(2003, 9, 25, 10, 0)
1418
>>> parse("10pm", default=DEFAULT)
1419
datetime.datetime(2003, 9, 25, 22, 0)
1421
>>> parse("12:00am", default=DEFAULT)
1422
datetime.datetime(2003, 9, 25, 0, 0)
1424
>>> parse("12pm", default=DEFAULT)
1425
datetime.datetime(2003, 9, 25, 12, 0)
1428
Some special treating for ''pertain'' relations:
1430
>>> parse("Sep 03", default=DEFAULT)
1431
datetime.datetime(2003, 9, 3, 0, 0)
1433
>>> parse("Sep of 03", default=DEFAULT)
1434
datetime.datetime(2003, 9, 25, 0, 0)
1439
>>> s = "Today is 25 of September of 2003, exactly " \
1440
... "at 10:49:41 with timezone -03:00."
1441
>>> parse(s, fuzzy=True)
1442
datetime.datetime(2003, 9, 25, 10, 49, 41, tzinfo=tzoffset(None, -10800))
1445
Other random formats:
1447
>>> parse("Wed, July 10, '96")
1448
datetime.datetime(1996, 7, 10, 0, 0)
1450
>>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True)
1451
datetime.datetime(1996, 7, 10, 15, 8, 56)
1453
>>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True)
1454
datetime.datetime(1952, 4, 12, 15, 30, 42)
1456
>>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True)
1457
datetime.datetime(1994, 11, 5, 8, 15, 30)
1459
>>> parse("3rd of May 2001")
1460
datetime.datetime(2001, 5, 3, 0, 0)
1462
>>> parse("5:50 A.M. on June 13, 1990")
1463
datetime.datetime(1990, 6, 13, 5, 50)
1467
This module offers a generic easter computing method for
1468
any given year, using Western, Orthodox or Julian algorithms.
1470
==== easter() function ====
1471
This method was ported from the work done by
1472
[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts],
1473
on top of the algorithm by
1474
[http://www.tondering.dk/claus/calendar.html Claus Tondering],
1475
which was based in part on the algorithm of Ouding (1940),
1476
as quoted in "Explanatory Supplement to the Astronomical
1477
Almanac", P. Kenneth Seidelmann, editor.
1479
This algorithm implements three different easter
1480
calculation methods:
1482
1. Original calculation in Julian calendar, valid in
1484
1. Original method, with date converted to Gregorian
1485
calendar, valid in years 1583 to 4099
1486
1. Revised method, in Gregorian calendar, valid in
1487
years 1583 to 4099 as well
1489
These methods are represented by the constants:
1496
The default method is method 3.
1499
This module offers timezone implementations subclassing
1500
the abstract {{{datetime.tzinfo}}} type. There are
1501
classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile]
1502
format files (usually are in /etc/localtime,
1503
/usr/share/zoneinfo, etc), TZ environment string (in all
1504
known formats), given ranges (with help from relative
1505
deltas), local machine timezone, fixed offset timezone,
1508
==== tzutc type ====
1509
This type implements a basic UTC timezone. The constructor of this
1510
type accepts no parameters.
1512
==== tzutc examples ====
1514
>>> from datetime import *
1515
>>> from dateutil.tz import *
1518
datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
1520
>>> datetime.now(tzutc())
1521
datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
1523
>>> datetime.now(tzutc()).tzname()
1527
==== tzoffset type ====
1528
This type implements a fixed offset timezone, with no
1529
support to daylight saving times. Here is the prototype of the
1532
tzoffset(name, offset)
1535
The {{{name}}} parameter may be optionally set to {{{None}}}, and
1536
{{{offset}}} must be given in seconds.
1538
==== tzoffset examples ====
1540
>>> from datetime import *
1541
>>> from dateutil.tz import *
1543
>>> datetime.now(tzoffset("BRST", -10800))
1544
datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, tzinfo=tzinfo=tzoffset('BRST', -10800))
1546
>>> datetime.now(tzoffset("BRST", -10800)).tzname()
1549
>>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc())
1550
datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, tzinfo=tzutc())
1553
==== tzlocal type ====
1554
This type implements timezone settings as known by the
1555
operating system. The constructor of this type accepts no
1558
==== tzlocal examples ====
1560
>>> from datetime import *
1561
>>> from dateutil.tz import *
1563
>>> datetime.now(tzlocal())
1564
datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, tzinfo=tzlocal())
1566
>>> datetime.now(tzlocal()).tzname()
1569
>>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0))
1570
datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, tzinfo=tzoffset(None, 0))
1573
==== tzstr type ====
1574
This type implements timezone settings extracted from a
1575
string in known TZ environment variable formats. Here is the prototype
1581
==== tzstr examples ====
1582
Here are examples of the recognized formats:
1585
* {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}}
1586
* {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}}
1587
* {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}}
1588
* {{{EST5EDT4,95/02:00:00,298/02:00}}}
1589
* {{{EST5EDT4,J96/02:00:00,J299/02:00}}}
1591
Notice that if daylight information is not present, but a
1592
daylight abbreviation was provided, {{{tzstr}}} will follow the
1593
convention of using the first sunday of April to start daylight
1594
saving, and the last sunday of October to end it. If start or
1595
end time is not present, 2AM will be used, and if the daylight
1596
offset is not present, the standard offset plus one hour will
1597
be used. This convention is the same as used in the GNU libc.
1599
This also means that some of the above examples are exactly
1600
equivalent, and all of these examples are equivalent
1601
in the year of 2003.
1603
Here is the example mentioned in the
1604
[http://www.python.org/doc/current/lib/module-time.html time module documentation].
1606
>>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0'
1608
>>> time.strftime('%X %x %Z')
1609
'02:07:36 05/08/03 EDT'
1610
>>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0'
1612
>>> time.strftime('%X %x %Z')
1613
'16:08:12 05/08/03 AEST'
1616
And here is an example showing the same information using {{{tzstr}}},
1617
without touching system settings.
1619
>>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0')
1620
>>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0')
1621
>>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1)
1622
>>> dt.strftime('%X %x %Z')
1623
'02:07:36 05/08/03 EDT'
1624
>>> dt.astimezone(tz2).strftime('%X %x %Z')
1625
'16:07:36 05/08/03 AEST'
1628
Are these really equivalent?
1630
>>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600')
1634
Check the daylight limit.
1636
>>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname()
1638
>>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname()
1640
>>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname()
1642
>>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname()
1646
==== tzrange type ====
1647
This type offers the same functionality as the {{{tzstr}}} type, but
1648
instead of timezone strings, information is passed using
1649
{{{relativedelta}}}s which are applied to a datetime set to the first
1650
day of the year. Here is the prototype of this type's constructor:
1652
tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, start=None, end=None):
1655
Offsets must be given in seconds. Information not provided will be
1656
set to the defaults, as explained in the {{{tzstr}}} section above.
1658
==== tzrange examples ====
1660
>>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
1663
>>> from dateutil.relativedelta import *
1664
>>> range1 = tzrange("EST", -18000, "EDT")
1665
>>> range2 = tzrange("EST", -18000, "EDT", -14400,
1666
... relativedelta(hours=+2, month=4, day=1, weekday=SU(+1)),
1667
... relativedelta(hours=+1, month=10, day=31, weekday=SU(-1)))>>> tzstr('EST5EDT') == range1 == range2
1668
>>> tzstr('EST5EDT') == range1 == range2
1672
Notice a minor detail in the last example: while the DST should end
1673
at 2AM, the delta will catch 1AM. That's because the daylight saving
1674
time should end at 2AM standard time (the difference between STD and
1675
DST is 1h in the given example) instead of the DST time. That's how
1676
the {{{tzinfo}}} subtypes should deal with the extra hour that happens
1677
when going back to the standard time. Check
1678
[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation]
1679
for more information.
1681
==== tzfile type ====
1682
This type allows one to use tzfile(5) format timezone files to extract
1683
current and historical zone information. Here is the type constructor
1689
Where {{{fileobj}}} is either a filename or a file-like object with
1690
a {{{read()}}} method.
1692
==== tzfile examples ====
1694
>>> tz = tzfile("/etc/localtime")
1695
>>> datetime.now(tz)
1696
datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, tzinfo=tzfile('/etc/localtime'))
1698
>>> datetime.now(tz).astimezone(tzutc())
1699
datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, tzinfo=tzutc())
1701
>>> datetime.now(tz).tzname()
1703
>>> datetime(2003, 1, 1, tzinfo=tz).tzname()
1707
Check the daylight limit.
1709
>>> tz = tzfile('/usr/share/zoneinfo/EST5EDT')
1710
>>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname()
1712
>>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname()
1714
>>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname()
1716
>>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname()
1720
==== tzical type ====
1721
This type is able to parse
1722
[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar]
1723
style {{{VTIMEZONE}}} sessions into a Python timezone object.
1724
The constuctor prototype is:
1729
Where {{{fileobj}}} is either a filename or a file-like object with
1730
a {{{read()}}} method.
1732
==== tzical methods ====
1734
tzical.get(tzid=None)::
1735
Since a single iCalendar file may contain more than one timezone,
1736
you must ask for the timezone you want with this method. If there's
1737
more than one timezone in the parsed file, you'll need to pass the
1738
{{{tzid}}} parameter. Otherwise, leaving it empty will yield the only
1741
==== tzical examples ====
1742
Here is a sample file extracted from the RFC. This file defines
1743
the {{{EST5EDT}}} timezone, and will be used in the following example.
1747
LAST-MODIFIED:19870101T000000Z
1748
TZURL:http://zones.stds_r_us.net/tz/US-Eastern
1750
DTSTART:19671029T020000
1751
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
1757
DTSTART:19870405T020000
1758
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
1766
And here is an example exploring a {{{tzical}}} type:
1768
>>> from dateutil.tz import *; from datetime import *
1770
>>> tz = tzical('EST5EDT.ics')
1774
>>> est = tz.get('US-Eastern')
1776
<tzicalvtz 'US-Eastern'>
1778
>>> datetime.now(est)
1779
datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, tzinfo=<tzicalvtz 'US-Eastern'>)
1785
Let's check the daylight ranges, as usual:
1787
>>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname()
1789
>>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname()
1792
>>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname()
1794
>>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname()
1798
==== gettz() function ====
1799
This function is a helper that will try its best to get the right
1800
timezone for your environment, or for the given string. The prototype
1806
If given, the parameter may be a filename, a path relative to the base
1807
of the timezone information path (the base could be
1808
{{{/usr/share/zoneinfo}}}, for example), a string timezone
1809
specification, or a timezone abbreviation. If {{{name}}} is not given,
1810
and the {{{TZ}}} environment variable is set, it's used instead. If the
1811
parameter is not given, and {{{TZ}}} is not set, the default tzfile
1812
paths will be tried.
1816
>>> from dateutil.tz import *
1818
tzfile('/etc/localtime')
1820
>>> gettz("America/Sao Paulo")
1821
tzfile('/usr/share/zoneinfo/America/Sao_Paulo')
1823
>>> gettz("EST5EDT")
1824
tzfile('/usr/share/zoneinfo/EST5EDT')
1832
>>> os.environ["TZ"] = "America/Sao Paulo"
1834
tzfile('/usr/share/zoneinfo/America/Sao_Paulo')
1836
>>> os.environ["TZ"] = "BRST"
1840
>>> gettz("Unavailable")