7
7
8
8
from pandas ._libs import lib , iNaT , NaT
9
9
from pandas ._libs .tslibs import timezones
10
+ from pandas .util ._decorators import Appender , cache_readonly
10
11
from pandas ._libs .tslibs .timedeltas import delta_to_nanoseconds , Timedelta
11
- from pandas ._libs .tslibs .timestamps import maybe_integer_op_deprecated
12
+ from pandas ._libs .tslibs .timestamps import (
13
+ maybe_integer_op_deprecated , RoundTo , round_nsint64 )
12
14
from pandas ._libs .tslibs .period import (
13
15
Period , DIFFERENT_FREQ_INDEX , IncompatibleFrequency )
14
16
@@ -91,7 +93,184 @@ def _get_attributes_dict(self):
91
93
return {k : getattr (self , k , None ) for k in self ._attributes }
92
94
93
95
94
- class DatetimeLikeArrayMixin (ExtensionOpsMixin , AttributesMixin ):
96
+ class DatelikeOps (ExtensionOpsMixin ):
97
+
98
+ def strftime (self , date_format ):
99
+ return self .format (date_format = date_format )
100
+ strftime .__doc__ = """
101
+ Convert to Index using specified date_format.
102
+
103
+ Return an Index of formatted strings specified by date_format, which
104
+ supports the same string format as the python standard library. Details
105
+ of the string format can be found in `python string format doc <{0}>`__
106
+
107
+ Parameters
108
+ ----------
109
+ date_format : str
110
+ Date format string (e.g. "%Y-%m-%d").
111
+
112
+ Returns
113
+ -------
114
+ Index
115
+ Index of formatted strings
116
+
117
+ See Also
118
+ --------
119
+ pandas.to_datetime : Convert the given argument to datetime
120
+ DatetimeIndex.normalize : Return DatetimeIndex with times to midnight.
121
+ DatetimeIndex.round : Round the DatetimeIndex to the specified freq.
122
+ DatetimeIndex.floor : Floor the DatetimeIndex to the specified freq.
123
+
124
+ Examples
125
+ --------
126
+ >>> rng = pd.date_range(pd.Timestamp("2018-03-10 09:00"),
127
+ ... periods=3, freq='s')
128
+ >>> rng.strftime('%B %d, %Y, %r')
129
+ Index(['March 10, 2018, 09:00:00 AM', 'March 10, 2018, 09:00:01 AM',
130
+ 'March 10, 2018, 09:00:02 AM'],
131
+ dtype='object')
132
+ """ .format ("https://docs.python.org/3/library/datetime.html"
133
+ "#strftime-and-strptime-behavior" )
134
+
135
+
136
+ class TimelikeOps (object ):
137
+ """ common ops for TimedeltaIndex/DatetimeIndex, but not PeriodIndex """
138
+
139
+ _round_doc = (
140
+ """
141
+ {op} the data to the specified `freq`.
142
+
143
+ Parameters
144
+ ----------
145
+ freq : str or Offset
146
+ The frequency level to {op} the index to. Must be a fixed
147
+ frequency like 'S' (second) not 'ME' (month end). See
148
+ :ref:`frequency aliases <timeseries.offset_aliases>` for
149
+ a list of possible `freq` values.
150
+ ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise'
151
+ Only relevant for DatetimeIndex:
152
+
153
+ - 'infer' will attempt to infer fall dst-transition hours based on
154
+ order
155
+ - bool-ndarray where True signifies a DST time, False designates
156
+ a non-DST time (note that this flag is only applicable for
157
+ ambiguous times)
158
+ - 'NaT' will return NaT where there are ambiguous times
159
+ - 'raise' will raise an AmbiguousTimeError if there are ambiguous
160
+ times
161
+
162
+ .. versionadded:: 0.24.0
163
+ nonexistent : 'shift', 'NaT', default 'raise'
164
+ A nonexistent time does not exist in a particular timezone
165
+ where clocks moved forward due to DST.
166
+
167
+ - 'shift' will shift the nonexistent time forward to the closest
168
+ existing time
169
+ - 'NaT' will return NaT where there are nonexistent times
170
+ - 'raise' will raise an NonExistentTimeError if there are
171
+ nonexistent times
172
+
173
+ .. versionadded:: 0.24.0
174
+
175
+ Returns
176
+ -------
177
+ DatetimeIndex, TimedeltaIndex, or Series
178
+ Index of the same type for a DatetimeIndex or TimedeltaIndex,
179
+ or a Series with the same index for a Series.
180
+
181
+ Raises
182
+ ------
183
+ ValueError if the `freq` cannot be converted.
184
+
185
+ Examples
186
+ --------
187
+ **DatetimeIndex**
188
+
189
+ >>> rng = pd.date_range('1/1/2018 11:59:00', periods=3, freq='min')
190
+ >>> rng
191
+ DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00',
192
+ '2018-01-01 12:01:00'],
193
+ dtype='datetime64[ns]', freq='T')
194
+ """ )
195
+
196
+ _round_example = (
197
+ """>>> rng.round('H')
198
+ DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00',
199
+ '2018-01-01 12:00:00'],
200
+ dtype='datetime64[ns]', freq=None)
201
+
202
+ **Series**
203
+
204
+ >>> pd.Series(rng).dt.round("H")
205
+ 0 2018-01-01 12:00:00
206
+ 1 2018-01-01 12:00:00
207
+ 2 2018-01-01 12:00:00
208
+ dtype: datetime64[ns]
209
+ """ )
210
+
211
+ _floor_example = (
212
+ """>>> rng.floor('H')
213
+ DatetimeIndex(['2018-01-01 11:00:00', '2018-01-01 12:00:00',
214
+ '2018-01-01 12:00:00'],
215
+ dtype='datetime64[ns]', freq=None)
216
+
217
+ **Series**
218
+
219
+ >>> pd.Series(rng).dt.floor("H")
220
+ 0 2018-01-01 11:00:00
221
+ 1 2018-01-01 12:00:00
222
+ 2 2018-01-01 12:00:00
223
+ dtype: datetime64[ns]
224
+ """
225
+ )
226
+
227
+ _ceil_example = (
228
+ """>>> rng.ceil('H')
229
+ DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00',
230
+ '2018-01-01 13:00:00'],
231
+ dtype='datetime64[ns]', freq=None)
232
+
233
+ **Series**
234
+
235
+ >>> pd.Series(rng).dt.ceil("H")
236
+ 0 2018-01-01 12:00:00
237
+ 1 2018-01-01 12:00:00
238
+ 2 2018-01-01 13:00:00
239
+ dtype: datetime64[ns]
240
+ """
241
+ )
242
+
243
+ def _round (self , freq , mode , ambiguous , nonexistent ):
244
+ # round the local times
245
+ # TODO
246
+ values = _ensure_datetimelike_to_i8 (self )
247
+ result = round_nsint64 (values , mode , freq )
248
+ result = self ._maybe_mask_results (result , fill_value = NaT )
249
+
250
+ attribs = self ._get_attributes_dict ()
251
+ attribs ['freq' ] = None
252
+ if 'tz' in attribs :
253
+ attribs ['tz' ] = None
254
+ return self ._ensure_localized (
255
+ self ._shallow_copy (result , ** attribs ), ambiguous , nonexistent
256
+ )
257
+
258
+ @Appender ((_round_doc + _round_example ).format (op = "round" ))
259
+ def round (self , freq , ambiguous = 'raise' , nonexistent = 'raise' ):
260
+ return self ._round (
261
+ freq , RoundTo .NEAREST_HALF_EVEN , ambiguous , nonexistent
262
+ )
263
+
264
+ @Appender ((_round_doc + _floor_example ).format (op = "floor" ))
265
+ def floor (self , freq , ambiguous = 'raise' , nonexistent = 'raise' ):
266
+ return self ._round (freq , RoundTo .MINUS_INFTY , ambiguous , nonexistent )
267
+
268
+ @Appender ((_round_doc + _ceil_example ).format (op = "ceil" ))
269
+ def ceil (self , freq , ambiguous = 'raise' , nonexistent = 'raise' ):
270
+ return self ._round (freq , RoundTo .PLUS_INFTY , ambiguous , nonexistent )
271
+
272
+
273
+ class DatetimeLikeArrayMixin (DatelikeOps , TimelikeOps , AttributesMixin ):
95
274
"""
96
275
Shared Base/Mixin class for DatetimeArray, TimedeltaArray, PeriodArray
97
276
@@ -103,6 +282,23 @@ class DatetimeLikeArrayMixin(ExtensionOpsMixin, AttributesMixin):
103
282
_generate_range
104
283
"""
105
284
285
+ # define my properties & methods for delegation
286
+ _bool_ops = ['is_month_start' , 'is_month_end' ,
287
+ 'is_quarter_start' , 'is_quarter_end' , 'is_year_start' ,
288
+ 'is_year_end' , 'is_leap_year' ]
289
+ _object_ops = ['weekday_name' , 'freq' , 'tz' ]
290
+ _field_ops = ['year' , 'month' , 'day' , 'hour' , 'minute' , 'second' ,
291
+ 'weekofyear' , 'week' , 'weekday' , 'dayofweek' ,
292
+ 'dayofyear' , 'quarter' , 'days_in_month' ,
293
+ 'daysinmonth' , 'microsecond' ,
294
+ 'nanosecond' ]
295
+ _other_ops = ['date' , 'time' , 'timetz' ]
296
+ _datetimelike_ops = _field_ops + _object_ops + _bool_ops + _other_ops
297
+ _datetimelike_methods = ['to_period' , 'tz_localize' ,
298
+ 'tz_convert' ,
299
+ 'normalize' , 'strftime' , 'round' , 'floor' ,
300
+ 'ceil' , 'month_name' , 'day_name' ,]
301
+
106
302
@property
107
303
def _box_func (self ):
108
304
"""
0 commit comments