Conversion from aware datetime to timestamp and back is gaining one hour? - python

I always get confused with datetimes and timezone conversion in Python, but now I'm experiencing a rather odd behavior. I suspect (strongly) that this is related to Daylight Saving Times, but I don't know for sure, and I definitely don't know how to handle it correctly.
Here's what happens: If I make a datetime instance aware of its timezone, I create an epoch UTC timestamp from it, and I re-create a datetime instance back from that timestamp, I seem to be gaining one hour:
>>> import pytz
>>> import datetime
>>> import time
>>>
>>> naive = datetime.datetime.now()
>>> print "Naive 'now' %s" % naive
Naive 'now' 2014-08-21 11:19:13.019046
>>> eastern_tz = pytz.timezone('US/Eastern')
>>> now_eastern = eastern_tz.localize(naive)
>>> print "Now (eastern) is %s" % now_eastern
Now (eastern) is 2014-08-21 11:19:13.019046-04:00
>>> print "Now (utc) is %s" % now_eastern.astimezone(pytz.utc)
Now (utc) is 2014-08-21 15:19:13.019046+00:00
# This one is correct
>>> now_eastern_utc_timetuple = now_eastern.utctimetuple()
>>> print "Now (eastern) as timetuple %s" % now_eastern_utc_timetuple
Now (eastern) as timetuple time.struct_time(tm_year=2014, tm_mon=8, tm_mday=21, \
tm_hour=15, tm_min=19, tm_sec=13, tm_wday=3, \
tm_yday=233, tm_isdst=0)
# Shouldn't this be isdst=1 ? ----------^^^
>>> now_epoch = time.mktime(now_eastern_utc_timetuple)
>>> print "now epoch (UTC) %s" % now_epoch
now epoch (UTC) 1408652353.0
# I'm pretty sure this is +3600 in advance
>>> print "Converted back: %s" % datetime.datetime.fromtimestamp(now_epoch)
Converted back: 2014-08-21 16:19:13
I've verified the times using epochconverter.com, and I'm pretty sure the timestamp generated from the utctimetuple is adding one hour. As I mentioned, I'm almost certain that this is related to Daylight Time Saving unawareness, because if I try with a date when the daylight time savings is not in use (for instance, December), it works fine.
>>> naive = datetime.datetime.strptime('2012/12/12 10:00', '%Y/%m/%d %H:%M')
>>> print "Naive 'now' %s" % naive
Naive 'now' 2012-12-12 10:00:00
>>> eastern_tz = pytz.timezone('US/Eastern')
>>> now_eastern = eastern_tz.localize(naive)
>>> print "Now (eastern) is %s" % now_eastern
Now (eastern) is 2012-12-12 10:00:00-05:00
>>> print "Now (utc) is %s" % now_eastern.astimezone(pytz.utc)
Now (utc) is 2012-12-12 15:00:00+00:00
>>> now_eastern_utc_timetuple = now_eastern.utctimetuple()
>>> print "Now (eastern) as timetuple %s" % now_eastern_utc_timetuple
Now (eastern) as timetuple time.struct_time(tm_year=2012, tm_mon=12, tm_mday=12,\
tm_hour=15, tm_min=0, tm_sec=0, tm_wday=2, \
tm_yday=347, tm_isdst=0)
>>> now_epoch = time.mktime(now_eastern_utc_timetuple)
>>> print "now epoch (UTC) %s" % now_epoch
now epoch (UTC) 1355342400.0
>>> print "Converted back: %s" % datetime.datetime.fromtimestamp(now_epoch)
Converted back: 2012-12-12 15:00:00
I'm using:
Mac Os X 10.9.4
Python 2.7
pytz 2012j
So the question is: How can I handle this kind of conversion correctly? Is this issue related to DST?
Thank you in advance.

Shouldn't this be isdst=1 ?
No. You ask an aware datetime object to give you a UTC time tuple. UTC has no DST therefore tm_isdst is always zero.
now_eastern.astimezone(pytz.utc) and now_eastern.utctimetuple() produce the same time. They are correct if now_eastern is correct.
time.mktime(now_eastern_utc_timetuple) is incorrect because mktime() expects local time but now_eastern_utc_timetuple is in UTC. You could use calendar.timegm(now_eastern_utc_timetuple) instead or better now_eastern.timestamp(), see Converting datetime.date to UTC timestamp in Python.
I would use: now_eastern = eastern_tz.localize(naive, is_dst=None) (assuming naive represents time in 'US/Eastern' i.e., assuming your local timezone is 'US/Eastern', you could use tzlocal.get_localzone() to get the local timezone automatically) <- raise an exception instead of returning a wrong answer or better: now_eastern = datetime.now(eastern).

Related

