Home > Software engineering >  Finding most recent noon or midnight preceding x hours ago
Finding most recent noon or midnight preceding x hours ago

Time:05-18

I have a need to get the time in seconds for the most recent noon UTC or midnight UTC preceding the time six hours before now. In other words, if it's currently 2022-05-17 04:00:00, I want the value 2022-05-16 12:00:00 to be returned (six hours before 2022-05-17 04:00:00 is 2022-05-16 22:00:00, so the most recent noon/midnight before that would be 2022-05-16 12:00:00).

I'm currently grabbing datetime.now(), using datetime.timedelta() to go back six hours, grabbing the hour and using a conditional to set midnight vs. noon, combining it all into a string then using datetime.strptime() to convert back to a datetime object, another datetime.timedelta() to check against the epoch, and finally datetime.total_seconds(). I figure there must be a more elegant way and I would greatly appreciate advice on shortening this code (although it does work):

from datetime import datetime, timedelta

now = datetime.now()
six_hours_ago = now-timedelta(hours = 6)
six_hours_ago_date = six_hours_ago.date()
six_hours_ago_hour = six_hours_ago.hour
if six_hours_ago_hour < 12:
    gribtime_to_search = '00:00'
else:
    gribtime_to_search = '12:00'
gribdate_string_to_search = f"{str(six_hours_ago_date)} {gribtime_to_search}"
gribdatetime_to_search = datetime.strptime(gribdate_string_to_search, "%Y-%m-%d %H:%M")
epoch_timedelta = gribdatetime_to_search - datetime(1970, 1, 1)
seconds = epoch_timedelta.total_seconds()

CodePudding user response:

Reply I might do something like the following, after you calculate six_hours_ago:

six_hours_ago_midnight = datetime.combine(six_hours_ago, datetime.min.time())
if six_hours_ago - six_hours_ago_midnight >= timedelta(hours=12):
    return six_hours_ago_midnight   timedelta(hours=12)
else:
    return six_hours_ago_midnight

CodePudding user response:

An easier way could be to use datetime.combine to combine date and time objects into a (time-zone aware) datetime, as shown below.

I would also ensure to use datetime methods like utcnow() and replace() with tzinfo argument, so that you can ensure that you're working with UTC dates and times.

from datetime import datetime, timedelta, time, timezone

# now = datetime.utcnow()
now = datetime.fromisoformat('2022-05-17 04:00:00').replace(tzinfo=timezone.utc)
print('Input:', now)

six_hours_ago = now - timedelta(hours=6)

six_hours_ago_date = six_hours_ago.date()
six_hours_ago_hour = six_hours_ago.hour
time_to_set: time = time.min if six_hours_ago_hour < 12 else time(hour=12)

# combine `date` and `time` into a UTC `datetime`
dt = datetime.combine(six_hours_ago_date, time_to_set, timezone.utc)
# get unix timestamp
seconds = round(dt.timestamp())

print('Result:', dt)
print('Epoch ts:', seconds)

Result:

Input: 2022-05-17 04:00:00 00:00
Result: 2022-05-16 12:00:00 00:00
Epoch ts: 1652702400
  • Related