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

No obvious and correct way to get the time zone offset #44521

Closed
jamesh mannequin opened this issue Jan 30, 2007 · 10 comments
Closed

No obvious and correct way to get the time zone offset #44521

jamesh mannequin opened this issue Jan 30, 2007 · 10 comments
Assignees
Labels
type-feature A feature request or enhancement

Comments

@jamesh
Copy link
Mannequin

jamesh mannequin commented Jan 30, 2007

BPO 1647654
Nosy @mdickinson, @abalkin
Dependencies
  • bpo-1667546: Time zone-capable variant of time.localtime
  • Superseder
  • bpo-9527: Add aware local time support to datetime module
  • Files
  • issue1647654.diff: Patch adding tm_zone and tm_gmtoff fields to timetuple.
  • issue1647654a.diff: Added tests checking that struct_time behaves as a 9-tuple
  • 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 2011-01-29.23:17:36.533>
    created_at = <Date 2007-01-30.05:48:17.000>
    labels = ['type-feature']
    title = 'No obvious and correct way to get the time zone offset'
    updated_at = <Date 2011-01-29.23:17:36.533>
    user = 'https://bugs.python.org/jamesh'

    bugs.python.org fields:

    activity = <Date 2011-01-29.23:17:36.533>
    actor = 'belopolsky'
    assignee = 'belopolsky'
    closed = True
    closed_date = <Date 2011-01-29.23:17:36.533>
    closer = 'belopolsky'
    components = ['None']
    creation = <Date 2007-01-30.05:48:17.000>
    creator = 'jamesh'
    dependencies = ['1667546']
    files = ['17554', '17555']
    hgrepos = []
    issue_num = 1647654
    keywords = ['patch']
    message_count = 10.0
    messages = ['31134', '31135', '31136', '31137', '31138', '31139', '31140', '107086', '122166', '126225']
    nosy_count = 6.0
    nosy_names = ['pboddie', 'jamesh', 'mark.dickinson', 'belopolsky', 'techtonik', 'LwarX']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'resolved'
    status = 'closed'
    superseder = '9527'
    type = 'enhancement'
    url = 'https://bugs.python.org/issue1647654'
    versions = ['Python 3.2']

    @jamesh
    Copy link
    Mannequin Author

    jamesh mannequin commented Jan 30, 2007

    It would be nice if the Python time module provided an obvious way to get the local time UTC offset for an arbitrary time stamp. The existing constants included in the module are not sufficient to correctly determine this value.

    As context, the Bazaar version control system (written in Python), the local time UTC offset is recorded in a commit.

    The method used in releases prior to 0.14 made use of the "daylight", "timezone" and "altzone" constants from the time module like this:

        if time.localtime(t).tm_isdst and time.daylight:
            return -time.altzone
        else:
            return -time.timezone

    This worked most of the time, but would occasionally give incorrect results.

    On Linux, the local time system can handle different daylight saving rules for different spans of years. For years where the rules change, these constants can provide incorrect data. Furthermore, they may be incorrect for time stamps in the past.

    I personally ran into this problem last December when Western Australia adopted daylight saving -- time.altzone gave an incorrect value until the start of 2007.

    Having a function in the standard library to calculate this offset would solve the problem. The implementation we ended up with for Bazaar was:

        offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
        return offset.days * 86400 + offset.seconds

    Another alternative would be to expose tm_gmtoff on time tuples (perhaps using the above code to synthesise it on platforms that don't have the field).

    @pboddie
    Copy link
    Mannequin

    pboddie mannequin commented Feb 24, 2007

    See patch bpo-1667546 for a time module function returning extended time tuples. The datetime-based solution you provide is quite a clever workaround using "naive" datetime objects, but I'm inclined to think that some more convenient way of getting "aware" datetime objects would be nicer.

    @jamesh
    Copy link
    Mannequin Author

    jamesh mannequin commented Mar 1, 2007

    The localtime_tz() function sounds like it would probably fit the bill.

    Another option would be to expose tm_gmtoff and tm_zone as non-sequence fields of time.struct_time for systems that support them. This would provide the data without needing new APIs.

    @gvanrossum
    Copy link
    Member

    Hm.... I'm not sure I understand why the first bit of code didn't work. Can you give a concrete example? (I.e. what was t, what was returned by localtime(t), and what were the three time variables that day.)

    I don't know the details of Western Australia's DST change. But looking at the source of timemodule.c, I notice that it simply samples the timezone on Jan 1st and July 1st, and if they differ, decides which one is summer time by which one is smaller. Your remark that the problem righted itself in January makes me wonder -- between what dates did you have DST?

    Alternatively, it could be that your system simply didn't have the correct DST change data loaded yet (this happens all the time when governments change the rules). Can you rule that out? I really don't want to have to change Python in order to correct for *that* problem.

    Yet another question, if you were to code this in C, how would you write it?

    Regardless, I think that it would be useful to support tm_gmtoff and other struct tm entries, the same way that we do this in struct stat.

    You could probably also get the correct result (assuming your system's timezone database is correct) by comparing localtime() and gmtime(). But the reverse engineering is a bit painful; your trick using datetime essentially does that.

    @jamesh
    Copy link
    Mannequin Author

    jamesh mannequin commented Mar 5, 2007

    In Western Australia, a 3 year daylight saving trial was introduced starting on 3rd December 2006. Prior to that, we had no daylight saving shifts (the previous time we had daylight saving was 15 years ago in another trial).

    Since there was no daylight savings for 1st January 2006 and 1st July 2006, time.timezone and time.altzone were both equal to -28800 (UTC+8) for Python interpreters run in 2006.

    I am sure that I had the tzdata updates installed: my computer displayed the correct time, and listed the UTC offset as +0900 in December. Creating a time tuple for a date in December 2006 had the tm_isdst flag set to 1.

    If I was programming this in C, I'd use the tm_gmtoff field of "struct tm" if it was available. On platforms that don't provide tm_gmtoff, other platform specific methods would be needed (e.g. using timezone/altzone).

    The other alternative is to do date arithmetic on the results of localtime() and gmtime(), as you say.

    @gvanrossum
    Copy link
    Member

    I see. There is code to decide the values for time.timezone, time.altzone and time.daylight that compares tm_gmtoff for Jan 1st of the current year to tm_gmtoff for July 1st; it uses this to decide whether DST is in effect and on which hemisphere you're on. I don't know why I didn't think of checking the tm_isdst flag instead, but either way the code would have failed for you prior to Jan 1st 07, because it could not have seen a difference if your timezone database was correct. You're just lucky you weren't running CYGWIN; the code inside #ifdef __CYGWIN__ doesn't even entertain the possibility that there's life possible on the Southern hemisphere. ;-)

    I think we should do two things; (a) export tm_zone and tm_gmtoff if they exist; (b) change the code that probes Jan 1st and Jul 1st of the current year to instead probe 4-6 spots starting today and covering the year forward.

    Unfortunately tm_zone and tm_gmtoff appear glibc inventions, so for supporting Solaris, Windows etc. I think we still need these. We really could use a module that accesses the entire timezone database but that's even more platform specific.

    If you want this to happen, please lobby for someone to help out on python-dev or c.l.py; I'm kind of overcommitted. :-)

    @pboddie
    Copy link
    Mannequin

    pboddie mannequin commented Mar 8, 2007

    Patch bpo-1667546 now tries to export tm_gmtoff in a covertly extended time tuple. (I think tm_gmtoff originates from BSD, by the way.)

    @devdanzin devdanzin mannequin added type-feature A feature request or enhancement labels Mar 30, 2009
    @abalkin
    Copy link
    Member

    abalkin commented Jun 4, 2010

    Issue bpo-1667546 is more ambitious than this. I propose a very simple patch which makes tm_zone and tm_gmtoff available on systems with HAVE_STRUCT_TM_TM_ZONE defined (Linux and BSD variants). The additional fields are only allowed as attributes so len(time.localtime()) is still the same. This choice allows to get access to extra fields without breaking code that relies on the size of timetuple.

    The patch needs documentation updates which I will add if the idea is well received.

    @LwarX
    Copy link
    Mannequin

    LwarX mannequin commented Nov 22, 2010

    Our region recently switched to another timezone and I've noticed similar issue while using Mercurial. There is some (hopefully) useful details: http://mercurial.selenic.com/bts/issue2511

    @abalkin
    Copy link
    Member

    abalkin commented Jan 14, 2011

    Closing this in favor of bpo-9527. See msg126064 for more details.

    @abalkin abalkin closed this as completed Jan 29, 2011
    @abalkin abalkin closed this as completed Jan 29, 2011
    @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
    type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants