2
\$\begingroup\$

I made a program that will take in a time and a weekday, and return which parts of the world are at times closest to the one specified. Part of the program focuses on extracting a date and country out of a user input.

Here are some example inputs and outputs:

"In what part of the world is it 4:00 PM Friday right now?" (datetime.datetime(2021, 1, 1, 16, 0), 'World')
"Where in America is it 6:40 AM Thu?" (datetime.datetime(2020, 12, 31, 6, 40), 'America')
"It is 10:30 pm fri in which part of Asia?" (datetime.datetime(2021, 1, 1, 22, 30), 'Asia')
"Where would the time be 10:10 AM Sat?" (datetime.datetime(2021, 1, 2, 10, 10), 'World')
"Which state of brazil has the time 8:30 AM Saturday now?" (datetime.datetime(2021, 1, 2, 8, 30), 'Brazil')

The reason that the only part of the date that needs to be given is the weekday, is because the maximum possible days in difference between a timezone and the timezone the user is currently at is one day, either ahead or behind.

So the program checks if the weekday given is at the current day, one day before the current day, or one day after the current day, and can return the rest of the date.

Here is my code:

import pytz
from datetime import datetime, timedelta
import re
def return_words(string):
 return re.findall(r'\b\S+\b', string.lower())
def string_to_datetime(string):
 weekdays = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
 string = string.lower()
 words = sorted(return_words(string), key=len)[::-1]
 countries = [t.split("/")[0] for t in pytz.all_timezones]
 for word in words:
 in_day = [weekday for weekday in weekdays if word in weekday]
 if len(in_day) == 1: # Make sure that the word found is a weekday name, not just something like "day"
 weekday = in_day[0]
 break
 else:
 return
 
 for word in words:
 if word.title() in countries:
 country = word.title()
 break
 else:
 country = "World" # If no country name found, use "World"
 
 date = datetime.now()
 one_day = timedelta(days=1)
 if (datetime.now() + one_day).strftime("%A").lower() == weekday:
 date += one_day
 elif (datetime.now() - one_day).strftime("%A").lower() == weekday:
 date -= one_day
 elif datetime.now().strftime("%A").lower() != weekday:
 return
 
 year, month, day = date.year, date.month, date.day
 hours_minutes = re.findall("\d+\:\d+", string)[0]
 
 half = re.findall(f"(?<={hours_minutes}).{{0,3}}[ap]m", string) # Play it safe, and only extract the am or pm that is at most 3 steps away from the hours:minutes
 if half: # If found an am or pm
 half = half[0].strip()
 else: # If not found when playing it safe, resort to finding any am or pm in the string
 half = re.findall("[ap]m", string)[0].strip()
 string = f"{year} {month} {day} {hours_minutes} {half}"
 try:
 return datetime.strptime(string, "%Y %m %d %I:%M %p"), country
 except ValueError:
 return
while True:
 print(string_to_datetime(input("Input your string >>> ")))

Can you show me how to improve the efficiency of my code? Also, any tips on tidying up would be of big help.

asked Jan 2, 2021 at 4:06
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
 in_day = [weekday for weekday in weekdays if word in weekday]
 if len(in_day) == 1:

seems odd. You make the entire list, put it in memory, take its length and then throw it away. Consider instead

n_matching = sum(1 for weekday in weekdays if word in weekday)
if n_matching == 1:

This loop:

for word in words:
 in_day = [weekday for weekday in weekdays if word in weekday]
 if len(in_day) == 1: # Make sure that the word found is a weekday name, not just something like "day"
 weekday = in_day[0]
 break

can be simplified if you use set operations; lower everything in words before this:

countries = {t.split("/", 1)[0].lower() for t in pytz.all_timezones}
try:
 country = next(iter(countries & set(words))).title()
except StopIteration:
 country = "World" # If no country name found, use "World"
answered Jan 2, 2021 at 5:19
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.