How to get UTC time given timezone? - python

I am in the US and I want to get the UTC time (without the effect of Daylight Saving Time) for a piece of code:
localtime = strftime("%m%d%y%H%M", gmtime())
Right now that code give me time in Greenwich, England. I know that I have a time offset of -8 (GMT -8). How can I get the UTC time to a specific timezone? (using Python library, not casting the hour to integer, - 8, and than convert it back)

Try the datetime module:
datetime.datetime.utcnow() + datetime.timedelta(hours=-8)
BTW, UTC doesn't have timezones, it's Universal Co-ordinated Time, it's the same everywhere.

Just use the localtime() rather than gmtime() function:
localtime = time.strftime("%m%d%y%H%M", time.localtime())
From the python time module:
"Like gmtime() but converts to local time. If secs is not provided or None, the current time as returned by time() is used. The dst flag is set to 1 when DST applies to the given time."
To see if DST applies:
time.daylight

Supporting timezones at whatever level of detail is required is up to the application. The rules for time adjustment across the world are more political than rational, and there is no standard suitable for every application.
There is a useful third party module for that purpose: http://pytz.sourceforge.net/

Related

PYTZ always 7 hours ahead

so I'm trying to make a discord bot in python and make a command that will display all timezones that I choose, but the problem is that all of these timezones are around 7-8 hours ahead of normal.
import datetime
from pytz import timezone
localFormat = "%Y-%m-%d %H:%M:%S, %Z%z"
UTC=datetime.datetime.utcnow()
timezonelist = ["US/Eastern", "US/Central", "US/Mountain", "US/Pacific", "Etc/UTC", "Europe/Berlin", "Australia/North", "Australia/South", "Australia/West"]
for tz in timezonelist:
localDatetime = UTC.astimezone(timezone(tz))
x = localDatetime.strftime(localFormat)
print(tz + " " + x)
for example, Etc/UTC outputs 05:56:25 when it should output 22:56:25, other timezones follow this example, EST outputs 00:56:25 when it should be 17:56:25, or MST (where I am), 22:56:25 instead of 15:56:25. However, datetime.utcnow() returns the correct time.
I had done some research and it said that PYTZ uses the LMT but since all are forward by an amount I do not think it has to do with that.
utcnow() gives you a naive datetime object - it is not aware that it's in UTC although the numbers show UTC. If you convert to another time zone, Python will assume all naive datetime objects are local time. Your local time (MST) is UTC-7, that's why you're off by 7 hours.
The behaviour of utcnow is confusing and can lead to unexpected results - Stop using utcnow and utcfromtimestamp. Instead, use now() and set the tz explicitly:
UTC = datetime.datetime.now(timezone('UTC'))

How should I serialize a dateutil.tz.tzlocal object?

I want to capture a timestamp and the current timezone and serialize it into a file (in JSON or YAML, but that's not really my question) for later retrieval on a different computer.
The timestamp is easy, I'll just use time.time().
For getting the current timezone, I read another SO question and it seems appropriate to use dateutil.tz.tzlocal
to get the current timezone.
Now I just need to figure out how to serialize it. The name is easy, that's just a string, but the offset seems to be weird; I was expecting just a number:
import time
import datetime
import dateutil
now = datetime.datetime.utcfromtimestamp(time.time())
tzlocal = dateutil.tz.tzlocal()
print tzlocal.tzname(now)
print tzlocal.utcoffset(now)
but this prints
US Mountain Standard Time
-1 day, 17:00:00
and the result of utcoffset appears to be an object. How do I just get the number?
Oh, never mind, tzlocal.utcoffset(now) returns a datetime.timedelta and I can just call total_seconds():
import time
import datetime
import dateutil
import json
now = datetime.datetime.utcfromtimestamp(time.time())
tzlocal = dateutil.tz.tzlocal()
info_str = json.dumps(dict(name=tzlocal.tzname(now),
offset=tzlocal.utcoffset(now).total_seconds()))
print info_str
which prints (on my PC)
{"name": "US Mountain Standard Time", "offset": -25200.0}
I'm not sure what your application is but as a default I recommend serializing to ISO 8601 timestamps with a time zone offset. Even better, convert to UTC first... this makes things easier for humans who happen to browse the serialized data, because they don't have to do the date math in their head.
There may be performance reasons for sticking with numeric timestamps, but I'd want proof this was a bottleneck in my application before giving up the human-readable bonus of ISO timestamps.

Why does creating a datetime with a tzinfo from pytz show a weird time offset?

Can someone explain me why I do not get the same result in those?
import datetime,pytz
var1 = datetime.datetime(2017,10,25,20,10,50,tzinfo=pytz.timezone("Europe/Athens")))
print(var1)
The output of this code is: 2017-10-25 20:10:50+01:35
import datetime,pytz
var1 = datetime.datetime(2017,10,25,20,10,50)
var1 = pytz.timezone("Europe/Athens").localize(var1)
print(var1)
The output of this code is: 2017-10-25 20:10:50+03:00
My question is why they have different timezones (1:35 and 3:00). I know that the second code is true because my UTC is 3:00. But can you tell me why I am getting 1:35 in the first one?
There is no problem, datetime just happily reports the offset of the tzinfo in whatever reference frame.
By default pytz.timezone doesn't give the UTC offset but the LMT (local mean time) offset:
>>> pytz.timezone("Europe/Athens")
<DstTzInfo 'Europe/Athens' LMT+1:35:00 STD>
# ^^^-------------------- local mean time
However when you localize it:
>>> var1 = datetime.datetime(2017,10,25,20,10,50)
>>> var1 = pytz.timezone("Europe/Athens").localize(var1)
>>> var1.tzinfo
<DstTzInfo 'Europe/Athens' EEST+3:00:00 DST>
# ^^^^-------------------- eastern european summer time
A different offset is now reported, this time based on the EEST.
tzinfo doesn't work well for some timezones and that could be the reason for the wrong result.
pytz doc:
Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones.
Using localize or astimezone is a fix to this problem. Doc says that The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans.
import datetime, pytz
localTimezone = pytz.timezone('Europe/Athens')
var1 = datetime.datetime(2017,10,25,20,10,50,tzinfo=pytz.utc)
loc_dt = var1.astimezone(localTimezone)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print(loc_dt.strftime(fmt))
This will print
2017-10-25 23:10:50 EEST+0300
In the second code, you use .localize(), which takes a naive datetime object and interprets it as if it is in that timezone. It does not move the time to another timezone. A naive datetime object has no timezone information to be able to make that move possible.
As you are making the time local in the second code, the time shown in the second one is correct. As you are not making the time local in the first code, the time shown is incorrect.

Elegant way to adjust date timezones in Python

