I am trying to build a function as follows:
Input
UTC timestamp in miliseconds, for example:
1456865863633
UTC offset, or miliseconds to add/substract to the UTC timestamp to obtain the time in the corresponding timezone, for example:
-14400
OutPut
Time zone name in the following format:
US/Alaska
US/Aleutian
US/Arizona
US/Central
US/East-Indiana
US/Eastern
US/Hawaii
.
.
.
I've been trying to find the rught combination to do it using datetime and pytz libraries, but I was not successful so far.
Any ideas?
You could loop through all the timezones
for name in pytz.all_timezones:
and compare the date's utcoffset to the given offset:
if date.utcoffset().total_seconds() == utcoffset:
result.append(name)
import datetime as DT
import pytz
utc = pytz.utc
def tzones(timestamp, utcoffset):
result = []
date = utc.localize(DT.datetime.utcfromtimestamp(timestamp/float(1000)))
for name in pytz.all_timezones:
timezone = pytz.timezone(name)
date = date.astimezone(timezone)
if date.utcoffset().total_seconds() == utcoffset:
result.append(name)
return result
print(tzones(1456865863633, -14400))
prints
['America/Anguilla', 'America/Antigua', 'America/Aruba', 'America/Barbados', 'America/Blanc-Sablon', 'America/Boa_Vista', 'America/Campo_Grande', 'America/Cuiaba', 'America/Curacao', 'America/Dominica', 'America/Glace_Bay', 'America/Goose_Bay', 'America/Grand_Turk', 'America/Grenada', 'America/Guadeloupe', 'America/Guyana', 'America/Halifax', 'America/Kralendijk', 'America/La_Paz', 'America/Lower_Princes', 'America/Manaus', 'America/Marigot', 'America/Martinique', 'America/Moncton', 'America/Montserrat', 'America/Port_of_Spain', 'America/Porto_Velho', 'America/Puerto_Rico', 'America/Santo_Domingo', 'America/St_Barthelemy', 'America/St_Kitts', 'America/St_Lucia', 'America/St_Thomas', 'America/St_Vincent', 'America/Thule', 'America/Tortola', 'America/Virgin', 'Atlantic/Bermuda', 'Brazil/West', 'Canada/Atlantic', 'Etc/GMT+4']
Here's a different implementation of the approach from #unutbu's answer:
from datetime import datetime
import pytz
def timezones_from_utc_offset(offset, now=None):
if now is None:
now = datetime.now(pytz.utc)
return {tz.zone for tz in map(pytz.timezone, pytz.all_timezones_set)
if now.astimezone(tz).utcoffset() == offset}
If the input is the POSIX time in milliseconds:
>>> from datetime import timedelta
>>> dt = datetime(1970,1,1,tzinfo=pytz.utc) + timedelta(milliseconds=1456865863633)
>>> timezones_from_utc_offset(offset=timedelta(seconds=-14400), now=dt)
{'America/Anguilla',
'America/Antigua',
'America/Aruba',
'America/Barbados',
'America/Blanc-Sablon',
'America/Boa_Vista',
'America/Campo_Grande',
'America/Cuiaba',
'America/Curacao',
'America/Dominica',
'America/Glace_Bay',
'America/Goose_Bay',
'America/Grand_Turk',
'America/Grenada',
'America/Guadeloupe',
'America/Guyana',
'America/Halifax',
'America/Kralendijk',
'America/La_Paz',
'America/Lower_Princes',
'America/Manaus',
'America/Marigot',
'America/Martinique',
'America/Moncton',
'America/Montserrat',
'America/Port_of_Spain',
'America/Porto_Velho',
'America/Puerto_Rico',
'America/Santo_Domingo',
'America/St_Barthelemy',
'America/St_Kitts',
'America/St_Lucia',
'America/St_Thomas',
'America/St_Vincent',
'America/Thule',
'America/Tortola',
'America/Virgin',
'Atlantic/Bermuda',
'Brazil/West',
'Canada/Atlantic',
'Etc/GMT+4'}
Related
I would like to write log in a file with the correct timezone time (Europe/Paris) in a UpdateSubsStatus.log file ...
Here what i tried, the commented line are what i tired but it does not work.
import pytz
class Formatter(logging.Formatter):
"""override logging.Formatter to use an aware datetime object"""
def converter(self, timestamp):
dt = datetime.datetime.fromtimestamp(timestamp)
tzinfo = pytz.timezone('America/Denver')
return tzinfo.localize(dt)
def formatTime(self, record, datefmt=None):
dt = self.converter(record.created)
if datefmt:
s = dt.strftime(datefmt)
else:
try:
s = dt.isoformat(timespec='milliseconds')
except TypeError:
s = dt.isoformat()
return s
#console = logging.StreamHandler()
logging.basicConfig(filename='UpdateSubsStatus.log', filemode='a', format='%(asctime)s;%(name)s - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S')
#console.setFormatter(Formatter)
#logging.getLogger('').addHandler(console)
Does it exist a simple way with the basic config to use a timezone ?
Regards
I tried logging events using your code. the events are logged in the local timezone, not the specified one. I think the problem is with this code
def converter(self, timestamp):
dt = datetime.datetime.fromtimestamp(timestamp)
tzinfo = pytz.timezone('America/Denver')
return tzinfo.localize(dt)
This code converts timestamp to local datetime and changes tzinfo without a real datetime conversion
>>> timestamp
1619258964.3946261
>>> dt = datetime.datetime.fromtimestamp(timestamp)
>>> dt
datetime.datetime(2021, 4, 24, 13, 9, 24, 394626)
>>> tzinfo = pytz.timezone('America/Denver')
>>> res = tzinfo.localize(dt)
>>> res
datetime.datetime(2021, 4, 24, 13, 9, 24, 394626, tzinfo=<DstTzInfo 'America/Denver' MDT-1 day, 18:00:00 DST>)
# Hours left unchanged
So I change method converter
def converter(self, timestamp):
# Create datetime in UTC
dt = datetime.datetime.fromtimestamp(timestamp, tz=pytz.UTC)
# Change datetime's timezone
return dt.astimezone(pytz.timezone('America/Denver'))
Here the final code
import pytz
import logging
import datetime
class Formatter(logging.Formatter):
"""override logging.Formatter to use an aware datetime object"""
def converter(self, timestamp):
# Create datetime in UTC
dt = datetime.datetime.fromtimestamp(timestamp, tz=pytz.UTC)
# Change datetime's timezone
return dt.astimezone(pytz.timezone('America/Denver'))
def formatTime(self, record, datefmt=None):
dt = self.converter(record.created)
if datefmt:
s = dt.strftime(datefmt)
else:
try:
s = dt.isoformat(timespec='milliseconds')
except TypeError:
s = dt.isoformat()
return s
console = logging.FileHandler('UpdateSubsStatus.log')
console.setFormatter(Formatter(
'%(asctime)s;%(name)s - %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S'))
logging.getLogger('').addHandler(console)
logging.critical("Critical event")
Log file UpdateSubsStatus.log (still America/Denver timezone)
2021-04-24 04:19:16;root - CRITICAL - Critical event
2021-04-24 04:19:17;root - CRITICAL - Critical event
Also, don't forget to change the timezone to Europe/Paris
Hope This helps, just using simple logic and passing in the required Timezone as an argument. Also, the return value is created with dateTimenow format.
from datetime import datetime
import pytz
def getTime(timeZoneVal):
# get the standard UTC time
UTC = pytz.utc
logTime = pytz.timezone(timeZoneVal)
#print("US Time in Default Format : ", datetime.now(logTime))
return datetime.now(logTime)
logTime = getTime('Europe/Paris')
print(logTime)
How I can change this code from localtime UTC to UTC+2. Now hours() function print 13 but I need to write 15.
import time;
def hours():
localtime = time.localtime(time.time())
return localtime.tm_hour
def minutes():
localtime = time.localtime(time.time())
return localtime.tm_min
def seconds():
localtime = time.localtime(time.time())
return localtime.tm_sec
print(hours())
#minutes()
#seconds()
How about using the datetime module:
import datetime;
today = datetime.datetime.now()
todayPlus2Hours = today + datetime.timedelta(hours=2)
print(todayPlus2Hours)
print(todayPlus2Hours.hour)
print(todayPlus2Hours.minute)
print(todayPlus2Hours.second)
You can use pytz along with datetime modules.
for a timezone reference i'd look here.
I'd do something of this sort:
import datetime
import pytz
utc_dt = datetime.datetime.now(tz=pytz.utc)
amsterdam_tz = pytz.timezone("Europe/Amsterdam")
local_amsterdam_time = amsterdam_tz.normalize(utc_dt)
print local_amsterdam_time.hour
print local_amsterdam_time.minute
print local_amsterdam_time.second
I can't seem to figure out how to convert a datetime string to another datetime string with timezone.
Here's the example.
07/27/2015:06:00 AM to 20150727060000 -0400
The default timezone would be EST.
Here's my code so far.
from datetime import datetime, timedelta
def _to_datetime(air_date, air_time):
schedule_time = '{}:{}'.format(air_date, air_time)
return datetime.strptime(schedule_time,'%m/%d/%Y:%I:%M %p')
Use pytz module to work with timezones in Python. To get the local timezone as pytz tzinfo object, you could use tzlocal module:
from tzlocal import get_localzone # $ pip install tzlocal
naive = _to_datetime('07/27/2015', '06:00 AM')
aware = get_localzone().localize(naive, is_dst=None)
print(aware.strftime('%Y%m%d%H%M%S %z'))
# -> 20150727060000 -0400
Add the time zone to the parsed string with %z. This will give it a tzinfo attribute:
from datetime import datetime, timedelta
def _to_datetime(air_date, air_time):
schedule_time = '{}:{}'.format(air_date, air_time)
return datetime.strptime(schedule_time + ' -0400', '%m/%d/%Y:%I:%M %p %z')
Example:
>>> datetime.strptime('03/19/2015:03:00 PM -0400','%m/%d/%Y:%I:%M %p %z')
datetime.datetime(2015, 3, 19, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
You could use dateutil to add the tzinfo to the datetime object.
from datetime import datetime, timedelta
from dateutil import tz
AmericaNewYorkTz = tz.gettz('America/New_York')
def _to_datetime(air_date, air_time):
schedule_time = '{}:{}'.format(air_date, air_time)
return datetime.strptime(schedule_time,'%m/%d/%Y:%I:%M %p').replace(tzinfo=AmericaNewYorkTz)
dt = _to_datetime('07/27/2015', '06:00 AM')
print('DateTime:', dt)
# DateTime: 2015-07-27 06:00:00-04:00
or as J.H. Sebastian pointed out, you can use pytz
from datetime import datetime, timedelta
from pytz import timezone
AmericaNewYorkTz = timezone('America/New_York')
def _to_datetime(air_date, air_time):
schedule_time = '{}:{}'.format(air_date, air_time)
naiveDateTime = datetime.strptime(schedule_time,'%m/%d/%Y:%I:%M %p')
localizedDateTime = AmericaNewYorkTz.localize(naiveDateTime, is_dst=None)
return localizedDateTime
dt = _to_datetime('05/27/2015', '06:00 AM')
print('DateTime:', dt)
I have a date string of the form '2009/05/13 19:19:30 -0400'. It seems that previous versions of Python may have supported a %z format tag in strptime for the trailing timezone specification, but 2.6.x seems to have removed that.
What's the right way to parse this string into a datetime object?
You can use the parse function from dateutil:
>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))
This way you obtain a datetime object you can then use.
As answered, dateutil2.0 is written for Python 3.0 and does not work with Python 2.x. For Python 2.x dateutil1.5 needs to be used.
%z is supported in Python 3.2+:
>>> from datetime import datetime
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z')
datetime.datetime(2009, 5, 13, 19, 19, 30,
tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
On earlier versions:
from datetime import datetime
date_str = '2009/05/13 19:19:30 -0400'
naive_date_str, _, offset_str = date_str.rpartition(' ')
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(repr(dt))
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240))
print(dt)
# -> 2009-05-13 19:19:30-04:00
where FixedOffset is a class based on the code example from the docs:
from datetime import timedelta, tzinfo
class FixedOffset(tzinfo):
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
Here is a fix of the "%z" issue for Python 2.7 and earlier
Instead of using:
datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
Use the timedelta to account for the timezone, like this:
from datetime import datetime,timedelta
def dt_parse(t):
ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
if t[18]=='+':
ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
elif t[18]=='-':
ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
return ret
Note that the dates would be converted to GMT, which would allow doing date arithmetic without worrying about time zones.
The problem with using dateutil is that you can't have the same format string for both serialization and deserialization, as dateutil has limited formatting options (only dayfirst and yearfirst).
In my application, I store the format string in .INI file, and each deployment can have its own format. Thus, I really don't like the dateutil approach.
Here's an alternative method that uses pytz instead:
from datetime import datetime, timedelta
from pytz import timezone, utc
from pytz.tzinfo import StaticTzInfo
class OffsetTime(StaticTzInfo):
def __init__(self, offset):
"""A dumb timezone based on offset such as +0530, -0600, etc.
"""
hours = int(offset[:3])
minutes = int(offset[0] + offset[3:])
self._utcoffset = timedelta(hours=hours, minutes=minutes)
def load_datetime(value, format):
if format.endswith('%z'):
format = format[:-2]
offset = value[-5:]
value = value[:-5]
return OffsetTime(offset).localize(datetime.strptime(value, format))
return datetime.strptime(value, format)
def dump_datetime(value, format):
return value.strftime(format)
value = '2009/05/13 19:19:30 -0400'
format = '%Y/%m/%d %H:%M:%S %z'
assert dump_datetime(load_datetime(value, format), format) == value
assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \
.astimezone(timezone('US/Eastern')) == load_datetime(value, format)
One liner for old Pythons out there. You can multiply a timedelta by 1/-1 depending on +/- sign, as in:
datetime.strptime(s[:19], '%Y-%m-%dT%H:%M:%S') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == '+' else 1)
If you are on Linux, then you can use the external date command to dwim:
import commands, datetime
def parsedate(text):
output=commands.getoutput('date -d "%s" +%%s' % text )
try:
stamp=eval(output)
except:
print output
raise
return datetime.datetime.frometimestamp(stamp)
This is of course less portable than dateutil, but slightly more flexible, because date will also accept inputs like "yesterday" or "last year" :-)
I have a UTC timestamp and a timezone offset timestamp (both in milliseconds):
utc_time = 1394452800000
timezoneoffset = -14400000
If I wanted to get the datetime I would do :
print datetime.utcfromtimestamp(utc_time/1000)
>>>2014-03-10 12:00:00
How can I localize this datetime but also the final object be timezone aware?
If I divide timezoneoffset, -14400000/(3600*1000) = -4 (hours). So the final output should be:
>>>2014-03-10 08:00:00-04:00
My try:
from pytz import timezone
from dateutil.tz import tzoffset
utc_time = 1394452800000
timezoneoffset = -14400000
tzinfooff = tzoffset(None, timezoneoffset/1000)
print timezone(tzinfooff).localize( datetime.utcfromtimestamp(utc_time/1000) )
>>>Traceback (most recent call last):
File "/Users/dionysis_lorentzos/Desktop/cmdline copy.py", line 25, in <module>
print timezone(tzinfo2).localize( datetime.utcfromtimestamp(time/1000) ).isoformat()
File "/usr/local/lib/python2.7/site-packages/pytz/__init__.py", line 162, in timezone
if zone.upper() == 'UTC':
AttributeError: 'tzoffset' object has no attribute 'upper'
You need to use just the dateutil.tz.tzoffset() type; pytz.timezone only takes names, not dateutil.tz objects.
The .localize() method is only needed for pytz-supplied timezones as they contain historic offsets as well, and they need to be applied to a datetime object using a little more care than just .replace() can do.
If the timestamp is a UNIX epoch value in UTC, then use fromtimestap with the timezone as a second argument:
>>> print datetime.fromtimestamp(utc_time/1000, tzinfooff)
2014-03-10 08:00:00-04:00
Or you could translate from UTC, using datetime.astimezone():
>>> from dateutil.tz impor tzutc
>>> dt_utc = datetime.utcfromtimestamp(utc_time/1000).replace(tzinfo=tzutc())
>>> print dt_utc.astimezone(tzinfooff)
2014-03-10 08:00:00-04:00
To convert POSIX timestamp to an timezone-aware datetime object in a timezone specified by its utc offset, you could create an aware utc datetime object and convert it to the fixed offset timezone:
from datetime import datetime
utc_dt = datetime.fromtimestamp(utc_time * 1e-3, utc)
dt = utc_dt.astimezone(FixedOffset(timezoneoffset * 1e-3 / 60, None))
print(dt.isoformat(' '))
# -> 2014-03-10 08:00:00-04:00
where utc and FixedOffset are defined in datetime docs:
from datetime import tzinfo, timedelta
class FixedOffset(tzinfo):
"""Fixed offset in minutes east from UTC."""
def __init__(self, offset, name):
self.__offset = timedelta(minutes = offset)
self.__name = name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return timedelta(0)
utc = FixedOffset(0, "UTC")