I have a datetime.datetime object (datetime.datetime(2014, 4, 11, 18, 0)) and I would like to assign it a timezone using pytz. I know you can use pytz with a datetime.datetime.now() object (datetime.datetime.now(pytz.timezone('America/Los_Angeles'))) but how would I do it with a custom object?
Use the localize method:
import pytz
import datetime
la = pytz.timezone('America/Los_Angeles')
now = la.localize(datetime.datetime.now())
print(repr(now))
yields
datetime.datetime(2014, 4, 11, 21, 36, 2, 981916, tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>)
localize is used to interpret timezone-unaware datetimes with respect to a timezone. The result is a timezone-aware datetime.
Note that some timezone-unaware datetimes, such as datetime(2002, 10, 27, 1, 30, 00), are ambiguous in certain timezones. Use the is_dst parameter to avoid the ambiguity.
astimezone is used to convert aware datetimes to other timezones.
Alternatively, you can assign timezone to os.environ['TZ'] directly.
import os
import datetime
print datetime.datetime.now()
os.environ['TZ'] = 'America/Los_Angeles'
print datetime.datetime.now()
Related
I have a datetime timedelta object, which I parse from received UTC seconds like this which is an offset from todays midnight:
datetime.timedelta(seconds=seconds)
This is in UTC, but I want to add timezone awareness to it.
So for example now, the seconds=18600 reports 5:10:00 which is correct in UTC.
I want to add a fixed timezone to it, like 'Europe/Budapest', so it will show 6:10:00 or 7:10:00 (based on daytime-saving time).
Is it somehow possible if I don't have a full datetime object, only a timedelta?
Thanks!
Assuming those seconds you get represent the offset since midnight UTC today (or any other particular day), then calculate them exactly as that:
>>> from datetime import datetime, timedelta, timezone
>>> import pytz
>>> midnight = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
datetime.datetime(2022, 4, 8, 0, 0, tzinfo=datetime.timezone.utc)
>>> timestamp = midnight + timedelta(seconds=seconds)
datetime.datetime(2022, 4, 8, 5, 10, tzinfo=datetime.timezone.utc)
>>> local_timestamp = timestamp.astimezone(pytz.timezone('Europe/Budapest'))
datetime.datetime(2022, 4, 8, 7, 10, tzinfo=<DstTzInfo 'Europe/Budapest' CEST+2:00:00 DST>)
Perhaps you would like to offset the timedelta by the UTC offset?
import datetime
import pytz
nowtz = datetime.datetime.now(pytz.timezone("Europe/Budapest"))
seconds = 18600 + nowtz.utcoffset().total_seconds()
x = datetime.timedelta(seconds=seconds)
>>> x
7:10:00
Or if you wanted a datetime
# This is a datetime object
>>> nowtz + x
datetime.datetime(2022, 4, 8, 21, 29, 2, 328802, tzinfo=<DstTzInfo 'Europe/Budapest' CEST+2:00:00 DST>)
# This is the above datetime formatted as a string
>>> (nowtz+x).strftime("%F %r")
'2022-04-08 09:27:31 PM'
I am trying to figure out how to make a datetime object aware through using a variable. I grab the timezone of the user and pass it through a form to be used.
I have tried both of the below methods and am not having much success
timezone_variable = "Europe/London"
new_datetime = datetime(int(date_year), int(date_month), int(date_day),
int(time_hour), int(date_minute), tzinfo=timezone_variable)
new_datetime = datetime(int(date_year), int(date_month), int(date_day),
int(time_hour), int(date_minute), tzinfo=timezone.timezone_variable)
This will then give me errors of TypeError: tzinfo argument must be None or of a tzinfo subclass, not type 'str'
The timezone will not always be known upfront, so it would not be possible to simply have the argument be as such tzinfo=timezone.utc.
Using dateutil or Python 3.9's zoneinfo:
from datetime import datetime
from dateutil.tz import gettz
# from zoneinfo import ZoneInfo # Python 3.9
date_year, date_month, date_day, time_hour, date_minute = 2020, 10, 21, 10, 21
timezone_variable = gettz("Europe/London") # ZoneInfo("Europe/London") # Python 3.9
new_datetime = datetime(int(date_year), int(date_month), int(date_day),
int(time_hour), int(date_minute), tzinfo=timezone_variable)
print(new_datetime)
# 2020-10-21 10:21:00+01:00
print(repr(new_datetime))
# datetime.datetime(2020, 10, 21, 10, 21, tzinfo=tzfile('GB-Eire'))
# with zoneinfo:
# datetime.datetime(2020, 10, 21, 10, 21, tzinfo=zoneinfo.ZoneInfo(key='Europe/London'))
Note: you can directly create a datetime object. If you use pytz (deprecated with Python 3.9), you must use the localize method of the timezone object. Otherwise, you'll end up with LMT (local mean time):
import pytz
timezone_variable = pytz.timezone("Europe/London")
# not what you want (most of the time...):
new_datetime = datetime(int(date_year), int(date_month), int(date_day),
int(time_hour), int(date_minute), tzinfo=timezone_variable)
print(repr(new_datetime))
# datetime.datetime(2020, 10, 21, 10, 21, tzinfo=<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>)
Side-note: interestingly, dateutil returns the deprecated GB-Eire time zone name for Europe/London. It is correct nevertheless, no worries.
You can create a timezone object from a string using pytz:
>>> from pytz import timezone
>>> timezone("Europe/London")
<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>
This can then be used in the datetime.datetime() constructor as the tzinfo parameter. Use the localize() function as described in the docs if needed.
How do I convert the following localized datetime string to UTC datetime. The string has date, time and timezone mentioned in it e.g. May 15,2015, 04.24AM IST, here IST is Indian Standard Time. It can be any time zone.
I tried using pytz but couldn't make it work.
The thing is that it's quite difficult to parse a string with an abbreviated timezone information. But, if you know your timezone, then you can look up it's name recognized by pytz. You can even list all timezone names with pytz.all_timezones.
In your case it is 'Asia/Calcutta' and this should work to convert it to UTC. Just strip the timezone information from the string and add it later:
import pytz
import datetime
# String without timezone info
str = "May 15, 2015, 04.24AM"
# Parse it to naive time
dt = datetime.datetime.strptime(str, "%b %d, %Y, %I.%M%p")
# Localize it as Asia/Calcutta
dt_localized = pytz.timezone('Asia/Calcutta').localize(dt)
# Convert it to UTC
dt_utc = dt_localized.astimezone(pytz.timezone('UTC'))
And we get:
>>> dt
datetime.datetime(2015, 5, 15, 4, 24)
>>> dt_localized
datetime.datetime(2015, 5, 15, 4, 24, tzinfo=<DstTzInfo 'Asia/Calcutta' IST+5:30:00 STD>)
>>> dt_utc
datetime.datetime(2015, 5, 14, 22, 54, tzinfo=<UTC>)
First, let's strip your date string of the IST timezone and then assign it the Asia/Calcutta timezone.
import pytz
dt_str = "May 15, 2015, 04.24AM IST"
dt_str_naive = dt_str[:-4]
new_dt = (pytz.timezone('Asia/Calcutta')
.localize(dt.datetime.strptime(dt_str_naive, "%b %d, %Y, %I.%M%p")))
Now that it is timezone aware, you can assign it to the UTC timezone:
>>> new_dt.astimezone(pytz.UTC)
datetime.datetime(2015, 5, 14, 22, 54, tzinfo=<UTC>)
This question already has answers here:
How to add timezone into a naive datetime instance in python [duplicate]
(2 answers)
Closed 7 years ago.
I ran across an interesting situation today. Can anyone explain why the offsets for ts1 and ts2 are different? ts1 is a datetime object that is timezone-aware right off the bat. ts2 is a datetime object that starts off timezone-naive and has its tzinfo replaced. However, they end up with different offsets.
>>> from pytz import timezone
>>> EST = timezone('America/New_York')
>>> ts1 = datetime.datetime.now(tz=EST)
>>> ts2 = datetime.datetime.now()
>>> ts2 = ts2.replace(tzinfo=EST)
>>> print ts1
2014-05-16 11:25:16.749748-04:00
>>> print ts2
2014-05-16 11:25:19.581710-05:00
When you call ts2.replace(tzinfo=EST), the tzinfo object you're getting doesn't match the one you get with ts1:
>>> ts1
datetime.datetime(2014, 5, 16, 11, 51, 7, 916090, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> ts2
datetime.datetime(2014, 5, 16, 11, 51, 30, 922692, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>)
You end up with LMT instead of EDT.
The pytz documentation actually notes that using pytz with the tzinfo argument of standard datetime objects simply doesn't work for many timezones:
Unfortunately using the tzinfo argument of the standard datetime
constructors ''does not work'' with pytz for many timezones.
>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) '2002-10-27 12:00:00 LMT+0020'
It is safe for timezones without daylight saving transitions though,
such as UTC:
>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) '2002-10-27 12:00:00 UTC+0000'
I'm not exactly sure why the first one works; perhaps because it doesn't actually have to convert anything when the object is initially constructed with the tzinfo object.
Edit:
Ah, the Python documentation notes that using datetime.datetime.now() with the tz arg is equivalent to:
EST.fromutc(datetime.utcnow().replace(tzinfo=EST))
Which means you're converting from UTC, which is safe with pytz. So that's why the first one works.
According to the documentation, the correct way to apply a time zone to a naive datetime is with the localize method.
ts1 = eastern.localize(datetime.datetime.now())
Also, I recommend you use avoid EST as a variable name, since it typically standard for "Eastern Standard Time", and America/New_York comprises both "Eastern Standard Time" (EST) and "Eastern Daylight Time" (EDT).
pytz asks you to use the .astimezone method for all time conversion to and from UTC. However, in one special case — datetime.fromtimestamp — it looks like you should be able to use the Python library's datetime methods.
It seems to work here:
>>> import datetime
>>> import pytz
>>> ambigtime = 1352017800 # http://www.wolframalpha.com/input/?i=1352017800+unix+time+in+Los+Angeles
>>> amla = pytz.timezone('America/Los_Angeles')
>>> datetime.datetime.fromtimestamp(ambigtime, tz=amla)
datetime.datetime(2012, 11, 4, 1, 30, tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>)
>>> datetime.datetime.fromtimestamp(ambigtime + 3600, tz=amla)
datetime.datetime(2012, 11, 4, 1, 30, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
Are there situations where datetime.fromtimestamp won't give you the correct results with pytz timezones?
As far as I know, pytz.timezone() will give you an instance of tzinfo (or rather a subclass thereof), and as such is totally fine to use with datetime.fromtimestamp().
As long as pytz has updated zoneinfo files, you can create localized datetimes using that method. Converting a datetime between two zones however is really loads easier to do with the astimezone() method. If I am correct, it basically switches the tzinfo property on the datetime.