How to *change* a struct_time object?
Question:
When dealing with times and dates in python, you will stumble across the time.struct_time object:
st = time.strptime("23.10.2012", "%d.%m.%Y")
print st
time.struct_time(tm_year=2012, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
Now as this struct does not support item assignment (i.e. you cannot do something like st[1]+=1
) how else is it possible to increase, say, the number of the month.
Solutions suggest to convert this time_struct into seconds and add the corresponding number of seconds, but this does not look nice. You also need to know how many days are in a month, or if the year is a leap year or not. I want an easy way to obtain a time_struct to be e.g.
time.struct_time(tm_year=2012, tm_mon=11, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
with just the month increased by one. Creating a time_struct
from scratch would be fine—but how? What ways are there?
Answers:
Use the datetime
module instead, which has a far richer set of objects to handle date(time) arithmetic:
import datetime
adate = datetime.datetime.strptime("23.10.2012", "%d.%m.%Y").date()
adate + datetime.timedelta(days=30)
You can use the excellent python-dateutil
add-on module to get an ever richer set of options for dealing with deltas:
from dateutil.relativedelta import relativedelta
adate + relativedelta(months=1)
relativedelta
knows about leap years, month lengths, etc. and will do the right thing when adding a month to, say, January 30th (you end up with February 28th or 29th, it won’t cross month boundaries).
You can first convert it to datetime, then add a timedelta offset to it:
from time import mktime
from datetime import datetime
dt = datetime.fromtimestamp(mktime(struct))
timedelta = datetime.timedelta(seconds=10)
dt = dt + timedelta
References:
So… the schema for the tuple underlying time_struct is given in the documentation here:
http://docs.python.org/2/library/time.html#time.struct_time
And even though it’s read-only as a time_struct, you can use casting to list() to get at that tuple directly (remembering to wrap-around your month after you increment it, and keep the end range in 1-12 rather than 0-11). Then the time.struct_time()
function will convert a valid 9-tuple back into a time_struct:
st = time.strptime("23.10.2012", "%d.%m.%Y")
st_writable = list(st)
st_writable[1] = (st_writable[1] + 1)%12 + 1
st = time.struct_time(tuple(st_writable))
If you want to avoid datetime all together and stick with time, you can convert to unix timestamp and then subtract the number of seconds you need. To get a time object for 24 hours ago:
time.gmtime(time.mktime(time.gmtime()) - 86400)
However, as OP pointed out this is not good for working with months and should be reserved for seconds, hours, and days.
This question of the OP seems to be still unanswered:
Creating a time_struct
from scratch would be fine—but how?
It can be done without importing any extra modules, but at the cost of taking an indirect and less efficient route:
def new_date( y, m, d ):
return time.strptime(
str(y) + str(m).rjust(2,'0') + str(d).rjust(2,'0'), "%Y%m%d" );
or use use str.format()
for brevity:
def new_date( y, m, d ):
return time.strptime( "{0}{1:0>2}{2:0>2}".format(y, m, d), "%Y%m%d");
It is indeed starge that the module implementing a type has not provided a direct means of creating instances of that type…
When dealing with times and dates in python, you will stumble across the time.struct_time object:
st = time.strptime("23.10.2012", "%d.%m.%Y")
print st
time.struct_time(tm_year=2012, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
Now as this struct does not support item assignment (i.e. you cannot do something like st[1]+=1
) how else is it possible to increase, say, the number of the month.
Solutions suggest to convert this time_struct into seconds and add the corresponding number of seconds, but this does not look nice. You also need to know how many days are in a month, or if the year is a leap year or not. I want an easy way to obtain a time_struct to be e.g.
time.struct_time(tm_year=2012, tm_mon=11, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
with just the month increased by one. Creating a time_struct
from scratch would be fine—but how? What ways are there?
Use the datetime
module instead, which has a far richer set of objects to handle date(time) arithmetic:
import datetime
adate = datetime.datetime.strptime("23.10.2012", "%d.%m.%Y").date()
adate + datetime.timedelta(days=30)
You can use the excellent python-dateutil
add-on module to get an ever richer set of options for dealing with deltas:
from dateutil.relativedelta import relativedelta
adate + relativedelta(months=1)
relativedelta
knows about leap years, month lengths, etc. and will do the right thing when adding a month to, say, January 30th (you end up with February 28th or 29th, it won’t cross month boundaries).
You can first convert it to datetime, then add a timedelta offset to it:
from time import mktime
from datetime import datetime
dt = datetime.fromtimestamp(mktime(struct))
timedelta = datetime.timedelta(seconds=10)
dt = dt + timedelta
References:
So… the schema for the tuple underlying time_struct is given in the documentation here:
http://docs.python.org/2/library/time.html#time.struct_time
And even though it’s read-only as a time_struct, you can use casting to list() to get at that tuple directly (remembering to wrap-around your month after you increment it, and keep the end range in 1-12 rather than 0-11). Then the time.struct_time()
function will convert a valid 9-tuple back into a time_struct:
st = time.strptime("23.10.2012", "%d.%m.%Y")
st_writable = list(st)
st_writable[1] = (st_writable[1] + 1)%12 + 1
st = time.struct_time(tuple(st_writable))
If you want to avoid datetime all together and stick with time, you can convert to unix timestamp and then subtract the number of seconds you need. To get a time object for 24 hours ago:
time.gmtime(time.mktime(time.gmtime()) - 86400)
However, as OP pointed out this is not good for working with months and should be reserved for seconds, hours, and days.
This question of the OP seems to be still unanswered:
Creating a
time_struct
from scratch would be fine—but how?
It can be done without importing any extra modules, but at the cost of taking an indirect and less efficient route:
def new_date( y, m, d ):
return time.strptime(
str(y) + str(m).rjust(2,'0') + str(d).rjust(2,'0'), "%Y%m%d" );
or use use str.format()
for brevity:
def new_date( y, m, d ):
return time.strptime( "{0}{1:0>2}{2:0>2}".format(y, m, d), "%Y%m%d");
It is indeed starge that the module implementing a type has not provided a direct means of creating instances of that type…