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

calendar.prcal(9999) output has a problem #72440

Closed
lijp003163com mannequin opened this issue Sep 23, 2016 · 29 comments
Closed

calendar.prcal(9999) output has a problem #72440

lijp003163com mannequin opened this issue Sep 23, 2016 · 29 comments
Assignees
Labels
3.7 (EOL) end of life stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@lijp003163com
Copy link
Mannequin

lijp003163com mannequin commented Sep 23, 2016

BPO 28253
Nosy @rhettinger, @abalkin, @serhiy-storchaka, @zhangyangyu, @lijp_003@163.com
Superseder
  • bpo-28292: Make Calendar.itermonthdates() behave consistently in edge cases
  • Files
  • 20160923154147.png: output result
  • calendar_pryear_9999.patch
  • calendar_prcal_9999_demo.patch
  • issue28253.diff
  • issue28253-2.diff
  • issue28253-3.diff
  • issue28253-4.diff
  • 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 2016-09-28.03:02:52.638>
    created_at = <Date 2016-09-23.05:59:40.192>
    labels = ['3.7', 'type-bug', 'library']
    title = 'calendar.prcal(9999) output has a problem'
    updated_at = <Date 2017-10-23.21:21:44.048>
    user = 'https://github.com/lijp003163com'

    bugs.python.org fields:

    activity = <Date 2017-10-23.21:21:44.048>
    actor = 'serhiy.storchaka'
    assignee = 'belopolsky'
    closed = True
    closed_date = <Date 2016-09-28.03:02:52.638>
    closer = 'belopolsky'
    components = ['Library (Lib)']
    creation = <Date 2016-09-23.05:59:40.192>
    creator = 'jiangping.li'
    dependencies = []
    files = ['44788', '44789', '44793', '44834', '44835', '44836', '44845']
    hgrepos = []
    issue_num = 28253
    keywords = ['patch']
    message_count = 29.0
    messages = ['277244', '277246', '277247', '277250', '277253', '277257', '277275', '277315', '277316', '277433', '277435', '277436', '277446', '277447', '277452', '277464', '277468', '277474', '277475', '277476', '277484', '277489', '277523', '277530', '277532', '277539', '277567', '277568', '277575']
    nosy_count = 6.0
    nosy_names = ['rhettinger', 'belopolsky', 'python-dev', 'serhiy.storchaka', 'xiang.zhang', 'jiangping.li']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = '28292'
    type = 'behavior'
    url = 'https://bugs.python.org/issue28253'
    versions = ['Python 2.7', 'Python 3.5', 'Python 3.6', 'Python 3.7']

    @lijp003163com
    Copy link
    Mannequin Author

    lijp003163com mannequin commented Sep 23, 2016

    hi
    I`m a python newer.
    when I use python3.4.3 to learn about package calendar,I found a problem, Could you help me to confirm it which is is a bug.

    Below is my env:
    ------------------------------
    os: win7 x86
    python version:3.4.3
    ------------------------------
    problem:
    when I use calendar.prcal() method to print detail calendar information. the display December of year 9999 `s localtion is wrong.
    my python source:
    --------------------------------------

    import calendar
    calendar.prcal(9999)

    partial output:

    but,when I use [print (calendar.month(9999,12))] to confirm, it`s OK .

    please help me to confirm.
    thank you.

    @lijp003163com lijp003163com mannequin added the OS-windows label Sep 23, 2016
    @lijp003163com lijp003163com mannequin changed the title the reply's additional "Re:" calendar.prcal(9999) output has a problem Sep 23, 2016
    @lijp003163com lijp003163com mannequin added the type-bug An unexpected behavior, bug, or error label Sep 23, 2016
    @serhiy-storchaka
    Copy link
    Member

    Thank you for your report lijp. This is interesting issue. It is not specific for Windows.

    itermonthdates() yields shortened sequence of dates at the end of maximal year. The formatted row of day numbers is centered. Since the number of days is less than expected, additional spaces are added at the left.

    @serhiy-storchaka serhiy-storchaka added stdlib Python modules in the Lib dir 3.7 (EOL) end of life and removed OS-windows labels Sep 23, 2016
    @serhiy-storchaka serhiy-storchaka self-assigned this Sep 23, 2016
    @zhangyangyu
    Copy link
    Member

    calendar internally relies on datetime and uses datetime.date. datetime.date can't represent date more than 9999.12.31 so some logic is broken for it(normally the week list should be of length 7, date outside the month will be (0, x) pair but this is not the case for 9999.12). This won't affect prmonth since it doesn't do center formatting. We can change to that behaviour to fix this. calendar_pryear_9999 tires to fix this.

    @serhiy-storchaka
    Copy link
    Member

    Html calendar formats the last week differently for years 9982 and 9999.

    Year 9982:
    <tr><td class="mon">27</td><td class="tue">28</td><td class="wed">29</td><td class="thu">30</td><td class="fri">31</td><td class="noday"> </td><td class="noday"> </td></tr>

    Year 9999:
    <tr><td class="mon">27</td><td class="tue">28</td><td class="wed">29</td><td class="thu">30</td><td class="fri">31</td></tr>

    I think this issue should be fixed on lower level than text calendar formatter.

    @zhangyangyu
    Copy link
    Member

    Something like this?

    diff -r 15f82b64eee0 Lib/calendar.py
    --- a/Lib/calendar.py	Thu Sep 22 17:11:53 2016 -0700
    +++ b/Lib/calendar.py	Fri Sep 23 16:27:03 2016 +0800
    @@ -181,6 +181,9 @@
                     yield (0, date.weekday())
                 else:
                     yield (date.day, date.weekday())
    +                if year == 9999 and month == 12 and date.day == 31:
    +                    yield (0, 6)
    +                    yield (0, 7)
     
         def itermonthdays(self, year, month):
             """

    Is there a more elegant way? I considered this but didn't quite like it so abandoned it.

    @serhiy-storchaka
    Copy link
    Member

    This is not just not elegant, but it doesn't work if firstweekday is not 0.

    The lowest level in the calendar module is itermonthdates(). But the problem is that dates outside supported range can't be represented.

    While the output for December of the year 9999 looks badly formatted, calendar doesn't work at all with January of the year 1 if firstweekday is not 0:

    >>> import calendar
    >>> calendar.setfirstweekday(6)
    >>> calendar.prmonth(1, 1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/serhiy/py/cpython-3.6/Lib/calendar.py", line 318, in prmonth
        print(self.formatmonth(theyear, themonth, w, l), end=' ')
      File "/home/serhiy/py/cpython-3.6/Lib/calendar.py", line 331, in formatmonth
        for week in self.monthdays2calendar(theyear, themonth):
      File "/home/serhiy/py/cpython-3.6/Lib/calendar.py", line 211, in monthdays2calendar
        days = list(self.itermonthdays2(year, month))
      File "/home/serhiy/py/cpython-3.6/Lib/calendar.py", line 179, in itermonthdays2
        for date in self.itermonthdates(year, month):
      File "/home/serhiy/py/cpython-3.6/Lib/calendar.py", line 162, in itermonthdates
        date -= datetime.timedelta(days=days)
    OverflowError: date value out of range

    @zhangyangyu
    Copy link
    Member

    How about the approach in calendar_prcal_9999_demo.patch? If it's not bad I can add tests then.

    @serhiy-storchaka
    Copy link
    Member

    Having additional tests is always nice. After writing tests we can search whether there is other solution.

    AFAIK the dummy data needs also the day attribute.

    @serhiy-storchaka
    Copy link
    Member

    The problem with year 1 was reported in bpo-26650.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    I would leave itermonthdates() alone and just fix itermonthdays2() (and itermonthdays() for consistency) as Xiang suggested. The fix can be implemented by breaking on date.month != month and adding something like

    for wd in range(date.weekday(), 7):
        yield (0, wd)

    after the existing for loop.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    On the second thought, I don't see why itermonthdays2() and itermonthdays() need to use itermonthdates() at all. It looks like it is easy to implement those using monthrange() and some simple integer arithmetics.

    @serhiy-storchaka
    Copy link
    Member

    itermonthdates() is documented public method. We should do something with it. Maybe emitting dummy data instances is the simplest way to solve this issue.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    Note that the stop on date.max behavior was introduced in bpo-15421.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    itermonthdates() is documented public method

    The current documentation is an impossibility:

    "The iterator will yield datetime.date values and will always iterate through complete weeks, so it will yield dates outside the specified
    month."

    The current implementation deals with this impossibility differently for months (9999, 12) and (1, 1). In the first case, the iterators stops on an out of bounds date:

    >>> list(calendar.Calendar().itermonthdates(9999, 12))[-1]
    datetime.date(9999, 12, 31)
    >>> list(calendar.Calendar().itermonthdates(9999, 12))[-1].weekday()
    4

    but in the second, it raises the OverflowError:

    >>> next(calendar.Calendar(1).itermonthdates(1, 1))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "calendar.py", line 160, in itermonthdates
        date -= datetime.timedelta(days=days)
    OverflowError: date value out of range

    Returning dummy instances instead of datetime.date in these cases will only make debugging harder for the users of .itermonthdates(). Sooner or later they would want to do something the returned value that the dummy won't support. If you are willing to sacrifice the "will yield datetime.date values" for "will always iterate through complete weeks", I would make it yield None for out of bounds values and require the caller to deal with this possibility right away.

    A better solution would be to simply raise OverflowError whenever the range of itermonthdates() does not fit within [date.min, date.max].

    @serhiy-storchaka
    Copy link
    Member

    Yes, the current documentation is an impossibility (unless we remove all date limits that is much harder issue). Raisin OverflowError will make the implementation of itermonthdays2() and itermonthdays() more complex. Yielding dummy instances or None requires rewriting user code (less with a dummy instance if we are lucky). I agree that in long perspective yielding None looks better.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    I am attaching the proposed reimplementation of itermonthdays2() and itermonthdays(). It does not use itermonthdates() and is not that complicated. It passes test_calendar, but I did not test it further than that.

    I would rather not mess up with itermonthdates(), particularly in a bugfix release. We can postpone the discussion of a better way to handle date over/underflow in itermonthdates() until 3.7.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    unless we remove all date limits that is much harder issue

    I don't think this is too hard. I think the original implementation did not have date limits. I've opened a separate issue for this. See bpo-28281.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    bpo-28253-2.diff is a small performance improvement over bpo-28253.diff

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    bpo-28253-3.diff uses itertools.repeat().

    @abalkin
    Copy link
    Member

    abalkin commented Sep 26, 2016

    bpo-28253-4.diff is bpo-28253-3.diff with tests.

    @zhangyangyu
    Copy link
    Member

    Patch LGTM.

    I would rather not mess up with itermonthdates(), particularly in a bugfix release. We can postpone the discussion of a better way to handle date over/underflow in itermonthdates() until 3.7.

    Before finally find a better way, can we at least make the two extreme cases behaviours consistent? Both emitting an exception or a shorter list.

    @serhiy-storchaka
    Copy link
    Member

    The patch LGTM except tests.

    But we should at least document the behavior of itermonthdates(), monthdatescalendar() and yeardatescalendar() at corner cases.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 27, 2016

    The patch LGTM except tests.

    What are your issues with the tests? Did you see the -4 patch?

    But we should at least document the behavior of itermonthdates(), monthdatescalendar() and yeardatescalendar() at corner cases.

    I would rather not. At least not before we make under and overflow behavior consistent. Frankly, I don't see why anyone would want to use these iterators.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 27, 2016

    Something went wrong with bpo-28253-4.diff. I'll investigate and replace.

    @abalkin
    Copy link
    Member

    abalkin commented Sep 27, 2016

    bpo-28253-4.diff should be good now.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 28, 2016

    New changeset c439bce36bf2 by Alexander Belopolsky in branch '3.5':
    Issue bpo-28253: Fixed calendar functions for extreme months: 0001-01 and 9999-12.
    https://hg.python.org/cpython/rev/c439bce36bf2

    New changeset cd384c4b441a by Alexander Belopolsky in branch '3.6':
    Issue bpo-28253: Fixed calendar functions for extreme months: 0001-01 and 9999-12.
    https://hg.python.org/cpython/rev/cd384c4b441a

    New changeset bc285a9ecc58 by Alexander Belopolsky in branch 'default':
    Issue bpo-28253: Fixed calendar functions for extreme months: 0001-01 and 9999-12.
    https://hg.python.org/cpython/rev/bc285a9ecc58

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 28, 2016

    New changeset 7efba48299e9 by Alexander Belopolsky in branch 'default':
    Issue bpo-28253: Added a NEWS entry.
    https://hg.python.org/cpython/rev/7efba48299e9

    New changeset 55f11196c949 by Alexander Belopolsky in branch '3.5':
    Issue bpo-28253: Added a NEWS entry.
    https://hg.python.org/cpython/rev/55f11196c949

    New changeset 1f1a085f533f by Alexander Belopolsky in branch '3.6':
    Issue bpo-28253: Added a NEWS entry.
    https://hg.python.org/cpython/rev/1f1a085f533f

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 28, 2016

    New changeset f2aff898f7c8 by Alexander Belopolsky in branch '2.7':
    Issue bpo-28253: Fixed calendar functions for extreme months: 0001-01 and 9999-12.
    https://hg.python.org/cpython/rev/f2aff898f7c8

    @abalkin abalkin closed this as completed Sep 28, 2016
    @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 stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants