calendar — Trabajar con fechas

Propósito:El módulo calendar implementa clases para trabajar con fechas para gestionar valores orientados año / mes / semana.

El módulo calendar define la clase Calendar, que encapsula cálculos para valores tales como las fechas de las semanas en un mes o año dado. Además, las clases TextCalendar y HTMLCalendar pueden producir salida pre formateada.

Ejemplos de formateo

El método prmonth() es una función simple que produce salida de texto formateado para un mes.

calendar_textcalendar.py
import calendar

c = calendar.TextCalendar(calendar.SUNDAY)
c.prmonth(2017, 7)

El ejemplo configura TextCalendar para comenzar semanas el domingo, siguiendo la convención estadounidense. El valor predeterminado es utilizar la convención europea de comenzar una semana el lunes.

La salida se ve así:

$ python3 calendar_textcalendar.py

     July 2017
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 31

Se puede generar una tabla HTML similar con HTMLCalendar y formatmonth(). La salida renderizada se ve más o menos lo mismo como la versión de texto sin formato, pero está envuelta con etiquetas HTML. Cada celda de la tabla tiene un atributo de clase correspondiente al día de la semana, por lo que el HTML se puede estilizar a través de CSS.

Para producir resultados en un formato que no sea uno de los disponibles por defecto, usa calendar para calcular las fechas y organizar los valores en rangos de semana y mes, y luego iterar sobre el resultado. Los métodos weekheader(), monthcalendar() y yeardays2calendar() de Calendar son especialmente útiles para eso.

Invocar a yeardays2calendar() produce una secuencia de listas «fila de mes». Cada lista incluye los meses como otra lista de semanas. Las semanas son listas de tuplas formadas por el número del día (1-31) y el número del día de la semana (0-6). Los días que quedan fuera del mes tienen un número de días 0.

calendar_yeardays2calendar.py
import calendar
import pprint

cal = calendar.Calendar(calendar.SUNDAY)

cal_data = cal.yeardays2calendar(2017, 3)
print('len(cal_data)      :', len(cal_data))

top_months = cal_data[0]
print('len(top_months)    :', len(top_months))

first_month = top_months[0]
print('len(first_month)   :', len(first_month))

print('first_month:')
pprint.pprint(first_month, width=65)

Invocar a yeardays2calendar(2017, 3) devuelve datos para 2017, organizados con tres meses por fila.

$ python3 calendar_yeardays2calendar.py

len(cal_data)      : 4
len(top_months)    : 3
len(first_month)   : 5
first_month:
[[(1, 6), (2, 0), (3, 1), (4, 2), (5, 3), (6, 4), (7, 5)],
 [(8, 6), (9, 0), (10, 1), (11, 2), (12, 3), (13, 4), (14, 5)],
 [(15, 6), (16, 0), (17, 1), (18, 2), (19, 3), (20, 4), (21,
5)],
 [(22, 6), (23, 0), (24, 1), (25, 2), (26, 3), (27, 4), (28,
5)],
 [(29, 6), (30, 0), (31, 1), (0, 2), (0, 3), (0, 4), (0, 5)]]

Esto es equivalente a los datos utilizados por formatyear().

calendar_formatyear.py
import calendar

cal = calendar.TextCalendar(calendar.SUNDAY)
print(cal.formatyear(2017, 2, 1, 1, 3))

Para los mismos argumentos, formatyear() produce este resultado:

$ python3 calendar_formatyear.py

                              2017

      January               February               March
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
 1  2  3  4  5  6  7            1  2  3  4            1  2  3  4
 8  9 10 11 12 13 14   5  6  7  8  9 10 11   5  6  7  8  9 10 11
15 16 17 18 19 20 21  12 13 14 15 16 17 18  12 13 14 15 16 17 18
22 23 24 25 26 27 28  19 20 21 22 23 24 25  19 20 21 22 23 24 25
29 30 31              26 27 28              26 27 28 29 30 31

       April                  May                   June
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
                   1      1  2  3  4  5  6               1  2  3
 2  3  4  5  6  7  8   7  8  9 10 11 12 13   4  5  6  7  8  9 10
 9 10 11 12 13 14 15  14 15 16 17 18 19 20  11 12 13 14 15 16 17
