pythondatetimeconditional-statementstimedeltaweekday

Trying to create a list of random times within specific date/time conditions


I am trying to modify this GitHub code for my own purposes in the title:

import random
from datetime import datetime, timedelta

min_year=1900
max_year=datetime.now().year

start = datetime(min_year, 1, 1, 00, 00, 00)
years = max_year - min_year+1
end = start + timedelta(days=365 * years)

for i in range(10):
    random_date = start + (end - start) * random.random()
    print(random_date)

My desired outcome specifically is, for all weekdays (Mon. - Fri.) April 1st, 2023 until July 31st, 2023 print two times (hh:mm:ss) which meet the following conditions:

I came up with this before remembering I need to add the two per weekday and hour-apart constraint in somewhere:

import random
from datetime import datetime, timedelta

start = datetime(2023, 4, 1, 00, 00, 00)
end = start + timedelta(days=160)

for i in range(10):
    random_date = start + (end - start) * random.random()
    no = random_date.weekday()
    if no < 5:
      print(random_date)

I'll be continuing to work on it, but if anyone has any advice I'd greatly appreciate it! Am fairly new to programming


Solution

  • You can create the time ranges dynamically (guarantees a O(N) runtime where N is the number of days).

    Based on your example, the start time must be from [8 AM, 5 PM]; the end time must be [start + 1h, 6 PM].

    from collections import namedtuple
    from datetime import date, timedelta, datetime
    from random import randint
    
    # Python built-in times are easy to mess up; work with "second tuples"
    SimpleTime = namedtuple("SimpleTime", "hh mm ss")
    
    def timetuple_to_seconds(time_tuple: SimpleTime) -> int:
      return (time_tuple[0] * 60 + time_tuple[1]) * 60 + time_tuple[2]
    
    def combine_timestamp(base_date: date, seconds_since_midnight: int) -> datetime:
      return (
        datetime.fromordinal(base_date.toordinal()) +
        timedelta(seconds=seconds_since_midnight)
      )
    
    one_day = timedelta(days=1)
    current_date = date(2023, 4, 1) - one_day               # start on Apr 1
    end_date = date(2023, 7, 31)                            # end on Jul 31
    start_time = timetuple_to_seconds(SimpleTime(8, 0, 0))  # 8 AM
    end_time = timetuple_to_seconds(SimpleTime(18, 0, 0))   # 6 PM
    min_gap = timetuple_to_seconds(SimpleTime(1, 0, 0))     # 1h
    
    while current_date < end_date:
        current_date += one_day
        if current_date.weekday() > 4: # weekend
            continue
        time_1 = randint(start_time, end_time - min_gap)    # from start to end - gap
        time_2 = randint(time_1 + min_gap, end_time)        # from time_1 to end
        print(
          combine_timestamp(current_date, time_1),
          'to',
          combine_timestamp(current_date, time_2)
        )
    

    which should return something like

    2023-04-03 08:14:14 to 2023-04-03 15:47:28
    2023-04-04 08:23:13 to 2023-04-04 16:11:04
    2023-04-05 16:08:53 to 2023-04-05 17:19:22
    2023-04-06 09:47:17 to 2023-04-06 12:07:44
    2023-04-07 11:27:45 to 2023-04-07 17:36:54
    2023-04-10 08:43:15 to 2023-04-10 13:56:21
    2023-04-11 09:06:26 to 2023-04-11 14:16:13
    2023-04-12 13:44:43 to 2023-04-12 17:10:56
    ...