0

My purpose is simply to output a time zone string like -0700 used in e-mail. Specifically, I want it to reflect the exact time zone, daylight saving included. This means I will get -0700 in California in summer, -0800 in California in winter, and always +0800 in China (no daylight saving).

I find it difficult for two reasons:

  1. The Python integer division, unlike in C99 and normal C/C++ implementations, always rounded towards the floor instead of zero. (This matters for calculations involving a time zone like -xx30).
  2. struct_time.tm_isdst and time.daylight does not reflect whether daylight saving is in effect.

I ended up with code like the following. It is longer than I expected (esp. for Python!):

import math
import time

def my_divide(dividend, divisor):
    if dividend < 0:
        if divisor < 0:
            diff_sign = False
        else:
            diff_sign = True
    else:
        if divisor >= 0:
            diff_sign = False
        else:
            diff_sign = True
    if diff_sign:
        return (int(math.ceil(1.0 * dividend / divisor)), dividend % -divisor)
    else:
        return (int(math.floor(1.0 * dividend / divisor)), dividend % divisor)

def my_timezone():
    gt = time.gmtime()
    lt = time.localtime()
    lt_write = list(lt)
    lt_write[8] = 0  # is_dst
    lt = time.struct_time(lt_write)
    seconds = time.mktime(lt) - time.mktime(gt)
    (hours, minutes) = my_divide(seconds, 3600)
    minutes = abs(minutes) // 60
    return '%(hours)+03d%(minutes)02d' % {'hours': hours, 'minutes': minutes}

Anybody having a better implementation?

4

1 回答 1

2

You can use the time.timezone and time.altzone values.

These provide:

The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK)

and

The offset of the local DST timezone, in seconds west of UTC, if one is defined. This is negative if the local DST timezone is east of UTC (as in Western Europe, including the UK). Only use this if daylight is nonzero.

As the documentation for time.altzone explains, use the latter when time.daylight is non-zero, but only if the current time is in summer time:

import time

def my_timezone():
    is_dst = time.daylight and time.localtime().tm_isdst
    offset = time.altzone if is_dst else time.timezone
    westerly = offset > 0
    minutes, seconds = divmod(abs(offset), 60)
    hours, minutes = divmod(minutes, 60)
    return '{}{:02d}{:02d}'.format('-' if westerly else '+', hours, minutes)

Using seconds as a base and divmod() there should be no rounding errors here.

For my British summertime location, that gives:

>>> my_timezone()
'+0100'
于 2013-10-10T06:58:47.290 回答