Python forum for Python programmers

Modifying a time.struct_time

Dec 16, 2011 9:45 am
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

Dec 16, 2011 10:32 am
Mazen Harake
Re: modifying a time.struct_time

Hi,

Easiest way is to change the time to seconds, add as many seconds as a
year/month/week/day/hour/minutes represent and then transform it back.

E.g.

>>> time.time()
1324031491.026137
>>> time.time() + 3600 # Add an hour
1324035105.082003
>>> time.gmtime(time.time() + 3600)
time.struct_time(tm_year=2011, tm_mon=12, tm_mday=16, tm_hour=11,
tm_min=31, tm_sec=57, tm_wday=4, tm_yday=350, tm_isdst=0)
>>>

On 16 December 2011 10:45, Ulrich Eckhardt
<ulrich.eckhardt@dominolaser.com> wrote:
> 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
>
> --
> http://mail.python.org/mailman/listinfo/python-list


Dec 16, 2011 10:44 am
Steven D'Aprano
Re: modifying a time.struct_time

On Fri, 16 Dec 2011 10:45:22 +0100, Ulrich Eckhardt wrote:

> 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.
[...]
> 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.

Feel free to propose a feature enhancement to time.struct_time, but the
order of the fields is stable and won't change. So ugly or not, that way
is guaranteed to work.


[...]
> 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

"struct"?


[...]
> 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.

Not a bug, but it does seem a very old and inelegant API more suited to
hairy C programmers gathered around a smokey fire in a cave chewing on
old dinosaur bones, and not worthy of space-age Python coders flying
around on anti-gravity belts.



Steven
Dec 16, 2011 10:44 am
Chris Angelico
Re: modifying a time.struct_time

On Fri, Dec 16, 2011 at 8:45 PM, Ulrich Eckhardt
<ulrich.eckhardt@dominolaser.com> wrote:
> 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.

Do you need it to be one exact calendar year, or would it make sense
to add/subtract integers from a Unix time?

t = time.time() + 365*86400 # Not actually a year ahead, it's 365 days ahead
t = time.localtime(t) # if you want a struct_time

ChrisA




Previous Thread: Class: @property -> .__dict__
Next Thread: Merging argparse parsers

Related Forum Topics
PyHook and time libraries
Hey, I'm tring to create a software that records the keyboard/mouse and sends email of the log every predetermined period.

I've manage to make the recorder and the auto-email sender, but I still can't make both of them work simultaneously.

Can someone help me with this please?
I thought...
Problem with eval and time
Dear all, I would like to convert tstr to representation of time, but encounter the following error. Is there a simple way to get what I want? Thanks.

>>> import time
>>> tstr = str(time.localtime())
>>> eval(tstr)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
...
Average time calculation??
Hi there guys i've got a script that's suppose to find the average of two times as strings. The times are in minutes:seconds:milliseconds
i'm doing ok in printing the right minutes and seconds my problem is with the milliseconds.

Example if i have 00:02:20 and 00:04:40 the average will be...
Real time event accuracy
I'd like to send MIDI events from python to another
program. I'd like advice as to how to accurately
time the events. I'll have a list of floating point
start times in seconds for the events, and I'd like to send them
off as close to the correct time as possible.

I'd also appreciate...
Limited time offer, so hurry up!
Take advantage of Smart Baba new offer and get your own customized
professional website and promote your business. For further details,
Follow us:

www.websitedeals.in


Accessing the files by last modified time
Hi

I am new to the python programming language.

I've been trying to write a script that would access the last modified file in one of my directories. I'm using Win XP.

I saw a similar topic, on the forum before, however the reply using (os.popen) didn't work out for me. I'm not sure...
Why does dead code costs time?
Hi,

I'm interested in compilers optimizations, so I study python compilation process

I ran that script:

import timeit

def f(x):
return None

def g(x):
return None
print(x)

number = 10000

print(timeit.timeit('f(1)',setup="from...
An object is and isn't an instance of a class at the same time
I was debugging some code using isinstance() to make sure the correct object was been passed to the method and came across something that is really ticking me off.

I have a class called 'Jitem' in its own file called 'jitem.py'. It's part of a package called 'jukebox'. I also have '__all__'...
PyWarts: time, datetime, and calendar modules
The interface for these modules is not intuitive. Instead of creating
true OOP objects we have lists and strings. Any calendar object should
expose string names of both: days of the week and months of the year.
It seems one (or possibly more) of the three expose this important
info however i...
Date-time comparison, aware vs naive
I want to compare a user entered date-and-time against the date-and-time of a pdf file. I posted on this (how to get a file's date-time) before, was advised to do it like:

import datetime, os, stat
mtime = os.lstat(filename)[stat.ST_MTIME] // the files modification time
dt =...