#! /usr/bin/python
### ---------------------------------------------------
### Name: html_cal.py
###
### Function:
### HTMLized Calendar printing functions
### Based on standard library module calendar.py Revision 2:
### Same interface as the original except only monthly cals with week numbers.
### prmonth() prints to stdout, HTMLmonth() returns a string
### Month names, day and week numbers have pseudo HTML tags
### that will be ignored by most current browsers (yes, it would have
### been cleaner to use real HTML comments...) and can be used by
### other programs to substitute real links based on dates.
### CSS styles can then be used to customize appearance.
###
### Version: 1999.08.24
###
### Author: Fred Pacquier <fredp@dial.oleane.com>
###
### Copyright: Blue Tango Software 1999
###
### Licence: PGPL (Pretty Generous Pacman's License) (just kiddin')
### ---------------------------------------------------
# Import functions and variables from time module
from time import gmtime, localtime, mktime, asctime, ctime, strftime
# Exception raised for bad input (with string parameter for details)
error = 'calendar.error'
# Note when comparing these calendars to the ones printed by cal(1):
# These calendars have Monday as the first day of the week, and Sunday as
# the last (European convention.)
# Constants for months referenced later
January = 1
February = 2
# Number of days per month (except for February in leap years)
mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
# Full and abbreviated names of weekdays
day_name = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', \
'Friday', 'Saturday', 'Sunday']
day_abbr = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
# Full and abbreviated names of months (1-based arrays!!!)
month_name = ['', 'January', 'February', 'March', 'April', \
'May', 'June', 'July', 'August', \
'September', 'October', 'November', 'December']
month_abbr = [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
# Return 1 for leap years, 0 for non-leap years
def isleap(year):
return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0)
# Return number of leap years in range [y1, y2)
# Assume y1 <= y2 and no funny (non-leap century) years
def leapdays(y1, y2):
return (y2+3)/4 - (y1+3)/4
# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31)
def weekday(year, month, day):
secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0))
tuple = localtime(secs)
return tuple[6]
# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month
def monthrange(year, month):
if not 1 <= month <= 12: raise ValueError, 'bad month number'
day1 = weekday(year, month, 1)
ndays = mdays[month] + (month == February and isleap(year))
return day1, ndays
# Return a matrix representing a month's calendar
# Each row represents a week; days outside this month are zero
# The eight element is the week number (from 0 to 52, weeks starting on Mondays)
def _monthcalendar(year, month):
day1, ndays = monthrange(year, month)
rows = []
r7 = range(7)
day = 1 - day1
while day <= ndays:
row = [0, 0, 0, 0, 0, 0, 0, 0]
for i in r7:
if 1 <= day <= ndays: row[i] = day
if row[7]==0 and row[i]>0:
row[7]=int(strftime('%W',localtime(mktime((year, month, day, 0, 0, 0, 0, 0, 0)))))
day = day + 1
rows.append(row)
return rows
# Caching interface to _monthcalendar
_mc_cache = {}
def monthcalendar(year, month):
key = (year, month)
if _mc_cache.has_key(key):
return _mc_cache[key]
else:
_mc_cache[key] = ret = _monthcalendar(year, month)
return ret
# Center a string in a field, add a prefix & suffix not used for calculation (hidden HTML tags)
def _center(str, prefix, suffix, width):
n = width - len(str)
if n <= 0: return prefix + str + suffix
return ' '*((n+1)/2) + prefix + str + suffix + ' '*((n)/2)
# XXX The following code knows that print separates items with space!
# Print a single week (no newline) & week number
def prweek(week, width, month):
for day in week[:-1]:
if day == 0: s = p = ''
else:
s = `day`
p = '<m%d>' % month
print _center(s, p, '', width),
print _center(`week[7]`, '<i><w>', '</i>', width),
# Return a header for a week (bold) & week number col.
def weekheader(width):
str = ''
if width >= 9: names = day_name
else: names = day_abbr
for i in range(7):
if str: str = str + ' '
str = str + _center(names[i%7][:width], '', '', width)
str = '<b>' + str + ' ' + _center('Sem', '<i>', '</i>', width) + '</b>'
return str
# Print a month's calendar with pseudo-HTML tags
def prmonth(year, month, w = 0, l = 0):
w = max(2, w)
l = max(1, l)
print '<pre>'
print _center(month_name[month], '<mn%d>' % month, '</mn%d>' % month, 7*(w+1) - 1),
print '\n'*l,
print weekheader(w),
print '\n'*l,
for week in monthcalendar(year, month):
prweek(week, w, month)
print '\n'*l,
print '</pre>'
# a class that acts as a file but buffers to a string, for stdout redirection
class fakefile:
def __init__(self):
self.buffer=''
def write(self,s):
self.buffer=self.buffer+s
def read(self):
return self.buffer
# same as prmonth(), but returns the calendar code in a string
def HTMLmonth(year, month, w = 0, l = 0):
import sys
ff = fakefile()
sys.stdout = ff
prmonth(year, month, w, l)
buf = ff.read()
del(ff)
return buf
|