# Simple Countdown Timer

Beginner level script for a countdown timer. Would appreciate if you could point the things I could do to be more efficient.

Basically, I would want to check if the current day is either a "workday"(Mon - Wed) or a "freeday"(Thur-Sun) and achieve the following:

1. If it's a workday, and the current hour is a working hour (7:00:00 AM - 5:00:00 PM), then count how many hour(s) remaining till end of the shift (5PM) base on the current time.

2. If it's a workday, and the current hour is outside of working hours (5:00:01 PM to 6:59:59 AM), say that it is not yet a working hour.

3. If it's a freeday, count till the next Monday.

I wouldn't want to rely on the if statements if possible, but my understanding level for Python is at this point only. Is there a better way to do it?

Thank you in advance! Happy coding.

import time, datetime

# Add the value to get the next Monday
get_future_monday = {
0: 1,
1: 2,
2: 3,
3: 4
}

def time_state():
# Check what day of the week
# 0 == Monday, 6 == Sunday
check_day = datetime.datetime.today().weekday()

# Get future Monday
future_monday = 6 - check_day

# Check current time
check_time_now = datetime.datetime.now()

# Parse current time
# Get the year, month and day
get_year = check_time_now.year
get_month = check_time_now.month
get_day = check_time_now.day

# Define timespan for each routine
working_hours = datetime.time(7, 0, 0)
after_hours_am = datetime.time(6, 59, 59)
after_hours_pm = datetime.time(17, 0, 1)

if check_day == 0 and check_time_now.time() < after_hours_am: # If Monday and current time not yet 7 AM
print("It's not time yeeeet!")
return datetime.datetime(get_year, get_month, get_day, 7, 0, 0)

elif check_day == 2 and check_time_now.time() > after_hours_pm: # If Wednesday and current time past 5 PM
print("Time to gooooo!")
return datetime.datetime(get_year, get_month, (get_day + get_future_monday[future_monday]), 7, 0, 0)

elif check_day <= 2 and check_time_now.time() < after_hours_am: # If day in Tuesday, Wed and current time not yet 7 AM
return datetime.datetime(get_year, get_month, get_day, 7, 0, 0)

elif check_day <= 2 and check_time_now.time() > after_hours_pm: # If day in Tuesday, Wed and current time not yet 5 PM
print("Free at last!")
return datetime.datetime(get_year, get_month, (get_day + 1), 7, 0, 0)

elif check_day <= 2 and check_time_now.time() >= working_hours and check_time_now.time() <= after_hours_pm: # If day in Mon - Wed and current time not yet 5 PM
print("Focus focus focus!!!")
return datetime.datetime(get_year, get_month, get_day, 17, 0, 0)

else:
print("Playtime foo UwU")
return datetime.datetime(get_year, get_month, (get_day + get_future_monday[future_monday]), 7, 0, 0) # Playtime

def countdown(time_state):
time_state = time_state

clock_tick = time_state - datetime.datetime.now()

days = clock_tick.total_seconds() / 86400
hours, rem = divmod(clock_tick.total_seconds(), 3600)
mins, secs = divmod(rem, 60)

print(f"{int(days):02d}:{int(hours):02d}:{int(mins):02d}:{int(secs):02d}")
time.sleep(1)

def main():
while True:
a = time_state()
countdown(a)

main()
$$$$


## Variable names

I find the get_ prefixes unnecessary on these:

get_year = check_time_now.year
get_month = check_time_now.month
get_day = check_time_now.day


That makes them look like functions.

## Boundaries

This:

working_hours = datetime.time(7, 0, 0)
after_hours_am = datetime.time(6, 59, 59)


should probably just use 7:00 for after_hours_am. Otherwise, the time 6:59:59 given your current usage will still be considered working hours.

Likewise, this:

check_time_now.time() > after_hours_pm


should use >=.

An easy convention to follow that makes your boundary checking consistent is to always use intervals that are closed at the beginning and open at the end, i.e. 7:00 <= time < 8:00.

## Redundant else

This:

    return datetime.datetime(get_year, get_month, get_day, 7, 0, 0)

elif ...


can use an if instead of an elif due to the previous return.

## Don't repeat yourself

This return:

    return datetime.datetime(get_year, get_month, get_day, 7, 0, 0)


shares many commonalities with the other returns in its function. Factor out a new_day and new_hour variable assignment, then at the end of your function,

return datetime.datetime(get_year, get_month, new_day, new_hour)


Note that 0 is the default for the remaining parameters.

## Timespan division

Trying not to do your own time math, this would be one option that doesn't require knowledge of time position multiples:

days = clock_tick.days
rem = clock_tick - timedelta(days=days)
hours = rem // timedelta(hours=1)
rem -= timedelta(hours=hours)
mins = rem // timedelta(minutes=1)
rem -= timedelta(minutes=mins)
secs = int(rem.total_seconds())
`

I don't like it, but built-in Python time libraries are kind of bad. Third-party libraries will reduce this to a one-liner format call. This is educational:

https://stackoverflow.com/questions/538666/format-timedelta-to-string