paulb@215 | 1 | #!/usr/bin/env python |
paulb@215 | 2 | |
paulb@464 | 3 | """ |
paulb@565 | 4 | Copyright (C) 2005, 2007 Paul Boddie <paul@boddie.org.uk> |
paulb@464 | 5 | |
paulb@464 | 6 | Additional copyrights for the monthcalendar function: |
paulb@464 | 7 | |
paulb@464 | 8 | Copyright (c) 2001, 2002, 2003, 2004, 2005 Python Software Foundation. |
paulb@464 | 9 | Copyright (c) 2000 BeOpen.com. |
paulb@464 | 10 | Copyright (c) 1995-2001 Corporation for National Research Initiatives. |
paulb@464 | 11 | Copyright (c) 1991-1995 Stichting Mathematisch Centrum. |
paulb@464 | 12 | |
paulb@600 | 13 | This program is free software; you can redistribute it and/or modify it under |
paulb@600 | 14 | the terms of the GNU Lesser General Public License as published by the Free |
paulb@600 | 15 | Software Foundation; either version 3 of the License, or (at your option) any |
paulb@600 | 16 | later version. |
paulb@464 | 17 | |
paulb@600 | 18 | This program is distributed in the hope that it will be useful, but WITHOUT |
paulb@600 | 19 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paulb@600 | 20 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
paulb@600 | 21 | details. |
paulb@464 | 22 | |
paulb@600 | 23 | You should have received a copy of the GNU Lesser General Public License along |
paulb@600 | 24 | with this program. If not, see <http://www.gnu.org/licenses/>. |
paulb@464 | 25 | """ |
paulb@464 | 26 | |
paulb@215 | 27 | import libxml2dom |
paulb@215 | 28 | import calendar |
paulb@215 | 29 | |
paulb@215 | 30 | # Borrowed from calendar, but with a non-global first weekday variable. |
paulb@215 | 31 | |
paulb@215 | 32 | def monthcalendar(year, month, firstweekday=0): |
paulb@215 | 33 | """Return a matrix representing a month's calendar. |
paulb@215 | 34 | Each row represents a week; days outside this month are zero.""" |
paulb@215 | 35 | day1, ndays = calendar.monthrange(year, month) |
paulb@215 | 36 | rows = [] |
paulb@215 | 37 | r7 = range(7) |
paulb@215 | 38 | day = (firstweekday - day1 + 6) % 7 - 5 # for leading 0's in first week |
paulb@215 | 39 | while day <= ndays: |
paulb@215 | 40 | row = [0, 0, 0, 0, 0, 0, 0] |
paulb@215 | 41 | for i in r7: |
paulb@215 | 42 | if 1 <= day <= ndays: row[i] = day |
paulb@215 | 43 | day = day + 1 |
paulb@215 | 44 | rows.append(row) |
paulb@215 | 45 | return rows |
paulb@215 | 46 | |
paulb@217 | 47 | # Helper functions. |
paulb@217 | 48 | |
paulb@217 | 49 | def get_previous_year_and_month(year, month): |
paulb@217 | 50 | if month - 1 == 0: |
paulb@217 | 51 | return year - 1, 12 |
paulb@217 | 52 | else: |
paulb@217 | 53 | return year, month - 1 |
paulb@217 | 54 | |
paulb@217 | 55 | def get_next_year_and_month(year, month): |
paulb@217 | 56 | if month + 1 == 13: |
paulb@217 | 57 | return year + 1, 1 |
paulb@217 | 58 | else: |
paulb@217 | 59 | return year, month + 1 |
paulb@217 | 60 | |
paulb@215 | 61 | # XML production functions. |
paulb@215 | 62 | |
paulb@216 | 63 | def write_month_to_document(doc, root, year, month): |
paulb@565 | 64 | |
paulb@565 | 65 | """ |
paulb@565 | 66 | Write into the document 'doc' appending to the child elements of the 'root' |
paulb@565 | 67 | element, inserting a month calendar based on the specified 'year' and |
paulb@565 | 68 | 'month'. |
paulb@565 | 69 | """ |
paulb@565 | 70 | |
paulb@215 | 71 | weeks = monthcalendar(year, month) |
paulb@216 | 72 | month_element = root.appendChild(doc.createElement("month")) |
paulb@217 | 73 | |
paulb@217 | 74 | # Add navigational attributes. |
paulb@217 | 75 | |
paulb@216 | 76 | month_element.setAttribute("number", str(month)) |
paulb@216 | 77 | month_element.setAttribute("year", str(year)) |
paulb@217 | 78 | yp, mp = get_previous_year_and_month(year, month) |
paulb@217 | 79 | month_element.setAttribute("number-previous", str(mp)) |
paulb@217 | 80 | month_element.setAttribute("year-previous", str(yp)) |
paulb@217 | 81 | yn, mn = get_next_year_and_month(year, month) |
paulb@217 | 82 | month_element.setAttribute("number-next", str(mn)) |
paulb@217 | 83 | month_element.setAttribute("year-next", str(yn)) |
paulb@217 | 84 | |
paulb@217 | 85 | # Add weeks and days. |
paulb@217 | 86 | |
paulb@216 | 87 | for numbers in weeks: |
paulb@215 | 88 | week_element = month_element.appendChild(doc.createElement("week")) |
paulb@216 | 89 | for number in numbers: |
paulb@215 | 90 | day_element = week_element.appendChild(doc.createElement("day")) |
paulb@216 | 91 | if number != 0: |
paulb@216 | 92 | day_element.setAttribute("date", "%04d%02d%02d" % (year, month, number)) |
paulb@216 | 93 | day_element.setAttribute("number", str(number)) |
paulb@215 | 94 | |
paulb@565 | 95 | return month_element |
paulb@565 | 96 | |
paulb@215 | 97 | def get_calendar_for_month(year, month): |
paulb@216 | 98 | doc = libxml2dom.createDocument(None, "calendar", None) |
paulb@216 | 99 | write_month_to_document(doc, doc.childNodes[-1], year, month) |
paulb@216 | 100 | return doc |
paulb@215 | 101 | |
paulb@215 | 102 | if __name__ == "__main__": |
paulb@215 | 103 | import sys |
paulb@215 | 104 | try: |
paulb@215 | 105 | print get_calendar_for_month(int(sys.argv[1]), int(sys.argv[2])).toString() |
paulb@215 | 106 | except (IndexError, ValueError): |
paulb@215 | 107 | print "Please specify a year and a month (numeric, 1-12)." |
paulb@215 | 108 | |
paulb@215 | 109 | # vim: tabstop=4 expandtab shiftwidth=4 |