Skip to content

calendar displays month names in a genitive case for some locales #131146

Closed

Description

@plashchynski

Bug report

Bug description:

A calendar module CLI displays month names in a Polish, and other Slavic languages using the genitive case, as it is used in a phrase "in January". However, for standalone usage, month names should appear in the nominative case to be grammatically correct. For instance, in Polish, "January" should be written as "styczeń" instead of "stycznia"; similarly, in Russian, it should be "январь" rather than "января". This issue likely affects Baltic languages and Greek as well.

Example command demonstrating the issue:

python3 -m calendar --locale pl_PL --encoding utf

This problem occurs because the calendar module uses the strftime %B format specifier, which returns month names suitable for complete date contexts (genitive case). Instead, a nominative form is required when months are mentioned independently:

cpython/Lib/calendar.py

Lines 138 to 140 in 4dcbe06

# Full and abbreviated names of months (1-based arrays!!!)
month_name = _localized_month('%B')
month_abbr = _localized_month('%b')

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Mar 12, 2025
  2. picnixz commented on Mar 12, 2025

    @picnixz
    Member

    This problem occurs because the calendar module uses the strftime %B format specifier, which returns month names suitable for complete date contexts (genitive case). Instead, a nominative form is required when months are mentioned independently:

    What would be the format specifier in this case?

  3. added a commit that references this issue on Mar 12, 2025
  4. plashchynski commented on Mar 12, 2025

    @plashchynski
    ContributorAuthor

    @picnixz to address this issue, I suggest using the %OB format specifier, which returns month names in the nominative case. This specifier is part of the C2x standard and is already supported by most major platforms. Specifically, it has been available in glibc since version 2.27, macOS since 15.3, and Windows as well (tested on Windows 11).

    For platforms that do not support %OB, we can continue using %B as a fallback. This way, the module will work correctly on all platforms, but will provide better results on platforms that support %OB. As calendar.month_name is used in other places in the standard library, I suggest adding a new lists alt_month_name and alt_month_abbr to not interfere with the existing behavior.

  5. picnixz commented on Mar 12, 2025

    @picnixz
    Member

    Ideally, I would want to avoid having a discrepency between platforms (for instance, parsing could be affected) =/ CPython only requires C11 so we can't really assume C2x. However, if this is implemented by major compilers and platforms, maybe we can make an exception? Otherwise, we'll need to wait until C2x is supported officially.

    cc @hugovk as the RM

  6. picnixz commented on Mar 12, 2025

    @picnixz
    Member

    Also, while it is a bug per se, I think we should treat it as a feature instead so to avoid breaking stable Python releases (namely make it only Python 3.14+)

  7. plashchynski commented on Mar 12, 2025

    @plashchynski
    ContributorAuthor

    @picnixz thank you for your comments. Just wanted to add that this only affects calendars displayed by TextCalendar and HTMLCalendar when the affected locale is specified, so side effects are minimal.

    Also, for locales, discrepancies across platforms are somewhat inevitable. One locale might have alternative ways of writing. A language might have multiple names for a month. For instance, in Belarusian, "May" has two alternative names "май" and "травень". So, it is generally not safe to assume that month names will be strictly consistent across platforms.

  8. picnixz commented on Mar 12, 2025

    @picnixz
    Member

    So, it is generally not safe to assume that month names will be strictly consistent across platforms.

    Oh, I see. So I don't need to bother about the discrepency as we already have possible ones.

  9. added a commit that references this issue on Jul 31, 2025
  10. kulikjak commented on Aug 4, 2025

    @kulikjak
    Contributor

    Hi! Atfer this change, test_months and test_standalone_month_name_and_abbr_C_locale started failing on Solaris. The reason is that the %0b specifier doesn't exist there and the standalone_month_abbr array becomes just a bunch of '%Ob's because of that.

    I see that you added except ValueError: likely to catch issues like this, but I don't think that strftime ever raises a ValueError in that case? (I wasn't able to force it on MacOS with nonexistent specifiers.)

    Full failure:

    ======================================================================
    FAIL: test_months (test.test_calendar.CalendarTestCase.test_months)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "..../build/components/python/pythonmain/cpython-main/Lib/test/test_calendar.py", line 557, in test_months
        self.assertEqual(len(set(value)), 13)
        ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
    AssertionError: 2 != 13
    ======================================================================
    FAIL: test_standalone_month_name_and_abbr_C_locale (test.test_calendar.CalendarTestCase.test_standalone_month_name_and_abbr_C_locale)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "..../build/components/python/pythonmain/cpython-main/Lib/test/test_calendar.py", line 590, in test_standalone_month_name_and_abbr_C_locale
        self.assertListEqual(list(calendar.month_abbr),
        ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
                             list(calendar.standalone_month_abbr))
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AssertionError: Lists differ: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', [36 chars]Dec'] != ['', '%Ob', '%Ob', '%Ob', '%Ob', '%Ob', '%Ob', [36 chars]%Ob']
    First differing element 1:
    'Jan'
    '%Ob'
      ['',
    -  'Jan',
    -  'Feb',
    -  'Mar',
    -  'Apr',
    -  'May',
    -  'Jun',
    -  'Jul',
    -  'Aug',
    -  'Sep',
    -  'Oct',
    -  'Nov',
    -  'Dec']
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob',
    +  '%Ob']
    
  11. added 2 commits that reference this issue on Aug 12, 2025
  12. added 2 commits that reference this issue on Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions