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.
Related
I'm trying to display my full time zone along with my current local time.
print "Your current time is {0} {1} ".format(datetime.datetime.now().time(), time.tzname[0])
And the result would look something like:
Your current time is 08:35:45.328000 Pacific Standard Time
The problem is I have to import the Time library (sorry if I call it wrong, I'm coming from C#) along with the Datetime library.
import datetime
import time
I've looked into the naive and aware states of time, but still can't seem to get the desired result.
Is there a way to get the full timezone name (i.e.: Pacific Standard Time) from Datetime without having to import Time?
The example for writing your own local timezone tzinfo class uses (scroll down one page from here) pulls the tzname from time.tzname, so Python doesn't have a better built-in solution to suggest.
You could copy that example LocalTimezone implementation, which would allow the use of the %Z format code for strftime on an aware datetime instance using the LocalTimezone, but that's the best you can do with the built-ins. On a naive datetime the tzname is the empty string, so you need an aware datetime for this to work.
I'm looking to build a Python application which will receive timezone information from an Android phone, which I'd like to convert to a datetime tzinfo object (for example, as implemented by pytz).
This little Java program shows a 'sample' of the formats for TimeZone available:
import java.util.TimeZone;
public class GetLocalTimeZone {
public static void main(String []args) {
TimeZone local_tz = TimeZone.getDefault();
System.out.println(local_tz.getDisplayName());
System.out.println(local_tz.getID());
System.out.println(local_tz.getRawOffset());
}
}
which prints
Central European Time
Europe/Amsterdam
3600000
In accordance with the TimeZone documentation, the getRawOffset() function returns "the amount of time in milliseconds to add to UTC to get standard time in this time zone". This seems like a good starting point to instantiate a datetime.tzinfo object.
The problem is that although I can instantiate one using the output of the getID() method, e.g.
import pytz
amsterdam = pytz.timezone('Europe/Amsterdam')
I'm not sure how to instantiate a timezone with the numerical offset, even if I convert it to hours. For example,
pytz.timezone('+01:00')
yields a UnknownTimeZoneError. How would I go about creating a datetime.tzinfo object from the offset from UTC (in milliseconds)? (I'm also open to other implementations such as Arrow and Pendulum).
Your problem is that a timezone includes both an offset, and daylight savings information.
There can be timezones with the same offset but which do daylight savings differently, so the offset alone is not sufficient to identify the timezone.
If possible, you should use the Display Name and/or ID.
If you can't do that, your best bet is to enumerate all timezones, and get a shortlist based on which ones have that offset for at least part of the year. Then you will have to pick one somehow.
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
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
In a Python project I'm working on, I'd like to be able to get a "human-readable" timezone name of the form America/New_York, corresponding to the system local timezone, to display to the user. Every piece of code I've seen that accesses timezone information only returns either a numeric offset (-0400) or a letter code (EDT) or sometimes both. Is there some Python library that can access this information, or if not that, convert the offset/letter code into a human-readable name?
If there's more than one human-readable name corresponding to a particular timezone, either a list of the possible results or any one of them is fine, and if there is no human-readable name corresponding to the current time zone, I'll take either an exception or None or [] or whatever.
A clarification: I don't remember exactly what I had in mind when I originally wrote this question, but I think what I really wanted was a way to turn a timezone into a human-readable name. I don't think this question was meant to focus on how to get the system local timezone specifically, but for the specific use case I had in mind, it just happened that the local timezone was the one I wanted the name for. I'm not editing the bit about the local timezone out of the question because there are answers focusing on both aspects.
The following generates a defaultdict mapping timezone offsets (e.g. '-0400') and abbreviations (e.g. 'EDT') to common geographic timezone names (e.g. 'America/New_York').
import os
import dateutil.tz as dtz
import pytz
import datetime as dt
import collections
result = collections.defaultdict(list)
for name in pytz.common_timezones:
timezone = dtz.gettz(name)
now = dt.datetime.now(timezone)
offset = now.strftime('%z')
abbrev = now.strftime('%Z')
result[offset].append(name)
result[abbrev].append(name)
for k, v in result.items():
print(k, v)
Note that timezone abbreviations can have vastly different meanings. For example, 'EST' could stand for Eastern Summer Time (UTC+10) in Australia, or Eastern Standard Time (UTC-5) in North America.
Also, the offsets and abbreviations may change for regions that use daylight standard time. So saving the static dict may not provide the correct timezone name 365 days a year.
I'd like to be able to get a "human-readable" timezone name of the form America/New_York, corresponding to the system local timezone, to display to the user.
There is tzlocal module that returns a pytz tzinfo object (before tzlocal 3.0 version) that corresponds to the system local timezone:
#!/usr/bin/env python
import tzlocal # $ pip install tzlocal
# display "human-readable" name (tzid)
print(tzlocal.get_localzone_name())
# Example Results:
# -> Europe/Moscow
# -> America/Chicago
To answer the question in the title (for people from google), you could use %Z%z to print the local time zone info:
#!/usr/bin/env python
import time
print(time.strftime('%Z%z'))
# Example Results:
# -> MSK+0300
# -> CDT-0500
It prints the current timezone abbreviation and the utc offset corresponding to your local timezone.
http://pytz.sourceforge.net/ may be of help. If nothing else, you may be able to grab a list of all of the timezones and then iterate through until you find one that matches your offset.
This may not have been around when this question was originally written, but here is a snippet to get the time zone official designation:
>>> eastern = timezone('US/Eastern')
>>> eastern.zone
'US/Eastern'
Further, this can be used with a non-naive datetime object (aka a datetime where the actual timezone has been set using pytz.<timezone>.localize(<datetime_object>) or datetime_object.astimezone(pytz.<timezone>) as follows:
>>> import datetime, pytz
>>> todaynow = datetime.datetime.now(tz=pytz.timezone('US/Hawaii'))
>>> todaynow.tzinfo # turned into a string, it can be split/parsed
<DstTzInfo 'US/Hawaii' HST-1 day, 14:00:00 STD>
>>> todaynow.strftime("%Z")
'HST'
>>> todaynow.tzinfo.zone
'US/Hawaii'
This is, of course, for the edification of those search engine users who landed here. ... See more at the pytz module site.
If you want only literally what you asked for, "the timezone name of the form America/New_York, corresponding to the system local timezone", and if you only care about Linux (and similar), then this should do the job:
import os
import os.path
import sys
def main(argv):
tzname = os.environ.get('TZ')
if tzname:
print tzname
elif os.path.exists('/etc/timezone'):
print file('/etc/timezone').read()
else:
sys.exit(1)
if __name__ == '__main__':
main(sys.argv)
Of course it would be nicer to have a library that encapsulates this in a cleaner way, and that perhaps handles the other cases you mention in comments like already having a tzinfo object. I think you can do that with pytz mentioned by Amber but it's not obvious to me just how...
Check out python-dateutil
py> from dateutil.tz import *
py> ny = gettz('America/New York')
py> ny._filename
'/usr/share/zoneinfo/America/New_York'
py> ny._filename.split('/', 4)[-1]
'America/New_York'
# use tzlocal library
from tzlocal import get_localzone
current_timezone = get_localzone()
zone = current_timezone.zone
print(zone)
Working with the latest version of tzlocal which is 4.1 as of today, tzlocal.get_localzone().key produces the following error: AttributeError: '_PytzShimTimezone' object has no attribute 'key'. But tzlocal.get_localzone().zone works lovely.