11from __future__ import annotations
22
33from contextlib import suppress
4+ import re
45import sys
56from typing import (
67 TYPE_CHECKING ,
2627 IndexingError ,
2728 InvalidIndexError ,
2829 LossySetitemError ,
30+ Pandas4Warning ,
2931)
3032from pandas .errors .cow import _chained_assignment_msg
3133from pandas .util ._decorators import (
3234 doc ,
3335)
36+ from pandas .util ._exceptions import find_stack_level
3437
3538from pandas .core .dtypes .cast import (
3639 can_hold_element ,
@@ -1249,6 +1252,31 @@ class _LocIndexer(_LocationIndexer):
12491252 "index is integers), listlike of labels, boolean"
12501253 )
12511254
1255+ # -------------------------------------------------------------------
1256+ # Helpers
1257+
1258+ @staticmethod
1259+ def _is_iso_format_string (date_str : str ) -> bool :
1260+ """
1261+ Check if a date string follows ISO 8601 format.
1262+
1263+ ISO format must start with a 4-digit year (YYYY), optionally followed by
1264+ hyphen or 'T' for time component.
1265+
1266+ Examples of ISO format (True):
1267+ - "2024"
1268+ - "2024-01"
1269+ - "2024-01-10"
1270+ - "2024-01-10T00:00:00"
1271+
1272+ Examples of non-ISO format (False):
1273+ - "2024/01/10" (/ separator)
1274+ - "2024 01 10" (space separator)
1275+ - "01/10/2024" (MM/DD/YYYY)
1276+ - "1Q01" (quarter format)
1277+ """
1278+ return re .match (r"^\d{4}(?:-|T|$)" , date_str ) is not None
1279+
12521280 # -------------------------------------------------------------------
12531281 # Key Checks
12541282
@@ -1459,6 +1487,19 @@ def _getitem_axis(self, key, axis: AxisInt):
14591487
14601488 # fall thru to straight lookup
14611489 self ._validate_key (key , axis )
1490+
1491+ # GH#58302 - Deprecate non-ISO string formats in .loc direct access
1492+ # Only warn for DatetimeIndex to avoid false positives with other index types
1493+ labels = self .obj ._get_axis (axis )
1494+ if type (labels ).__name__ == "DatetimeIndex" :
1495+ if isinstance (key , str ) and not self ._is_iso_format_string (key ):
1496+ msg = (
1497+ "Parsing non-ISO datetime strings in .loc is deprecated "
1498+ "and will be removed in a future version. Use ISO format "
1499+ f"(YYYY-MM-DD) instead. Got '{ key } '."
1500+ )
1501+ warnings .warn (msg , Pandas4Warning , stacklevel = find_stack_level ())
1502+
14621503 return self ._get_label (key , axis = axis )
14631504
14641505 def _get_slice_axis (self , slice_obj : slice , axis : AxisInt ):
@@ -1471,6 +1512,19 @@ def _get_slice_axis(self, slice_obj: slice, axis: AxisInt):
14711512 return obj .copy (deep = False )
14721513
14731514 labels = obj ._get_axis (axis )
1515+
1516+ # GH#58302 - Deprecate non-ISO string formats in .loc slicing
1517+ # Only warn for DatetimeIndex to avoid false positives with other index types
1518+ if type (labels ).__name__ == "DatetimeIndex" :
1519+ for key in [slice_obj .start , slice_obj .stop ]:
1520+ if isinstance (key , str ) and not self ._is_iso_format_string (key ):
1521+ msg = (
1522+ "Parsing non-ISO datetime strings in .loc is deprecated "
1523+ "and will be removed in a future version. Use ISO format "
1524+ f"(YYYY-MM-DD) instead. Got '{ key } '."
1525+ )
1526+ warnings .warn (msg , Pandas4Warning , stacklevel = find_stack_level ())
1527+
14741528 indexer = labels .slice_indexer (slice_obj .start , slice_obj .stop , slice_obj .step )
14751529
14761530 if isinstance (indexer , slice ):
0 commit comments