Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 48 additions & 5 deletions Doc/library/calendar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -493,25 +493,68 @@ The :mod:`calendar` module exports the following data attributes:

.. data:: month_name

A sequence that represents the months of the year in the current locale. This
follows normal convention of January being month number 1, so it has a length of
13 and ``month_name[0]`` is the empty string.
A sequence that represents the months of the year in the current locale.
This follows normal convention of January being month number 1, so it has
a length of 13 and ``month_name[0]`` is the empty string.

>>> import calendar
>>> list(calendar.month_name)
['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

.. caution::

In locales with alternative forms of month names, the :data:`!month_name` sequence
may not be suitable when a month name stands by itself and not as part of a date.
For instance, in Greek and in many Slavic and Baltic languages, :data:`!month_name`
will produce the month in genitive case. Use :data:`standalone_month_name` for a form
suitable for standalone use.


.. data:: month_abbr

A sequence that represents the abbreviated months of the year in the current
locale. This follows normal convention of January being month number 1, so it
has a length of 13 and ``month_abbr[0]`` is the empty string.
locale. This follows normal convention of January being month number 1, so
it has a length of 13 and ``month_abbr[0]`` is the empty string.

>>> import calendar
>>> list(calendar.month_abbr)
['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

.. caution::

In locales with alternative forms of month names, the :data:`!month_abbr` sequence
may not be suitable when a month name stands by itself and not as part of a date.
Use :data:`standalone_month_abbr` for a form suitable for standalone use.


.. data:: standalone_month_name

A sequence that represents the months of the year in the current locale
in the grammatical form used when a month name stands by itself if the locale
provides one. If the locale does not supply an alternative form, it is equal to
:data:`month_name`.

>>> import calendar
>>> list(calendar.standalone_month_name)
['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

.. versionadded:: next


.. data:: standalone_month_abbr

A sequence that represents the abbreviated months of the year in the current
locale in the grammatical form used when a month name stands by itself if the
locale provides one. If the locale does not supply an alternative form, it is equal to
:data:`month_abbr`.

>>> import calendar
>>> list(calendar.standalone_month_abbr)
['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

.. versionadded:: next


.. data:: JANUARY
FEBRUARY
MARCH
Expand Down
22 changes: 17 additions & 5 deletions Lib/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
"firstweekday", "isleap", "leapdays", "weekday", "monthrange",
"monthcalendar", "prmonth", "month", "prcal", "calendar",
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
"timegm", "month_name", "month_abbr", "standalone_month_name",
"standalone_month_abbr", "day_name", "day_abbr", "Calendar",
"TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
"LocaleHTMLCalendar", "weekheader",
"Day", "Month", "JANUARY", "FEBRUARY", "MARCH",
"APRIL", "MAY", "JUNE", "JULY",
Expand Down Expand Up @@ -139,6 +140,17 @@ def __len__(self):
month_name = _localized_month('%B')
month_abbr = _localized_month('%b')

# On platforms that support the %OB and %Ob specifiers, it is used
# to get the standalone form of the month name. This is required for
# some languages such as Greek, Slavic, and Baltic languages.
try:
standalone_month_name = _localized_month('%OB')
standalone_month_abbr = _localized_month('%Ob')
except ValueError:
# The platform does not support the %OB and %Ob specifiers.
standalone_month_name = month_name
standalone_month_abbr = month_abbr


def isleap(year):
"""Return True for leap years, False for non-leap years."""
Expand Down Expand Up @@ -377,7 +389,7 @@ def formatmonthname(self, theyear, themonth, width, withyear=True):
"""
_validate_month(themonth)

s = month_name[themonth]
s = standalone_month_name[themonth]
if withyear:
s = "%s %r" % (s, theyear)
return s.center(width)
Expand Down Expand Up @@ -510,9 +522,9 @@ def formatmonthname(self, theyear, themonth, withyear=True):
"""
_validate_month(themonth)
if withyear:
s = '%s %s' % (month_name[themonth], theyear)
s = '%s %s' % (standalone_month_name[themonth], theyear)
else:
s = '%s' % month_name[themonth]
s = standalone_month_name[themonth]
return '<tr><th colspan="7" class="%s">%s</th></tr>' % (
self.cssclass_month_head, s)

Expand Down
13 changes: 12 additions & 1 deletion Lib/test/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ def test_days(self):
self.assertEqual(value[::-1], list(reversed(value)))

def test_months(self):
for attr in "month_name", "month_abbr":
for attr in ("month_name", "month_abbr", "standalone_month_name",
"standalone_month_abbr"):
value = getattr(calendar, attr)
self.assertEqual(len(value), 13)
self.assertEqual(len(value[:]), 13)
Expand All @@ -556,6 +557,16 @@ def test_months(self):
# verify it "acts like a sequence" in two forms of iteration
self.assertEqual(value[::-1], list(reversed(value)))

def test_standalone_month_name_and_abbr(self):
# Ensure that the standalone month names and abbreviations are
# equal to the regular month names and abbreviations for
# the "C" locale.
with calendar.different_locale("C"):
self.assertListEqual(list(calendar.month_name),
list(calendar.standalone_month_name))
self.assertListEqual(list(calendar.month_abbr),
list(calendar.standalone_month_abbr))

def test_locale_text_calendar(self):
try:
cal = calendar.LocaleTextCalendar(locale='')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add :func:`calendar.standalone_month_name` and :func:`calendar.standalone_month_abbr` to
provide month names and abbreviations in a grammatical form used when a month name stands
by itself if the locale provides one.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :class:`calendar.TextCalendar` and :class:`calendar.HTMLCalendar` and
:mod:`calendar` CLI to display month names in the nominative case if
provided by the locale.
Loading