How do you convert a Python time.struct_time object into a datetime.datetime object?
I have a library that provides the first one and a second library that wants the second one.
Use time.mktime() to convert the time tuple (in localtime) into seconds since the Epoch, then use datetime.fromtimestamp() to get the datetime object.
from datetime import datetime
from time import mktime
dt = datetime.fromtimestamp(mktime(struct))
tm_isdst data? I think so, the resulting datetime object remains naive to the extent to return None on .dst() even if struct.tm_isdst is 1.mktime() should take tm_isdst into account and Python time.mktime() calls C mktime() function on CPython. mktime() may choose the wrong local time when it is ambiguous (e.g., during end-of-DST ("fall back") transition) if struct.tm_isdst is -1 or if mktime() on the given platform ignores the input tm_isdst. Also, if the local timezone had different utc offset in the past and C mktime() does not use a historical tz database that can provide the old utc offset values then mktime() may return a wrong (e.g., by an hour) value too.mktime() doesn't ignore tm_isdst on the given platform (it does on mine) then fromtimestamp() definitely looses the info: the returned naive datetime object representing local time may be ambiguous (timestamp -> local time is deterministic (if we ignore leap seconds) but local time -> timestamp may be ambiguous e.g., during end-of-DST transition). Also, fromtimestamp()` may choose a wrong utc offset if the it doesn't use a historical tz database.Like this:
import time, datetime
st = time.localtime()
dt = datetime.datetime(*st[:6])
print(dt)
which prints 2009-11-08 20:32:35.
Update: if you want to include any timezone information from the struct_time value, you could use this method:
def datetime_of_struct_time(st: time.struct_time) -> datetime.datetime:
"Convert a struct_time to datetime maintaining timezone information when present"
tz = None
if st.tm_gmtoff is not None:
tz = datetime.timezone(datetime.timedelta(seconds=st.tm_gmtoff))
# datetime doesn't like leap seconds so just truncate to 59 seconds
if st.tm_sec in {60, 61}:
return datetime.datetime(*st[:5], 59, tzinfo=tz)
return datetime.datetime(*st[:6], tzinfo=tz)
Which could be used with the struct_time value from above:
print(datetime_of_struct_time(st))
printing 2009-11-08 20:32:35-04:00.
* and ** syntax allows you to expand a listy or dicty type object in to separate arguments - it's one of my favourite pieces of Python lovelyness. See docs.python.org/2/tutorial/… for more infot=time.strptime("30 Jun 1997 22:59:60", "%d %b %Y %H:%M:%S"); datetime.datetime(*t[:6])datetime: datetime(*t[:5]+(min(t[5], 59),)) e.g., to accept "2015-06-30 16:59:60 PDT".This is not a direct answer to your question (which was answered pretty well already). However, having had times bite me on the fundament several times, I cannot stress enough that it would behoove you to look closely at what your time.struct_time object is providing, vs. what other time fields may have.
Assuming you have both a time.struct_time object, and some other date/time string, compare the two, and be sure you are not losing data and inadvertently creating a naive datetime object, when you can do otherwise.
For example, the excellent feedparser module will return a "published" field and may return a time.struct_time object in its "published_parsed" field:
time.struct_time(
tm_year=2013, tm_mon=9, tm_mday=9,
tm_hour=23, tm_min=57, tm_sec=42,
tm_wday=0, tm_yday=252, tm_isdst=0,
)
Now note what you actually get with the "published" field.
Mon, 09 Sep 2013 19:57:42 -0400
By Stallman's Beard! Timezone information!
In this case, the lazy man might want to use the excellent dateutil module to keep the timezone information:
from dateutil import parser
dt = parser.parse(entry["published"])
print "published", entry["published"])
print "dt", dt
print "utcoffset", dt.utcoffset()
print "tzinfo", dt.tzinfo
print "dst", dt.dst()
which gives us:
published Mon, 09 Sep 2013 19:57:42 -0400
dt 2013-09-09 19:57:42-04:00
utcoffset -1 day, 20:00:00
tzinfo tzoffset(None, -14400)
dst 0:00:00
One could then use the timezone-aware datetime object to normalize all time to UTC or whatever you think is awesome.
*_parsed fields from feedparsed are already normalized to UTC as can be checked in the date parsing documentation so this is redundant.datetime object which is lost when feedparser parses raw string dates.