16 17 18 19 20 21 22  21 22 23 24 25 26 27  18 19 20 21 22 23 24
23 24 25 26 27 28 29  28 29 30 31           25 26 27 28 29 30
30

        July                 August              September
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
                   1         1  2  3  4  5                  1  2
 2  3  4  5  6  7  8   6  7  8  9 10 11 12   3  4  5  6  7  8  9
 9 10 11 12 13 14 15  13 14 15 16 17 18 19  10 11 12 13 14 15 16
16 17 18 19 20 21 22  20 21 22 23 24 25 26  17 18 19 20 21 22 23
23 24 25 26 27 28 29  27 28 29 30 31        24 25 26 27 28 29 30
30 31

      October               November              December
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
 1  2  3  4  5  6  7            1  2  3  4                  1  2
 8  9 10 11 12 13 14   5  6  7  8  9 10 11   3  4  5  6  7  8  9
15 16 17 18 19 20 21  12 13 14 15 16 17 18  10 11 12 13 14 15 16
22 23 24 25 26 27 28  19 20 21 22 23 24 25  17 18 19 20 21 22 23
29 30 31              26 27 28 29 30        24 25 26 27 28 29 30
                                            31

Los atributos day_name, day_abbr, month_name, y month_abbr del módulo son útiles para producir salida formateada personalizada (es decir, para incluir enlaces en la salida HTML). Son configurados automáticamente correctamente para la configuración regional actual.

Configuraciones regionales

Para producir un calendario formateado para una configuración regional diferente a la actual predeterminado, usa LocaleTextCalendar o LocaleHTMLCalendar.

calendar_locale.py
import calendar

c = calendar.LocaleTextCalendar(locale='en_US')
c.prmonth(2017, 7)

print()

c = calendar.LocaleTextCalendar(locale='fr_FR')
c.prmonth(2017, 7)

El primer día de la semana no es parte de la configuración regional, y el valor se toma del argumento a la clase de calendario al igual que con el TextCalendar habitual.

$ python3 calendar_locale.py

     July 2017
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
31

    juillet 2017
Lu Ma Me Je Ve Sa Di
                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
31

Calculando fechas

Aunque el módulo calendar se centra principalmente en la impresión de calendarios completos en varios formatos, también proporciona funciones útiles para trabajar con fechas de otras maneras, como el cálculo de las fechas de un evento recurrente. Por ejemplo, el grupo de usuarios de Python Atlanta se reúne en el segundo jueves de cada mes. Para calcular las fechas para las reuniones durante un año, utiliza el valor de retorno de monthcalendar().

calendar_monthcalendar.py
import calendar
import pprint

pprint.pprint(calendar.monthcalendar(2017, 7))

Algunos días tienen un valor de 0. Esos son días de la semana que se superponen con el mes dado, pero son parte de otro mes.

$ python3 calendar_monthcalendar.py

[[0, 0, 0, 0, 0, 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],
 [31, 0, 0, 0, 0, 0, 0]]

El primer día de la semana está pre determinado para el lunes. Es posible cambiarque al llamar a setfirstweekday(), pero ya que el módulo calendar incluye constantes para indexar en los rangos de fechas devueltos por monthcalendar(), es más conveniente omitir ese paso en este caso.

Para calcular las fechas de reunión del grupo por un año, suponiendo que son siempre el segundo jueves de cada mes, mira la salida de monthcalendar() para encontrar las fechas en las que caen los jueves. La primera y última semana del mes se rellenan con valores 0 como marcadores de posición para los días que caen en el mes anterior o posterior. Por ejemplo, si un mes comienza el viernes, el valor en la primera semana en la posición del jueves será 0.

calendar_secondthursday.py
import calendar
import sys

year = int(sys.argv[1])

# Show every month
for month in range(1, 13):

    # Compute the dates for each week that overlaps the month
    c = calendar.monthcalendar(year, month)
    first_week = c[0]
    second_week = c[1]
    third_week = c[2]

    # If there is a Thursday in the first week,
    # the second Thursday is # in the second week.
    # Otherwise, the second Thursday must be in
    # the third week.
    if first_week[calendar.THURSDAY]:
        meeting_date = second_week[calendar.THURSDAY]
    else:
        meeting_date = third_week[calendar.THURSDAY]

    print('{:>3}: {:>2}'.format(calendar.month_abbr[month],
                                meeting_date))

Entonces el horario de la reunión para el año es:

$ python3 calendar_secondthursday.py 2017

Jan: 12
Feb:  9
Mar:  9
Apr: 13
May: 11
Jun:  8
Jul: 13
Aug: 10
Sep: 14
Oct: 12
Nov:  9
Dec: 14

Ver también