period.py
This is an early version of a basic time period checking libary for Python. It is in part inspired by perl's Time::Period module and the time class mechanism of Cfengine.
There was a major change at version 0.5 in how the code works. Previous to that you couldn't do any grouping. In order to add grouping, I had to completely change how the parser and the logic of the system works. All tests show that both versions give the same answers, at least for the test cases.
The purpose of this library is simply to allow you to specify a time period and check to see if some time is within that time period. By default, it checks against the current computer time. You can also check to see if a time is on a holiday.
The time period specifications are reasonably straightforward, but there are a few tricky bits. It understands the following time units:
Now if you had some Python script you didn't ever want to run on a weekend, you could do this:
from period import in_period import sys if in_period('Weekend'): sys.exit(0) # Only run on weekdays!
You can negate a time unit with a bang
(!
), so you could also say this, a bit
cryptically:
from period import in_period import sys if in_period('!Weekday'): sys.exit(0) # Don't run on weekends!
You can combine time units into more complex period
specifications with a dot (it's confusing to call it a "period" in
this context). In this case, everything in the period specification
must be true for in_period
to return true. So,
April.Weekend
will be true for every weekend in
April.
In addition to these simple period units, you can
express ranges of times for the ones that use digits. Ranges are
indicated with a '-
' dash. So,
Hr07-Hr21
is true from 7am to 9pm. You can easily
specify your normal working hours, or at something least very close to
them: Weekday.Hr07-Hr16
.
Please note very carefully: time ranges are inclusive. So,
Hr01-Hr03
includes all of 1:00-3:59. If you only want to specify 1:00 to 3:00, then you need instead to sayHr01-Hr02
which includes 1:00-2:59.This is inclusive range behavior is true for the minute, day, year and week ranges as well.
You can also use ranges for days of the week and
months. These will wrap around, so if you do
November-March
, you'll get what you expect. Same
for day ranges: Friday-Tuesday
will match on
Friday, Saturday, Sunday, Monday and Tuesday.
If you want, you can omit the unit part from the
second part of a range. So, Hr07-Hr16
and
Hr07-16
are effectively the same.
If you want leave your lunch hour out of the period
above you have to use a slightly different notation. If you said
Weekday.Hr07-12.Hr13-16
this will fail, because
one or the other of the Hr
periods will fail. So,
to indicate several ranges of these, you use a comma. The correct
period is Weekday.Hr07-11,13-16
. Note that
Hr12
would everything between 12:00 and 12:59, so
we need to get that entire hour out of the time spec.
Hr07-11,12-16
is exactly the same as
Hr07-16
.
In addition to logical "and" you can join periods
with "or" with the |
character (that's a pipe):
Weekday|Weekend.Hr10-22
will be true if it's a
weekday or between 10am and 10pm on a weekend. Note that the "and"
operation (the dot) has higher precedence than the "or" (the pipe).
Finally, you may do some grouping with parentheses,
which work as you'd expect: (Monday|Friday).Hr11-14
or more complex expressions with nested sub-expressions:
(Monday|(Friday.January-March)).Yr2002
You can also negate groups by prefixing the bang:
!(Monday|Friday).Hr11-14
.
If you wish to check some time other than the
current computer time, just pass that time as a second argument to
in_period
:
from period import in_period import sys, time # 86400 == 60 * 60 * 24, a day of seconds if in_period('Weekend', time.time() + 86400): sys.exit(0) # Don't run if tomorrow is a weekend.
The time specifications There is another function in the period library,
The format of the holidays file is fairly strict.
All comment lines must begin with a star, If you happen to have turned on SYSV accounting on a
system, it will start griping several days before the new year to
remind you to update the holidays file. So, if you aren't using SYSV
accounting, that file may be several years out of date. The
If you don't use a system that has SYSV accounting,
you can specify the location of a central holidays file in that format
just fine:
You can also specify some other time to check:
Everything is case sensitive.
Doesn't use distutils to install.
Send questions and problems to
William S. Annis.
Always
and Never
always return true and false
respectively.
Holidays
is_holiday
. This will attempt to consult a SYSV
accounting holidays file. By default, it checks in
/etc/acct/holidays
, but you can specify other
locations.
*
. The
first non-comment line must be the year, prime-time start and
prime-time end. All following non-comment lines take the format
"month/day name-of-holiday" where only the single
month/day
token is significant. So, here's our
example:
* BCG Holidays
*
* Curr Prime Non-Prime
* Year Start Start
*
2002 0700 1800
*
* only the first column (month/day) is significiant.
*
* month/day Holiday name or comment.
*
1/1 New Years Day
* 1/2 A holiday for testing.
1/15 Martin Luther King, Jr. Day
7/4 Independence Day
11/24 Thanksgiving Day
12/25 Christmas
is_holiday
function will ignore an out of
date holidays file, and will always report that a day is not a holiday
until the file is fixed.
from period import is_holiday, in_period
if in_period('Weekend') or is_holiday(holidays="/export/etc/holidays"):
sys.exit(0)
from period import in_period
import sys, time
# 86400 == 60 * 60 * 24, a day of seconds
tomorrow = time.time() + 86400
if in_period('Weekend', tomorrow) or is_holiday(now=tomorrow):
sys.exit(0) # Don't run if tomorrow is a weekend or a holiday.
BUGS