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