Skip to content Skip to sidebar Skip to footer

Python Generator To Return Series Of Times

I hope this is not outside of the abilities of Python generators, but I'd like to build one so that every time the function is called, it returns the next minute up until the end t

Solution 1:

The datetime module is quite awesome. There are two datatypes you need to know about: datetime and timedelta. datetime is a point in time, while timedelta is a period of time. Basically, what I'm going to do here is start at a time and end at a time (as a datetime object), and progressively add 1 minute.

This obviously has the caveat that you have to figure out how to get your start and end time into a datetime. There are a number of ways to do this: through the constructor, right now, from UTC timestamp, etc.

import datetime

def minute_range(start, end, step=1):
   cur = start
   while cur < end:
      yield cur
      cur += datetime.timedelta(minutes=step)

Solution 2:

Just because fewer lines of code is always better (tm):

def minutes(s, e):
    secs = (e - s).seconds 
    return(s + datetime.timedelta(minutes = x)for x in xrange(secs / 60 + 1))

Use it like this:

>>>today = datetime.datetime(2012, 1, 31, 15, 20)>>>for m in minutes(today, today + datetime.timedelta(minutes = 5)):...print m
2012-01-31 15:20:00
2012-01-31 15:21:00
2012-01-31 15:22:00
2012-01-31 15:23:00
2012-01-31 15:24:00
2012-01-31 15:25:00

Solution 3:

Here is generator I use for this purpose. It could be enhanced to stop after some time, or you could keep that logic in your calling code, or in some other iterators arround.

import time

defsleep_gen(period):
    """Generator, returning not sooner, then period seconds since last call.

    returned value: time of next planned start (no need to use this value)
    """
    next_time = 0whileTrue:
        now = time.time()
        sleep_time = max(next_time - now, 0)
        next_time = now + sleep_time + period
        time.sleep(sleep_time)
        yield next_time

You could use following code to test the behaviour

import plac
import time
from itertools import count, izip
import random

#sleep_gen to be defined here@plac.annotations(
    period=      ("planned period for cycling in seconds (default: %(default)s)", "positional", None, float),
    min_duration=("minimal real 'action' duration in seconds (default:%(default)s)", "positional", None, float),
    max_duration=("maximal 'real action' duration in seconds (default:%(default)s)", "positional", None, float),
)    defmain(period = 1.0, min_duration = 0.1, max_duration = 2.0):
    """Tries to start some randomly long action in regular periods"""print"""call with -h for help.
    period      : %(period)f
    min_duration: %(min_duration)f
    max_duration: %(max_duration)f""" % locals()
    try:
        last_time = now = time.time()
        header = (   "%5s|"          +"%14s|"    +"%14s|"           +"%8s|"         +"%8s|"          +"%14s|") % ("cycle", "last_time", "now", "action", "real", "next_time")
        row =    "%(i) 5d|%(last_time)14.2f|%(now)14.2f|%(action_dur)8.3f|%(real_dur)8.3f|%(next_time)14.2f|"print header
        action_dur = real_dur = 0.0for i, next_time in izip(count(), sleep_gen(period)):
            #we care about starting the action on time, not ending
            now = time.time() #sleep_gen just tried to keep the period on schedule
            real_dur = now - last_time
            print row % locals()
            last_time = now
            #performing the "action"
            action_dur = random.random() * (max_duration - min_duration) + min_duration
            time.sleep(action_dur)
    except KeyboardInterrupt:
        print"...cancelled."if __name__ == "__main__":
    plac.call(main)

Calling it from command line:

$ python cycle.py
callwith-h for help.
    period      : 1.000000
    min_duration: 0.100000
    max_duration: 2.000000cycle|     last_time|           now|  action|real|     next_time|0|1337368558.55|1337368558.55|0.000|0.002|1337368559.55|1|1337368558.55|1337368559.59|1.042|1.042|1337368560.59|2|1337368559.59|1337368561.32|1.722|1.723|1337368562.32|3|1337368561.32|1337368562.32|0.686|1.000|1337368563.32|4|1337368562.32|1337368563.32|0.592|1.000|1337368564.32|5|1337368563.32|1337368564.75|1.439|1.439|1337368565.75|6|1337368564.75|1337368566.08|1.323|1.323|1337368567.08|7|1337368566.08|1337368567.08|0.494|0.999|1337368568.08|8|1337368567.08|1337368568.20|1.120|1.121|1337368569.20|9|1337368568.20|1337368569.20|0.572|1.000|1337368570.20|10|1337368569.20|1337368570.20|0.586|1.000|1337368571.20|11|1337368570.20|1337368571.20|0.309|0.999|1337368572.20|12|1337368571.20|1337368572.20|0.290|1.000|1337368573.20|13|1337368572.20|1337368573.25|1.052|1.053|1337368574.25|14|1337368573.25|1337368574.25|0.737|1.000|1337368575.25|15|1337368574.25|1337368575.83|1.579|1.579|1337368576.83|
...cancelled.

Comparing your question with my answer:

  • generator: yes, it is
  • enter start time: I use just the current moment (what could be what one often needs)
  • enter end time: Stop calling the generator at that moment. Or modify generator to loop only some number of loops or end at certain time.

Post a Comment for "Python Generator To Return Series Of Times"