Pyfdate Tutorial

Pyfdate Home             Contact Info for Stephen Ferg
Updated: 2008-10-09

Table of Contents

 
 
 
 
 
 
 
 
 
 
 
 
 
 

1 Where is pyfdate documentation?

There is Epydoc documentation and Pydoc documentation

An example file that really puts pyfdate through its paces is pyfdateTester.py. Download it and run it to see what pyfdate can do.

2 Pyfdate's two main classes

Pyfdate provides two major classes:

3 Producing date/time information in different formats

The simplest way to get printable strings for output is to use one of the three properties: w (weekday name), d (civil date), and t (civil time) or combinations thereof.

>>> from pyfdate import *

>>> myTime = Time()

>>> myTime.w
'Sunday'

>>> myTime.d
'December 16, 2007'

>>> myTime.t
'1:52pm'

>>> myTime.wd
'Sunday December 16, 2007'

>>> myTime.wdt
'Sunday December 16, 2007 1:52pm'

>>> myTime.dt
'December 16, 2007 1:52pm'

You can get the integer representations of various parts of the datetime

>>> from pyfdate import *

>>> myTime = Time()
>>> myTime.year
2007
>>> myTime.month
12
>>> myTime.day
16
>>> myTime.hour
13
>>> myTime.minute
52
>>> myTime.second
35

4 Date arithmetic

Subtracting one datetime from another will return the difference between the two datetimes as a timedelta, a Period object.

Adding a timedelta to a datetime will return a new datetime.

>>> myTime = Time()   # create myTime, a Time object


>>> print myTime   
2007-12-16 14:05:09
>>> print myTime.wdt
Sunday December 16, 2007 2:05pm


>>> t2 = Time(2007, 12, 25,6) # Santa arrives at 6am on Christmas morning

>>> timeUntilSantaArrives = t2 - myTime   # timeUntilSantaArrives is a Period object
>>> print timeUntilSantaArrives
8 days 15 hours 54 minutes 50 seconds

>>> # if I'm good, Santa will arrive 12 hours earlier
... g = Period(0,12) # zero days, 12 hours


>>> # I'm good.  Therefore:
... print "Santa will be here in", timeUntilSantaArrives - g
Santa will be here in 8 days 3 hours 54 minutes 50 seconds

>>> newArrivalTime = t2 - g
>>> print "He will arrive:", newArrivalTime.twd
He will arrive: 6:00pm Monday December 24, 2007

5 Date arithmetic (continued) — the add(), subtract(), plus(), minus() methods

The add() method does just what you'd expect: it adds units of time to a datetime.

myTime = Time().add(years=3,months=3,weeks=3,days=3,hours=3,minutes=3,seconds=3)

To subtract time, use the add method to add negative units or use the subtract method.

plus is an alias off add.

minus is an alias of subtract.

>>> myTime = Time()

>>> print myTime.twd
2:43pm Sunday December 16, 2007

>>> t2 = myTime.plus(years=3,weeks=3)  # add 3 years and 3 weeks
>>> print t2.d
January 6, 2011

>>> t2 = t2.add(years=-3)      # subtract 3 years (add negative 3 years)
>>> print  t2.d
January 6, 2008

>>> t2 = t2.minus(weeks=3)     # subtract 3 weeks
>>> print t2.d                 # we're back to where we started
December 16, 2007

>>> print myTime.d
December 16, 2007

6 Chaining operations on Time objects

Pyfdate Time objects (like Python strings) are immutable. Methods that "change" a Time object (for example, add days to it) return a new Time object.

The fact that Time objects are immutable means that you can chain method invocations on Time objects. For example, to find the date on which Memorial Day (the last Monday in May) falls in a range of years, you can code this. (There are shorter ways, but this way illustrates chaining.)

from pyfdate import *
for year in range(2007,2011):
    #-------------------------------------------------------------------------
    # We start with May 1 of the specified year.
    # From there, we go to the end of the month
    # From there we find the previous Monday.  
    # If the last day of the month is itself a Monday, we use it.
    #-------------------------------------------------------------------------
    memorialDay = Time(year,MAY,1).gotoMonthEnd().gotoWeekday(MONDAY, PREVIOUS, useToday=True)
    print memorialDay.wd

which produces

Monday May 28, 2007
Monday May 26, 2008
Monday May 25, 2009
Monday May 31, 2010

7 goto*() methods

Pyfdate provides a number of methods for navigating from one date to another. These are the goto methods.

Syntax:

myTime = Time().gotoMonth(monthname, direction, useToday)
myTime = Time().gotoMonthEnd()

myTime = Time().gotoWeekday(weekdayname, direction, useToday)
myTime = Time().exitWeekend(direction)
Thisproduces this
from pyfdate import *

print "Example 1"

# get the current date/tiem
myTime = Time()
print myTime.dt

