U
Ulrich Eckhardt
Hi!
I'm trying to create a struct_time that is e.g. one year ahead or a
month back in order to test some parsing/formatting code with different
dates.
Now, the straightforward approach is
t = time.localtime()
t.tm_year += 1
This fails with "TypeError: readonly attribute". This kind-of makes
sense, as an immutable object allows you to use it as key in a dict.
The second approach is this:
l = list(t) # convert to a sequence
l[0] += 1 # increment year
t = time.struct_time(l) # convert to a struct_time
This works but is ugly, because the code relies on the order inside the
list and uses magic numbers to access them. The order is AFAICT not
accessible programmatically but only documented, and not even in a way
that makes clear that it is part of the API and as such actualy
guaranteed. I could try to assert that the indices match using "if l[0]
is t.tm_year", but this is still ugly.
The next approach I tried was to simply create a derived class:
class my_time(time.struct_time):
pass
This fails again with "TypeError: Error when calling the metaclass
bases, type 'time.struct_time' is not an acceptable base type. I could
try to encapsulate a struct_time and delegate attribute access to it in
order to do this, but it also seems overkill. Also, using an immutable
type as a baseclass and delegating access to members seems like hackery
to me, prone to fail in situations where it is least expected.
Then I tried duck typing. If it quacks like a duck, it better not be a
crocodile! This looks like this:
struct my_time(object): pass
t = my_time()
t.tm_year = 2012
t.tm_month = 12
t.tm... # other fields accordingly
time.mktime(t)
This fails with "TypeError: argument must be 9-item sequence, not
my_time". I thought about using a collections.namedtuple, because a
namedtuple is a tuple and therefore also a sequence, but that only leads
me back to the problem that time.mktime() takes a sequence and the order
of the sequence is not accessible programmatically.
A last approach was to convert the thing to a dict and back. Alas, there
is no conversion to a dict, otherwise
d = dict(t)
d['tm_year'] += 1
t = time.struct_time(d)
would have been a straightforward approach.
Does anyone have a suggestion how to solve this elegantly and
pythonically? Also, what I'm wondering is if the lack of a clear way
should be considered a bug or not.
Cheers!
Uli
I'm trying to create a struct_time that is e.g. one year ahead or a
month back in order to test some parsing/formatting code with different
dates.
Now, the straightforward approach is
t = time.localtime()
t.tm_year += 1
This fails with "TypeError: readonly attribute". This kind-of makes
sense, as an immutable object allows you to use it as key in a dict.
The second approach is this:
l = list(t) # convert to a sequence
l[0] += 1 # increment year
t = time.struct_time(l) # convert to a struct_time
This works but is ugly, because the code relies on the order inside the
list and uses magic numbers to access them. The order is AFAICT not
accessible programmatically but only documented, and not even in a way
that makes clear that it is part of the API and as such actualy
guaranteed. I could try to assert that the indices match using "if l[0]
is t.tm_year", but this is still ugly.
The next approach I tried was to simply create a derived class:
class my_time(time.struct_time):
pass
This fails again with "TypeError: Error when calling the metaclass
bases, type 'time.struct_time' is not an acceptable base type. I could
try to encapsulate a struct_time and delegate attribute access to it in
order to do this, but it also seems overkill. Also, using an immutable
type as a baseclass and delegating access to members seems like hackery
to me, prone to fail in situations where it is least expected.
Then I tried duck typing. If it quacks like a duck, it better not be a
crocodile! This looks like this:
struct my_time(object): pass
t = my_time()
t.tm_year = 2012
t.tm_month = 12
t.tm... # other fields accordingly
time.mktime(t)
This fails with "TypeError: argument must be 9-item sequence, not
my_time". I thought about using a collections.namedtuple, because a
namedtuple is a tuple and therefore also a sequence, but that only leads
me back to the problem that time.mktime() takes a sequence and the order
of the sequence is not accessible programmatically.
A last approach was to convert the thing to a dict and back. Alas, there
is no conversion to a dict, otherwise
d = dict(t)
d['tm_year'] += 1
t = time.struct_time(d)
would have been a straightforward approach.
Does anyone have a suggestion how to solve this elegantly and
pythonically? Also, what I'm wondering is if the lack of a clear way
should be considered a bug or not.
Cheers!
Uli