Python's Datetime: Conversion to time zones based on lat_long - python

I have been reading python's datetime documentation and it seems like there are few things which are not clearly mentioned there.
date = datetime.datetime(2014,10,1,11,45,30)
Which timezone will the above date be in? UTC?
If I have to make sure that the above date remains in EST what could be done. I am not clear on tzinfo object here?
If I have to convert these datetimes to some other time zones based on latitude and longitude what should I do?

Your code would create a "timezone naive" datetime object. That means - no timezone. It'll be interpreted as local time based on where it is used.
If you want to set a timezone, try using the pytz library.
import pytz # 3rd party: $ pip install pytz
u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) # NOTE: it works only with a fixed utc offset
# Then you can change timezones, e.g. http://www.timezoneconverter.com/cgi-bin/zoneinfo?tz=America/New_York
print u.astimezone(pytz.timezone("America/New_York"))
As for the lat/lon conversion to a timezone, this isn't a simple task. Here's a question that discusses possible solutions.

Related

How can I convert a half-hour timezone to a pytz timezone object?

I am trying to read times with their timezone specified by its UTC-offset and store them as python datetimes.
The pytz module provides the available timezones and I think the complete list is given in this question. If so, most of the times can be stored by using the corresponding Etc/ timezone and flipping the sign:
Etc/GMT
Etc/GMT+0
Etc/GMT+1
Etc/GMT+10
Etc/GMT+11
Etc/GMT+12
Etc/GMT+2
Etc/GMT+3
Etc/GMT+4
Etc/GMT+5
Etc/GMT+6
Etc/GMT+7
Etc/GMT+8
Etc/GMT+9
Etc/GMT-0
Etc/GMT-1
Etc/GMT-10
Etc/GMT-11
Etc/GMT-12
Etc/GMT-13
Etc/GMT-14
Etc/GMT-2
Etc/GMT-3
Etc/GMT-4
Etc/GMT-5
Etc/GMT-6
Etc/GMT-7
Etc/GMT-8
Etc/GMT-9
However, some timezones, like Newfoundland Standard Time and Afghanistan Time are half-hour offsets from GMT (-3:30 and +4:30, respectively). How can I store these times with their appropriate timezone without manually mapping these specific offsets to America/St_Johns or Asia/Kabul?
There is something oyu can do, although not exactly what you seem to want.
>>> nf_offset = pytz.FixedOffset(-150) # offset is in minutes, so 150=2.5 hours
>>> nf_tz = pytz.datetime("Canada/Newfoundland")
>>> datetime.now(nf_tz).strftime("%H:%M") == datetime.now(nf_offset).strftime("%H:%M")
True
They are different objects, so it's not certain you can do what you're hoping after this point, but this will get you a generic object from which you can compare times at arbitrary offsets from UTC.
Do not use Etc/GMT±h POSIX timezones. They are present only for historical reasons (and perhaps for ships in the sea).
In general, utc offset is not enough to specify a timezone i.e., the same timezone may have different utc offsets at different times. And in reverse, multiple timezones may have the same utc offset at some point.
If you are given a fixed utc offset with corresponding dates then you could use any FixedOffset implementation.
If you want to get the correct time for other dates then you have to map your input data to the correct timezone ids such as 'America/St_Johns'. See pytz: return Olson Timezone name from only a GMT Offset.

How do you convert local time (PDT) to PST using python