I'm based in the UK, and grappling with summer time BST and timezones.
Here's my code:
TIME_OFFSET = 1 # 0 for GMT, 1 for BST
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
return (datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ') +
datetime.timedelta(hours=TIME_OFFSET)).strftime('%d/%m %H:%M')
Setting a variable like this feels very wrong, but I can't find any elegant way to achieve the above without hideous amounts of code. Am I missing something, and is there no way to (for example) read the system timezone?
To convert UTC to given timezone:
from datetime import datetime
import pytz
local_tz = pytz.timezone("Europe/London") # time zone name from Olson database
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
rfc3339s = "2013-04-08T22:35:00Z"
utc_dt = datetime.strptime(rfc3339s, '%Y-%m-%dT%H:%M:%SZ')
local_dt = utc_to_local(utc_dt)
print(local_dt.strftime('%d/%m %H:%M')) # -> 08/04 23:35
See also How to convert a python utc datetime to a local datetime using only python standard library?.
You seem to be asking a few separate questions here.
First, if you only care about your own machine's current local timezone, you don't need to know what it is. Just use the local-to-UTC functions. There are a few holes in the API, but even if you can't find the function you need, you can always just get from local to UTC or vice-versa by going through the POSIX timestamp and the fromtimestamp and utcfromtimestamp methods.
If you want to be able to deal with any timezone, see the top of the docs for the difference between aware and naive objects, but basically: an aware object is one that knows its timezone. So, that's what you need. The problem is that, as the docs say:
Note that no concrete tzinfo classes are supplied by the datetime module. Supporting timezones at whatever level of detail is required is up to the application.
The easiest way to support timezones is to install and use the third-party library pytz.
Meanwhile, as strftime() and strptime() Behavior sort-of explains, strptime always returns a naive object. You then have to call replace and/or astimezone (depending on whether the string was a UTC time or a local time) to get an aware object imbued with the right timezone.
But, even with all this, you still need to know what local timezone you're in, which means you still need a constant. In other words:
TIMEZONE = pytz.timezone('Europe/London')
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc_naive = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
utc = utc_naive.replace(pytz.utc)
bst = utc.astimezone(TIMEZONE)
return bst.strftime('%d/%m %H:%M')
So, how do you get the OS to give you the local timezone? Well, that's different for different platforms, and Python has nothing built in to help. But there are a few different third-party libraries that do, such as dateutil. For example:
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
bst = utc.astimezone(dateutil.tz.tzlocal())
return bst.strftime('%d/%m %H:%M')
But now we've come full circle. If all you wanted was the local timezone, you didn't really need the timezone at all (at least for your simple use case). So, this is only necessary if you need to support any timezone, and also want to be able to, e.g., default to your local timezone (without having to write two copies of all of your code for the aware and naive cases).
(Also, if you're going to use dateutil in the first place, you might want to use it for more than just getting the timezone—it can basically replacing everything you're doing with both datetime and pytz.)
Of course there are other options besides these libraries—search PyPI, Google, and/or the ActiveState recipes.
If you want to convert a UTC input into a local time, regardless of which timezone you're in, try this:
def utctolocal(input):
if time.localtime()[-1] == 1: st=3600
else: st=0
return time.localtime(time.time()-time.mktime(time.gmtime())+time.mktime(time.localtime(time.mktime(time.strptime(input, '%Y-%m-%dT%H:%M:%SZ'))))+st)
Quite long code, but what it does is it simply adds the difference between time.gmtime() and time.localtime() to the time tuple created from the input.
Here's a function I use to do what I think you want. This assumes that the input is really a gmt, or more precisely, a utc datetime object:
def utc_to_local(utc_dt):
'''Converts a utc datetime obj to local datetime obj.'''
t = utc_dt.timetuple()
secs = calendar.timegm(t)
loc = time.localtime(secs)
return datetime.datetime.fromtimestamp(time.mktime(loc))
Like you said, this relies on the system time zone, which may give you shaky results, as some of the comments have pointed out. It has worked perfectly for me on Windows, however.
A simple function to check if a UCT corresponds to BST in London or GMT (for setting TIME_OFFSET above)
import datetime
def is_BST(input_date):
if input_date.month in range(4,9):
return True
if input_date.month in [11,12,1,2]:
return False
# Find start and end dates for current year
current_year = input_date.year
for day in range(25,32):
if datetime.datetime(current_year,3,day).weekday()==6:
BST_start = datetime.datetime(current_year,3,day,1)
if datetime.datetime(current_year,10,day).weekday()==6:
BST_end = datetime.datetime(current_year,10,day,1)
if (input_date > BST_start) and (input_date < BST_end):
return True
return False

python convert date and time into linux timestmap

i have timestamps in the following format:
2011 February 2nd 13h 27min 21s
110202 132721
I want to convert 110202 132721 into the corresponding linux timestamp: 1296682041
Is there any quick efficient way to achieve this?
Something like
>>> s = "110202 132721"
>>> print time.mktime(time.strptime(s, "%y%m%d %H%M%S"))
1296653241.0
This interprets the time as a local time (your current time zone).
To create a Unix timestamp, use the time.mktime(t) function. It takes a time.struct_time object.
The objects definition can be viewed here. So you just have to parse the date and the time and put it into the object before handing it over to the mktime() function
Without your timezone information, this is not the 'corresponding' unix timestamp.
After a few attempts I have guessed you could be located in the Pacific coast of USA, so you have to define it explicitely in your script:
from datetime import datetime
import pytz
import calendar
a = "110202 132721"
yourTZ = 'America/Los_Angeles'
calendar.timegm(pytz.timezone(yourTZ).localize(datetime.strptime(a, '%y%m%d %H%M%S')).utctimetuple())
# returns 1296682041

Categories