]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.10/Lib/calendar.py
1 """Calendar printing functions
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)."""
10 import locale
as _locale
12 __all__
= ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
13 "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
14 "monthcalendar", "prmonth", "month", "prcal", "calendar",
15 "timegm", "month_name", "month_abbr", "day_name", "day_abbr"]
17 # Exception raised for bad input (with string parameter for details)
20 # Exceptions raised for bad input
21 class IllegalMonthError(ValueError):
22 def __init__(self
, month
):
25 return "bad month number %r; must be 1-12" % self
.month
28 class IllegalWeekdayError(ValueError):
29 def __init__(self
, weekday
):
30 self
.weekday
= weekday
32 return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self
.weekday
35 # Constants for months referenced later
39 # Number of days per month (except for February in leap years)
40 mdays
= [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
42 # This module used to have hard-coded lists of day and month names, as
43 # English strings. The classes following emulate a read-only version of
44 # that, but supply localized names. Note that the values are computed
45 # fresh on each call, in case the user changes locale between calls.
47 class _localized_month
:
49 _months
= [datetime
.date(2001, i
+1, 1).strftime
for i
in range(12)]
50 _months
.insert(0, lambda x
: "")
52 def __init__(self
, format
):
55 def __getitem__(self
, i
):
56 funcs
= self
._months
[i
]
57 if isinstance(i
, slice):
58 return [f(self
.format
) for f
in funcs
]
60 return funcs(self
.format
)
68 # January 1, 2001, was a Monday.
69 _days
= [datetime
.date(2001, 1, i
+1).strftime
for i
in range(7)]
71 def __init__(self
, format
):
74 def __getitem__(self
, i
):
76 if isinstance(i
, slice):
77 return [f(self
.format
) for f
in funcs
]
79 return funcs(self
.format
)
85 # Full and abbreviated names of weekdays
86 day_name
= _localized_day('%A')
87 day_abbr
= _localized_day('%a')
89 # Full and abbreviated names of months (1-based arrays!!!)
90 month_name
= _localized_month('%B')
91 month_abbr
= _localized_month('%b')
93 # Constants for weekdays
94 (MONDAY
, TUESDAY
, WEDNESDAY
, THURSDAY
, FRIDAY
, SATURDAY
, SUNDAY
) = range(7)
98 """Return True for leap years, False for non-leap years."""
99 return year
% 4 == 0 and (year
% 100 != 0 or year
% 400 == 0)
102 def leapdays(y1
, y2
):
103 """Return number of leap years in range [y1, y2).
107 return (y2
//4 - y1
//4) - (y2
//100 - y1
//100) + (y2
//400 - y1
//400)
110 def weekday(year
, month
, day
):
111 """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
113 return datetime
.date(year
, month
, day
).weekday()
116 def monthrange(year
, month
):
117 """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
119 if not 1 <= month
<= 12:
120 raise IllegalMonthError(month
)
121 day1
= weekday(year
, month
, 1)
122 ndays
= mdays
[month
] + (month
== February
and isleap(year
))
126 class Calendar(object):
128 Base calendar class. This class doesn't do any formatting. It simply
129 provides data to subclasses.
132 def __init__(self
, firstweekday
=0):
133 self
.firstweekday
= firstweekday
# 0 = Monday, 6 = Sunday
135 def getfirstweekday(self
):
136 return self
._firstweekday
% 7
138 def setfirstweekday(self
, firstweekday
):
139 self
._firstweekday
= firstweekday
141 firstweekday
= property(getfirstweekday
, setfirstweekday
)
143 def iterweekdays(self
):
145 Return a iterator for one week of weekday numbers starting with the
146 configured first one.
148 for i
in range(self
.firstweekday
, self
.firstweekday
+ 7):
151 def itermonthdates(self
, year
, month
):
153 Return an iterator for one month. The iterator will yield datetime.date
154 values and will always iterate through complete weeks, so it will yield
155 dates outside the specified month.
157 date
= datetime
.date(year
, month
, 1)
158 # Go back to the beginning of the week
159 days
= (date
.weekday() - self
.firstweekday
) % 7
160 date
-= datetime
.timedelta(days
=days
)
161 oneday
= datetime
.timedelta(days
=1)
166 except OverflowError:
167 # Adding one day could fail after datetime.MAXYEAR
169 if date
.month
!= month
and date
.weekday() == self
.firstweekday
:
172 def itermonthdays2(self
, year
, month
):
174 Like itermonthdates(), but will yield (day number, weekday number)
175 tuples. For days outside the specified month the day number is 0.
177 for date
in self
.itermonthdates(year
, month
):
178 if date
.month
!= month
:
179 yield (0, date
.weekday())
181 yield (date
.day
, date
.weekday())
183 def itermonthdays(self
, year
, month
):
185 Like itermonthdates(), but will yield day numbers. For days outside
186 the specified month the day number is 0.
188 for date
in self
.itermonthdates(year
, month
):
189 if date
.month
!= month
:
194 def monthdatescalendar(self
, year
, month
):
196 Return a matrix (list of lists) representing a month's calendar.
197 Each row represents a week; week entries are datetime.date values.
199 dates
= list(self
.itermonthdates(year
, month
))
200 return [ dates
[i
:i
+7] for i
in range(0, len(dates
), 7) ]
202 def monthdays2calendar(self
, year
, month
):
204 Return a matrix representing a month's calendar.
205 Each row represents a week; week entries are
206 (day number, weekday number) tuples. Day numbers outside this month
209 days
= list(self
.itermonthdays2(year
, month
))
210 return [ days
[i
:i
+7] for i
in range(0, len(days
), 7) ]
212 def monthdayscalendar(self
, year
, month
):
214 Return a matrix representing a month's calendar.
215 Each row represents a week; days outside this month are zero.
217 days
= list(self
.itermonthdays(year
, month
))
218 return [ days
[i
:i
+7] for i
in range(0, len(days
), 7) ]
220 def yeardatescalendar(self
, year
, width
=3):
222 Return the data for the specified year ready for formatting. The return
223 value is a list of month rows. Each month row contains up to width months.
224 Each month contains between 4 and 6 weeks and each week contains 1-7
225 days. Days are datetime.date objects.
228 self
.monthdatescalendar(year
, i
)
229 for i
in range(January
, January
+12)
231 return [months
[i
:i
+width
] for i
in range(0, len(months
), width
) ]
233 def yeardays2calendar(self
, year
, width
=3):
235 Return the data for the specified year ready for formatting (similar to
236 yeardatescalendar()). Entries in the week lists are
237 (day number, weekday number) tuples. Day numbers outside this month are
241 self
.monthdays2calendar(year
, i
)
242 for i
in range(January
, January
+12)
244 return [months
[i
:i
+width
] for i
in range(0, len(months
), width
) ]
246 def yeardayscalendar(self
, year
, width
=3):
248 Return the data for the specified year ready for formatting (similar to
249 yeardatescalendar()). Entries in the week lists are day numbers.
250 Day numbers outside this month are zero.
253 self
.monthdayscalendar(year
, i
)
254 for i
in range(January
, January
+12)
256 return [months
[i
:i
+width
] for i
in range(0, len(months
), width
) ]
259 class TextCalendar(Calendar
):
261 Subclass of Calendar that outputs a calendar as a simple plain text
262 similar to the UNIX program cal.
265 def prweek(self
, theweek
, width
):
267 Print a single week (no newline).
269 print self
.formatweek(theweek
, width
),
271 def formatday(self
, day
, weekday
, width
):
273 Returns a formatted day.
278 s
= '%2i' % day
# right-align single-digit days
279 return s
.center(width
)
281 def formatweek(self
, theweek
, width
):
283 Returns a single week in a string (no newline).
285 return ' '.join(self
.formatday(d
, wd
, width
) for (d
, wd
) in theweek
)
287 def formatweekday(self
, day
, width
):
289 Returns a formatted week day name.
295 return names
[day
][:width
].center(width
)
297 def formatweekheader(self
, width
):
299 Return a header for a week.
301 return ' '.join(self
.formatweekday(i
, width
) for i
in self
.iterweekdays())
303 def formatmonthname(self
, theyear
, themonth
, width
, withyear
=True):
305 Return a formatted month name.
307 s
= month_name
[themonth
]
309 s
= "%s %r" % (s
, theyear
)
310 return s
.center(width
)
312 def prmonth(self
, theyear
, themonth
, w
=0, l
=0):
314 Print a month's calendar.
316 print self
.formatmonth(theyear
, themonth
, w
, l
),
318 def formatmonth(self
, theyear
, themonth
, w
=0, l
=0):
320 Return a month's calendar string (multi-line).
324 s
= self
.formatmonthname(theyear
, themonth
, 7 * (w
+ 1) - 1)
327 s
+= self
.formatweekheader(w
).rstrip()
329 for week
in self
.monthdays2calendar(theyear
, themonth
):
330 s
+= self
.formatweek(week
, w
).rstrip()
334 def formatyear(self
, theyear
, w
=2, l
=1, c
=6, m
=3):
336 Returns a year's calendar as a multi-line string.
341 colwidth
= (w
+ 1) * 7 - 1
344 a(repr(theyear
).center(colwidth
*m
+c
*(m
-1)).rstrip())
346 header
= self
.formatweekheader(w
)
347 for (i
, row
) in enumerate(self
.yeardays2calendar(theyear
, m
)):
349 months
= range(m
*i
+1, min(m
*(i
+1)+1, 13))
351 names
= (self
.formatmonthname(theyear
, k
, colwidth
, False)
353 a(formatstring(names
, colwidth
, c
).rstrip())
355 headers
= (header
for k
in months
)
356 a(formatstring(headers
, colwidth
, c
).rstrip())
358 # max number of weeks for this row
359 height
= max(len(cal
) for cal
in row
)
360 for j
in range(height
):
366 weeks
.append(self
.formatweek(cal
[j
], w
))
367 a(formatstring(weeks
, colwidth
, c
).rstrip())
371 def pryear(self
, theyear
, w
=0, l
=0, c
=6, m
=3):
372 """Print a year's calendar."""
373 print self
.formatyear(theyear
, w
, l
, c
, m
)
376 class HTMLCalendar(Calendar
):
378 This calendar returns complete HTML pages.
381 # CSS classes for the day <td>s
382 cssclasses
= ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
384 def formatday(self
, day
, weekday
):
386 Return a day as a table cell.
389 return '<td class="noday"> </td>' # day outside month
391 return '<td class="%s">%d</td>' % (self
.cssclasses
[weekday
], day
)
393 def formatweek(self
, theweek
):
395 Return a complete week as a table row.
397 s
= ''.join(self
.formatday(d
, wd
) for (d
, wd
) in theweek
)
398 return '<tr>%s</tr>' % s
400 def formatweekday(self
, day
):
402 Return a weekday name as a table header.
404 return '<th class="%s">%s</th>' % (self
.cssclasses
[day
], day_abbr
[day
])
406 def formatweekheader(self
):
408 Return a header for a week as a table row.
410 s
= ''.join(self
.formatweekday(i
) for i
in self
.iterweekdays())
411 return '<tr>%s</tr>' % s
413 def formatmonthname(self
, theyear
, themonth
, withyear
=True):
415 Return a month name as a table row.
418 s
= '%s %s' % (month_name
[themonth
], theyear
)
420 s
= '%s' % month_name
[themonth
]
421 return '<tr><th colspan="7" class="month">%s</th></tr>' % s
423 def formatmonth(self
, theyear
, themonth
, withyear
=True):
425 Return a formatted month as a table.
429 a('<table border="0" cellpadding="0" cellspacing="0" class="month">')
431 a(self
.formatmonthname(theyear
, themonth
, withyear
=withyear
))
433 a(self
.formatweekheader())
435 for week
in self
.monthdays2calendar(theyear
, themonth
):
436 a(self
.formatweek(week
))
442 def formatyear(self
, theyear
, width
=3):
444 Return a formatted year as a table of tables.
448 width
= max(width
, 1)
449 a('<table border="0" cellpadding="0" cellspacing="0" class="year">')
451 a('<tr><th colspan="%d" class="year">%s</th></tr>' % (width
, theyear
))
452 for i
in range(January
, January
+12, width
):
454 months
= range(i
, min(i
+width
, 13))
458 a(self
.formatmonth(theyear
, m
, withyear
=False))
464 def formatyearpage(self
, theyear
, width
=3, css
='calendar.css', encoding
=None):
466 Return a formatted year as a complete HTML page.
469 encoding
= sys
.getdefaultencoding()
472 a('<?xml version="1.0" encoding="%s"?>\n' % encoding
)
473 a('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n')
476 a('<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n' % encoding
)
478 a('<link rel="stylesheet" type="text/css" href="%s" />\n' % css
)
479 a('<title>Calendar for %d</title>\n' % theyear
)
482 a(self
.formatyear(theyear
, width
))
485 return ''.join(v
).encode(encoding
, "xmlcharrefreplace")
489 def __init__(self
, locale
):
493 self
.oldlocale
= _locale
.getlocale(_locale
.LC_TIME
)
494 _locale
.setlocale(_locale
.LC_TIME
, self
.locale
)
495 return _locale
.getlocale(_locale
.LC_TIME
)[1]
497 def __exit__(self
, *args
):
498 _locale
.setlocale(_locale
.LC_TIME
, self
.oldlocale
)
501 class LocaleTextCalendar(TextCalendar
):
503 This class can be passed a locale name in the constructor and will return
504 month and weekday names in the specified locale. If this locale includes
505 an encoding all strings containing month and weekday names will be returned
509 def __init__(self
, firstweekday
=0, locale
=None):
510 TextCalendar
.__init
__(self
, firstweekday
)
512 locale
= _locale
.getdefaultlocale()
515 def formatweekday(self
, day
, width
):
516 with
TimeEncoding(self
.locale
) as encoding
:
522 if encoding
is not None:
523 name
= name
.decode(encoding
)
524 return name
[:width
].center(width
)
526 def formatmonthname(self
, theyear
, themonth
, width
, withyear
=True):
527 with
TimeEncoding(self
.locale
) as encoding
:
528 s
= month_name
[themonth
]
529 if encoding
is not None:
530 s
= s
.decode(encoding
)
532 s
= "%s %r" % (s
, theyear
)
533 return s
.center(width
)
536 class LocaleHTMLCalendar(HTMLCalendar
):
538 This class can be passed a locale name in the constructor and will return
539 month and weekday names in the specified locale. If this locale includes
540 an encoding all strings containing month and weekday names will be returned
543 def __init__(self
, firstweekday
=0, locale
=None):
544 HTMLCalendar
.__init
__(self
, firstweekday
)
546 locale
= _locale
.getdefaultlocale()
549 def formatweekday(self
, day
):
550 with
TimeEncoding(self
.locale
) as encoding
:
552 if encoding
is not None:
553 s
= s
.decode(encoding
)
554 return '<th class="%s">%s</th>' % (self
.cssclasses
[day
], s
)
556 def formatmonthname(self
, theyear
, themonth
, withyear
=True):
557 with
TimeEncoding(self
.locale
) as encoding
:
558 s
= month_name
[themonth
]
559 if encoding
is not None:
560 s
= s
.decode(encoding
)
562 s
= '%s %s' % (s
, theyear
)
563 return '<tr><th colspan="7" class="month">%s</th></tr>' % s
566 # Support for old module level interface
569 firstweekday
= c
.getfirstweekday
571 def setfirstweekday(firstweekday
):
573 firstweekday
.__index
__
574 except AttributeError:
575 raise IllegalWeekdayError(firstweekday
)
576 if not MONDAY
<= firstweekday
<= SUNDAY
:
577 raise IllegalWeekdayError(firstweekday
)
578 c
.firstweekday
= firstweekday
580 monthcalendar
= c
.monthdayscalendar
583 weekheader
= c
.formatweekheader
585 month
= c
.formatmonth
586 calendar
= c
.formatyear
590 # Spacing of month columns for multi-column year calendar
591 _colwidth
= 7*3 - 1 # Amount printed by prweek()
592 _spacing
= 6 # Number of spaces between columns
595 def format(cols
, colwidth
=_colwidth
, spacing
=_spacing
):
596 """Prints multi-column formatting for year calendars"""
597 print formatstring(cols
, colwidth
, spacing
)
600 def formatstring(cols
, colwidth
=_colwidth
, spacing
=_spacing
):
601 """Returns a string formatted from n strings, centered within n columns."""
603 return spacing
.join(c
.center(colwidth
) for c
in cols
)
607 _EPOCH_ORD
= datetime
.date(EPOCH
, 1, 1).toordinal()
611 """Unrelated but handy function to calculate Unix timestamp from GMT."""
612 year
, month
, day
, hour
, minute
, second
= tuple[:6]
613 days
= datetime
.date(year
, month
, 1).toordinal() - _EPOCH_ORD
+ day
- 1
614 hours
= days
*24 + hour
615 minutes
= hours
*60 + minute
616 seconds
= minutes
*60 + second
622 parser
= optparse
.OptionParser(usage
="usage: %prog [options] [year [month]]")
625 dest
="width", type="int", default
=2,
626 help="width of date column (default 2, text only)"
630 dest
="lines", type="int", default
=1,
631 help="number of lines for each week (default 1, text only)"
635 dest
="spacing", type="int", default
=6,
636 help="spacing between months (default 6, text only)"
640 dest
="months", type="int", default
=3,
641 help="months per row (default 3, text only)"
645 dest
="css", default
="calendar.css",
646 help="CSS to use for page (html only)"
650 dest
="locale", default
=None,
651 help="locale to be used from month and weekday names"
655 dest
="encoding", default
=None,
656 help="Encoding to use for output"
660 dest
="type", default
="text",
661 choices
=("text", "html"),
662 help="output type (text or html)"
665 (options
, args
) = parser
.parse_args(args
)
667 if options
.locale
and not options
.encoding
:
668 parser
.error("if --locale is specified --encoding is required")
671 locale
= options
.locale
, options
.encoding
673 if options
.type == "html":
675 cal
= LocaleHTMLCalendar(locale
=locale
)
678 encoding
= options
.encoding
680 encoding
= sys
.getdefaultencoding()
681 optdict
= dict(encoding
=encoding
, css
=options
.css
)
683 print cal
.formatyearpage(datetime
.date
.today().year
, **optdict
)
685 print cal
.formatyearpage(int(args
[1]), **optdict
)
687 parser
.error("incorrect number of arguments")
691 cal
= LocaleTextCalendar(locale
=locale
)
694 optdict
= dict(w
=options
.width
, l
=options
.lines
)
696 optdict
["c"] = options
.spacing
697 optdict
["m"] = options
.months
699 result
= cal
.formatyear(datetime
.date
.today().year
, **optdict
)
701 result
= cal
.formatyear(int(args
[1]), **optdict
)
703 result
= cal
.formatmonth(int(args
[1]), int(args
[2]), **optdict
)
705 parser
.error("incorrect number of arguments")
708 result
= result
.encode(options
.encoding
)
712 if __name__
== "__main__":