Specify which timezone a datetime is in, in python - python

I have a datetime that i get from a database, this datetime is a UTC datetime. But when i pull it from the DB, it is unaware of the timezone. What i need to do, is convert this datetime to a "seconds from epoch" time for another function. The problem with this, is that the system's time is in PST and i am not able to change it for specific reasons.
So, what i want to do is, take this datetime that i get from the database, and tell python that this datetime is a UTC datetime. Every way that i have done that, results in it losing time or gaining time due to timezone conversions. Again, not trying to convert the time, just trying to specify that it is UTC.
If anyone can help with this that would be great.
Thanks!
Example
Assume database_function() returns a datetime data type that is '2013-06-01 01:06:18'
datetime = database_function()
epoch = datetime.strftime('%s')
pytz.utc.localize(database_function()).datetime.strftime('%s')
datetime.replace(tzinfo=pytz.utc).datetime.strftime('%s')
Both of these return a epoch timestamp of 1370077578
But, it SHOULD return a timestamp of 1370048778 per http://www.epochconverter.com/
Remember, this timestamp is a utc timestamp

Using the fabolous pytz:
import datetime, pytz
dt = datetime.datetime(...)
utc_dt = pytz.utc.localize(dt)
This creates a tz-aware datetime object, in UTC.

How about Setting timezone in Python This appears to reset the timezone within your python script. You are changing the time zone that your system sees given the specified time, not changing the specified time into the specified time zone. You probably want to set it to 'UTC'
time.tzset()
Resets the time conversion rules used by the library routines.
The environment variable TZ specifies how this is done.
New in version 2.3.
Availability: Unix.
I do not have this available on my home platform so I could not test it. I had to get this from the previous answer.
The answer marked best on the question is:
>>> import os, time
>>> time.strftime('%X %x %Z')
'12:45:20 08/19/09 CDT'
>>> os.environ['TZ'] = 'Europe/London'
>>> time.tzset()
>>> time.strftime('%X %x %Z')
'18:45:39 08/19/09 BST'
To get the specific values you've listed:
>>> year = time.strftime('%Y')
>>> month = time.strftime('%m')
>>> day = time.strftime('%d')
>>> hour = time.strftime('%H')
>>> minute = time.strftime('%M')
See here for a complete list of directives. Keep in mind that the strftime() function will always return a string, not an integer or other type.

You can Use pytz, which is a time zone definitions package.
from datetime import datetime
from pytz import timezone
fmt = "%Y-%m-%d %H:%M:%S %Z%z"
# Current time in UTC
now_utc = datetime.now(timezone('UTC'))
print now_utc.strftime(fmt)
# Convert to US/Pacific time zone
now_pacific = now_utc.astimezone(timezone('US/Pacific'))
print now_pacific.strftime(fmt)
# Convert to Europe/Berlin time zone
now_berlin = now_pacific.astimezone(timezone('Europe/Berlin'))
print now_berlin.strftime(fmt)
output:
2014-04-04 21:50:55 UTC+0000
2014-04-04 14:50:55 PDT-0700
2014-04-04 23:50:55 CEST+0200
or may be it helps
>> import pytz
>>> import datetime
>>>
>>> now_utc = datetime.datetime.utcnow() #Our UTC naive time from DB,
for the time being here I'm taking it as current system UTC time..
>>> now_utc
datetime.datetime(2011, 5, 9, 6, 36, 39, 883479) # UTC time in Naive
form.
>>>
>>> local_tz = pytz.timezone('Europe/Paris') #Our Local timezone, to
which we want to convert the UTC time.
>>>
>>> now_utc = pytz.utc.localize(now_utc) #Add Timezone information to
UTC time.
>>>
>>> now_utc
datetime.datetime(2011, 5, 9, 6, 36, 39, 883479, tzinfo=<UTC>) # The
full datetime tuple
>>>
>>> local_time = now_utc.astimezone(local\_tz) # Convert to local
time.
>>>
>>> local_time #Current local time in Paris
datetime.datetime(2011, 5, 9, 8, 36, 39, 883479, tzinfo=<DstTzInfo
'Europe/Paris' CEST+2:00:00 DST>)

