Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2datetimelike delegation 

3""" 

4import numpy as np 

5 

6from pandas.core.dtypes.common import ( 

7 is_categorical_dtype, 

8 is_datetime64_dtype, 

9 is_datetime64tz_dtype, 

10 is_datetime_arraylike, 

11 is_integer_dtype, 

12 is_list_like, 

13 is_period_arraylike, 

14 is_timedelta64_dtype, 

15) 

16from pandas.core.dtypes.generic import ABCSeries 

17 

18from pandas.core.accessor import PandasDelegate, delegate_names 

19from pandas.core.arrays import DatetimeArray, PeriodArray, TimedeltaArray 

20from pandas.core.base import NoNewAttributesMixin, PandasObject 

21from pandas.core.indexes.datetimes import DatetimeIndex 

22from pandas.core.indexes.timedeltas import TimedeltaIndex 

23 

24 

25class Properties(PandasDelegate, PandasObject, NoNewAttributesMixin): 

26 def __init__(self, data, orig): 

27 if not isinstance(data, ABCSeries): 

28 raise TypeError( 

29 f"cannot convert an object of type {type(data)} to a datetimelike index" 

30 ) 

31 

32 self._parent = data 

33 self.orig = orig 

34 self.name = getattr(data, "name", None) 

35 self._freeze() 

36 

37 def _get_values(self): 

38 data = self._parent 

39 if is_datetime64_dtype(data.dtype): 

40 return DatetimeIndex(data, copy=False, name=self.name) 

41 

42 elif is_datetime64tz_dtype(data.dtype): 

43 return DatetimeIndex(data, copy=False, name=self.name) 

44 

45 elif is_timedelta64_dtype(data.dtype): 

46 return TimedeltaIndex(data, copy=False, name=self.name) 

47 

48 else: 

49 if is_period_arraylike(data): 

50 # TODO: use to_period_array 

51 return PeriodArray(data, copy=False) 

52 if is_datetime_arraylike(data): 

53 return DatetimeIndex(data, copy=False, name=self.name) 

54 

55 raise TypeError( 

56 f"cannot convert an object of type {type(data)} to a datetimelike index" 

57 ) 

58 

59 def _delegate_property_get(self, name): 

60 from pandas import Series 

61 

62 values = self._get_values() 

63 

64 result = getattr(values, name) 

65 

66 # maybe need to upcast (ints) 

67 if isinstance(result, np.ndarray): 

68 if is_integer_dtype(result): 

69 result = result.astype("int64") 

70 elif not is_list_like(result): 

71 return result 

72 

73 result = np.asarray(result) 

74 

75 if self.orig is not None: 

76 index = self.orig.index 

77 else: 

78 index = self._parent.index 

79 # return the result as a Series, which is by definition a copy 

80 result = Series(result, index=index, name=self.name) 

81 

82 # setting this object will show a SettingWithCopyWarning/Error 

83 result._is_copy = ( 

84 "modifications to a property of a datetimelike " 

85 "object are not supported and are discarded. " 

86 "Change values on the original." 

87 ) 

88 

89 return result 

90 

91 def _delegate_property_set(self, name, value, *args, **kwargs): 

92 raise ValueError( 

93 "modifications to a property of a datetimelike object are not supported. " 

94 "Change values on the original." 

95 ) 

96 

97 def _delegate_method(self, name, *args, **kwargs): 

98 from pandas import Series 

99 

100 values = self._get_values() 

101 

102 method = getattr(values, name) 

103 result = method(*args, **kwargs) 

104 

105 if not is_list_like(result): 

106 return result 

107 

108 result = Series(result, index=self._parent.index, name=self.name) 

109 

110 # setting this object will show a SettingWithCopyWarning/Error 

111 result._is_copy = ( 

112 "modifications to a method of a datetimelike " 

113 "object are not supported and are discarded. " 

114 "Change values on the original." 

115 ) 

116 

117 return result 

118 

119 

120@delegate_names( 

121 delegate=DatetimeArray, accessors=DatetimeArray._datetimelike_ops, typ="property" 

122) 

123@delegate_names( 

124 delegate=DatetimeArray, accessors=DatetimeArray._datetimelike_methods, typ="method" 

125) 

126class DatetimeProperties(Properties): 

127 """ 

128 Accessor object for datetimelike properties of the Series values. 

129 

130 Examples 

131 -------- 

132 >>> s.dt.hour 

133 >>> s.dt.second 

134 >>> s.dt.quarter 

135 

136 Returns a Series indexed like the original Series. 

137 Raises TypeError if the Series does not contain datetimelike values. 

138 """ 

139 

140 def to_pydatetime(self): 

141 """ 

142 Return the data as an array of native Python datetime objects. 

143 

144 Timezone information is retained if present. 

145 

146 .. warning:: 

147 

148 Python's datetime uses microsecond resolution, which is lower than 

149 pandas (nanosecond). The values are truncated. 

150 

151 Returns 

152 ------- 

153 numpy.ndarray 

154 Object dtype array containing native Python datetime objects. 

155 

156 See Also 

157 -------- 

158 datetime.datetime : Standard library value for a datetime. 

159 

160 Examples 

161 -------- 

162 >>> s = pd.Series(pd.date_range('20180310', periods=2)) 

163 >>> s 

164 0 2018-03-10 

165 1 2018-03-11 

166 dtype: datetime64[ns] 

167 

168 >>> s.dt.to_pydatetime() 

169 array([datetime.datetime(2018, 3, 10, 0, 0), 

170 datetime.datetime(2018, 3, 11, 0, 0)], dtype=object) 

171 

172 pandas' nanosecond precision is truncated to microseconds. 

173 