convert python's time.ctime() to unix time stamp

I am trying to convert the current time ('Wed Sep 6 15:31:35 2017') that returns Python3.5 to Unix time stamp.
time.ctime.astype(np.int64)
I am getting this error:
AttributeError: 'builtin_function_or_method' object has no attribute 'astype'
when I try
np.int64(time.ctime())
I get:
ValueError: invalid literal for int() with base 10: 'Wed Sep 6 15:34:08 2017'
time.ctime() returns a string representation of the time
use strptime from module datetime to parse string to a datetime object
import datetime
import time
t = datetime.datetime.strptime(time.ctime(), "%a %b %d %H:%M:%S %Y")
print(t.timestamp()) #1504730409.0
https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior
time.ctime() returns a string representation of the current time, as returned (in seconds since the epoch) by time.time().
You can cut out the middleman and use time.time() on its own, which returns a floating point representation of the seconds:
t = int(time.time())
You can do it more easily this way:
import time
math.floor(time.time())

parsing of seconds and millisecond using python

I have time stamp in format of "10:24:00.744" I want to fetch the seconds value (here -- 00) and millisecond value (here -- 744) in different variables using python. Hope someone can help me with this.
You can use datetime.datetime module to parse the time, and then get the seconds and milliseconds from it -
>>> from datetime import datetime
>>> h = datetime.strptime('10:24:00.744','%H:%M:%S.%f')
>>> seconds = h.second
>>> milliseconds = h.microsecond/1000
>>> print(seconds)
0
>>> print(milliseconds)
744.0
strptime() function is used to parse datetime from string, the directives mean -
%H - Hour
%M - Minutes
%S - Seconds
%f - Microseconds
More details about support directives can be found here.
Try the following:
a = "10:24:00.744"
seconds = a[6:8]
milliseconds = a[9:]
print "Seconds", seconds
print "Milliseconds", milliseconds
You will get the following output:
Seconds '00'
Milliseconds '744'

How to convert epoch time with nanoseconds to human-readable?

