diff --git a/app/integrations/google_workspace/google_calendar.py b/app/integrations/google_workspace/google_calendar.py index 15a39092..3f119c1b 100644 --- a/app/integrations/google_workspace/google_calendar.py +++ b/app/integrations/google_workspace/google_calendar.py @@ -142,6 +142,9 @@ def find_first_available_slot( # EST timezone est = pytz.timezone("US/Eastern") + starting_hour = get_utc_hour(13, 0, "US/Eastern") + ending_hour = get_utc_hour(15, 0, "US/Eastern") + # Combine all busy times into a single list and sort them busy_times = [] for calendar in freebusy_response["calendars"].values(): @@ -164,10 +167,10 @@ def find_first_available_slot( continue search_start = search_date.replace( - hour=17, minute=0, second=0, microsecond=0 + hour=starting_hour, minute=0, second=0, microsecond=0 ) # 1 PM EST, times are in UTC search_end = search_date.replace( - hour=19, minute=0, second=0, microsecond=0 + hour=ending_hour, minute=0, second=0, microsecond=0 ) # 3 PM EST, times are in UTC # if the day is a federal holiday, skip it @@ -205,3 +208,33 @@ def get_federal_holidays(): for holiday in response.json()["holidays"]: holidays.append(holiday["observedDate"]) return holidays + + +def get_utc_hour(hour, minute, tz_name, date=None): + """ + Converts a specific time in a given time zone to UTC and returns the hour. + + Args: + hour (int): The hour of the time in 24-hour format. + minute (int): The minute of the time. + tz_name (str): The name of the time zone (e.g., "US/Eastern"). + + Returns: + str: The corresponding UTC hour. + """ + # Define the local timezone + local_tz = pytz.timezone(tz_name) + + # If we are not passing the date, then initialize it to the current date:w + if date is None: + date = datetime.utcnow() + + # Create a datetime object for the given time in the local timezone + local_time = local_tz.localize( + datetime(date.year, date.month, date.day, hour, minute) + ) + + # Convert to UTC + utc_time = local_time.astimezone(pytz.utc) + + return utc_time.hour diff --git a/app/tests/integrations/google_workspace/test_google_calendar.py b/app/tests/integrations/google_workspace/test_google_calendar.py index 1698c8ce..fecbd764 100644 --- a/app/tests/integrations/google_workspace/test_google_calendar.py +++ b/app/tests/integrations/google_workspace/test_google_calendar.py @@ -730,3 +730,86 @@ def test_leap_year_handling(requests_mock): # Verify leap year is considered assert "2024-02-29" in holidays, "Leap year date should be included in the holidays" + + +def test_get_utc_hour_same_zone(): + """ + Test case for the same timezone (UTC). + """ + assert ( + google_calendar.get_utc_hour(13, 0, "UTC") == 13 + ) # 1 PM UTC should remain 13 in UTC. + + +def test_get_utc_hour_us_eastern_daylight_time_winter(): + """ + Test case for US Eastern Daylight Time during the winter + """ + # Explicitly set a date in December when daylight saving time is not active + tz_name = "US/Eastern" + local_tz = pytz.timezone(tz_name) + test_date = datetime(2023, 12, 1, 13, 0) # December 1, 2023, 1 PM EDT + localized_time = local_tz.localize(test_date) + utc_time = localized_time.astimezone(pytz.utc).hour + + # Assert that 1 PM EDT is 6 PM UTC + assert google_calendar.get_utc_hour(13, 0, tz_name, test_date) == utc_time + + +def test_get_utc_hour_us_eastern_daylight_time_summer(): + """ + Test case for US Eastern Daylight Time (EDT, UTC-4) during the summer. + """ + # Explicitly set a date in August when daylight saving time is active + tz_name = "US/Eastern" + local_tz = pytz.timezone(tz_name) + test_date = datetime(2023, 8, 1, 13, 0) # August 1, 2023, 1 PM EDT + localized_time = local_tz.localize(test_date) + utc_time = localized_time.astimezone(pytz.utc).hour + + # Assert that 1 PM EDT is 5 PM UTC + assert google_calendar.get_utc_hour(13, 0, tz_name, test_date) == utc_time + + +def test_get_utc_hour_pacific_time(): + """ + Test case for Pacific Standard Time (PST, UTC-8). + """ + test_date = datetime(2023, 12, 1, 13, 0) # December 1, 2023, 1 PM PDT + + assert ( + google_calendar.get_utc_hour(13, 0, "US/Pacific", test_date) == 21 + ) # 1 PM PST should be 9 PM UTC. + + +def test_get_utc_hour_with_invalid_timezone(): + """ + Test case for invalid timezone input. + """ + with pytest.raises(pytz.UnknownTimeZoneError): + google_calendar.get_utc_hour(13, 0, "Invalid/Zone") + + +def test_get_utc_hour_midnight_transition(): + """ + Test case for midnight transition. + """ + assert ( + google_calendar.get_utc_hour(23, 0, "US/Eastern") == 4 + ) # 11 PM EST should be 4 AM UTC. + + +def test_get_utc_hour_negative_hour(): + """ + Test case for invalid hour input. + """ + with pytest.raises(ValueError): + google_calendar.get_utc_hour(-1, 0, "UTC") + + +def test_get_utc_hour_invalid_minute(): + """ + Test case for invalid minute input. + """ + with pytest.raises(ValueError): + google_calendar.get_utc_hour(13, 60, "UTC")