Jguy
Jguy

Reputation: 580

Python find tomorrow's date if time is last in list

I have a program that has functions that run in an interval (example: default is every hour but you can set it from seconds to every 23 hours). This is user settable in a config file. I'm attempting to change the code so that if you input "0" as the interval, it reads the next line of the config file which is a setting poll_times, wherein the user can input a list of times that he wishes a "poll" to be done in full hours. For example, if I set poll_times in the configuration file as such:

poll_times = 16,17,19,20,22,23

The poll would be done at 4pm, 5pm, 7pm, 8pm, 10pm and 11pm every day.

I've nearly got everything down except when it comes to skipping to the next day. Currently the function in question is performing flawlessly if I start the program at anytime before the first poll and it'll run through all the polls until it gets to the last one. Once it hits the last one of the list on any day it'll simply try to keep setting the next_poll to that same hour of that same day, instead of skipping to the next_poll of the next day.

Here's my code:

def set_next_poll_time(self):
    now = datetime.datetime.now()
    next_poll = datetime.datetime(year=now.year, month=now.month, day=now.day)
    next_poll_time = self.next_poll_time
    if self.poll_frequency is 0:
        poll_times = self.poll_times
        LOGGER.info("Poll Times: {0}".format(self.poll_times))
        # Determine what the next poll_time should be
        for hour in poll_times:
            next_poll = datetime.datetime(year=now.year, month=now.month, day=now.day, hour=hour)
            if next_poll == now:  # This is the last time in the sequence, so the next_poll should be tomorrow at the first entry in poll_times
                tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
                next_poll = datetime.datetime(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day, hour=poll_times[0])
                break
            elif next_poll > now:
                break  # Done, return
            else:
                continue
        next_poll_time = time.mktime(next_poll.timetuple())
        LOGGER.info("Next poll: {0}".format(next_poll))
    else:
        poll_minutes = self.poll_frequency / 60
        while next_poll <= now:
            next_poll += datetime.timedelta(minutes=poll_minutes)
            next_poll_time = time.mktime(next_poll.timetuple())
    LOGGER.info("{0} -> {1} {2}".format(self.next_poll_time, next_poll_time, next_poll))
    self.next_poll_time = next_poll_time

this is all in a class so here are some values that are set as part of the class init:

self.next_poll_time = 0
self.poll_times  # directly set from what the user enters in the config file
self.poll_frequency  # directly set from config file 

What this function should do:

  1. If the poll frequency is anything other than 0 then use it to determine what the next time to poll should be based on that interval. Example: if the poll_frequency is 3600, then the next_poll_time should be every hour. This is working as it should.
  2. If the poll_frequency is 0 then determine the next_poll_time based on the list of poll_times. This is working as it should until the last time of the day
  3. If you reach the end of the poll_times list, then skip to the next day and get the first poll_time for the new day and set next_poll_time to that value.

What this function does is get to the end of the list and keeps setting the next_poll_time to the last poll_time of that same day, not the next day as I need it to (and from what I see it is programmed to).

The debug lines give the following outputs. SKIPPING past due poll is the output from the part of the program that calls this function (hence why it just calls the function again and again):

[02-20-2019 21:01:05] INFO, MainThread, - SKIPPING past due poll 1550696400.0.
[02-20-2019 21:01:05] INFO, MainThread, - Poll Times: [16, 17, 19, 20, 21]
[02-20-2019 21:01:05] INFO, MainThread, - Next poll: 2019-02-20 21:00:00
[02-20-2019 21:01:05] INFO, MainThread, - 1550696400.0 -> 1550696400.0 2019-02-20 21:00:00
[02-20-2019 21:01:07] INFO, MainThread, - SKIPPING past due poll 1550696400.0.
[02-20-2019 21:01:07] INFO, MainThread, - Poll Times: [16, 17, 19, 20, 21]
[02-20-2019 21:01:07] INFO, MainThread, - Next poll: 2019-02-20 21:00:00
[02-20-2019 21:01:07] INFO, MainThread, - 1550696400.0 -> 1550696400.0 2019-02-20 21:00:00
[02-20-2019 21:01:08] INFO, MainThread, - SKIPPING past due poll 1550696400.0.
[02-20-2019 21:01:08] INFO, MainThread, - Poll Times: [16, 17, 19, 20, 21]
[02-20-2019 21:01:08] INFO, MainThread, - Next poll: 2019-02-20 21:00:00
[02-20-2019 21:01:08] INFO, MainThread, - 1550696400.0 -> 1550696400.0 2019-02-20 21:00:00
[02-20-2019 21:01:09] INFO, MainThread, - SKIPPING past due poll 1550696400.0.
[02-20-2019 21:01:09] INFO, MainThread, - Poll Times: [16, 17, 19, 20, 21]
[02-20-2019 21:01:09] INFO, MainThread, - Next poll: 2019-02-20 21:00:00
[02-20-2019 21:01:09] INFO, MainThread, - 1550696400.0 -> 1550696400.0 2019-02-20 21:00:00

Thanks for any guidance you can provide.

Upvotes: 1

Views: 120

Answers (2)

Jguy
Jguy

Reputation: 580

With @ferrix's advice I was able to solve this myself. I just needed to tell the code when the hour was the last in the list and put the code to find tomorrow under that. So the for block changes to this:

for hour in poll_times:
  next_poll = datetime.datetime(year=now.year, month=now.month, day=now.day, hour=hour)
  if next_poll <= now:
    if hour == poll_times[-1]:  # This is the last time in the sequence and it still isn't greater than, so skip to next day
     tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
     next_poll = datetime.datetime(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day, hour=poll_times[0])
    else:
      continue
  elif next_poll > now:
    break  # Done, return
  else:
    continue

Upvotes: 0

ferrix
ferrix

Reputation: 761

It seems to me that next_poll == now is not the only condition when tomorrow would have to be considered. Also, datetime accounts for seconds even if you do not set them, so next_poll == now will be True at a very specific second of the day.

Upvotes: 1

Related Questions