Konwersja DateTime ze strefą czasową na czas lokalny w Pythonie
Jak przekonwertować obiekt datetime ze strefą czasową na równoważny datetime bez strefy czasowej dla lokalnej strefy czasowej?
Moja konkretna aplikacja używa Django (chociaż w rzeczywistości jest to ogólne Pytanie Pythona):
import iso8601
....
date_str="2010-10-30T17:21:12Z"
....
d = iso8601.parse_date(date_str)
foo = app.models.FooModel(the_date=d)
foo.save()
To powoduje, że Django wyrzuca błąd:
raise ValueError("MySQL backend does not support timezone-aware datetimes.")
Potrzebuję:
d = iso8601.parse_date(date_str)
local_d = SOME_FUNCTION(d)
foo = app.models.FooModel(the_date=local_d)
Co by było SOME_FUNCTION?
4 answers
Ogólnie rzecz biorąc, aby przekonwertować dowolny DateTime świadomy strefy czasowej na naiwny (lokalny) datetime, użyłbym modułu pytz
i astimezone
Aby przekonwertować na czas lokalny, i replace
aby uczynić DateTime naiwnym:
In [76]: import pytz
In [77]: est=pytz.timezone('US/Eastern')
In [78]: d.astimezone(est)
Out[78]: datetime.datetime(2010, 10, 30, 13, 21, 12, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
In [79]: d.astimezone(est).replace(tzinfo=None)
Out[79]: datetime.datetime(2010, 10, 30, 13, 21, 12)
Ale ponieważ twoja konkretna data wydaje się być w strefie czasowej UTC, możesz to zrobić zamiast tego:
In [65]: d
Out[65]: datetime.datetime(2010, 10, 30, 17, 21, 12, tzinfo=tzutc())
In [66]: import datetime
In [67]: import calendar
In [68]: datetime.datetime.fromtimestamp(calendar.timegm(d.timetuple()))
Out[68]: datetime.datetime(2010, 10, 30, 13, 21, 12)
Przy okazji, może lepiej będzie przechowywać dane jako naiwne daty UTC zamiast naiwnych lokalnych dat. W ten sposób Twoje dane są niezależne od czasu lokalnego i konwertujesz na czas lokalny lub inną strefę czasową tylko wtedy, gdy jest to konieczne. Jak najbardziej analogiczne do pracy w unicode, a kodowanie tylko wtedy, gdy jest to konieczne.
Więc jeśli zgadzasz się, że przechowywanie danych w UTC jest najlepszym sposobem, to wszystko, co musisz zrobić, to zdefiniować:
local_d = d.replace(tzinfo=None)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-27 23:25:18
W najnowszych wersjach Django (co najmniej 1.4.1):
from django.utils.timezone import localtime
result = localtime(some_time_object)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-17 16:09:04
Przenośne solidne rozwiązanie powinno korzystać z bazy danych tz. Aby uzyskać lokalną strefę czasową jako pytz
tzinfo
obiekt, use tzlocal
module :
#!/usr/bin/env python
import iso8601
import tzlocal # $ pip install tzlocal
local_timezone = tzlocal.get_localzone()
aware_dt = iso8601.parse_date("2010-10-30T17:21:12Z") # some aware datetime object
naive_local_dt = aware_dt.astimezone(local_timezone).replace(tzinfo=None)
Uwaga: Może być kuszące użycie czegoś takiego jak:
#!/usr/bin/env python3
# ...
naive_local_dt = aware_dt.astimezone().replace(tzinfo=None)
Ale może się nie udać, jeśli lokalna Strefa czasowa ma zmienną UTC offset, ale python nie używa historycznej bazy danych strefy czasowej na danej platformie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 07:55:38
Za pomocą python-dateutil
możesz przetworzyć datę w formacie iso-8561 za pomocą dateutil.parsrser.parse()
, która da ci aware datetime
w strefie czasowej UTC/Zulu.
Za pomocą .astimezone()
można przekonwertować go do świadomej datetime w innej strefie czasowej.
Użycie .replace(tzinfo=None)
przekształci świadomy datetime w naiwny datetime.
from datetime import datetime
from dateutil import parser as datetime_parser
from dateutil.tz import tzutc,gettz
aware = datetime_parser.parse('2015-05-20T19:51:35.998931Z').astimezone(gettz("CET"))
naive = aware.replace(tzinfo=None)
Ogólnie najlepszym pomysłem jest konwersja wszystkich dat NA UTC i zapisywanie ich w ten sposób, a następnie konwersja z powrotem na lokalne w razie potrzeby. Używam aware.astimezone(tzutc()).replace(tzinfo=None)
, aby upewnić się, że jest w UTC i przekonwertować na naiwny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-29 10:04:34