Here is one way, using the pytz module:
import pytz
utc_datetime = (datetime.datetime(1970, 1, 1, tzinfo=pytz.utc)
+ datetime.timedelta(seconds=seconds_since_epoch)
If you don't want to install the pytz module, you can copy the example UTC class from the datetime documentation (search for "class UTC"):
https://docs.python.org/2/library/datetime.html#tzinfo-objects

Here's stdlib only solution without 3-party modules.
.., this datetime is a UTC datetime. But when i pull it from the DB, it is unaware of the timezone. What i need to do, is convert this datetime to a "seconds from epoch" time for another function.emphasize is mine
To convert an unaware (naive) datetime object that represents time in UTC to POSIX timestamp:
from datetime import datetime
timestamp = (dt_from_db - datetime(1970, 1, 1)).total_seconds()
Example:
>>> from datetime import datetime
>>> dt = datetime.strptime('2013-06-01 01:06:18', '%Y-%m-%d %H:%M:%S')
>>> (dt - datetime(1970, 1, 1)).total_seconds()
1370048778.0
See Converting datetime.date to UTC timestamp in Python that provides solutions for various Python versions.
To answer the question from the title: In general you need pytz library to handle timezones in Python. In particular, you should use .localize method to convert an unaware datetime object into timezone-aware one.
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal
tz = get_localzone() # local timezone whatever it is (just an example)
aware_dt = tz.localize(naive_dt_in_local_timezone, is_dst=None)
is_dst=None asserts that naive_dt_in_local_timezone exists and unambiguous.
Though you don't need it for UTC timezone because it always has the same UTC offset (zero) around the year and in all past years:
import pytz
aware_dt = utc_dt.replace(tzinfo=pytz.utc)
See Python - simplest and most coherent way to get timezone-aware current time in UTC? (it provides a stdlib-only solution):
aware_dt = utc_dt.replace(tzinfo=timezone.utc)

Related

Python convert timestamp to unix

I know these questions have been asked before but I'm struggling to convert a timestamp string to a unix time and figuring out whether the datetime objects are naive or aware
For example, to convert the time "2021-05-19 12:51:47" to unix:
>>> from datetime import datetime as dt
>>> dt_obj = dt.strptime("2021-05-19 12:51:47", "%Y-%m-%d %H:%M:%S")
>>> dt_obj
datetime.datetime(2021, 5, 19, 12, 51, 47)
is dt_obj naive or aware and how would you determine this? The methods on dt_obj such as timetz, tzinfo, and tzname don't seem to indicate anything - does that mean that dt_obj is naive?
Then to get unix:
>>> dt_obj.timestamp()
1621421507.0
However when I check 1621421507.0 on say https://www.unixtimestamp.com then it tells me that gmt for the above is Wed May 19 2021 10:51:47 GMT+0000, ie 2 hours behind the original timestamp?
since Python's datetime treats naive datetime as local time by default, you need to set the time zone (tzinfo attribute):
from datetime import datetime, timezone
# assuming "2021-05-19 12:51:47" represents UTC:
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47").replace(tzinfo=timezone.utc)
Or, as #Wolf suggested, instead of setting the tzinfo attribute explicitly, you can also modify the input string by adding "+00:00" which is parsed to UTC;
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47" + "+00:00")
In any case, the result
dt_obj.timestamp()
# 1621428707.0
now converts as expected on https://www.unixtimestamp.com/:
As long as you don't specify the timezone when calling strptime, you will produce naive datetime objects. You may pass time zone information via %z format specifier and +00:00 added to the textual date-time representation to get a timezone aware datetime object:
from datetime import datetime
dt_str = "2021-05-19 12:51:47"
print(dt_str)
dt_obj = datetime.strptime(dt_str+"+00:00", "%Y-%m-%d %H:%M:%S%z")
print(dt_obj)
print(dt_obj.timestamp())
The of above script is this:
2021-05-19 12:51:47
2021-05-19 12:51:47+00:00
1621428707.0
datetime.timestamp()
Naive datetime instances are assumed to represent local time and this method relies on the platform C mktime() function to perform the conversion.
So using this does automatically apply yours machine current timezone, following recipe is given to calculate timestamp from naive datetime without influence of timezone:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

Localizing Epoch Time with pytz in Python

Im working on converting epoch timestamps to dates in different timezones with pytz. What I am trying to do is create a DateTime object that accepts an Olson database timezone and an epoch time and returns a localized datetime object. Eventually I need to answer questions like "What hour was it in New York at epoch time 1350663248?"
Something is not working correctly here:
import datetime, pytz, time
class DateTime:
def __init__(self, timezone, epoch):
self.timezone = timezone
self.epoch = epoch
timezoneobject = pytz.timezone(timezone)
datetimeobject = datetime.datetime.fromtimestamp( self.epoch )
self.datetime = timezoneobject.localize(datetimeobject)
def hour(self):
return self.datetime.hour
if __name__=='__main__':
epoch = time.time()
dt = DateTime('America/Los_Angeles',epoch)
print dt.datetime.hour
dt = DateTime('America/New_York',epoch)
print dt.datetime.hour
This prints the same hour, whereas one should be 3 or so hours ahead. Whats going wrong here? I'm a total Python beginner, any help is appreciated!
datetime.fromtimestamp(self.epoch) returns localtime that shouldn't be used with an arbitrary timezone.localize(); you need utcfromtimestamp() to get datetime in UTC and then convert it to a desired timezone:
from datetime import datetime
import pytz
# get time in UTC
utc_dt = datetime.utcfromtimestamp(posix_timestamp).replace(tzinfo=pytz.utc)
# convert it to tz
tz = pytz.timezone('America/New_York')
dt = utc_dt.astimezone(tz)
# print it
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
Or a simpler alternative is to construct from the timestamp directly:
from datetime import datetime
import pytz
# get time in tz
tz = pytz.timezone('America/New_York')
dt = datetime.fromtimestamp(posix_timestamp, tz)
# print it
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
It converts from UTC implicitly in this case.
For creating the datetime object belonging to particular timezone from a unix timestamp, you may pass the pytz object as a tz parameter while creating your datetime. For example:
>>> from datetime import datetime
>>> import pytz
>>> datetime.fromtimestamp(1350663248, tz= pytz.timezone('America/New_York'))
datetime.datetime(2012, 10, 19, 12, 14, 8, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
You can get the list of all timezones using pytz.all_timezones which returns exhaustive list of the timezone names that can be used.
Also take a look at List of tz database time zones wiki.
epochdt = datetime.datetime.fromtimestamp(epoch)
timezone1 = timezone("Timezone/String")
adjusted_datetime = timezone1.localize(epochdt)
Working from memory, so excuse any syntax errors, but that should get you on the right track.
EDIT: Missed the part about knowing the hour,etc. Python has great Time/Date Formatting. At pretty much the bottom of that link is the table showing how to pull different attributes from the datetime object.

From a timezone and a UTC time, get the difference in seconds vs local time at that point in time

This should be very simple, but I can't quite figure it out in Python.
I want to have a function which takes two arguments, a UTC time in seconds and a zoneinfo name like 'Europe/Vienna' and returns the offset in seconds from local time and UTC for that point in time.
In C it would be:
/* ... code to to set local time to the time zone I want to compare against,
not shown here. Then call function below to get difference vs localtime.
Hardly an ideal solution,
but just to demonstrate what I want in a "lingua franca" (C): */
int get_diff_vs_localtime(const time_t original_utc_time)
{
struct tm* ts;
ts = localtime(&original_utc_time);
return mktime(ts) - original_utc_time;
}
I guess my question really boils down to: "given an Olson timezone (example 'Europe/Stockholm') and a UTC time, what is the local time?
Assuming "UTC time in seconds" means POSIX timestamp. To convert it to Stockholm time:
from datetime import datetime
import pytz
tz = pytz.timezone('Europe/Stockholm')
utc_dt = datetime.utcfromtimestamp(posix_timestamp).replace(tzinfo=pytz.utc)
dt = tz.normalize(utc_dt.astimezone(tz))
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
tz.normalize() is unnecessary if the source timezone is UTC (like in this case).
A simpler alternative is to use fromtimestamp()'s tz parameter, to convert "seconds since the epoch" to local time:
from datetime import datetime
import pytz
tz = pytz.timezone('Europe/Stockholm')
dt = datetime.fromtimestamp(posix_timestamp, tz)
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
Both examples produce the same result.
If local machine uses "right" timezones then to convert POSIX timestamp received from an external source to UTC, an explicit formula could be used:
from datetime import datetime, timedelta
import pytz
utc_dt = datetime(1970, 1, 1, tzinfo=pytz.utc) + timedelta(seconds=posix_timestamp)
The latest formula may also support a larger date range (less likely issues with dates before 1970, after 2038 or 3000 years).
If the timestamp comes from the local "right" source then the first two examples should be used instead (they call "right" time.gmtime()).
You could use pytz and datetime to do something in the manner of:
from datetime import datetime
from pytz import timezone
def get_diff(now, tzname):
tz = timezone(tzname)
utc = timezone('UTC')
utc.localize(datetime.now())
delta = utc.localize(now) - tz.localize(now)
return delta
Which for the following example...
now = datetime.utcnow()
print(now)
tzname = 'Europe/Stockholm'
delta = get_diff(now, tzname)
print(delta)
now_in_stockholm = now + delta
print(now_in_stockholm)
... outputs:
2012-10-02 14:38:56.547475
2:00:00
2012-10-02 16:38:56.547475
This is pretty old, but I couldn't find a great answer, so here's what I came up with:
from datetime import datetime
local = datetime.now()
utc = datetime.utcnow()
int((local - utc).days * 86400 + round((local - utc).seconds, -1))
Returns:
-21600
because I am (currently) 21600 seconds (6 hours) behind UTC.
Note: the second date calculated (in this case UTC) needs to be rounded since there is a super small difference in time at each calculation.
I guess my question really boils down to: "given an Olson timezone
(example 'Europe/Stockholm') and a UTC time, what is the local time?
If I understand your problem correctly:
from pytz import timezone
import datetime, time
tz = timezone('Asia/Kuwait')
utc_dt = datetime.datetime.utcfromtimestamp(time.time())
utc_dt + tz.utcoffset(utc_dt)
>>> tz.utcoffset(utc_dt).seconds
10800
>>> tz
<DstTzInfo 'Asia/Kuwait' LMT+3:12:00 STD>
>>> utc_dt + tz.utcoffset(utc_dt)
datetime.datetime(2012, 10, 2, 17, 13, 53, 504322)
>>> utc_dt
datetime.datetime(2012, 10, 2, 14, 13, 53, 504322)

how to findout local time using utcoffset and countryname in python

I have countrynames and utcoffset of that country
How to find out out local time in that country using utcoffset?
Check out pytz for looking up timezones by location. Maybe something like this:
>>> import pytz, datetime
>>> pytz.country_timezones['de']
['Europe/Berlin']
>>> matching_tzs = [t for t in pytz.country_timezones['de'] if pytz.timezone(t)._utcoffset.total_seconds() == 3600]
>>> datetime.datetime.now(tz=pytz.timezone(matching_tzs[0]))
datetime.datetime(2011, 5, 6, 17, 5, 26, 174828, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)
call datetime.now() with the time zone (as a tzinfo object) as an argument.
A country may span several timezones. A utc offset for a place may change through the time.
Given a country code and a utc offset, you could try to find matching timezone from Olson tz database for the current time. Here's variant of #Mu Mind's answer that takes into account current time (otherwise the result can be unexpected for some timezones):
from datetime import datetime, timedelta
import pytz
country_code, utc_offset = 'de', timedelta(hours=1)
# find matching timezones and print corresponding local time
now_in_utc = datetime.now(pytz.utc)
for zonename in pytz.country_timezones[country_code]:
tz = pytz.timezone(zonename)
local_time = now_in_utc.astimezone(tz)
if tz.utcoffset(local_time) == utc_offset: #NOTE: utc offset depends on time
print("%s\t%s" % (tz.zone, local_time.strftime("%Y-%m-%d %H:%M:%S %Z%z")))
Output
Europe/Berlin 2013-12-02 20:42:49 CET+0100
Save the current TZ environ variable value and then do
>>> os.environ['TZ'] = 'US/Eastern'
>>> time.tzset()
And for the library, whatever time function you use will be for the US/Eastern timezone, you c can reset it back to original one later.
Example usage:
>>> time.strftime('%X %x %Z')
'22:54:11 05/06/11 SGT'
>>> os.environ['TZ'] = 'US/Eastern'
>>> time.strftime('%X %x %Z')
'10:54:30 05/06/11 EDT'
Please refer to time module documentation for examples.
working code
utcoffset='+5:30'
utctime=datetime.datetime.utcnow()
hr=utcoffset[0:utcoffset.find(':')]
min=utcoffset[utcoffset.find(':')+1:]
datetimeofclient=datetime.timedelta(hours=int(hr),minutes=int(min))

How to get current isoformat datetime string including the default timezone?

I need to produce a time string that matches the iso format yyyy-mm-ddThh:mm:ss.ssssss-ZO:NE. The now() and utcnow() class methods almost do what I want.
>>> import datetime
>>> #time adjusted for current timezone
>>> datetime.datetime.now().isoformat()
'2010-08-03T03:00:00.000000'
>>> #unadjusted UTC time
>>> datetime.datetime.utcnow().isoformat()
'2010-08-03T10:00:00.000000'
>>>
>>> #How can I do this?
>>> datetime.datetime.magic()
'2010-08-03T10:00:00.000000-07:00'
To get the current time in UTC in Python 3.2+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2015-01-27T05:57:31.399861+00:00'
To get local time in Python 3.3+:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2015-01-27T06:59:17.125448+01:00'
Explanation: datetime.now(timezone.utc) produces a timezone aware datetime object in UTC time. astimezone() then changes the timezone of the datetime object, to the system's locale timezone if called with no arguments. Timezone aware datetime objects then produce the correct ISO format automatically.
You need to make your datetime objects timezone aware. from the datetime docs:
There are two kinds of date and time objects: “naive” and “aware”. This distinction refers to whether the object has any notion of time zone, daylight saving time, or other kind of algorithmic or political time adjustment. Whether a naive datetime object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it’s up to the program whether a particular number represents metres, miles, or mass. Naive datetime objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.
When you have an aware datetime object, you can use isoformat() and get the output you need.
To make your datetime objects aware, you'll need to subclass tzinfo, like the second example in here, or simpler - use a package that does it for you, like pytz or python-dateutil
Using pytz, this would look like:
import datetime, pytz
datetime.datetime.now(pytz.timezone('US/Central')).isoformat()
You can also control the output format, if you use strftime with the '%z' format directive like
datetime.datetime.now(pytz.timezone('US/Central')).strftime('%Y-%m-%dT%H:%M:%S.%f%z')
With arrow:
>>> import arrow
>>> arrow.now().isoformat()
'2015-04-17T06:36:49.463207-05:00'
>>> arrow.utcnow().isoformat()
'2015-04-17T11:37:17.042330+00:00'
You can do it in Python 2.7+ with python-dateutil (which is insalled on Mac by default):
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> datetime.now(tzlocal()).isoformat()
'2016-10-22T12:45:45.353489-03:00'
Or you if you want to convert from an existed stored string:
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from dateutil.parser import parse
>>> parse("2016-10-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-10-21T16:33:27.696173-03:00' <-- Atlantic Daylight Time (ADT)
>>> parse("2016-01-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-01-21T16:33:27.696173-04:00' <-- Atlantic Standard Time (AST)
Nine years later. If you know your time zone. I like the T between date and time. And if you don't want microseconds.
Python <= 3.8
pip3 install pytz # needed!
python3
>>> import datetime
>>> import pytz
>>> datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:23:28+01:00'
Tested on Ubuntu 18.04 and Python 3.6.9.
Python >= 3.9
pip3 install tzdata # only on Windows needed!
py -3
>>> import datetime
>>> import zoneinfo
>>> datetime.datetime.now(zoneinfo.ZoneInfo('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:39:36+01:00'
Tested on Windows 10 and Python 3.9.0.
Something like the following example. Note I'm in Eastern Australia (UTC + 10 hours at the moment).
>>> import datetime
>>> dtnow = datetime.datetime.now();dtutcnow = datetime.datetime.utcnow()
>>> dtnow
datetime.datetime(2010, 8, 4, 9, 33, 9, 890000)
>>> dtutcnow
datetime.datetime(2010, 8, 3, 23, 33, 9, 890000)
>>> delta = dtnow - dtutcnow
>>> delta
datetime.timedelta(0, 36000)
>>> hh,mm = divmod((delta.days * 24*60*60 + delta.seconds + 30) // 60, 60)
>>> hh,mm
(10, 0)
>>> "%s%+02d:%02d" % (dtnow.isoformat(), hh, mm)
'2010-08-04T09:33:09.890000+10:00'
>>>

Categories