Usually what I do if I want to convert time zone is the following
# local interpreted as pst to utc
utc = pytz.utc
pst = pytz.timezone('America/Los_Angeles')
start_time_str = time.strftime('%Y-%m-%d %H:%M:%S', \
time.localtime(start_time))
start_time_datetime = \
datetime.datetime.strptime(start_time_str, "%Y-%m-%d %H:%M:%S")
start_time_datetime = \
start_time_datetime.replace(tzinfo=pst).astimezone(utc)
Now I want to do similar stuff such that I want localtime convert to pst
localtime = datetime.datetime.fromtimestamp(time.mktime(
time.localtime()))
I am not exactly sure how would you achieve this
Any help would be appreciated
Two things:
The "America/Los_Angeles" identifier represents the entire Pacific time zone, including both PST and PDT. It will use the either -8 or -7 as the time zone offset depending on the specific date and time it is used on.
Calling replace(tzinfo=...) is a mistake. Use localize instead. See the pytz documentation. This is discussed in the introduction and in the very first example.
Your code contains unnecessary (calling strptime after strftime) or just wrong (.replace()) conversions.
To create an aware datetime object given "seconds since epoch" start_time (a value returned by time.time()):
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
tz = pytz.timezone('America/Los_Angeles')
start_time_datetime = datetime.fromtimestamp(start_time, tz)
As #Matt Johnson mentions, 'America/Los_Angeles' timezone id produces time with PST or PDT tzname depending on the date. No conversion is necessary.
The last code example in your question has both unnecessary conversions and may fail in some cases. If the intent is to get the current time in the local timezone as an aware datetime object then you could use tzlocal module:
#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # $ pip install tzlocal
local_timezone = get_localzone() # pytz timezone corresponding to the local time
current_localtime = datetime.now(local_timezone)
First, as a note, local time is either Standard Time or Daylight Savings Time -- it cannot be both simultaneously. I believe what you are really getting at is asking whether there is a way to tell if a time is either a Daylight Savings Time or not. In other words, given a specific day, is a particular time in Daylight Savings Time? Another common use case is converting tabular data pegged at a specific time offset to the current correct time.
Okay, I can think of three ways to do this.
(1) You can convert the datetime into a time object and look at the .tm_isdst property, similar to this answer. You can do a test on it to see if that property equals one and then subtract a timedelta of one hour.
>>> time.localtime()
time.struct_time(tm_year=2019, tm_mon=11, tm_mday=16, tm_hour=12,
tm_min=36, tm_sec=32, tm_wday=5, tm_yday=320, tm_isdst=0)
>>> time.localtime().tm_isdst
0
(2) Second way is to crawl month by month over noon on the fifteenth of each month and check if the offset varies. (Note that some areas do not implement DST.) The greater value indicates a skip ahead for Daylight Savings Time. (For instance, PDT is UTC -7 while PST is UTC -8.) From those values you can calculate the time difference. Then you can test your time by checking the offset to see if it is in Standard Time or Daylight Savings Time. Offest is checked this way:
>>> my_special_pdt_datetime.strftime('%z')
'-0700'
(3) And, maybe the easiest, is to calculate the existing offset by getting offset = datetime.datetime.utcnow() - datetime.datetime.now() and then comparing that to the known offset from pytz:
>>> pytz.timezone('US/Pacific').localize(datetime.datetime(2019,1,1)).strftime('%z')
'-0800'

Assign timezone to a Python datetime [duplicate]

This question already has answers here:
pytz localize vs datetime replace
(4 answers)
Closed 8 years ago.
Assume that I have a timezone-less datetime object:
import datetime
import pytz
fmt = "%Y-%m-%d %H:%M:%S %Z%z"
dtUnaware = datetime.datetime(1979,2,20,6)
print(dtUnaware.strftime(fmt))
This yields:
1979-02-20 06:00:00
So far, so good. Now, I want to assign a timezone to this object. It seems like I could use either datetime.replace or pytz.localize.
First:
dtAware1 = dtUnaware.replace(tzinfo=pytz.timezone('Asia/Jerusalem'))
print(dtAware1.strftime(fmt))
returns: 1979-02-20 06:00:00 LMT+0221. Secondly:
dtAware2 = pytz.timezone('Asia/Jerusalem').localize(dtUnaware, is_dst=None)
print(dtAware2.strftime(fmt))
returns 1979-02-20 06:00:00 IST+0200.
What's wrong with the first method? It seems to assign a wrong timezone. Am I doing something wrong?
From Pytz documentation : This library differs from the documented Python API for
tzinfo implementations; if you want to create local wallclock
times you need to use the localize() method documented in this
document... Unfortunately these
issues cannot be resolved without modifying the Python datetime
implementation (see PEP-431)
My reading of that is that a pytz timezone is not exactly the same thing as a standard timezone. If you had a genuine timezone, first method should be good, but you have not.
There is a flaw in the datetime API: when you assign a timezone to it, the timezone is not given the opportunity to know the date and time it should be configured for. The historical database that pytz uses goes back a long way, often to periods when the timezone name or offset were different than the ones in use today. Without being given the chance to adjust to a specific date period, the details of the timezone may be wrong.
Using localize is the way around this problem, since both the date and timezone are available within the function at the same time.

How to remove the tzinfo completely from the time after converting to UTC in Python?

