How do you build non overlapping timestamp range in Python with dynamic interval using a start and end date?

Viewed 25

I'm working on building some multithreaded api calls that requires passing in a first start timestamp followed by a period count. For example, the following parameters: ('2022-09-05 10:00:00.000000', 7) would indicate starting the api at hour 10:00 and would pull 7 hours of data back up to but not including hour 17:00.

Full time periods in the api are also always evaluated. Even if the first time does not coincide with the beginning of a period, all of the data for the period which contains time first will be used.

Ultimately, I'm trying to build a list of tuples with chunked parameters that do not overlap but cover the full range of a start and end timestamp. There can't be any duplicates, overlaps, or excessive hours included.

So far I've come up with this:

from datetime import date, datetime, timedelta

def build_params(start, end, delta, num):
    pattern = "%Y-%m-%d %H:%M:%S.%f"
    start_dt = datetime.strptime(start, pattern)
    end_dt = datetime.strptime(end, pattern)
    curr = start_dt
    l = []
    while curr <= end_dt:
        l.append((datetime.strftime(curr, pattern), num))
        curr += delta
    return l

I'm currently struggling on how to edit num to get the right final num value for the last item in the list. I have noticed there is a nuance I haven't pinned down related to the num value and the start and end timestamps.

I'm testing using:

start = "2022-09-05 10:00:00.000000"
end = "2022-09-06 16:00:00.000000"

start = "2022-09-05 10:00:00.000000"
end = "2022-09-06 16:59:59.999999"

start = "2022-09-05 10:59:59.999999"
end = "2022-09-06 16:00:00.000000"

num = 7
delta = timedelta(hours=num)
l = build_params(start, end, delta, num)
for i in l:
    print(i)

I've tried something like this but keep getting incorrect values even when adjusting the logic. I'm missing something simple but I'm not seeing it:

from datetime import date, datetime, timedelta
import math

def build_params(start, end, delta, num):
    pattern = "%Y-%m-%d %H:%M:%S.%f"
    start_dt = datetime.strptime(start, pattern)
    end_dt = datetime.strptime(end, pattern)
    curr = start_dt
    l = []
    while curr <= end_dt:
        future = curr + delta
        if future > end_dt:
            diff = end_dt - curr
            diff_hours = diff.total_seconds()/3600
            num = math.ceil(diff_hours)
        l.append((datetime.strftime(curr, pattern), num))
        curr += delta
    return l

Final list would look something like this but would work for all num variables and start and end timestamps:

start = "2022-09-05 10:00:00.000000"
end = "2022-09-06 16:00:00.000000"
num = 7

('2022-09-05 10:00:00.000000', 7)
('2022-09-05 17:00:00.000000', 7)
('2022-09-06 00:00:00.000000', 7)
('2022-09-06 07:00:00.000000', 7)
('2022-09-06 14:00:00.000000', 3)
1 Answers

This works but I wish it was a bit more elegant.

def build_params(start, end, delta, num):
    pattern = "%Y-%m-%d %H:%M:%S.%f"
    start_dt = datetime.strptime(start, pattern)
    end_dt = datetime.strptime(end, pattern)
    curr = start_dt
    l = []
    while curr <= end_dt:
        future = curr + delta
        if future > end_dt:
            diff = end_dt - curr
            diff_hours = diff.total_seconds()/3600
            num_rounded = math.ceil(diff_hours)
            adjusted_curr = curr - timedelta(hours=1)
            forecasted = adjusted_curr + timedelta(hours=(num_rounded))
            forecasted_diff = end_dt - forecasted
            if forecasted_diff.total_seconds()/3600 < 1:
                if num_rounded != 0:
                    num = num_rounded
                else:
                    num = 1
            if forecasted_diff.total_seconds()/3600 == 1:
                num = num_rounded + 1
        l.append((datetime.strftime(curr, pattern), num))
        curr += delta
    return l
Related