Skip to content

DayLocator is returning incorrect times around daylights switch over #9018

Closed

Description

@LanceJenkinZA

Bug report

Bug summary

DayLocator returning incorrect times around daylights switch over, resulting in duplicate day labels.

Code for reproduction

import datetime

import pylab
import matplotlib.dates as mdates
import pytz

x = [datetime.datetime(2017, 3, 30), datetime.datetime(2017,4,4)]
y = [0, 1]

pylab.plot(x, y)

ax = pylab.gca()

tz = pytz.timezone("Australia/Sydney")
ax.xaxis.set_major_locator(mdates.DayLocator(tz=tz))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%a", tz=tz))

pylab.show()

Actual outcome
The day labels for the day of the daylight switch over are duplicated, see figure below:

image

Expected outcome
The labels should not be duplicated.

Matplotlib version

  • Operating System: Kubuntu 17.04
  • Matplotlib Version: 2.02
  • Python Version: Python 2.7.13
  • pytz: 2017.2

Activity

  1. pganssle commented on Aug 12, 2017

    @pganssle
    Member

    FWIW, this is specifically an issue with pytz time zones:

    import datetime
    
    import pylab
    import matplotlib.dates as mdates
    import pytz
    from dateutil import tz
    
    x = [datetime.datetime(2017, 3, 30), datetime.datetime(2017,4,4)]
    y = [0, 1]
    
    pylab.plot(x, y)
    
    ax = pylab.gca()
    
    tz = tz.gettz('Australia/Sydney')
    ax.xaxis.set_major_locator(mdates.DayLocator(tz=tz))
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%a", tz=tz))
    
    pylab.show()

    daylocator

  2. added this to the milestone on Aug 13, 2017
  3. pganssle commented on Aug 13, 2017

    @pganssle
    Member

    I'm not sure why it just works for dateutil and not for pytz, but I think the issue is that by passing tz to the DayLocator, you're telling the DayLocator that your points should represent that absolute time (it's possible it's represented internally as UTC), and by passing tz again to the formatter, you're converting that back, and that's where the error lies. If you want to keep with the pytz zones, this version of the code will also work as expected:

    TZ = pytz.timezone('Australia/Sydney')
    ax.xaxis.set_major_locator(mdates.DayLocator())
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%a %Y-%m-%d %Z", tz=TZ))
  4. pganssle commented on Aug 13, 2017

    @pganssle
    Member

    OK, I found the problem, I can prepare a patch for this. The issue is that the rrule is being constructed using timezone-aware dates. This is problematic even for dateutil zones, for various reasons, but it's especially problematic for pytz zones, which do not implement the tzinfo interface in the recommended fashion.

    What needs to happen is that RRuleLocator needs to generate naive dates, which, in the case of pytz zones, are then localized (I think it doesn't matter which side of DST they end up on in ambiguous situations, but I think we should default to the DST side for PEP-495 related reasons), and for dateutil zones, they can just be attached as normal.

    One thing to note (and I will make a separate issue to discuss this if my suspicions prove correct) is that I am fairly certain that the current approach will have this same bug if there's ever a DST transition that starts at midnight (i.e. if midnight doesn't exist in a given zone) - though it may be less obvious.

  5. LanceJenkinZA commented on Aug 17, 2017

    @LanceJenkinZA
    Author

    Thanks for looking into the problem, and creating a patch fixing it!

  6. modified the milestones: , on Oct 9, 2017
  7. modified the milestones: , v2.2.0 on Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions