python-2.5.2/win32/Lib/calendar.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Calendar printing functions
       
     2 
       
     3 Note when comparing these calendars to the ones printed by cal(1): By
       
     4 default, these calendars have Monday as the first day of the week, and
       
     5 Sunday as the last (the European convention). Use setfirstweekday() to
       
     6 set the first day of the week (0=Monday, 6=Sunday)."""
       
     7 
       
     8 from __future__ import with_statement
       
     9 import sys
       
    10 import datetime
       
    11 import locale as _locale
       
    12 
       
    13 __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
       
    14            "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
       
    15            "monthcalendar", "prmonth", "month", "prcal", "calendar",
       
    16            "timegm", "month_name", "month_abbr", "day_name", "day_abbr"]
       
    17 
       
    18 # Exception raised for bad input (with string parameter for details)
       
    19 error = ValueError
       
    20 
       
    21 # Exceptions raised for bad input
       
    22 class IllegalMonthError(ValueError):
       
    23     def __init__(self, month):
       
    24         self.month = month
       
    25     def __str__(self):
       
    26         return "bad month number %r; must be 1-12" % self.month
       
    27 
       
    28 
       
    29 class IllegalWeekdayError(ValueError):
       
    30     def __init__(self, weekday):
       
    31         self.weekday = weekday
       
    32     def __str__(self):
       
    33         return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self.weekday
       
    34 
       
    35 
       
    36 # Constants for months referenced later
       
    37 January = 1
       
    38 February = 2
       
    39 
       
    40 # Number of days per month (except for February in leap years)
       
    41 mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
       
    42 
       
    43 # This module used to have hard-coded lists of day and month names, as
       
    44 # English strings.  The classes following emulate a read-only version of
       
    45 # that, but supply localized names.  Note that the values are computed
       
    46 # fresh on each call, in case the user changes locale between calls.
       
    47 
       
    48 class _localized_month:
       
    49 
       
    50     _months = [datetime.date(2001, i+1, 1).strftime for i in xrange(12)]
       
    51     _months.insert(0, lambda x: "")
       
    52 
       
    53     def __init__(self, format):
       
    54         self.format = format
       
    55 
       
    56     def __getitem__(self, i):
       
    57         funcs = self._months[i]
       
    58         if isinstance(i, slice):
       
    59             return [f(self.format) for f in funcs]
       
    60         else:
       
    61             return funcs(self.format)
       
    62 
       
    63     def __len__(self):
       
    64         return 13
       
    65 
       
    66 
       
    67 class _localized_day:
       
    68 
       
    69     # January 1, 2001, was a Monday.
       
    70     _days = [datetime.date(2001, 1, i+1).strftime for i in xrange(7)]
       
    71 
       
    72     def __init__(self, format):
       
    73         self.format = format
       
    74 
       
    75     def __getitem__(self, i):
       
    76         funcs = self._days[i]
       
    77         if isinstance(i, slice):
       
    78             return [f(self.format) for f in funcs]
       
    79         else:
       
    80             return funcs(self.format)
       
    81 
       
    82     def __len__(self):
       
    83         return 7
       
    84 
       
    85 
       
    86 # Full and abbreviated names of weekdays
       
    87 day_name = _localized_day('%A')
       
    88 day_abbr = _localized_day('%a')
       
    89 
       
    90 # Full and abbreviated names of months (1-based arrays!!!)
       
    91 month_name = _localized_month('%B')
       
    92 month_abbr = _localized_month('%b')
       
    93 
       
    94 # Constants for weekdays
       
    95 (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
       
    96 
       
    97 
       
    98 def isleap(year):
       
    99     """Return 1 for leap years, 0 for non-leap years."""
       
   100     return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
       
   101 
       
   102 
       
   103 def leapdays(y1, y2):
       
   104     """Return number of leap years in range [y1, y2).
       
   105        Assume y1 <= y2."""
       
   106     y1 -= 1
       
   107     y2 -= 1
       
   108     return (y2//4 - y1//4) - (y2//100 - y1//100) + (y2//400 - y1//400)
       
   109 
       
   110 
       
   111 def weekday(year, month, day):
       
   112     """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
       
   113        day (1-31)."""
       
   114     return datetime.date(year, month, day).weekday()
       
   115 
       
   116 
       
   117 def monthrange(year, month):
       
   118     """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
       
   119        year, month."""
       
   120     if not 1 <= month <= 12:
       
   121         raise IllegalMonthError(month)
       
   122     day1 = weekday(year, month, 1)
       
   123     ndays = mdays[month] + (month == February and isleap(year))
       
   124     return day1, ndays
       
   125 
       
   126 
       
   127 class Calendar(object):
       
   128     """
       
   129     Base calendar class. This class doesn't do any formatting. It simply
       
   130     provides data to subclasses.
       
   131     """
       
   132 
       
   133     def __init__(self, firstweekday=0):
       
   134         self.firstweekday = firstweekday # 0 = Monday, 6 = Sunday
       
   135 
       
   136     def getfirstweekday(self):
       
   137         return self._firstweekday % 7
       
   138 
       
   139     def setfirstweekday(self, firstweekday):
       
   140         self._firstweekday = firstweekday
       
   141 
       
   142     firstweekday = property(getfirstweekday, setfirstweekday)
       
   143 
       
   144     def iterweekdays(self):
       
   145         """
       
   146         Return a iterator for one week of weekday numbers starting with the
       
   147         configured first one.
       
   148         """
       
   149         for i in xrange(self.firstweekday, self.firstweekday + 7):
       
   150             yield i%7
       
   151 
       
   152     def itermonthdates(self, year, month):
       
   153         """
       
   154         Return an iterator for one month. The iterator will yield datetime.date
       
   155         values and will always iterate through complete weeks, so it will yield
       
   156         dates outside the specified month.
       
   157         """
       
   158         date = datetime.date(year, month, 1)
       
   159         # Go back to the beginning of the week
       
   160         days = (date.weekday() - self.firstweekday) % 7
       
   161         date -= datetime.timedelta(days=days)
       
   162         oneday = datetime.timedelta(days=1)
       
   163         while True:
       
   164             yield date
       
   165             date += oneday
       
   166             if date.month != month and date.weekday() == self.firstweekday:
       
   167                 break
       
   168 
       
   169     def itermonthdays2(self, year, month):
       
   170         """
       
   171         Like itermonthdates(), but will yield (day number, weekday number)
       
   172         tuples. For days outside the specified month the day number is 0.
       
   173         """
       
   174         for date in self.itermonthdates(year, month):
       
   175             if date.month != month:
       
   176                 yield (0, date.weekday())
       
   177             else:
       
   178                 yield (date.day, date.weekday())
       
   179 
       
   180     def itermonthdays(self, year, month):
       
   181         """
       
   182         Like itermonthdates(), but will yield day numbers. For days outside
       
   183         the specified month the day number is 0.
       
   184         """
       
   185         for date in self.itermonthdates(year, month):
       
   186             if date.month != month:
       
   187                 yield 0
       
   188             else:
       
   189                 yield date.day
       
   190 
       
   191     def monthdatescalendar(self, year, month):
       
   192         """
       
   193         Return a matrix (list of lists) representing a month's calendar.
       
   194         Each row represents a week; week entries are datetime.date values.
       
   195         """
       
   196         dates = list(self.itermonthdates(year, month))
       
   197         return [ dates[i:i+7] for i in xrange(0, len(dates), 7) ]
       
   198 
       
   199     def monthdays2calendar(self, year, month):
       
   200         """
       
   201         Return a matrix representing a month's calendar.
       
   202         Each row represents a week; week entries are
       
   203         (day number, weekday number) tuples. Day numbers outside this month
       
   204         are zero.
       
   205         """
       
   206         days = list(self.itermonthdays2(year, month))
       
   207         return [ days[i:i+7] for i in xrange(0, len(days), 7) ]
       
   208 
       
   209     def monthdayscalendar(self, year, month):
       
   210         """
       
   211         Return a matrix representing a month's calendar.
       
   212         Each row represents a week; days outside this month are zero.
       
   213         """
       
   214         days = list(self.itermonthdays(year, month))
       
   215         return [ days[i:i+7] for i in xrange(0, len(days), 7) ]
       
   216 
       
   217     def yeardatescalendar(self, year, width=3):
       
   218         """
       
   219         Return the data for the specified year ready for formatting. The return
       
   220         value is a list of month rows. Each month row contains upto width months.
       
   221         Each month contains between 4 and 6 weeks and each week contains 1-7
       
   222         days. Days are datetime.date objects.
       
   223         """
       
   224         months = [
       
   225             self.monthdatescalendar(year, i)
       
   226             for i in xrange(January, January+12)
       
   227         ]
       
   228         return [months[i:i+width] for i in xrange(0, len(months), width) ]
       
   229 
       
   230     def yeardays2calendar(self, year, width=3):
       
   231         """
       
   232         Return the data for the specified year ready for formatting (similar to
       
   233         yeardatescalendar()). Entries in the week lists are
       
   234         (day number, weekday number) tuples. Day numbers outside this month are
       
   235         zero.
       
   236         """
       
   237         months = [
       
   238             self.monthdays2calendar(year, i)
       
   239             for i in xrange(January, January+12)
       
   240         ]
       
   241         return [months[i:i+width] for i in xrange(0, len(months), width) ]
       
   242 
       
   243     def yeardayscalendar(self, year, width=3):
       
   244         """
       
   245         Return the data for the specified year ready for formatting (similar to
       
   246         yeardatescalendar()). Entries in the week lists are day numbers.
       
   247         Day numbers outside this month are zero.
       
   248         """
       
   249         months = [
       
   250             self.monthdayscalendar(year, i)
       
   251             for i in xrange(January, January+12)
       
   252         ]
       
   253         return [months[i:i+width] for i in xrange(0, len(months), width) ]
       
   254 
       
   255 
       
   256 class TextCalendar(Calendar):
       
   257     """
       
   258     Subclass of Calendar that outputs a calendar as a simple plain text
       
   259     similar to the UNIX program cal.
       
   260     """
       
   261 
       
   262     def prweek(self, theweek, width):
       
   263         """
       
   264         Print a single week (no newline).
       
   265         """
       
   266         print self.formatweek(theweek, width),
       
   267 
       
   268     def formatday(self, day, weekday, width):
       
   269         """
       
   270         Returns a formatted day.
       
   271         """
       
   272         if day == 0:
       
   273             s = ''
       
   274         else:
       
   275             s = '%2i' % day             # right-align single-digit days
       
   276         return s.center(width)
       
   277 
       
   278     def formatweek(self, theweek, width):
       
   279         """
       
   280         Returns a single week in a string (no newline).
       
   281         """
       
   282         return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
       
   283 
       
   284     def formatweekday(self, day, width):
       
   285         """
       
   286         Returns a formatted week day name.
       
   287         """
       
   288         if width >= 9:
       
   289             names = day_name
       
   290         else:
       
   291             names = day_abbr
       
   292         return names[day][:width].center(width)
       
   293 
       
   294     def formatweekheader(self, width):
       
   295         """
       
   296         Return a header for a week.
       
   297         """
       
   298         return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
       
   299 
       
   300     def formatmonthname(self, theyear, themonth, width, withyear=True):
       
   301         """
       
   302         Return a formatted month name.
       
   303         """
       
   304         s = month_name[themonth]
       
   305         if withyear:
       
   306             s = "%s %r" % (s, theyear)
       
   307         return s.center(width)
       
   308 
       
   309     def prmonth(self, theyear, themonth, w=0, l=0):
       
   310         """
       
   311         Print a month's calendar.
       
   312         """
       
   313         print self.formatmonth(theyear, themonth, w, l),
       
   314 
       
   315     def formatmonth(self, theyear, themonth, w=0, l=0):
       
   316         """
       
   317         Return a month's calendar string (multi-line).
       
   318         """
       
   319         w = max(2, w)
       
   320         l = max(1, l)
       
   321         s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
       
   322         s = s.rstrip()
       
   323         s += '\n' * l
       
   324         s += self.formatweekheader(w).rstrip()
       
   325         s += '\n' * l
       
   326         for week in self.monthdays2calendar(theyear, themonth):
       
   327             s += self.formatweek(week, w).rstrip()
       
   328             s += '\n' * l
       
   329         return s
       
   330 
       
   331     def formatyear(self, theyear, w=2, l=1, c=6, m=3):
       
   332         """
       
   333         Returns a year's calendar as a multi-line string.
       
   334         """
       
   335         w = max(2, w)
       
   336         l = max(1, l)
       
   337         c = max(2, c)
       
   338         colwidth = (w + 1) * 7 - 1
       
   339         v = []
       
   340         a = v.append
       
   341         a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip())
       
   342         a('\n'*l)
       
   343         header = self.formatweekheader(w)
       
   344         for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
       
   345             # months in this row
       
   346             months = xrange(m*i+1, min(m*(i+1)+1, 13))
       
   347             a('\n'*l)
       
   348             names = (self.formatmonthname(theyear, k, colwidth, False)
       
   349                      for k in months)
       
   350             a(formatstring(names, colwidth, c).rstrip())
       
   351             a('\n'*l)
       
   352             headers = (header for k in months)
       
   353             a(formatstring(headers, colwidth, c).rstrip())
       
   354             a('\n'*l)
       
   355             # max number of weeks for this row
       
   356             height = max(len(cal) for cal in row)
       
   357             for j in xrange(height):
       
   358                 weeks = []
       
   359                 for cal in row:
       
   360                     if j >= len(cal):
       
   361                         weeks.append('')
       
   362                     else:
       
   363                         weeks.append(self.formatweek(cal[j], w))
       
   364                 a(formatstring(weeks, colwidth, c).rstrip())
       
   365                 a('\n' * l)
       
   366         return ''.join(v)
       
   367 
       
   368     def pryear(self, theyear, w=0, l=0, c=6, m=3):
       
   369         """Print a year's calendar."""
       
   370         print self.formatyear(theyear, w, l, c, m)
       
   371 
       
   372 
       
   373 class HTMLCalendar(Calendar):
       
   374     """
       
   375     This calendar returns complete HTML pages.
       
   376     """
       
   377 
       
   378     # CSS classes for the day <td>s
       
   379     cssclasses = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
       
   380 
       
   381     def formatday(self, day, weekday):
       
   382         """
       
   383         Return a day as a table cell.
       
   384         """
       
   385         if day == 0:
       
   386             return '<td class="noday">&nbsp;</td>' # day outside month
       
   387         else:
       
   388             return '<td class="%s">%d</td>' % (self.cssclasses[weekday], day)
       
   389 
       
   390     def formatweek(self, theweek):
       
   391         """
       
   392         Return a complete week as a table row.
       
   393         """
       
   394         s = ''.join(self.formatday(d, wd) for (d, wd) in theweek)
       
   395         return '<tr>%s</tr>' % s
       
   396 
       
   397     def formatweekday(self, day):
       
   398         """
       
   399         Return a weekday name as a table header.
       
   400         """
       
   401         return '<th class="%s">%s</th>' % (self.cssclasses[day], day_abbr[day])
       
   402 
       
   403     def formatweekheader(self):
       
   404         """
       
   405         Return a header for a week as a table row.
       
   406         """
       
   407         s = ''.join(self.formatweekday(i) for i in self.iterweekdays())
       
   408         return '<tr>%s</tr>' % s
       
   409 
       
   410     def formatmonthname(self, theyear, themonth, withyear=True):
       
   411         """
       
   412         Return a month name as a table row.
       
   413         """
       
   414         if withyear:
       
   415             s = '%s %s' % (month_name[themonth], theyear)
       
   416         else:
       
   417             s = '%s' % month_name[themonth]
       
   418         return '<tr><th colspan="7" class="month">%s</th></tr>' % s
       
   419 
       
   420     def formatmonth(self, theyear, themonth, withyear=True):
       
   421         """
       
   422         Return a formatted month as a table.
       
   423         """
       
   424         v = []
       
   425         a = v.append
       
   426         a('<table border="0" cellpadding="0" cellspacing="0" class="month">')
       
   427         a('\n')
       
   428         a(self.formatmonthname(theyear, themonth, withyear=withyear))
       
   429         a('\n')
       
   430         a(self.formatweekheader())
       
   431         a('\n')
       
   432         for week in self.monthdays2calendar(theyear, themonth):
       
   433             a(self.formatweek(week))
       
   434             a('\n')
       
   435         a('</table>')
       
   436         a('\n')
       
   437         return ''.join(v)
       
   438 
       
   439     def formatyear(self, theyear, width=3):
       
   440         """
       
   441         Return a formatted year as a table of tables.
       
   442         """
       
   443         v = []
       
   444         a = v.append
       
   445         width = max(width, 1)
       
   446         a('<table border="0" cellpadding="0" cellspacing="0" class="year">')
       
   447         a('\n')
       
   448         a('<tr><th colspan="%d" class="year">%s</th></tr>' % (width, theyear))
       
   449         for i in xrange(January, January+12, width):
       
   450             # months in this row
       
   451             months = xrange(i, min(i+width, 13))
       
   452             a('<tr>')
       
   453             for m in months:
       
   454                 a('<td>')
       
   455                 a(self.formatmonth(theyear, m, withyear=False))
       
   456                 a('</td>')
       
   457             a('</tr>')
       
   458         a('</table>')
       
   459         return ''.join(v)
       
   460 
       
   461     def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
       
   462         """
       
   463         Return a formatted year as a complete HTML page.
       
   464         """
       
   465         if encoding is None:
       
   466             encoding = sys.getdefaultencoding()
       
   467         v = []
       
   468         a = v.append
       
   469         a('<?xml version="1.0" encoding="%s"?>\n' % encoding)
       
   470         a('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n')
       
   471         a('<html>\n')
       
   472         a('<head>\n')
       
   473         a('<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n' % encoding)
       
   474         if css is not None:
       
   475             a('<link rel="stylesheet" type="text/css" href="%s" />\n' % css)
       
   476         a('<title>Calendar for %d</title\n' % theyear)
       
   477         a('</head>\n')
       
   478         a('<body>\n')
       
   479         a(self.formatyear(theyear, width))
       
   480         a('</body>\n')
       
   481         a('</html>\n')
       
   482         return ''.join(v).encode(encoding, "xmlcharrefreplace")
       
   483 
       
   484 
       
   485 class TimeEncoding:
       
   486     def __init__(self, locale):
       
   487         self.locale = locale
       
   488 
       
   489     def __enter__(self):
       
   490         self.oldlocale = _locale.setlocale(_locale.LC_TIME, self.locale)
       
   491         return _locale.getlocale(_locale.LC_TIME)[1]
       
   492 
       
   493     def __exit__(self, *args):
       
   494         _locale.setlocale(_locale.LC_TIME, self.oldlocale)
       
   495 
       
   496 
       
   497 class LocaleTextCalendar(TextCalendar):
       
   498     """
       
   499     This class can be passed a locale name in the constructor and will return
       
   500     month and weekday names in the specified locale. If this locale includes
       
   501     an encoding all strings containing month and weekday names will be returned
       
   502     as unicode.
       
   503     """
       
   504 
       
   505     def __init__(self, firstweekday=0, locale=None):
       
   506         TextCalendar.__init__(self, firstweekday)
       
   507         if locale is None:
       
   508             locale = _locale.getdefaultlocale()
       
   509         self.locale = locale
       
   510 
       
   511     def formatweekday(self, day, width):
       
   512         with TimeEncoding(self.locale) as encoding:
       
   513             if width >= 9:
       
   514                 names = day_name
       
   515             else:
       
   516                 names = day_abbr
       
   517             name = names[day]
       
   518             if encoding is not None:
       
   519                 name = name.decode(encoding)
       
   520             return name[:width].center(width)
       
   521 
       
   522     def formatmonthname(self, theyear, themonth, width, withyear=True):
       
   523         with TimeEncoding(self.locale) as encoding:
       
   524             s = month_name[themonth]
       
   525             if encoding is not None:
       
   526                 s = s.decode(encoding)
       
   527             if withyear:
       
   528                 s = "%s %r" % (s, theyear)
       
   529             return s.center(width)
       
   530 
       
   531 
       
   532 class LocaleHTMLCalendar(HTMLCalendar):
       
   533     """
       
   534     This class can be passed a locale name in the constructor and will return
       
   535     month and weekday names in the specified locale. If this locale includes
       
   536     an encoding all strings containing month and weekday names will be returned
       
   537     as unicode.
       
   538     """
       
   539     def __init__(self, firstweekday=0, locale=None):
       
   540         HTMLCalendar.__init__(self, firstweekday)
       
   541         if locale is None:
       
   542             locale = _locale.getdefaultlocale()
       
   543         self.locale = locale
       
   544 
       
   545     def formatweekday(self, day):
       
   546         with TimeEncoding(self.locale) as encoding:
       
   547             s = day_abbr[day]
       
   548             if encoding is not None:
       
   549                 s = s.decode(encoding)
       
   550             return '<th class="%s">%s</th>' % (self.cssclasses[day], s)
       
   551 
       
   552     def formatmonthname(self, theyear, themonth, withyear=True):
       
   553         with TimeEncoding(self.locale) as encoding:
       
   554             s = month_name[themonth]
       
   555             if encoding is not None:
       
   556                 s = s.decode(encoding)
       
   557             if withyear:
       
   558                 s = '%s %s' % (s, theyear)
       
   559             return '<tr><th colspan="7" class="month">%s</th></tr>' % s
       
   560 
       
   561 
       
   562 # Support for old module level interface
       
   563 c = TextCalendar()
       
   564 
       
   565 firstweekday = c.getfirstweekday
       
   566 
       
   567 def setfirstweekday(firstweekday):
       
   568     if not MONDAY <= firstweekday <= SUNDAY:
       
   569         raise IllegalWeekdayError(firstweekday)
       
   570     c.firstweekday = firstweekday
       
   571 
       
   572 monthcalendar = c.monthdayscalendar
       
   573 prweek = c.prweek
       
   574 week = c.formatweek
       
   575 weekheader = c.formatweekheader
       
   576 prmonth = c.prmonth
       
   577 month = c.formatmonth
       
   578 calendar = c.formatyear
       
   579 prcal = c.pryear
       
   580 
       
   581 
       
   582 # Spacing of month columns for multi-column year calendar
       
   583 _colwidth = 7*3 - 1         # Amount printed by prweek()
       
   584 _spacing = 6                # Number of spaces between columns
       
   585 
       
   586 
       
   587 def format(cols, colwidth=_colwidth, spacing=_spacing):
       
   588     """Prints multi-column formatting for year calendars"""
       
   589     print formatstring(cols, colwidth, spacing)
       
   590 
       
   591 
       
   592 def formatstring(cols, colwidth=_colwidth, spacing=_spacing):
       
   593     """Returns a string formatted from n strings, centered within n columns."""
       
   594     spacing *= ' '
       
   595     return spacing.join(c.center(colwidth) for c in cols)
       
   596 
       
   597 
       
   598 EPOCH = 1970
       
   599 _EPOCH_ORD = datetime.date(EPOCH, 1, 1).toordinal()
       
   600 
       
   601 
       
   602 def timegm(tuple):
       
   603     """Unrelated but handy function to calculate Unix timestamp from GMT."""
       
   604     year, month, day, hour, minute, second = tuple[:6]
       
   605     days = datetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
       
   606     hours = days*24 + hour
       
   607     minutes = hours*60 + minute
       
   608     seconds = minutes*60 + second
       
   609     return seconds
       
   610 
       
   611 
       
   612 def main(args):
       
   613     import optparse
       
   614     parser = optparse.OptionParser(usage="usage: %prog [options] [year [month]]")
       
   615     parser.add_option(
       
   616         "-w", "--width",
       
   617         dest="width", type="int", default=2,
       
   618         help="width of date column (default 2, text only)"
       
   619     )
       
   620     parser.add_option(
       
   621         "-l", "--lines",
       
   622         dest="lines", type="int", default=1,
       
   623         help="number of lines for each week (default 1, text only)"
       
   624     )
       
   625     parser.add_option(
       
   626         "-s", "--spacing",
       
   627         dest="spacing", type="int", default=6,
       
   628         help="spacing between months (default 6, text only)"
       
   629     )
       
   630     parser.add_option(
       
   631         "-m", "--months",
       
   632         dest="months", type="int", default=3,
       
   633         help="months per row (default 3, text only)"
       
   634     )
       
   635     parser.add_option(
       
   636         "-c", "--css",
       
   637         dest="css", default="calendar.css",
       
   638         help="CSS to use for page (html only)"
       
   639     )
       
   640     parser.add_option(
       
   641         "-L", "--locale",
       
   642         dest="locale", default=None,
       
   643         help="locale to be used from month and weekday names"
       
   644     )
       
   645     parser.add_option(
       
   646         "-e", "--encoding",
       
   647         dest="encoding", default=None,
       
   648         help="Encoding to use for output"
       
   649     )
       
   650     parser.add_option(
       
   651         "-t", "--type",
       
   652         dest="type", default="text",
       
   653         choices=("text", "html"),
       
   654         help="output type (text or html)"
       
   655     )
       
   656 
       
   657     (options, args) = parser.parse_args(args)
       
   658 
       
   659     if options.locale and not options.encoding:
       
   660         parser.error("if --locale is specified --encoding is required")
       
   661         sys.exit(1)
       
   662 
       
   663     locale = options.locale, options.encoding
       
   664 
       
   665     if options.type == "html":
       
   666         if options.locale:
       
   667             cal = LocaleHTMLCalendar(locale=locale)
       
   668         else:
       
   669             cal = HTMLCalendar()
       
   670         encoding = options.encoding
       
   671         if encoding is None:
       
   672             encoding = sys.getdefaultencoding()
       
   673         optdict = dict(encoding=encoding, css=options.css)
       
   674         if len(args) == 1:
       
   675             print cal.formatyearpage(datetime.date.today().year, **optdict)
       
   676         elif len(args) == 2:
       
   677             print cal.formatyearpage(int(args[1]), **optdict)
       
   678         else:
       
   679             parser.error("incorrect number of arguments")
       
   680             sys.exit(1)
       
   681     else:
       
   682         if options.locale:
       
   683             cal = LocaleTextCalendar(locale=locale)
       
   684         else:
       
   685             cal = TextCalendar()
       
   686         optdict = dict(w=options.width, l=options.lines)
       
   687         if len(args) != 3:
       
   688             optdict["c"] = options.spacing
       
   689             optdict["m"] = options.months
       
   690         if len(args) == 1:
       
   691             result = cal.formatyear(datetime.date.today().year, **optdict)
       
   692         elif len(args) == 2:
       
   693             result = cal.formatyear(int(args[1]), **optdict)
       
   694         elif len(args) == 3:
       
   695             result = cal.formatmonth(int(args[1]), int(args[2]), **optdict)
       
   696         else:
       
   697             parser.error("incorrect number of arguments")
       
   698             sys.exit(1)
       
   699         if options.encoding:
       
   700             result = result.encode(options.encoding)
       
   701         print result
       
   702 
       
   703 
       
   704 if __name__ == "__main__":
       
   705     main(sys.argv)