Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove year limits from calendar #72468

Closed
abalkin opened this issue Sep 26, 2016 · 15 comments
Closed

Remove year limits from calendar #72468

abalkin opened this issue Sep 26, 2016 · 15 comments
Assignees
Labels
3.7 (EOL) end of life easy type-feature A feature request or enhancement

Comments

@abalkin
Copy link
Member

abalkin commented Sep 26, 2016

BPO 28281
Nosy @doerwalter, @rhettinger, @abalkin, @serhiy-storchaka, @matrixise, @zhangyangyu, @Mariatta, @csabella
PRs
  • Closes bpo-28281: Remove year (1-9999) limits on the weekday() function. #4109
  • Dependencies
  • bpo-28253: calendar.prcal(9999) output has a problem
  • Files
  • calendar-no-year-limits.patch: Remove year (0...9999) limit on weekday() function
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/abalkin'
    closed_at = <Date 2017-10-26.19:34:15.205>
    created_at = <Date 2016-09-26.20:44:06.368>
    labels = ['easy', 'type-feature', '3.7']
    title = 'Remove year limits from calendar'
    updated_at = <Date 2017-10-26.19:34:15.203>
    user = 'https://github.com/abalkin'

    bugs.python.org fields:

    activity = <Date 2017-10-26.19:34:15.203>
    actor = 'belopolsky'
    assignee = 'belopolsky'
    closed = True
    closed_date = <Date 2017-10-26.19:34:15.205>
    closer = 'belopolsky'
    components = []
    creation = <Date 2016-09-26.20:44:06.368>
    creator = 'belopolsky'
    dependencies = ['28253']
    files = ['44917']
    hgrepos = []
    issue_num = 28281
    keywords = ['patch', 'easy']
    message_count = 15.0
    messages = ['277467', '277503', '277526', '277541', '277544', '277634', '277641', '277661', '277835', '279136', '279225', '279228', '304891', '304933', '305085']
    nosy_count = 9.0
    nosy_names = ['doerwalter', 'rhettinger', 'belopolsky', 'serhiy.storchaka', 'matrixise', 'xiang.zhang', 'Mariatta', 'golly', 'cheryl.sabella']
    pr_nums = ['4109']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue28281'
    versions = ['Python 3.7']

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 26, 2016

    The calendar module currently relies on datetime for some calculations and is therefore restricted to years 1 through 9999. With exception to some public methods that are documented to return datetime.date instances, this dependence on the datetime module can be removed.

    @abalkin abalkin added the 3.7 (EOL) end of life label Sep 26, 2016
    @abalkin abalkin self-assigned this Sep 26, 2016
    @abalkin abalkin added the type-feature A feature request or enhancement label Sep 26, 2016
    @doerwalter
    Copy link
    Contributor

    I don't think that's necessary. What's the use case for this?

    And if we want to to this, wouldn't it be better to enhance datetime, so that this use case is supported too?

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 27, 2016

    What's the use case for this?

    Why did George Mallory climb Mount Everest? "Because it's there."

    We have two open issues complaining about calendar behavior for years 1 and 9999: bpo-28253 and bpo-26650. There is also a closed issue bpo-15421 that attempted to fix an overflow in the year 9999 only to introduce a silent error.

    I don't think there are use cases beyond educational (demonstrating calendar periodicity?) or testing, but since several users bothered to report edge case bugs, it is probably easier to remove the limits than to properly document them.

    Fortunately, extending calendar to arbitrary years does not require climbing Mount Everest. Since the proleptic calendar repeats every 400 years, all we need (assuming bpo-28253 patch is applied) is to fix the weekday() function as follows:

     def weekday(year, month, day):
         """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
            day (1-31)."""
    +    if not 0 < year < 10000:
    +        year = 2000 + year % 400
         return datetime.date(year, month, day).weekday()
    $ ./python.exe -mcalendar 40000 12
       December 40000
    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
    
    $ ./python.exe -mcalendar -104 2
       February -104
    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

    We can also treat negative years "properly" so that year 1 is preceded by year -1, but I don't think there is any value in this.

    @abalkin abalkin added the easy label Sep 27, 2016
    @serhiy-storchaka
    Copy link
    Member

    I think data range is limited by year 1 due to ambiguity of year -1. Is it 1 B.D. or 2 years before year 1 (2 B.D.)?

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 27, 2016

    Under my proposal year=-1 is 2 B.C. and year 0 is a leap year

    $ ./python.exe -mcalendar 0 2
         February 0
    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

    This is the simplest extension and people who require other variants can make their own adjustments. (This suggests that we should probably bring weekday(), isleap(), etc. methods to the Calendar class to allow users to override them.)

    @rhettinger
    Copy link
    Contributor

    Under my proposal year=-1 is 2 B.C. and year 0 is a leap year

    We should refuse the temptation to guess (i.e. make up our own arbitrary interpretations). Instead, just document the known limits.

    @abalkin
    Copy link
    Member Author

    abalkin commented Sep 28, 2016

    The proposed interpretation of nonpositive years is not arbitrary, it is a natural extension of the same formulas that we use for positive years. On the other hand 1-9999 limits are arbitrary. If we wanted to restrict calendars to 4-digit years we would limit years to the 1000-9999 range.

    Note that interpreting year 0 as 1 BCE is not without a precedent. ISO 8601 standard does exactly that with the caveat that "values in the range [0000] through [1582] shall only be used by mutual agreement of the partners in information interchange." Furthermore, "an expanded year representation [±YYYYY] must have an agreed-upon number of extra year digits beyond the four-digit minimum, and it must be prefixed with a + or − sign instead of the more common AD/BC (or BCE/CE) notation; by convention 1 BC is labelled +0000, 2 BC is labeled -0001, and so on." See <https://en.wikipedia.org/wiki/ISO_8601#Years\> citing ISO 8601:2004 sections 3.4.2, 4.1.2.4 and Annex B.1.1.

    Furthermore, documenting the existing limits is not an easy task. For example

    >>> from calendar import *
    >>> cal = TextCalendar(1)
    >>> cal.prmonth(1, 1)
         January 1
    Tu We Th Fr Sa Su Mo
                       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

    displays 6 days in December of 1 BCE as blanks. Similarly itermonthdays() and itermonthdays2() generators yield objects corresponding to these days. Are these days within the calendar limits or not?

    Note that I am not proposing to extend the range of the datetime.date objects. Doing that would be a much more difficult task, but defining calendars for out of range years as those for year % 400 is trivial and much easier than to figure out and document the edge behaviors.

    @serhiy-storchaka
    Copy link
    Member

    Okay, if this is specified by ISO 8601 standard, I think we can extend calendar below year 1. But the meaning of non-positive years should be documented. And maybe even provide a way to customize the representation of year (this is a separate issue).

    Standard Unix utilities cal and ncal support only years in range 1..9999.

    @golly
    Copy link
    Mannequin

    golly mannequin commented Oct 2, 2016

    First time patch for CPython. I followed instructions given by belopolsky and added tests. Please critique.

    @matrixise
    Copy link
    Member

    Who can merge this patch ?

    @serhiy-storchaka
    Copy link
    Member

    Alexander as core developer and the creator of this issue can merge the patch after making his review. But first we should make a decision whether it is worth to do at all. I'm +0 now. Raymond seems has objections.

    @abalkin
    Copy link
    Member Author

    abalkin commented Oct 22, 2016

    The patch should include an update to documentation.

    1. We should probably explain that python -mcalendar does not reproduce the output of UNIX cal. For example, on Mac OS (and various Linux variants):
    $ cal 9 1752
       September 1752
    Su Mo Tu We Th Fr Sa
           1  2 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30

    but

    $ python3 -mcalendar 1752 9
       September 1752
    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
    1. We should explain that while the calendar module relies on datetime, it implements an infinite calendar with a period of 400 years.

    2. A reference should be made to ISO 8601 for our treatment of nonpositive years.

    Given ISO 8601 and the simplicity of this change, I don't think Raymond will insist that we continue imposing datetime-like limits, but I would like to give him a chance to renew his objection once the no-limits calendar is documented.

    @csabella
    Copy link
    Contributor

    Hello Mark,

    Would you be able to prepare a pull request on GitHub for your patch?

    Thanks!

    @abalkin
    Copy link
    Member Author

    abalkin commented Oct 24, 2017

    I submitted Mark's patch unchanged as PR 4109. If we don't hear from Mark, I will address my own comments and merge.

    @abalkin
    Copy link
    Member Author

    abalkin commented Oct 26, 2017

    New changeset 66c88ce by Alexander Belopolsky in branch 'master':
    Closes bpo-28281: Remove year (1-9999) limits on the weekday() function. (bpo-4109)
    66c88ce

    @abalkin abalkin closed this as completed Oct 26, 2017
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life easy type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    6 participants