# goto the current time-of-day on May 8, 1935
myTime2 = myTime.goto(year=1935, month=5, day=8)   
print myTime2.dt
August 30, 2008 1:19pm
May 8, 1935 1:19pm
from pyfdate import *

myTime = Time(2003, 3, 31)
print myTime.d

myTime2 = myTime.goto(month=2)  # note the use of monthly date arithmetic
print myTime2.d
March 31, 2003
February 28, 2003

8 Monthly date arithmetic

Doing date arithmetic in terms of months and years (groups of 12 months) is tricky because the number of days in a month can vary from month to month, and from year to year. A year can have 365 days... unless it is a leap year with 366 days. A month can have anywhere from 28 to 31 days, depending on which month it is and whether or not it occurs in a leap year. Simple addition can produce invalid results.

February 29, 2004 plus 1 year = February 29, 2005, right? Wrong. 2005 is not a leap year, so in 2005 April has only 28 days.

October 31 minus 1 month = September 31, right? Wrong. October has 31 days, but September has only 30 days.

So you need to define the special principles that will be used for doing monthly arithmetic.

Let A and B be months.

Let Q be a day-of-month (an integer between 1 and 31).

Let A.Q be the day-of-month in month A, and B.Q be the day-of-month in month B.

Pyfdate uses Principle 1 of monthly arithmetic:

If you add X months to A.Q to get B.Q, then B will always be the same month, regardless of whether A.Q is the first day or the last day in A.

If month B has fewer than Q days, you will get the date in B which is as close as possible to B.Q.

So, for pyfdate

February 29, 2004 plus 1 year = February 28, 2005
. . . because in 2005, a non-leap year, February has only 28 days

October 31 minus 1 month = September 30
. . . because September has only 30 days.

There may be situations in which you would prefer a different approach to monthly arithmetic, situations in which you would prefer to use Principle 2.

If you add X months to A.Q to get B.Q, then if B has at least Q days, you will get B.Q.

If B has fewer than Q days, you will get the date in month B+1 which is as close as possible to B.Q (if it existed).

In such situations:

February 29, 2004 plus 1 year = March 1, 2005
. . . because in 2005, a non-leap year, February has only 28 days

October 31 minus 1 month = October 1
. . . because September has only 30 days.

Pyfdate provides a special method — Time.flex() — to do monthly aritmetic using Principle 2 (see below).

Pyfdate provides special methods for doing date arithmetic in terms of years and months.

(Expanded discussion coming soon)
t1 = Time()
t2 = t1.plus(weeks=6)

months, period = t1.diffm(t2)
years, period = t1.diffy(t2)
years, months, period = t1.diffym(t2)

t3 = t2.goto(month=5)

t4 = t3.anniversaryOf(t1)
>>> from pyfdate import *


>>> t1 = Time()
>>> print t1.d
December 17, 2007

>>> t2 = t1.add(months=1,days=14)
>>> print t2.d
January 31, 2008

>>> months, period = t2.diffmonths(t1)
>>> print months
1
>>> print period.short
14 days

>>> t3 = t2.goto(month=2,day=17)


>>> months, period = t3.diffmonths(t1)
>>> print months
2
>>> print period.short
0 seconds

>>> t3=t3.add(days=1)
>>> print t3.d
February 18, 2008
>>> months, period = t3.diffmonths(t1)
>>> print months
2
>>> print period.short
1 day
'''
calculate a person's age using pyfdate
'''
from pyfdate import *

personName = "Elvis Presley"
personDateOfBirth = Time(1935, 1, 8, 6)  # born January 8, 1935 (at 6 am ?)
now = Time()

# show date of birth
print (personName + " was born " + personDateOfBirth.wdt)

# show most recent birthday
personLastBirthday = now.anniversaryOf(personDateOfBirth)
print ("His/her last birthday was " + personLastBirthday.wd )

# show age in various ways

years, months, days = now.diffym(personDateOfBirth)
print ("1. He/she is " + str(years)  + " years " + str(months) + " months " + days.shortest)

years, days = now.diffy(personDateOfBirth)
print ("2. He/she is " + str(years) + " years " + days.shortest)

months, days = now.diffm(personDateOfBirth)
print ("3. He/she is " + str(months) + " months " + days.shortest)

personAge = now - personDateOfBirth
print("4. He/she is "+ personAge.short )

----------------------- produces output ----------------------
Elvis Presley was born Tuesday January 8, 1935 6:00am
His/her last birthday was Monday January 8, 2007
1. He/she is 72 years 11 months 9 days 14 hours 40 minutes 30 seconds
2. He/she is 72 years 343 days 14 hours 40 minutes 30 seconds
3. He/she is 875 months 9 days 14 hours 40 minutes 30 seconds
4. He/she is 26641 days 14 hours 40 minutes 30 seconds

