Get the Olson TZ name for the local timezone?

前端 未结 11 1287
孤街浪徒
孤街浪徒 2020-11-30 03:19

How do I get the Olson timezone name (such as Australia/Sydney) corresponding to the value given by C\'s localtime call?

This is the value overridden vi

相关标签:
11条回答
  • 2020-11-30 03:20

    I think best bet is to go thru all pytz timezones and check which one matches local timezone, each pytz timezone object contains info about utcoffset and tzname like CDT, EST, same info about local time can be obtained from time.timezone/altzone and time.tzname, and I think that is enough to correctly match local timezone in pytz database e.g.

    import time
    import pytz
    import datetime
    
    local_names = []
    if time.daylight:
        local_offset = time.altzone
        localtz = time.tzname[1]
    else:
        local_offset = time.timezone
        localtz = time.tzname[0]
    
    local_offset = datetime.timedelta(seconds=-local_offset)
    
    for name in pytz.all_timezones:
        timezone = pytz.timezone(name)
        if not hasattr(timezone, '_tzinfos'):
            continue#skip, if some timezone doesn't have info
        # go thru tzinfo and see if short name like EDT and offset matches
        for (utcoffset, daylight, tzname), _ in timezone._tzinfos.iteritems():
            if utcoffset == local_offset and tzname == localtz:
                local_names.append(name)
    
    print local_names
    

    output:

    ['America/Atikokan', 'America/Bahia_Banderas', 'America/Bahia_Banderas', 'America/Belize', 'America/Cambridge_Bay', 'America/Cancun', 'America/Chicago', 'America/Chihuahua', 'America/Coral_Harbour', 'America/Costa_Rica', 'America/El_Salvador', 'America/Fort_Wayne', 'America/Guatemala', 'America/Indiana/Indianapolis', 'America/Indiana/Knox', 'America/Indiana/Marengo', 'America/Indiana/Marengo', 'America/Indiana/Petersburg', 'America/Indiana/Tell_City', 'America/Indiana/Vevay', 'America/Indiana/Vincennes', 'America/Indiana/Winamac', 'America/Indianapolis', 'America/Iqaluit', 'America/Kentucky/Louisville', 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', 'America/Knox_IN', 'America/Louisville', 'America/Louisville', 'America/Managua', 'America/Matamoros', 'America/Menominee', 'America/Merida', 'America/Mexico_City', 'America/Monterrey', 'America/North_Dakota/Beulah', 'America/North_Dakota/Center', 'America/North_Dakota/New_Salem', 'America/Ojinaga', 'America/Pangnirtung', 'America/Rainy_River', 'America/Rankin_Inlet', 'America/Resolute', 'America/Resolute', 'America/Tegucigalpa', 'America/Winnipeg', 'CST6CDT', 'Canada/Central', 'Mexico/General', 'US/Central', 'US/East-Indiana', 'US/Indiana-Starke']

    In production you can create such a mapping beforehand and save it instead of iterating always.

    Testing script after changing timezone:

    $ export TZ='Australia/Sydney'
    $ python get_tz_names.py
    ['Antarctica/Macquarie', 'Australia/ACT', 'Australia/Brisbane', 'Australia/Canberra', 'Australia/Currie', 'Australia/Hobart', 'Australia/Lindeman', 'Australia/Melbourne', 'Australia/NSW', 'Australia/Queensland', 'Australia/Sydney', 'Australia/Tasmania', 'Australia/Victoria']

    0 讨论(0)
  • 2020-11-30 03:20

    This will get you the time zone name, according to what's in the TZ variable, or localtime file if unset:

    #! /usr/bin/env python
    
    import time
    
    time.tzset
    print time.tzname
    
    0 讨论(0)
  • 2020-11-30 03:23

    I changed tcurvelo's script to find the right form of time zone (Continent/..../City), in most of cases, but return all of them if fails

    #!/usr/bin/env python
    
    from hashlib import sha224
    import os
    from os import listdir
    from os.path import join, isfile, isdir
    
    infoDir = '/usr/share/zoneinfo/'
    
    def get_current_olsonname():
        result = []
        tzfile_digest = sha224(open('/etc/localtime').read()).hexdigest()
    
        test_match = lambda filepath: sha224(open(filepath).read()).hexdigest() == tzfile_digest
    
        def walk_over(dirpath):
            for root, dirs, filenames in os.walk(dirpath):
                for fname in filenames:
                    fpath = join(root, fname)
                    if test_match(fpath):
                        result.append(tuple(root.split('/')[4:]+[fname]))
    
        for dname in listdir(infoDir):
            if dname in ('posix', 'right', 'SystemV', 'Etc'):
                continue
            dpath = join(infoDir, dname)
            if not isdir(dpath):
                continue
            walk_over(dpath)
    
        if not result:
            walk_over(join(infoDir))
    
        return result
    
    
    if __name__ == '__main__':
        print get_current_olsonname()
    
    0 讨论(0)
  • 2020-11-30 03:30

    This JavaScript project attempts to solve the same issue in the browser client-side. It works by playing "twenty questions" with the locale, asking for the UTC offset of certain past times (to test for summer time boundaries, etc.) and using those results to deduce what the local time zone must be. I am not aware of any equivalent Python package unfortunately, so if someone wanted to use this solution it would have to be ported to Python.

    While this formula will require updating every time (at worst) the TZ database is updated, a combination of this algorithm and the solution proposed by Anurag Uniyal (keeping only possibilities returned by both methods) sounds to me like the surest way to compute the effective local timezone. As long as there is some difference between the UTC offset of at least one local time in any two time zones, such a system can correctly choose between them.

    0 讨论(0)
  • 2020-11-30 03:31

    This is kind of cheating, I know, but getting from '/etc/localtime' doesn't work for you? Like following:

    >>>  import os
    >>> '/'.join(os.readlink('/etc/localtime').split('/')[-2:])
    'Australia/Sydney'
    

    Hope it helps.

    Edit: I liked @A.H.'s idea, in case '/etc/localtime' isn't a symlink. Translating that into Python:

    #!/usr/bin/env python
    
    from hashlib import sha224
    import os
    
    def get_current_olsonname():
        tzfile = open('/etc/localtime')
        tzfile_digest = sha224(tzfile.read()).hexdigest()
        tzfile.close()
    
        for root, dirs, filenames in os.walk("/usr/share/zoneinfo/"):
            for filename in filenames:
                fullname = os.path.join(root, filename)
                f = open(fullname)
                digest = sha224(f.read()).hexdigest()
                if digest == tzfile_digest:
                    return '/'.join((fullname.split('/'))[-2:])
                f.close()
            return None
    
    if __name__ == '__main__':
        print get_current_olsonname()
    
    0 讨论(0)
  • 2020-11-30 03:32

    If evaluating /etc/localtime is OK for you, the following trick might work - after translating it to python:

    > md5sum /etc/localtime
    abcdefabcdefabcdefabcdefabcdefab /etc/localtime
    > find /usr/share/zoneinfo -type f |xargs md5sum | grep abcdefabcdefabcdefabcdefabcdefab
    abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/Europe/London
    abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/posix/Europe/London
    ...
    

    The duplicates could be filtered using only the official region names "Europe", "America" ... If there are still duplicates, you could take the shortest name :-)

    0 讨论(0)
提交回复
热议问题