174 >>> s = pd.Series(pd.date_range('20180310', periods=2, freq='ns')) 

175 >>> s 

176 0 2018-03-10 00:00:00.000000000 

177 1 2018-03-10 00:00:00.000000001 

178 dtype: datetime64[ns] 

179 

180 >>> s.dt.to_pydatetime() 

181 array([datetime.datetime(2018, 3, 10, 0, 0), 

182 datetime.datetime(2018, 3, 10, 0, 0)], dtype=object) 

183 """ 

184 return self._get_values().to_pydatetime() 

185 

186 @property 

187 def freq(self): 

188 return self._get_values().inferred_freq 

189 

190 

191@delegate_names( 

192 delegate=TimedeltaArray, accessors=TimedeltaArray._datetimelike_ops, typ="property" 

193) 

194@delegate_names( 

195 delegate=TimedeltaArray, 

196 accessors=TimedeltaArray._datetimelike_methods, 

197 typ="method", 

198) 

199class TimedeltaProperties(Properties): 

200 """ 

201 Accessor object for datetimelike properties of the Series values. 

202 

203 Examples 

204 -------- 

205 >>> s.dt.hours 

206 >>> s.dt.seconds 

207 

208 Returns a Series indexed like the original Series. 

209 Raises TypeError if the Series does not contain datetimelike values. 

210 """ 

211 

212 def to_pytimedelta(self): 

213 """ 

214 Return an array of native `datetime.timedelta` objects. 

215 

216 Python's standard `datetime` library uses a different representation 

217 timedelta's. This method converts a Series of pandas Timedeltas 

218 to `datetime.timedelta` format with the same length as the original 

219 Series. 

220 

221 Returns 

222 ------- 

223 numpy.ndarray 

224 Array of 1D containing data with `datetime.timedelta` type. 

225 

226 See Also 

227 -------- 

228 datetime.timedelta 

229 

230 Examples 

231 -------- 

232 >>> s = pd.Series(pd.to_timedelta(np.arange(5), unit='d')) 

233 >>> s 

234 0 0 days 

235 1 1 days 

236 2 2 days 

237 3 3 days 

238 4 4 days 

239 dtype: timedelta64[ns] 

240 

241 >>> s.dt.to_pytimedelta() 

242 array([datetime.timedelta(0), datetime.timedelta(1), 

243 datetime.timedelta(2), datetime.timedelta(3), 

244 datetime.timedelta(4)], dtype=object) 

245 """ 

246 return self._get_values().to_pytimedelta() 

247 

248 @property 

249 def components(self): 

250 """ 

251 Return a Dataframe of the components of the Timedeltas. 

252 

253 Returns 

254 ------- 

255 DataFrame 

256 

257 Examples 

258 -------- 

259 >>> s = pd.Series(pd.to_timedelta(np.arange(5), unit='s')) 

260 >>> s 

261 0 00:00:00 

262 1 00:00:01 

263 2 00:00:02 

264 3 00:00:03 

265 4 00:00:04 

266 dtype: timedelta64[ns] 

267 >>> s.dt.components 

268 days hours minutes seconds milliseconds microseconds nanoseconds 

269 0 0 0 0 0 0 0 0 

270 1 0 0 0 1 0 0 0 

271 2 0 0 0 2 0 0 0 

272 3 0 0 0 3 0 0 0 

273 4 0 0 0 4 0 0 0 

274 """ # noqa: E501 

275 return self._get_values().components.set_index(self._parent.index) 

276 

277 @property 

278 def freq(self): 

279 return self._get_values().inferred_freq 

280 

281 

282@delegate_names( 

283 delegate=PeriodArray, accessors=PeriodArray._datetimelike_ops, typ="property" 

284) 

285@delegate_names( 

286 delegate=PeriodArray, accessors=PeriodArray._datetimelike_methods, typ="method" 

287) 

288class PeriodProperties(Properties): 

289 """ 

290 Accessor object for datetimelike properties of the Series values. 

291 

292 Examples 

293 -------- 

294 >>> s.dt.hour 

295 >>> s.dt.second 

296 >>> s.dt.quarter 

297 

298 Returns a Series indexed like the original Series. 

299 Raises TypeError if the Series does not contain datetimelike values. 

300 """ 

301 

302 

303class CombinedDatetimelikeProperties( 

304 DatetimeProperties, TimedeltaProperties, PeriodProperties 

305): 

306 def __new__(cls, data): 

307 # CombinedDatetimelikeProperties isn't really instantiated. Instead 

308 # we need to choose which parent (datetime or timedelta) is 

309 # appropriate. Since we're checking the dtypes anyway, we'll just 

310 # do all the validation here. 

311 from pandas import Series 

312 

313 if not isinstance(data, ABCSeries): 

314 raise TypeError( 

315 f"cannot convert an object of type {type(data)} to a datetimelike index" 

316 ) 

317 

318 orig = data if is_categorical_dtype(data) else None 

319 if orig is not None: 

320 data = Series( 

321 orig.array, 

322 name=orig.name, 

323 copy=False, 

324 dtype=orig.values.categories.dtype, 

325 ) 

326 

327 if is_datetime64_dtype(data.dtype): 

328 return DatetimeProperties(data, orig) 

329 elif is_datetime64tz_dtype(data.dtype): 

330 return DatetimeProperties(data, orig) 

331 elif is_timedelta64_dtype(data.dtype): 

332 return TimedeltaProperties(data, orig) 

333 elif is_period_arraylike(data): 

334 return PeriodProperties(data, orig) 

335 elif is_datetime_arraylike(data): 

336 return DatetimeProperties(data, orig) 

337 

338 raise AttributeError("Can only use .dt accessor with datetimelike values")