diff --git a/litellm/litellm_core_utils/duration_parser.py b/litellm/litellm_core_utils/duration_parser.py index 70c28c4e06..f78cb9b1b0 100644 --- a/litellm/litellm_core_utils/duration_parser.py +++ b/litellm/litellm_core_utils/duration_parser.py @@ -12,6 +12,8 @@ from typing import Optional, Tuple from zoneinfo import ZoneInfo +from litellm._logging import verbose_logger + def _extract_from_regex(duration: str) -> Tuple[int, str]: match = re.match(r"(\d+)(mo|[smhdw]?)", duration) @@ -156,7 +158,11 @@ def _setup_timezone( else: tz = ZoneInfo(timezone_str) except Exception: - # If timezone is invalid, fall back to UTC + verbose_logger.warning( + "Failed to load timezone '%s', falling back to UTC. " + "Check that the timezone is valid and that the 'tzdata' package is installed.", + timezone_str, + ) tz = timezone.utc # Convert current_time to the target timezone diff --git a/tests/test_litellm/litellm_core_utils/test_duration_parser.py b/tests/test_litellm/litellm_core_utils/test_duration_parser.py index 52316d4d97..e7c9c80cb4 100644 --- a/tests/test_litellm/litellm_core_utils/test_duration_parser.py +++ b/tests/test_litellm/litellm_core_utils/test_duration_parser.py @@ -1,5 +1,6 @@ import unittest from datetime import datetime, timezone +from unittest.mock import patch from zoneinfo import ZoneInfo from litellm.litellm_core_utils.duration_parser import get_next_standardized_reset_time @@ -184,5 +185,14 @@ def test_dst_spring_forward(self): self.assertEqual(result, expected) + def test_invalid_timezone_logs_warning(self): + """Test that an invalid timezone logs a warning when falling back to UTC.""" + base_time = datetime(2023, 5, 15, 14, 0, 0, tzinfo=timezone.utc) + with patch("litellm.litellm_core_utils.duration_parser.verbose_logger") as mock_logger: + get_next_standardized_reset_time("1d", base_time, "NonExistentTimeZone") + mock_logger.warning.assert_called_once() + assert "NonExistentTimeZone" in mock_logger.warning.call_args.args[1] + + if __name__ == "__main__": unittest.main()