Модуль calendar языка Python
В стандартной библиотеки Python есть модуль calendar
, который в первую очередь предназначен для вывода календаря на заданный месяц или целый год на экран
- в текстовом формате, когда форматирование достигается пробелами и символами перехода на новую строку,
- формате HTML, когда для структуризации и оформления вывода используются теги HTML и стили CSS; данные следует самостоятельно сохранить в файл и для просмотра результата открывать в браузере.
В первом случае используется класс TextCalendar
, во втором – HTMLCalendar
.
Оба они являются подклассами класса Calendar
(следовательно наследуют все его атрибуты), который сам по себе не предназначен для вывода данных. Если этого не требуется, а необходимо только получать коллекции дат, дней недели с привязкой к дате или дню месяца и тому подобное, достаточно использовать Calendar
. Также сюда относятся случаи, когда данные должны в последующем сохраняться или передаваться в каких-то особых форматах (не текстовом и не HTML).
Дополнительно в самом модуле calendar
есть различные функции и константы, с помощью которых можно узнать день недели даты, является ли год високосным, количество високосных лет между датами и другое.
import calendar # Является ли год високосным print(calendar.isleap(2000)) # True print(calendar.isleap(2100)) # False # Строка заголовков дней недели print(calendar.weekheader(2)) # Mo Tu We Th Fr Sa Su # weekday() возвращает индекс дня недели для заданной даты june3 = calendar.weekday(2023, 6, 3) wh = calendar.weekheader(9).split() print(wh[june3]) # Saturday # Дни недели в текущей локали dn = calendar.day_name print(list(dn)[5:]) # ['Saturday', 'Sunday']
Функции month
, prmonth
, calendar
, prcal
являются вариантами "быстрого доступа" к соответствующим методам класса TextCalendar
: formatmonth
, prmonth
, formatyear
, pryear
.
При создании календаря первым днем недели по умолчанию является понедельник. Его индексный номер 0. Индексы всех дней можно узнать через соответствующие константы модуля.
>>> import calendar >>> calendar.MONDAY 0 >>> calendar.THURSDAY 3 >>> calendar.SUNDAY 6
При создании экземпляра календаря, если требуется, чтобы неделя начиналась с отличного от понедельника дня, следует передать индекс другого дня недели (это можно сделать через константу).
from calendar import TextCalendar monday_cal = TextCalendar() sunday_cal = TextCalendar(6) monday_cal.prmonth(2023, 6) sunday_cal.prmonth(2023, 6) m_days = monday_cal.monthdatescalendar(2023, 6) s_days = sunday_cal.monthdatescalendar(2023, 6) print("\nПервый день первой недели месяца:") print(m_days[0][0], "- если с понедельника") print(s_days[0][0], "- если с воскресенья")
June 2023 Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 June 2023 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Первый день первой недели месяца: 2023-05-29 - если с понедельника 2023-05-28 - если с воскресенья
Поскольку модуль calendar
в первую очередь заточен на вывод данных, работу с группами дат (неделя, месяц), то в данные месяца захватываются все дни первой и последней недели, даже если их даты принадлежат другим месяцам.
Методы monthdatescalendar
, monthdayscalendar
, monthdays2calendar
и аналогичные для года возвращают списки дней месяца или года в разных формах представления.
from calendar import Calendar, SUNDAY cal = Calendar() dates = cal.monthdatescalendar(2023, 6) # Список, состоящий из списков по 7 элементов-дней print(type(dates)) # <class 'list'> # Количество вложенных списков = сколько недель в месяце print(len(dates)) # 5 # Длина вложенного списка = количество дней в неделе print(len(dates[0])) # 7 # Тип данных элемента вложенного списка print(type(dates[0][0])) # <class 'datetime.date'> # Даты воскресений месяца for week in dates: print(week[SUNDAY], end=', ') # 2023-06-04, 2023-06-11, 2023-06-18, 2023-06-25, 2023-07-02,
В отличие от monthdatescalendar
элементами вложенных списков, возвращаемых monthdayscalendar
и monthdays2calendar
, являются целые числа и кортежи соответственно. В первом случае числа обозначают даты месяца. Во втором случае первый элемент кортежа – это дата, второй элемент – индекс дня недели. Если день недели приходится на дату другого месяца, то вместо даты записывается 0.
В случае года список имеет более многоуровневую структуру. На верхнем уровне он состоит из четырех списков, соответствующих кварталам (по три месяца). Однако длину и, следовательно, количество этих списков можно менять, передавая второй аргумент в методы.
from calendar import Calendar cal = Calendar() year = cal.yeardayscalendar(2023) # Элементами года являются списки-кварталы print(len(year)) # 4 # В первом квартале 3 месяца print(len(year[0])) # 3 # Кол-во недель в третьем месяце второго квартала print(len(year[1][2])) # 5 # Даты последней недели июня print(year[1][2][4]) # [26, 27, 28, 29, 30, 0, 0] # Год, состоящий из списков полугодий, а не кварталов year = cal.yeardayscalendar(2023, 6) print(len(year)) # 2
Другими вариациями являются методы с приставкой "iter" (для года таких нет). Они возвращают объекты-итераторы, данные из которых извлекаются последовательно и безвозвратно:
from calendar import Calendar, WEDNESDAY cal = Calendar() dates = cal.itermonthdates(2023, 6) print(dates) print(type(dates)) for i in dates: if i.weekday() == WEDNESDAY: print(i) # в dates больше ничего нет print(next(iter(dates)))
<generator object Calendar.itermonthdates at 0x7f1b14742570> <class 'generator'> 2023-05-31 2023-06-07 2023-06-14 2023-06-21 2023-06-28 Traceback (most recent call last): File "7_iter.py", line 14, in <module> print(next(iter(dates))) StopIteration
В классе HTMLCalendar
есть методы, которые возвращают строку с тегами HTML: formatmonth
, formatyear
.
Данные в таком виде вставляются в исходный код веб-страниц.
Метод formatyearpage
класса HTMLCalendar
возвращает тип bytes
, а не str
, и формирует страницу полностью (с начальными и конечными тегами, не относящимися непосредственно к календарю).
Для стилизации календаря класс HTMLCalendar
включает поля, значения которых можно заменять на свои путем создания дочернего класса.