The Time.flex() method can be used to "flex" a date to produce the results that you would get using monthly arithmetic Principle 2.

In the first of the following examples, we add 1 month to January 31. Because February contains only 28 days, we get February 28. If we want to get the counterpart of January 31 in February (February 31, which resolves to March 3) we can "flex" the date based on the base date of January 31.

>>> startDate = Time(2003,1,31)

>>> startDate.d
'January 31, 2003'
>>> startDate.add(months=1).d
'February 28, 2003'
>>> startDate.add(months=1).flex(startDate).d
'March 3, 2003'


>>> t1 = Time(2005,10,31)
>>> t1.d
'October 31, 2005'
>>> t2 = t1.addmonths(-1)
>>> t2.d
'September 30, 2005'
>>> t2 = t2.flex(t1)
>>> t2.d
'October 1, 2005'

9 Example: finding Memorial Day, the last Monday in May

"""
use pyfdate to do Memorial Day calculations.
In the United States, Memorial Day is the last Monday in May.
"""
from pyfdate import *
myTime = Time() # get today

# version 1
# go to the last day of May and backtrack to Monday
print ("Memorial Day of this year: " + 
Time(myTime.year,MAY,1).gotoMonthEnd().gotoWeekday (MONDAY,  PREVIOUS, useToday=True).wd   )

# version 2
# go to the first day of June and backtrack to Monday
print ("Memorial Day of this year: " +
Time(myTime.year,6,1).gotoWeekday(MONDAY, PREVIOUS, useToday=False).wd   )

print("")

print ("Memorial Day of last year: " +  
Time(myTime.year-1,6,1).gotoWeekday(MONDAY, PREVIOUS, useToday=False).wd   )

print ("Memorial Day of next year: " + 
Time(myTime.year+1,6,1).gotoWeekday(MONDAY, PREVIOUS, useToday=False).wd   )

# find the next Memorial Day.
memorialDay_thisYear = Time(myTime.year  ,6,1).gotoWeekday(MONDAY,PREVIOUS,useToday=False)
memorialDay_nextYear = Time(myTime.year+1,6,1).gotoWeekday(MONDAY,PREVIOUS,useToday=False)
 
if myTime < memorialDay_thisYear: m = memorialDay_thisYear
else: m = memorialDay_nextYear
print("")
print("Today is.................: " + myTime.wd)
print("Next Memorial Day is.....: " + m.wd)

This program produces:

Memorial Day of this year: Monday May 28, 2007
Memorial Day of this year: Monday May 28, 2007

Memorial Day of last year: Monday May 29, 2006
Memorial Day of next year: Monday May 26, 2008

Today is.................: Sunday December 16, 2007
Next Memorial Day is.....: Monday May 26, 2008

10 Common Tasks: rename a directory or log file using today's date

The isofilename property returns the ISO datetime with components separated by dashes. It is very handy for constructing filenames.

>>> from pyfdate import *
>>> import os

>>> oldName = "SomeApplication.log"
>>> newName = Time().isofilename + ".log"

>>> print newName
2007-12-09-17-24-30.log

>>> os.rename(oldName,newName)

11 Common Tasks: create timestamped backup directories

"""
A simple Python program to do backups
"""
import os,path,sys
import pyfdate

# get the date and time using pyfdate
myTime = pyfdate.Time()

# put date/time (in the desired format)
# into a string named "today"
today = myTime.isofilename

# make a subdirectory called "backup" if it doesn't already exist
try: os.mkdir("backup")
except: pass
	
# make a subdirectory of the "backup" subdirectory.
# It has the current date/time as the directory name
backupdir = os.path.join("backup",today)
os.mkdir(backupdir)

# copy all files from the current directory 
# into the dated backup directory
os.system("copy *.* " + os.path.join(backupdir,"*.*"))

print "backup done. Backup directory is: ", backupdir

12 Common Tasks: retrieve the timestamp of a file

>>> from pyfdate import *
>>> myTime = Time().fromFile("c:\\autoexec.bat")
>>> myTime.wdt
'Sunday April 15, 2007 10:25pm'

>>> print myTime
2007-04-15 22:25:45

13 Common Tasks: get the current week number

The weeknumber property returns the ISO weeknumber as an int.

>>> from pyfdate import *
>>> myTime = Time()

>>> print myTime.weeknumber
49

14 Common Tasks: parsing a date string

Suppose a user supplies you with a date string, such as "21/03/2005". How can you convert it to a pyfdate Time object?

Pyfdate provides a function called numsplit that parses a string that contains a date into a list of integers. The integers can then be used to construct a Time object.

from pyfdate import *

user_entered_string = "21/03/2005"

day,month,year = numsplit(user_entered_string)

startDate = Time(year, month,day)

Valid CSS!