How to add timezone into a naive datetime instance in python
Solution 1
Use tz.localize(d)
to localize the instance. From the documentation:
The first is to use the localize() method provided by the pytz library. This is used to localize a naive datetime (datetime with no timezone information):
>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0)) >>> print(loc_dt.strftime(fmt)) 2002-10-27 06:00:00 EST-0500
If you don't use tz.localize()
, but use datetime.replace()
, chances are that a historical offset is used instead; tz.localize()
will pick the right offset in effect for the given date. The US Eastern timezone DST start and end dates have changed over time, for example.
When you try to localize a datetime value that is ambiguous because it straddles the transition period from summer to winter time or vice-versa, the timezone will be consulted to see if the resulting datetime object should have .dst()
return True or False. You can override the default for the timezone with the is_dst
keyword argument for .localize()
:
dt = tz.localize(naive, is_dst=True)
or even switch off the choice altogether by setting is_dst=None
. In that case, or in the rare cases there is no default set for a timezone, an ambiguous datetime value would lead to a AmbiguousTimeError
exception being raised. The is_dst
flag is only consulted for datetime values that are ambiguous and is ignored otherwise.
To go back the other way, turn a timezone-aware object back to a naive object, use .replace(tzinfo=None)
:
naivedt = awaredt.replace(tzinfo=None)
Solution 2
If you know that your original datetime was "measured" in the time zone you are trying to add to it, you could (but probably shouldn't) use replace
rather than localize
.
# d = datetime.datetime.now()
# tz = pytz.timezone('Asia/Taipei')
d = d.replace(tzinfo=tz)
I can imagine 2 times when this might make sense (the second one happened to me):
- Your server locale is set to the incorrect time zone and you are trying to correct a
datetime
instance by making it aware of this incorrect timezone (and presumably later localizing it to the "correct" time zone so the values of now() match up to other times you are comparing it to (your watch, perhaps) - You want to "tag" a
time
instance (NOT adatetime
) with a time zone (tzinfo) attribute so that attribute can be used later to form a fulldatetime
instance.
waitingkuo
Updated on July 09, 2022Comments
-
waitingkuo almost 2 years
I've got a
datetime
which has no timezone information. I'm now getting the timezone info and would like to add the timezone into the existed datetime instance, how can I do?d = datetime.datetime.now() tz = pytz.timezone('Asia/Taipei')
How to add the timezone info
tz
into datetimea
-
waitingkuo over 11 yearsIs there any convenient way to get the naive
datetime
fromdatetime
which has tzinfo? -
Martijn Pieters over 11 years@waitingkuo: call
.replace(tzinfo=None)
on thedatetime
object. The return value is a naivedatetime
instance. -
jfs over 11 years
is_dst
parameter is worth mentioning to resolve ambiguous times or to assert that there is no DST transition at the time. -
Martijn Pieters over 11 years@J.F.Sebastian: There, a short paragraph on
is_dst
added. -
jfs over 9 yearsalso,
local_dt = tz.localize(dt)
may produce a non-existing time (during "sprint forward" DST transition). To fix it, calllocal_dt = tz.normalize(local_dt)
. Or useis_dst=None
that preventstz.localize()
from returning ambiguous or non-existing times. -
hobs about 9 years
pytz.timezone.localize(datetime.time, pyzt)
will fail for timzones other than GMT/UTC (pytz.timezone.tzinfo.timedelta
is nonzero). Thelocalize
method works great fordatetime
s but not fortime
s (because it might have to wrap around to a new day). For atime
just usenew_time = old_time.replace(tzinfo=pytz.timezone(timezone_name))
. This will NOT adjust the time to account for the new time zone, just presume it was already "measured" in local time. Incidentally, if you don't want to "shift" a datetime it.replace
works for datetimes as well. -
Martijn Pieters about 9 years@hobs: I'd not expect localize to work for
time
objects, no, because the localisation requires a date to do its job correctly. Timezone offsets make no sense for just a time component, you are missing the information for DST and historical context. -
hobs about 9 years@MartjinPieters Exactly. But if you need a tz-aware time (which is only useful with other aware times in the same time zone) you can use
.replace()
. I agree that doesn't normally make sense... but if you inform atime
of a time zone that tz can be used later when forming a datetime. -
jfs about 9 years@hobs: it is wrong to use
.replace()
with apytz
timezone that may have multiple utc offsets (many timezones do). The default tzinfo object usually corresponds to LMT (solar time) that is not what you want in most cases (I think the reasoning behind the default is to help reveal the incorrect.replace()
usage). -
hobs about 9 years@J.F.Sebastian Makes sense that it is 'wrong'. But it might be OK for someone in my situation (with
datetime.time
instances without date info yet). This happened to me processing a CSV from wunderground.com. The TZ info is available in the column header (and sometimes in the field string), but date is available elsewhere. So I just tagged the time with the tzinfo and used that tzinfo to localize with the date later. I'm sure it's wrong, a hack, but it worked for me. The downvote on my misguided answer will hopefully encourage others to think hard about how to solve this edge case properly. -
Martijn Pieters about 9 years@hobs: why not just store the timezone and time separately and when you combine that with the date then apply the timezone?
-
hobs about 9 years@MartjinPieters Agree that's probably safer from a timezone accuracy/confusion/ambiguity perspective, but adds complication and might introduce bookkeeping (indexing) errors... I prefer to create one object per CSV "cell" and pass a list of lists of objects around rather than a list of lists of 2-tuples of objects.
-
Marc almost 4 years3. you've retrieved a datetime from a DB where the column is naive, but you know the TZ it was stored in, and you want to manipulate it after retrieval.
-
Marc about 3 years4. you've generated a utc time using utcnow, which is tz-naive, and you need to compare it against a tx-aware time.