I came across this exact issue, and I can't figure out how to achieve the solution in my case.
Guido says
The solution is to remove the tzinfo completely from the time after
converting to UTC.
This is what I have tried:
date_time = parser.parse(i.pubDate.text)
news.publication_date = date_time.replace(tzinfo=None).date()
And I get the same error:
NotImplementedError: DatetimeProperty publication_date_time can only support UTC. Please derive a new Property to support alternative timezones.
So it seems I have to convert the date to UTC first. And here my research has failed me.
I came across this solution:
The solution suggested is this:
def date_time_to_utc(date_time):
tz = pytz.timezone('???')
return tz.normalize(tz.localize(date_time)).astimezone(pytz.utc)
But I don't have the timezone. I am scraping the date from a html source. So the timezone could really be from anywhere in the world. Is there no easy and reliable way to convert a date time to UTC?
I could use both dateutil and pytz to achieve this. Many Thanks.
UPDATE
It has been a really long day. I have misread the stack trace. However the question remains valid.
date_time = (datetime}2015-01-13 18:13:26+00:00
news.publication_date_time = date_time
This caused the crash. And it seems by doing this, I pass the unit test:
news.publication_date_time = date_time.replace(tzinfo=None)
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
If aware datetime object is already in UTC (+0000) then your formula works:
naive_utc = aware_utc.replace(tzinfo=None)
where aware_utc is a timezone-aware datetime object that represents time in UTC.
But if aware datetime object is not in UTC; it fails. You should take into account a (possibly) non-zero UTC offset in the general case:
assert aware.tzinfo is not None and aware.utcoffset() is not None
# local time = utc time + utc offset (by definition)
# -> utc = local - offset
naive_utc = aware.replace(tzinfo=None) - aware.utcoffset()
where aware is a timezone-aware datetime object in an arbitrary timezone.
But I don't have the timezone. I am scraping the date from a html
source. So the timezone could really be from anywhere in the world. Is
there no easy and reliable way to convert a date time to UTC? I could
use both dateutil and pytz to achieve this. Many Thanks.
No. dateutil, pytz won't help you unless the date string itself contains the timezone (or at least its utc offset).
Remember: It is always noon somewhere on Earth i.e., if you collect date/time strings from different places on Earth then you can't compare them unless you attach the corresponding timezones. You can't convert it to UTC, you can't get a valid POSIX timestamp if you don't know the source timezone for the date.
I'm an idiot and it's late here, this time I read the question.
tstmp= date_time.replace(tzinfo=utc).total_seconds()
naive_date = datetime.utcfromtimestamp(tstmp)
First answer will just give you the current naive time
Try this:
dateTime = dateTime.replace(tzinfo=None)
dtUtcAware = pytz.UTC.localize(dateTime)

Django timezone: feeling a bit confused

So, we have 'Europe/Moscow' TZ in our settings.
Currently this means daylight saving (this is going to change in the future, but at the moment it's UTC+03/04).
I understand that this TZ is used when saving dates to the DB, and when extracting them.
Now, I have to serialize the datetime object to ISO string, including the UTC offset. What is the correct way of doing this?
The dates don't contain the TZ info (i.e. d.strftime('%z') is empty)
I think I could convert them to UTC and serialize with +00:00, but how do I convert them to UTC if I don't know if the specific date is +03 (Moscow winter) or +04 (Moscow summer)
how do I convert them to UTC if I don't know if the specific date is +03 (Moscow winter) or +04 (Moscow summer)
There is no need for UTC conversion, pytz handles such thing for you.
Here's the code to convert from timezone-naive datetime to ISO with timezone offset:
from datetime import datetime
from pytz import timezone
server_timezone = timezone('Europe/Moscow')
server_timezone.localize(datetime(2011, 1, 1)).isoformat()
>>> '2011-01-01T00:00:00+03:00'
server_timezone.localize(datetime(2011, 7, 1)).isoformat()
>>> '2011-07-01T00:00:00+04:00'
First run new_dt = datetime.replace(tzinfo=tz) to create a new timezone-aware datetime. Then run your datetime.strftime() with %z.
Note that you can't then convert the date string back to a timezone-aware datetime directly -- datetime.strptime() doesn't support %z. So you need to instead create a naive datetime and a tzinfo then do datetime.replace(tzinfo=tz) as before.
Some useful external libraries:
http://pytz.sourceforge.net/
http://code.google.com/p/parsedatetime/
http://labix.org/python-dateutil
Also try searching right here on Stack Overflow for more questions on (Python OR django OR appengine) AND (datetime OR timezone OR date OR time OR tzinfo).
ISO-8601 has no notion of "Timezones", only dates and times, and as a convenience, times may be presented with an "offset".
To make matters even more annoying, datetime has only a half-hearted nod in acknowledgement of timezones; the tzinfo attribute on datetime objects is optional, and no implementation of that interface is provided by the main-line python.
The standard answer to this is to just always do everything in UTC; including having the server in UTC, not in local time. This is actually a pretty good idea; it's not the times that are different, only the way individual users prefer to read those times (which is similar to preferring '42' over '0b101010').
You can satisfy your users' (reasonable!) desire to view times in their local timezone by storing the preferred timezone (perhaps just a sitewide preference if everyone is in Moscow) separately from the actual times, and then you can use a robust timezone library (like pytz) to do the formatting to and from local time.

Categories