Convert a python UTC datetime to a local datetime

2019-01-02 17:29发布

I have a python datetime instance that was created using datetime.utcnow() and persisted in database.

For display, I would like to convert the datetime instance retrieved from the database to local datetime using the default local timezone (i.e., as if the datetime was created using datetime.now()).

How can I convert the UTC datetime to a local datetime using only python standard library (e.g., no pytz dependency)?

It seems one solution would be to use datetime.astimezone( tz ), but how would you get the default local timezone?

9条回答
无色无味的生活
2楼-- · 2019-01-02 17:43

I think I figured it out: computes number of seconds since epoch, then converts to a local timzeone using time.localtime, and then converts the time struct back into a datetime...

EPOCH_DATETIME = datetime.datetime(1970,1,1)
SECONDS_PER_DAY = 24*60*60

def utc_to_local_datetime( utc_datetime ):
    delta = utc_datetime - EPOCH_DATETIME
    utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds
    time_struct = time.localtime( utc_epoch )
    dt_args = time_struct[:6] + (delta.microseconds,)
    return datetime.datetime( *dt_args )

It applies the summer/winter DST correctly:

>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 6, 6, 19, 29, 7, 730000)
>>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)
查看更多
有味是清欢
3楼-- · 2019-01-02 17:45

A simple (but maybe flawed) way that works in Python 2 and 3:

import time
import datetime

def utc_to_local(dt):
    return dt - datetime.timedelta(seconds = time.timezone)

Its advantage is that it's trivial to write an inverse function

查看更多
几人难应
4楼-- · 2019-01-02 17:47

Here is another way to change timezone in datetime format (I know I wasted my energy on this but I didn't see this page so I don't know how) without min. and sec. cause I don't need it for my project:

def change_time_zone(year, month, day, hour):
      hour = hour + 7 #<-- difference
      if hour >= 24:
        difference = hour - 24
        hour = difference
        day += 1
        long_months = [1, 3, 5, 7, 8, 10, 12]
        short_months = [4, 6, 9, 11]
        if month in short_months:
          if day >= 30:
            day = 1
            month += 1
            if month > 12:
              year += 1
        elif month in long_months:
          if day >= 31:
            day = 1
            month += 1
            if month > 12:
              year += 1
        elif month == 2:
          leap_years = [2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048]
          if year in leap_years:
            if day >= 29:
              day = 1
              month += 1
              if month > 12:
                year += 1
          elif year not in leap_years:
            if day >= 28:
              day = 1
              month += 1
              if month > 12:
                year += 1
      return datetime(int(year), int(month), int(day), int(hour), 00)
查看更多
高级女魔头
5楼-- · 2019-01-02 17:50

You can't do it with only the standard library as the standard library doesn't have any timezones. You need pytz or dateutil.

>>> from datetime import datetime
>>> now = datetime.utcnow()
>>> from dateutil import tz
>>> HERE = tz.tzlocal()
>>> UTC = tz.gettz('UTC')

The Conversion:
>>> gmt = now.replace(tzinfo=UTC)
>>> gmt.astimezone(HERE)
datetime.datetime(2010, 12, 30, 15, 51, 22, 114668, tzinfo=tzlocal())

Or well, you can do it without pytz or dateutil by implementing your own timezones. But that would be silly.

查看更多
倾城一夜雪
6楼-- · 2019-01-02 17:50

Building on Alexei's comment. This should work for DST too.

import time
import datetime

def utc_to_local(dt):
    if time.localtime().tm_isdst:
        return dt - datetime.timedelta(seconds = time.altzone)
    else:
        return dt - datetime.timedelta(seconds = time.timezone)
查看更多
宁负流年不负卿
7楼-- · 2019-01-02 18:02

You can't do it with standard library. Using pytz module you can convert any naive/aware datetime object to any other time zone. Lets see some examples using Python 3.

Naive objects created through class method utcnow()

To convert a naive object to any other time zone, first you have to convert it into aware datetime object. You can use the replace method for converting a naive datetime object to an aware datetime object. Then to convert an aware datetime object to any other timezone you can use astimezone method.

The variable pytz.all_timezones gives you the list of all available time zones in pytz module.

import datetime,pytz

dtobj1=datetime.datetime.utcnow()   #utcnow class method
print(dtobj1)

dtobj3=dtobj1.replace(tzinfo=pytz.UTC) #replace method

dtobj_hongkong=dtobj3.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)

Naive objects created through class method now()

Because now method returns current date and time, so you have to make the datetime object timezone aware first. The localize function converts a naive datetime object into a timezone-aware datetime object. Then you can use the astimezone method to convert it into another timezone.

dtobj2=datetime.datetime.now()

mytimezone=pytz.timezone("Europe/Vienna") #my current timezone
dtobj4=mytimezone.localize(dtobj2)        #localize function

dtobj_hongkong=dtobj4.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)
查看更多
登录 后发表回答