I have a timestamp in epoch time with nanoseconds - e.g. 1360287003083988472 nanoseconds since 1970-01-01.
The Python datetime objects and conversion methods only support up to millisecond precision.
Is there an easy way to convert this epoch time into human-readable time?
First, convert it to a datetime object with second precision (floored, not rounded):
>>> from datetime import datetime
>>> dt = datetime.fromtimestamp(1360287003083988472 // 1000000000)
>>> dt
datetime.datetime(2013, 2, 7, 17, 30, 3)
Then to make it human-readable, use the strftime() method on the object you get back:
>>> s = dt.strftime('%Y-%m-%d %H:%M:%S')
>>> s
'2013-02-07 17:30:03'
Finally, add back in the nanosecond precision:
>>> s += '.' + str(int(1360287003083988472 % 1000000000)).zfill(9)
>>> s
'2013-02-07 17:30:03.083988472'
Actually, Python's datetime methods handle microsecond precision, not millisecond:
>>> nanos = 1360287003083988472
>>> secs = nanos / 1e9
>>> dt = datetime.datetime.fromtimestamp(secs)
>>> dt.strftime('%Y-%m-%dT%H:%M:%S.%f')
'2013-02-07T17:30:03.083988'
But if you actually need nanoseconds, that still doesn't help. Your best bet is to write your own wrapper:
def format_my_nanos(nanos):
dt = datetime.datetime.fromtimestamp(nanos / 1e9)
return '{}{:03.0f}'.format(dt.strftime('%Y-%m-%dT%H:%M:%S.%f'), nanos % 1e3)
This gives me:
'2013-02-07T17:30:03.083988472'
Of course you could have done the same thing even if Python didn't do sub-second precision at all…
def format_my_nanos(nanos):
dt = datetime.datetime.fromtimestamp(nanos / 1e9)
return '{}.{:09.0f}'.format(dt.strftime('%Y-%m-%dT%H:%M:%S'), nanos % 1e9)

Converting an ambigious time to a correct local time with Python

I'm wrestling with what appears to be a common timezone issue in Python, but have not been able to solve it or find the exact issue I'm running into here on SO, so I pose the question below.
I have a timetuple that does not have a timezone set. I also have a timezone. And I have the computer in a different timezone. How do I convert the time to the local time taking DST into account?
>>> type(dt.value)
<type 'datetime.datetime'>
>>> print dt.timetuple()
time.struct_time(tm_year=2012, tm_mon=6, tm_mday=28, ..., tm_isdst=-1)
>>> print somezone.zone
America/New_York
If I add the zone info to dt as follows, DST isn't handled properly... tm_isdst always shows up as zero, regardless of the month being in DST or not.
dt.value = dt.value.replace(tzinfo=somezone)
>>> print dt.timetuple()
time.struct_time(tm_year=2012, tm_mon=6, tm_mday=28, ..., tm_isdst=0)
Use the pytz library. It will let you easily do this.
from pytz import timezone
zone_tz = timezone(zone)
zone_aware_dt = zone_tz.localize(dt)
local_tz = timezone("America/Los_Angeles")
local_dt = local_tz.normalize(zone_aware_dt)

Using %f with strftime() in Python to get microseconds

I'm trying to use strftime() to microsecond precision, which seems possible using %f (as stated here). However when I try the following code:
import time
import strftime from time
print strftime("%H:%M:%S.%f")
...I get the hour, the minutes and the seconds, but %f prints as %f, with no sign of the microseconds. I'm running Python 2.6.5 on Ubuntu, so it should be fine and %f should be supported (it's supported for 2.6 and above, as far as I know.)
You can use datetime's strftime function to get this. The problem is that time's strftime accepts a timetuple that does not carry microsecond information.
from datetime import datetime
datetime.now().strftime("%H:%M:%S.%f")
Should do the trick!
You are looking at the wrong documentation. The time module has different documentation.
You can use the datetime module strftime like this:
>>> from datetime import datetime
>>>
>>> now = datetime.now()
>>> now.strftime("%H:%M:%S.%f")
'12:19:40.948000'
With Python's time module you can't get microseconds with %f.
For those who still want to go with time module only, here is a workaround:
now = time.time()
mlsec = repr(now).split('.')[1][:3]
print time.strftime("%Y-%m-%d %H:%M:%S.{} %Z".format(mlsec), time.localtime(now))
You should get something like 2017-01-16 16:42:34.625 EET (yes, I use milliseconds as it's fairly enough).
To break the code into details, paste the below code into a Python console:
import time
# Get current timestamp
now = time.time()
# Debug now
now
print now
type(now)
# Debug strf time
struct_now = time.localtime(now)
print struct_now
type(struct_now)
# Print nicely formatted date
print time.strftime("%Y-%m-%d %H:%M:%S %Z", struct_now)
# Get miliseconds
mlsec = repr(now).split('.')[1][:3]
print mlsec
# Get your required timestamp string
timestamp = time.strftime("%Y-%m-%d %H:%M:%S.{} %Z".format(mlsec), struct_now)
print timestamp
For clarification purposes, I also paste my Python 2.7.12 result here:
>>> import time
>>> # get current timestamp
... now = time.time()
>>> # debug now
... now
1484578293.519106
>>> print now
1484578293.52
>>> type(now)
<type 'float'>
>>> # debug strf time
... struct_now = time.localtime(now)
>>> print struct_now
time.struct_time(tm_year=2017, tm_mon=1, tm_mday=16, tm_hour=16, tm_min=51, tm_sec=33, tm_wday=0, tm_yday=16, tm_isdst=0)
>>> type(struct_now)
<type 'time.struct_time'>
>>> # print nicely formatted date
... print time.strftime("%Y-%m-%d %H:%M:%S %Z", struct_now)
2017-01-16 16:51:33 EET
>>> # get miliseconds
... mlsec = repr(now).split('.')[1][:3]
>>> print mlsec
519
>>> # get your required timestamp string
... timestamp = time.strftime("%Y-%m-%d %H:%M:%S.{} %Z".format(mlsec), struct_now)
>>> print timestamp
2017-01-16 16:51:33.519 EET
>>>
This should do the work
import datetime
datetime.datetime.now().strftime("%H:%M:%S.%f")
It will print
HH:MM:SS.microseconds like this e.g 14:38:19.425961
You can also get microsecond precision from the time module using its time() function.
(time.time() returns the time in seconds since epoch. Its fractional part is the time in microseconds, which is what you want.)
>>> from time import time
>>> time()
... 1310554308.287459 # the fractional part is what you want.
# comparision with strftime -
>>> from datetime import datetime
>>> from time import time
>>> datetime.now().strftime("%f"), time()
... ('287389', 1310554310.287459)
When the "%f" for micro seconds isn't working, please use the following method:
import datetime
def getTimeStamp():
dt = datetime.datetime.now()
return dt.strftime("%Y%j%H%M%S") + str(dt.microsecond)
If you want an integer, try this code:
import datetime
print(datetime.datetime.now().strftime("%s%f")[:13])
Output:
1545474382803
If you want speed, try this:
def _timestamp(prec=0):
t = time.time()
s = time.strftime("%H:%M:%S", time.localtime(t))
if prec > 0:
s += ("%.9f" % (t % 1,))[1:2+prec]
return s
Where prec is precision -- how many decimal places you want.
Please note that the function does not have issues with leading zeros in fractional part like some other solutions presented here.

Categories