pycron icon indicating copy to clipboard operation
pycron copied to clipboard

has been fails oftend if timeframe start and end stemps differ less than a minute.

Open Wissperwind opened this issue 2 years ago • 5 comments

from datetime import datetime

import pycron

if __name__ == "__main__":

    start_as_string = "2022-12-02 16:32:57.382138"
    end_as_string = "2022-12-02 16:33:01.459094"

    format = "%Y-%m-%d %H:%M:%S.%f"

    start_time = datetime.strptime(start_as_string, format)
    end_time = datetime.strptime(end_as_string, format)

    cron_expression = "15,33,59 * * * *"


    print(pycron.has_been(cron_expression, start_time, dt=end_time))

-> Returns False

This is a bug, right? It shall return true because minute 33 is in the time window (16:33:01.459094) Why does it return False?

Wissperwind avatar Dec 05 '22 09:12 Wissperwind

My idea: Iterate over seconds

def has_been(s, since, dt=None):
    if dt is None:
        dt = datetime.now(tz=since.tzinfo)

    if dt < since:
        raise ValueError("The since datetime must be before the current datetime.")

    while since <= dt:
        if pycron.is_now(s, since):
            return True
        since += timedelta(seconds=1)

    return False

Wissperwind avatar Dec 05 '22 10:12 Wissperwind

But with this implementation

    start_as_string = "2022-12-02 16:32:59.999999"
    end_as_string = "2022-12-02 16:33:00.00001"

Would still return false.

Wissperwind avatar Dec 05 '22 10:12 Wissperwind

How about that?

# own implementation of has been, that respects seconds.
def has_been(s, since, dt=None):
    if dt is None:
        dt = datetime.now(tz=since.tzinfo)

    if dt < since:
        raise ValueError("The since datetime must be before the current datetime.")

    while since <= dt:
        if pycron.is_now(s, since):
            return True

        if (dt-since).total_seconds() < 1:
            since = dt
        else:
            since += timedelta(seconds=1)


    return False

It also works in case of:

    start_as_string = "2022-12-02 16:32:59.999999"
    end_as_string = "2022-12-02 16:33:00.00001"

Wissperwind avatar Dec 05 '22 10:12 Wissperwind

Ok, that can lead to infinite looping :(

Wissperwind avatar Dec 05 '22 12:12 Wissperwind

testing now this:

# own implementation of has been, that respects seconds.
def has_been(s, since, dt=None):
    if dt is None:
        dt = datetime.now(tz=since.tzinfo)

    if dt < since:
        raise ValueError("The since datetime must be before the current datetime.")

    while since <= dt:
        if pycron.is_now(s, since):
            return True

        if (dt-since).total_seconds() < 1:
            since = dt
            if pycron.is_now(s, since):
                return True
            else:
                return False
        else:
            since += timedelta(seconds=1)


    return False

Wissperwind avatar Dec 05 '22 12:12 Wissperwind