@@ -2571,63 +2571,15 @@ def _get_grouper(
25712571 def _get_time_bins (self , ax : DatetimeIndex ):
25722572 if not isinstance (ax , DatetimeIndex ):
25732573 raise TypeError (
2574- "axis must be a DatetimeIndex, but got "
2574+ "axis must be a DatetimeIndex, but got"
25752575 f"an instance of { type (ax ).__name__ } "
25762576 )
25772577
25782578 if len (ax ) == 0 :
25792579 empty = DatetimeIndex (data = [], freq = self .freq , name = ax .name , dtype = ax .dtype )
25802580 return empty , [], empty
25812581
2582- if ax .tz is not None :
2583- try :
2584- first , last = _get_timestamp_range_edges (
2585- ax .min (),
2586- ax .max (),
2587- self .freq ,
2588- unit = ax .unit ,
2589- closed = self .closed ,
2590- origin = self .origin ,
2591- offset = self .offset ,
2592- )
2593- binner = labels = date_range (
2594- freq = self .freq ,
2595- start = first ,
2596- end = last ,
2597- tz = ax .tz ,
2598- name = ax .name ,
2599- ambiguous = True ,
2600- nonexistent = "shift_forward" ,
2601- unit = ax .unit ,
2602- )
2603- except Exception as e :
2604- if "nonexistent" not in str (e ).lower ():
2605- raise
2606-
2607- ax_utc = ax .tz_convert ("UTC" )
2608-
2609- first_utc , last_utc = _get_timestamp_range_edges (
2610- ax_utc .min (),
2611- ax_utc .max (),
2612- self .freq ,
2613- unit = ax .unit ,
2614- closed = self .closed ,
2615- origin = self .origin ,
2616- offset = self .offset ,
2617- )
2618-
2619- binner_utc = date_range (
2620- start = first_utc ,
2621- end = last_utc ,
2622- freq = self .freq ,
2623- tz = "UTC" ,
2624- name = ax .name ,
2625- unit = ax .unit ,
2626- )
2627-
2628- binner = labels = binner_utc .tz_convert (ax .tz )
2629-
2630- else :
2582+ try :
26312583 first , last = _get_timestamp_range_edges (
26322584 ax .min (),
26332585 ax .max (),
@@ -2647,9 +2599,34 @@ def _get_time_bins(self, ax: DatetimeIndex):
26472599 nonexistent = "shift_forward" ,
26482600 unit = ax .unit ,
26492601 )
2602+ except Exception :
2603+ # Fallback to UTC calculation for timezone-aware data
2604+ # to handle DST transition
2605+ # 62601
2606+ ax_utc = ax .tz_convert ("UTC" )
2607+ first_utc , last_utc = _get_timestamp_range_edges (
2608+ ax_utc .min (),
2609+ ax_utc .max (),
2610+ self .freq ,
2611+ unit = ax .unit ,
2612+ closed = self .closed ,
2613+ origin = self .origin ,
2614+ offset = self .offset ,
2615+ )
2616+ binner_utc = date_range (
2617+ freq = self .freq ,
2618+ start = first_utc ,
2619+ end = last_utc ,
2620+ tz = "UTC" ,
2621+ name = ax .name ,
2622+ unit = ax .unit ,
2623+ )
2624+ binner = labels = binner_utc .tz_convert (ax .tz )
2625+
26502626 ax_values = ax .asi8
26512627 binner , bin_edges = self ._adjust_bin_edges (binner , ax_values )
26522628
2629+ # general version, knowing nothing about relative frequencies
26532630 bins = lib .generate_bins_dt64 (
26542631 ax_values , bin_edges , self .closed , hasnans = ax .hasnans
26552632 )
@@ -2665,6 +2642,9 @@ def _get_time_bins(self, ax: DatetimeIndex):
26652642 binner = binner .insert (0 , NaT )
26662643 labels = labels .insert (0 , NaT )
26672644
2645+ # if we end up with more labels than bins
2646+ # adjust the labels
2647+ # GH4076
26682648 if len (bins ) < len (labels ):
26692649 labels = labels [: len (bins )]
26702650
0 commit comments