test_constructors.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. import calendar
  2. from datetime import (
  3. date,
  4. datetime,
  5. timedelta,
  6. timezone,
  7. )
  8. import dateutil.tz
  9. from dateutil.tz import tzutc
  10. import numpy as np
  11. import pytest
  12. import pytz
  13. from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
  14. from pandas.compat import (
  15. PY39,
  16. PY310,
  17. )
  18. from pandas.errors import OutOfBoundsDatetime
  19. from pandas import (
  20. Period,
  21. Timedelta,
  22. Timestamp,
  23. )
  24. if PY39:
  25. import zoneinfo
  26. class TestTimestampConstructors:
  27. def test_construct_from_string_invalid_raises(self):
  28. # dateutil (weirdly) parses "200622-12-31" as
  29. # datetime(2022, 6, 20, 12, 0, tzinfo=tzoffset(None, -111600)
  30. # which besides being mis-parsed, is a tzoffset that will cause
  31. # str(ts) to raise ValueError. Ensure we raise in the constructor
  32. # instead.
  33. # see test_to_datetime_malformed_raise for analogous to_datetime test
  34. with pytest.raises(ValueError, match="gives an invalid tzoffset"):
  35. Timestamp("200622-12-31")
  36. def test_constructor_str_infer_reso(self):
  37. # non-iso8601 path
  38. # _parse_delimited_date path
  39. ts = Timestamp("01/30/2023")
  40. assert ts.unit == "s"
  41. # _parse_dateabbr_string path
  42. ts = Timestamp("2015Q1")
  43. assert ts.unit == "s"
  44. # dateutil_parse path
  45. ts = Timestamp("2016-01-01 1:30:01 PM")
  46. assert ts.unit == "s"
  47. ts = Timestamp("2016 June 3 15:25:01.345")
  48. assert ts.unit == "ms"
  49. def test_constructor_from_iso8601_str_with_offset_reso(self):
  50. # GH#49737
  51. ts = Timestamp("2016-01-01 04:05:06-01:00")
  52. assert ts.unit == "s"
  53. ts = Timestamp("2016-01-01 04:05:06.000-01:00")
  54. assert ts.unit == "ms"
  55. ts = Timestamp("2016-01-01 04:05:06.000000-01:00")
  56. assert ts.unit == "us"
  57. ts = Timestamp("2016-01-01 04:05:06.000000001-01:00")
  58. assert ts.unit == "ns"
  59. def test_constructor_from_date_second_reso(self):
  60. # GH#49034 constructing from a pydate object gets lowest supported
  61. # reso, i.e. seconds
  62. obj = date(2012, 9, 1)
  63. ts = Timestamp(obj)
  64. assert ts.unit == "s"
  65. @pytest.mark.parametrize("typ", [int, float])
  66. def test_construct_from_int_float_with_unit_out_of_bound_raises(self, typ):
  67. # GH#50870 make sure we get a OutOfBoundsDatetime instead of OverflowError
  68. val = typ(150000000000000)
  69. msg = f"cannot convert input {val} with the unit 'D'"
  70. with pytest.raises(OutOfBoundsDatetime, match=msg):
  71. Timestamp(val, unit="D")
  72. @pytest.mark.parametrize("typ", [int, float])
  73. def test_constructor_int_float_with_YM_unit(self, typ):
  74. # GH#47266 avoid the conversions in cast_from_unit
  75. val = typ(150)
  76. ts = Timestamp(val, unit="Y")
  77. expected = Timestamp("2120-01-01")
  78. assert ts == expected
  79. ts = Timestamp(val, unit="M")
  80. expected = Timestamp("1982-07-01")
  81. assert ts == expected
  82. def test_constructor_float_not_round_with_YM_unit_deprecated(self):
  83. # GH#47267 avoid the conversions in cast_from-unit
  84. msg = "Conversion of non-round float with unit=[MY] is ambiguous"
  85. with pytest.raises(ValueError, match=msg):
  86. Timestamp(150.5, unit="Y")
  87. with pytest.raises(ValueError, match=msg):
  88. Timestamp(150.5, unit="M")
  89. def test_constructor_datetime64_with_tz(self):
  90. # GH#42288, GH#24559
  91. dt = np.datetime64("1970-01-01 05:00:00")
  92. tzstr = "UTC+05:00"
  93. # pre-2.0 this interpreted dt as a UTC time. in 2.0 this is treated
  94. # as a wall-time, consistent with DatetimeIndex behavior
  95. ts = Timestamp(dt, tz=tzstr)
  96. alt = Timestamp(dt).tz_localize(tzstr)
  97. assert ts == alt
  98. assert ts.hour == 5
  99. def test_constructor(self):
  100. base_str = "2014-07-01 09:00"
  101. base_dt = datetime(2014, 7, 1, 9)
  102. base_expected = 1_404_205_200_000_000_000
  103. # confirm base representation is correct
  104. assert calendar.timegm(base_dt.timetuple()) * 1_000_000_000 == base_expected
  105. tests = [
  106. (base_str, base_dt, base_expected),
  107. (
  108. "2014-07-01 10:00",
  109. datetime(2014, 7, 1, 10),
  110. base_expected + 3600 * 1_000_000_000,
  111. ),
  112. (
  113. "2014-07-01 09:00:00.000008000",
  114. datetime(2014, 7, 1, 9, 0, 0, 8),
  115. base_expected + 8000,
  116. ),
  117. (
  118. "2014-07-01 09:00:00.000000005",
  119. Timestamp("2014-07-01 09:00:00.000000005"),
  120. base_expected + 5,
  121. ),
  122. ]
  123. timezones = [
  124. (None, 0),
  125. ("UTC", 0),
  126. (pytz.utc, 0),
  127. ("Asia/Tokyo", 9),
  128. ("US/Eastern", -4),
  129. ("dateutil/US/Pacific", -7),
  130. (pytz.FixedOffset(-180), -3),
  131. (dateutil.tz.tzoffset(None, 18000), 5),
  132. ]
  133. for date_str, date_obj, expected in tests:
  134. for result in [Timestamp(date_str), Timestamp(date_obj)]:
  135. result = result.as_unit("ns") # test originally written before non-nano
  136. # only with timestring
  137. assert result.as_unit("ns")._value == expected
  138. # re-creation shouldn't affect to internal value
  139. result = Timestamp(result)
  140. assert result.as_unit("ns")._value == expected
  141. # with timezone
  142. for tz, offset in timezones:
  143. for result in [Timestamp(date_str, tz=tz), Timestamp(date_obj, tz=tz)]:
  144. result = result.as_unit(
  145. "ns"
  146. ) # test originally written before non-nano
  147. expected_tz = expected - offset * 3600 * 1_000_000_000
  148. assert result.as_unit("ns")._value == expected_tz
  149. # should preserve tz
  150. result = Timestamp(result)
  151. assert result.as_unit("ns")._value == expected_tz
  152. # should convert to UTC
  153. if tz is not None:
  154. result = Timestamp(result).tz_convert("UTC")
  155. else:
  156. result = Timestamp(result, tz="UTC")
  157. expected_utc = expected - offset * 3600 * 1_000_000_000
  158. assert result.as_unit("ns")._value == expected_utc
  159. def test_constructor_with_stringoffset(self):
  160. # GH 7833
  161. base_str = "2014-07-01 11:00:00+02:00"
  162. base_dt = datetime(2014, 7, 1, 9)
  163. base_expected = 1_404_205_200_000_000_000
  164. # confirm base representation is correct
  165. assert calendar.timegm(base_dt.timetuple()) * 1_000_000_000 == base_expected
  166. tests = [
  167. (base_str, base_expected),
  168. ("2014-07-01 12:00:00+02:00", base_expected + 3600 * 1_000_000_000),
  169. ("2014-07-01 11:00:00.000008000+02:00", base_expected + 8000),
  170. ("2014-07-01 11:00:00.000000005+02:00", base_expected + 5),
  171. ]
  172. timezones = [
  173. (None, 0),
  174. ("UTC", 0),
  175. (pytz.utc, 0),
  176. ("Asia/Tokyo", 9),
  177. ("US/Eastern", -4),
  178. ("dateutil/US/Pacific", -7),
  179. (pytz.FixedOffset(-180), -3),
  180. (dateutil.tz.tzoffset(None, 18000), 5),
  181. ]
  182. for date_str, expected in tests:
  183. for result in [Timestamp(date_str)]:
  184. # only with timestring
  185. assert result.as_unit("ns")._value == expected
  186. # re-creation shouldn't affect to internal value
  187. result = Timestamp(result)
  188. assert result.as_unit("ns")._value == expected
  189. # with timezone
  190. for tz, offset in timezones:
  191. result = Timestamp(date_str, tz=tz)
  192. expected_tz = expected
  193. assert result.as_unit("ns")._value == expected_tz
  194. # should preserve tz
  195. result = Timestamp(result)
  196. assert result.as_unit("ns")._value == expected_tz
  197. # should convert to UTC
  198. result = Timestamp(result).tz_convert("UTC")
  199. expected_utc = expected
  200. assert result.as_unit("ns")._value == expected_utc
  201. # This should be 2013-11-01 05:00 in UTC
  202. # converted to Chicago tz
  203. result = Timestamp("2013-11-01 00:00:00-0500", tz="America/Chicago")
  204. assert result._value == Timestamp("2013-11-01 05:00")._value
  205. expected = "Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago')"
  206. assert repr(result) == expected
  207. assert result == eval(repr(result))
  208. # This should be 2013-11-01 05:00 in UTC
  209. # converted to Tokyo tz (+09:00)
  210. result = Timestamp("2013-11-01 00:00:00-0500", tz="Asia/Tokyo")
  211. assert result._value == Timestamp("2013-11-01 05:00")._value
  212. expected = "Timestamp('2013-11-01 14:00:00+0900', tz='Asia/Tokyo')"
  213. assert repr(result) == expected
  214. assert result == eval(repr(result))
  215. # GH11708
  216. # This should be 2015-11-18 10:00 in UTC
  217. # converted to Asia/Katmandu
  218. result = Timestamp("2015-11-18 15:45:00+05:45", tz="Asia/Katmandu")
  219. assert result._value == Timestamp("2015-11-18 10:00")._value
  220. expected = "Timestamp('2015-11-18 15:45:00+0545', tz='Asia/Katmandu')"
  221. assert repr(result) == expected
  222. assert result == eval(repr(result))
  223. # This should be 2015-11-18 10:00 in UTC
  224. # converted to Asia/Kolkata
  225. result = Timestamp("2015-11-18 15:30:00+05:30", tz="Asia/Kolkata")
  226. assert result._value == Timestamp("2015-11-18 10:00")._value
  227. expected = "Timestamp('2015-11-18 15:30:00+0530', tz='Asia/Kolkata')"
  228. assert repr(result) == expected
  229. assert result == eval(repr(result))
  230. def test_constructor_invalid(self):
  231. msg = "Cannot convert input"
  232. with pytest.raises(TypeError, match=msg):
  233. Timestamp(slice(2))
  234. msg = "Cannot convert Period"
  235. with pytest.raises(ValueError, match=msg):
  236. Timestamp(Period("1000-01-01"))
  237. def test_constructor_invalid_tz(self):
  238. # GH#17690
  239. msg = (
  240. "Argument 'tzinfo' has incorrect type "
  241. r"\(expected datetime.tzinfo, got str\)"
  242. )
  243. with pytest.raises(TypeError, match=msg):
  244. Timestamp("2017-10-22", tzinfo="US/Eastern")
  245. msg = "at most one of"
  246. with pytest.raises(ValueError, match=msg):
  247. Timestamp("2017-10-22", tzinfo=pytz.utc, tz="UTC")
  248. msg = "Cannot pass a date attribute keyword argument when passing a date string"
  249. with pytest.raises(ValueError, match=msg):
  250. # GH#5168
  251. # case where user tries to pass tz as an arg, not kwarg, gets
  252. # interpreted as `year`
  253. Timestamp("2012-01-01", "US/Pacific")
  254. def test_constructor_strptime(self):
  255. # GH25016
  256. # Test support for Timestamp.strptime
  257. fmt = "%Y%m%d-%H%M%S-%f%z"
  258. ts = "20190129-235348-000001+0000"
  259. msg = r"Timestamp.strptime\(\) is not implemented"
  260. with pytest.raises(NotImplementedError, match=msg):
  261. Timestamp.strptime(ts, fmt)
  262. def test_constructor_tz_or_tzinfo(self):
  263. # GH#17943, GH#17690, GH#5168
  264. stamps = [
  265. Timestamp(year=2017, month=10, day=22, tz="UTC"),
  266. Timestamp(year=2017, month=10, day=22, tzinfo=pytz.utc),
  267. Timestamp(year=2017, month=10, day=22, tz=pytz.utc),
  268. Timestamp(datetime(2017, 10, 22), tzinfo=pytz.utc),
  269. Timestamp(datetime(2017, 10, 22), tz="UTC"),
  270. Timestamp(datetime(2017, 10, 22), tz=pytz.utc),
  271. ]
  272. assert all(ts == stamps[0] for ts in stamps)
  273. def test_constructor_positional_with_tzinfo(self):
  274. # GH#31929
  275. ts = Timestamp(2020, 12, 31, tzinfo=timezone.utc)
  276. expected = Timestamp("2020-12-31", tzinfo=timezone.utc)
  277. assert ts == expected
  278. @pytest.mark.parametrize("kwd", ["nanosecond", "microsecond", "second", "minute"])
  279. def test_constructor_positional_keyword_mixed_with_tzinfo(self, kwd, request):
  280. # TODO: if we passed microsecond with a keyword we would mess up
  281. # xref GH#45307
  282. if kwd != "nanosecond":
  283. # nanosecond is keyword-only as of 2.0, others are not
  284. mark = pytest.mark.xfail(reason="GH#45307")
  285. request.node.add_marker(mark)
  286. kwargs = {kwd: 4}
  287. ts = Timestamp(2020, 12, 31, tzinfo=timezone.utc, **kwargs)
  288. td_kwargs = {kwd + "s": 4}
  289. td = Timedelta(**td_kwargs)
  290. expected = Timestamp("2020-12-31", tz=timezone.utc) + td
  291. assert ts == expected
  292. def test_constructor_positional(self):
  293. # see gh-10758
  294. msg = (
  295. "'NoneType' object cannot be interpreted as an integer"
  296. if PY310
  297. else "an integer is required"
  298. )
  299. with pytest.raises(TypeError, match=msg):
  300. Timestamp(2000, 1)
  301. msg = "month must be in 1..12"
  302. with pytest.raises(ValueError, match=msg):
  303. Timestamp(2000, 0, 1)
  304. with pytest.raises(ValueError, match=msg):
  305. Timestamp(2000, 13, 1)
  306. msg = "day is out of range for month"
  307. with pytest.raises(ValueError, match=msg):
  308. Timestamp(2000, 1, 0)
  309. with pytest.raises(ValueError, match=msg):
  310. Timestamp(2000, 1, 32)
  311. # see gh-11630
  312. assert repr(Timestamp(2015, 11, 12)) == repr(Timestamp("20151112"))
  313. assert repr(Timestamp(2015, 11, 12, 1, 2, 3, 999999)) == repr(
  314. Timestamp("2015-11-12 01:02:03.999999")
  315. )
  316. def test_constructor_keyword(self):
  317. # GH 10758
  318. msg = "function missing required argument 'day'|Required argument 'day'"
  319. with pytest.raises(TypeError, match=msg):
  320. Timestamp(year=2000, month=1)
  321. msg = "month must be in 1..12"
  322. with pytest.raises(ValueError, match=msg):
  323. Timestamp(year=2000, month=0, day=1)
  324. with pytest.raises(ValueError, match=msg):
  325. Timestamp(year=2000, month=13, day=1)
  326. msg = "day is out of range for month"
  327. with pytest.raises(ValueError, match=msg):
  328. Timestamp(year=2000, month=1, day=0)
  329. with pytest.raises(ValueError, match=msg):
  330. Timestamp(year=2000, month=1, day=32)
  331. assert repr(Timestamp(year=2015, month=11, day=12)) == repr(
  332. Timestamp("20151112")
  333. )
  334. assert repr(
  335. Timestamp(
  336. year=2015,
  337. month=11,
  338. day=12,
  339. hour=1,
  340. minute=2,
  341. second=3,
  342. microsecond=999999,
  343. )
  344. ) == repr(Timestamp("2015-11-12 01:02:03.999999"))
  345. def test_constructor_fromordinal(self):
  346. base = datetime(2000, 1, 1)
  347. ts = Timestamp.fromordinal(base.toordinal())
  348. assert base == ts
  349. assert base.toordinal() == ts.toordinal()
  350. ts = Timestamp.fromordinal(base.toordinal(), tz="US/Eastern")
  351. assert Timestamp("2000-01-01", tz="US/Eastern") == ts
  352. assert base.toordinal() == ts.toordinal()
  353. # GH#3042
  354. dt = datetime(2011, 4, 16, 0, 0)
  355. ts = Timestamp.fromordinal(dt.toordinal())
  356. assert ts.to_pydatetime() == dt
  357. # with a tzinfo
  358. stamp = Timestamp("2011-4-16", tz="US/Eastern")
  359. dt_tz = stamp.to_pydatetime()
  360. ts = Timestamp.fromordinal(dt_tz.toordinal(), tz="US/Eastern")
  361. assert ts.to_pydatetime() == dt_tz
  362. @pytest.mark.parametrize(
  363. "result",
  364. [
  365. Timestamp(datetime(2000, 1, 2, 3, 4, 5, 6), nanosecond=1),
  366. Timestamp(
  367. year=2000,
  368. month=1,
  369. day=2,
  370. hour=3,
  371. minute=4,
  372. second=5,
  373. microsecond=6,
  374. nanosecond=1,
  375. ),
  376. Timestamp(
  377. year=2000,
  378. month=1,
  379. day=2,
  380. hour=3,
  381. minute=4,
  382. second=5,
  383. microsecond=6,
  384. nanosecond=1,
  385. tz="UTC",
  386. ),
  387. Timestamp(2000, 1, 2, 3, 4, 5, 6, None, nanosecond=1),
  388. Timestamp(2000, 1, 2, 3, 4, 5, 6, tz=pytz.UTC, nanosecond=1),
  389. ],
  390. )
  391. def test_constructor_nanosecond(self, result):
  392. # GH 18898
  393. # As of 2.0 (GH 49416), nanosecond should not be accepted positionally
  394. expected = Timestamp(datetime(2000, 1, 2, 3, 4, 5, 6), tz=result.tz)
  395. expected = expected + Timedelta(nanoseconds=1)
  396. assert result == expected
  397. @pytest.mark.parametrize("z", ["Z0", "Z00"])
  398. def test_constructor_invalid_Z0_isostring(self, z):
  399. # GH 8910
  400. msg = f"Unknown datetime string format, unable to parse: 2014-11-02 01:00{z}"
  401. with pytest.raises(ValueError, match=msg):
  402. Timestamp(f"2014-11-02 01:00{z}")
  403. @pytest.mark.parametrize(
  404. "arg",
  405. [
  406. "year",
  407. "month",
  408. "day",
  409. "hour",
  410. "minute",
  411. "second",
  412. "microsecond",
  413. "nanosecond",
  414. ],
  415. )
  416. def test_invalid_date_kwarg_with_string_input(self, arg):
  417. kwarg = {arg: 1}
  418. msg = "Cannot pass a date attribute keyword argument"
  419. with pytest.raises(ValueError, match=msg):
  420. Timestamp("2010-10-10 12:59:59.999999999", **kwarg)
  421. def test_out_of_bounds_integer_value(self):
  422. # GH#26651 check that we raise OutOfBoundsDatetime, not OverflowError
  423. msg = str(Timestamp.max._value * 2)
  424. with pytest.raises(OutOfBoundsDatetime, match=msg):
  425. Timestamp(Timestamp.max._value * 2)
  426. msg = str(Timestamp.min._value * 2)
  427. with pytest.raises(OutOfBoundsDatetime, match=msg):
  428. Timestamp(Timestamp.min._value * 2)
  429. def test_out_of_bounds_value(self):
  430. one_us = np.timedelta64(1).astype("timedelta64[us]")
  431. # By definition we can't go out of bounds in [ns], so we
  432. # convert the datetime64s to [us] so we can go out of bounds
  433. min_ts_us = np.datetime64(Timestamp.min).astype("M8[us]") + one_us
  434. max_ts_us = np.datetime64(Timestamp.max).astype("M8[us]")
  435. # No error for the min/max datetimes
  436. Timestamp(min_ts_us)
  437. Timestamp(max_ts_us)
  438. # We used to raise on these before supporting non-nano
  439. us_val = NpyDatetimeUnit.NPY_FR_us.value
  440. assert Timestamp(min_ts_us - one_us)._creso == us_val
  441. assert Timestamp(max_ts_us + one_us)._creso == us_val
  442. # https://github.com/numpy/numpy/issues/22346 for why
  443. # we can't use the same construction as above with minute resolution
  444. # too_low, too_high are the _just_ outside the range of M8[s]
  445. too_low = np.datetime64("-292277022657-01-27T08:29", "m")
  446. too_high = np.datetime64("292277026596-12-04T15:31", "m")
  447. msg = "Out of bounds"
  448. # One us less than the minimum is an error
  449. with pytest.raises(ValueError, match=msg):
  450. Timestamp(too_low)
  451. # One us more than the maximum is an error
  452. with pytest.raises(ValueError, match=msg):
  453. Timestamp(too_high)
  454. def test_out_of_bounds_string(self):
  455. msg = "Cannot cast .* to unit='ns' without overflow"
  456. with pytest.raises(ValueError, match=msg):
  457. Timestamp("1676-01-01").as_unit("ns")
  458. with pytest.raises(ValueError, match=msg):
  459. Timestamp("2263-01-01").as_unit("ns")
  460. ts = Timestamp("2263-01-01")
  461. assert ts.unit == "s"
  462. ts = Timestamp("1676-01-01")
  463. assert ts.unit == "s"
  464. def test_barely_out_of_bounds(self):
  465. # GH#19529
  466. # GH#19382 close enough to bounds that dropping nanos would result
  467. # in an in-bounds datetime
  468. msg = "Out of bounds nanosecond timestamp: 2262-04-11 23:47:16"
  469. with pytest.raises(OutOfBoundsDatetime, match=msg):
  470. Timestamp("2262-04-11 23:47:16.854775808")
  471. def test_bounds_with_different_units(self):
  472. out_of_bounds_dates = ("1677-09-21", "2262-04-12")
  473. time_units = ("D", "h", "m", "s", "ms", "us")
  474. for date_string in out_of_bounds_dates:
  475. for unit in time_units:
  476. dt64 = np.datetime64(date_string, unit)
  477. ts = Timestamp(dt64)
  478. if unit in ["s", "ms", "us"]:
  479. # We can preserve the input unit
  480. assert ts._value == dt64.view("i8")
  481. else:
  482. # we chose the closest unit that we _do_ support
  483. assert ts._creso == NpyDatetimeUnit.NPY_FR_s.value
  484. # With more extreme cases, we can't even fit inside second resolution
  485. info = np.iinfo(np.int64)
  486. msg = "Out of bounds nanosecond timestamp:"
  487. for value in [info.min + 1, info.max]:
  488. for unit in ["D", "h", "m"]:
  489. dt64 = np.datetime64(value, unit)
  490. with pytest.raises(OutOfBoundsDatetime, match=msg):
  491. Timestamp(dt64)
  492. in_bounds_dates = ("1677-09-23", "2262-04-11")
  493. for date_string in in_bounds_dates:
  494. for unit in time_units:
  495. dt64 = np.datetime64(date_string, unit)
  496. Timestamp(dt64)
  497. @pytest.mark.parametrize("arg", ["001-01-01", "0001-01-01"])
  498. def test_out_of_bounds_string_consistency(self, arg):
  499. # GH 15829
  500. msg = "Cannot cast 0001-01-01 00:00:00 to unit='ns' without overflow"
  501. with pytest.raises(OutOfBoundsDatetime, match=msg):
  502. Timestamp(arg).as_unit("ns")
  503. ts = Timestamp(arg)
  504. assert ts.unit == "s"
  505. assert ts.year == ts.month == ts.day == 1
  506. def test_min_valid(self):
  507. # Ensure that Timestamp.min is a valid Timestamp
  508. Timestamp(Timestamp.min)
  509. def test_max_valid(self):
  510. # Ensure that Timestamp.max is a valid Timestamp
  511. Timestamp(Timestamp.max)
  512. def test_now(self):
  513. # GH#9000
  514. ts_from_string = Timestamp("now")
  515. ts_from_method = Timestamp.now()
  516. ts_datetime = datetime.now()
  517. ts_from_string_tz = Timestamp("now", tz="US/Eastern")
  518. ts_from_method_tz = Timestamp.now(tz="US/Eastern")
  519. # Check that the delta between the times is less than 1s (arbitrarily
  520. # small)
  521. delta = Timedelta(seconds=1)
  522. assert abs(ts_from_method - ts_from_string) < delta
  523. assert abs(ts_datetime - ts_from_method) < delta
  524. assert abs(ts_from_method_tz - ts_from_string_tz) < delta
  525. assert (
  526. abs(
  527. ts_from_string_tz.tz_localize(None)
  528. - ts_from_method_tz.tz_localize(None)
  529. )
  530. < delta
  531. )
  532. def test_today(self):
  533. ts_from_string = Timestamp("today")
  534. ts_from_method = Timestamp.today()
  535. ts_datetime = datetime.today()
  536. ts_from_string_tz = Timestamp("today", tz="US/Eastern")
  537. ts_from_method_tz = Timestamp.today(tz="US/Eastern")
  538. # Check that the delta between the times is less than 1s (arbitrarily
  539. # small)
  540. delta = Timedelta(seconds=1)
  541. assert abs(ts_from_method - ts_from_string) < delta
  542. assert abs(ts_datetime - ts_from_method) < delta
  543. assert abs(ts_from_method_tz - ts_from_string_tz) < delta
  544. assert (
  545. abs(
  546. ts_from_string_tz.tz_localize(None)
  547. - ts_from_method_tz.tz_localize(None)
  548. )
  549. < delta
  550. )
  551. @pytest.mark.parametrize("tz", [None, pytz.timezone("US/Pacific")])
  552. def test_disallow_setting_tz(self, tz):
  553. # GH 3746
  554. ts = Timestamp("2010")
  555. msg = "Cannot directly set timezone"
  556. with pytest.raises(AttributeError, match=msg):
  557. ts.tz = tz
  558. @pytest.mark.parametrize("offset", ["+0300", "+0200"])
  559. def test_construct_timestamp_near_dst(self, offset):
  560. # GH 20854
  561. expected = Timestamp(f"2016-10-30 03:00:00{offset}", tz="Europe/Helsinki")
  562. result = Timestamp(expected).tz_convert("Europe/Helsinki")
  563. assert result == expected
  564. @pytest.mark.parametrize(
  565. "arg", ["2013/01/01 00:00:00+09:00", "2013-01-01 00:00:00+09:00"]
  566. )
  567. def test_construct_with_different_string_format(self, arg):
  568. # GH 12064
  569. result = Timestamp(arg)
  570. expected = Timestamp(datetime(2013, 1, 1), tz=pytz.FixedOffset(540))
  571. assert result == expected
  572. @pytest.mark.parametrize("box", [datetime, Timestamp])
  573. def test_raise_tz_and_tzinfo_in_datetime_input(self, box):
  574. # GH 23579
  575. kwargs = {"year": 2018, "month": 1, "day": 1, "tzinfo": pytz.utc}
  576. msg = "Cannot pass a datetime or Timestamp"
  577. with pytest.raises(ValueError, match=msg):
  578. Timestamp(box(**kwargs), tz="US/Pacific")
  579. msg = "Cannot pass a datetime or Timestamp"
  580. with pytest.raises(ValueError, match=msg):
  581. Timestamp(box(**kwargs), tzinfo=pytz.timezone("US/Pacific"))
  582. def test_dont_convert_dateutil_utc_to_pytz_utc(self):
  583. result = Timestamp(datetime(2018, 1, 1), tz=tzutc())
  584. expected = Timestamp(datetime(2018, 1, 1)).tz_localize(tzutc())
  585. assert result == expected
  586. def test_constructor_subclassed_datetime(self):
  587. # GH 25851
  588. # ensure that subclassed datetime works for
  589. # Timestamp creation
  590. class SubDatetime(datetime):
  591. pass
  592. data = SubDatetime(2000, 1, 1)
  593. result = Timestamp(data)
  594. expected = Timestamp(2000, 1, 1)
  595. assert result == expected
  596. def test_constructor_fromisocalendar(self):
  597. # GH 30395
  598. expected_timestamp = Timestamp("2000-01-03 00:00:00")
  599. expected_stdlib = datetime.fromisocalendar(2000, 1, 1)
  600. result = Timestamp.fromisocalendar(2000, 1, 1)
  601. assert result == expected_timestamp
  602. assert result == expected_stdlib
  603. assert isinstance(result, Timestamp)
  604. def test_constructor_ambigous_dst():
  605. # GH 24329
  606. # Make sure that calling Timestamp constructor
  607. # on Timestamp created from ambiguous time
  608. # doesn't change Timestamp.value
  609. ts = Timestamp(1382835600000000000, tz="dateutil/Europe/London")
  610. expected = ts._value
  611. result = Timestamp(ts)._value
  612. assert result == expected
  613. @pytest.mark.parametrize("epoch", [1552211999999999872, 1552211999999999999])
  614. def test_constructor_before_dst_switch(epoch):
  615. # GH 31043
  616. # Make sure that calling Timestamp constructor
  617. # on time just before DST switch doesn't lead to
  618. # nonexistent time or value change
  619. ts = Timestamp(epoch, tz="dateutil/America/Los_Angeles")
  620. result = ts.tz.dst(ts)
  621. expected = timedelta(seconds=0)
  622. assert Timestamp(ts)._value == epoch
  623. assert result == expected
  624. def test_timestamp_constructor_identity():
  625. # Test for #30543
  626. expected = Timestamp("2017-01-01T12")
  627. result = Timestamp(expected)
  628. assert result is expected
  629. @pytest.mark.parametrize("kwargs", [{}, {"year": 2020}, {"year": 2020, "month": 1}])
  630. def test_constructor_missing_keyword(kwargs):
  631. # GH 31200
  632. # The exact error message of datetime() depends on its version
  633. msg1 = r"function missing required argument '(year|month|day)' \(pos [123]\)"
  634. msg2 = r"Required argument '(year|month|day)' \(pos [123]\) not found"
  635. msg = "|".join([msg1, msg2])
  636. with pytest.raises(TypeError, match=msg):
  637. Timestamp(**kwargs)
  638. @pytest.mark.parametrize("nano", [-1, 1000])
  639. def test_timestamp_nano_range(nano):
  640. # GH 48255
  641. with pytest.raises(ValueError, match="nanosecond must be in 0..999"):
  642. Timestamp(year=2022, month=1, day=1, nanosecond=nano)
  643. def test_non_nano_value():
  644. # https://github.com/pandas-dev/pandas/issues/49076
  645. result = Timestamp("1800-01-01", unit="s").value
  646. # `.value` shows nanoseconds, even though unit is 's'
  647. assert result == -5364662400000000000
  648. # out-of-nanoseconds-bounds `.value` raises informative message
  649. msg = (
  650. r"Cannot convert Timestamp to nanoseconds without overflow. "
  651. r"Use `.asm8.view\('i8'\)` to cast represent Timestamp in its "
  652. r"own unit \(here, s\).$"
  653. )
  654. ts = Timestamp("0300-01-01")
  655. with pytest.raises(OverflowError, match=msg):
  656. ts.value
  657. # check that the suggested workaround actually works
  658. result = ts.asm8.view("i8")
  659. assert result == -52700112000
  660. def test_timestamp_constructor_invalid_fold_raise():
  661. # Test forGH #25057
  662. # Valid fold values are only [None, 0, 1]
  663. msg = "Valid values for the fold argument are None, 0, or 1."
  664. with pytest.raises(ValueError, match=msg):
  665. Timestamp(123, fold=2)
  666. def test_timestamp_constructor_pytz_fold_raise():
  667. # Test for GH#25057
  668. # pytz doesn't support fold. Check that we raise
  669. # if fold is passed with pytz
  670. msg = "pytz timezones do not support fold. Please use dateutil timezones."
  671. tz = pytz.timezone("Europe/London")
  672. with pytest.raises(ValueError, match=msg):
  673. Timestamp(datetime(2019, 10, 27, 0, 30, 0, 0), tz=tz, fold=0)
  674. @pytest.mark.parametrize("fold", [0, 1])
  675. @pytest.mark.parametrize(
  676. "ts_input",
  677. [
  678. 1572136200000000000,
  679. 1572136200000000000.0,
  680. np.datetime64(1572136200000000000, "ns"),
  681. "2019-10-27 01:30:00+01:00",
  682. datetime(2019, 10, 27, 0, 30, 0, 0, tzinfo=timezone.utc),
  683. ],
  684. )
  685. def test_timestamp_constructor_fold_conflict(ts_input, fold):
  686. # Test for GH#25057
  687. # Check that we raise on fold conflict
  688. msg = (
  689. "Cannot pass fold with possibly unambiguous input: int, float, "
  690. "numpy.datetime64, str, or timezone-aware datetime-like. "
  691. "Pass naive datetime-like or build Timestamp from components."
  692. )
  693. with pytest.raises(ValueError, match=msg):
  694. Timestamp(ts_input=ts_input, fold=fold)
  695. @pytest.mark.parametrize("tz", ["dateutil/Europe/London", None])
  696. @pytest.mark.parametrize("fold", [0, 1])
  697. def test_timestamp_constructor_retain_fold(tz, fold):
  698. # Test for GH#25057
  699. # Check that we retain fold
  700. ts = Timestamp(year=2019, month=10, day=27, hour=1, minute=30, tz=tz, fold=fold)
  701. result = ts.fold
  702. expected = fold
  703. assert result == expected
  704. _tzs = ["dateutil/Europe/London"]
  705. if PY39:
  706. try:
  707. _tzs = ["dateutil/Europe/London", zoneinfo.ZoneInfo("Europe/London")]
  708. except zoneinfo.ZoneInfoNotFoundError:
  709. pass
  710. @pytest.mark.parametrize("tz", _tzs)
  711. @pytest.mark.parametrize(
  712. "ts_input,fold_out",
  713. [
  714. (1572136200000000000, 0),
  715. (1572139800000000000, 1),
  716. ("2019-10-27 01:30:00+01:00", 0),
  717. ("2019-10-27 01:30:00+00:00", 1),
  718. (datetime(2019, 10, 27, 1, 30, 0, 0, fold=0), 0),
  719. (datetime(2019, 10, 27, 1, 30, 0, 0, fold=1), 1),
  720. ],
  721. )
  722. def test_timestamp_constructor_infer_fold_from_value(tz, ts_input, fold_out):
  723. # Test for GH#25057
  724. # Check that we infer fold correctly based on timestamps since utc
  725. # or strings
  726. ts = Timestamp(ts_input, tz=tz)
  727. result = ts.fold
  728. expected = fold_out
  729. assert result == expected
  730. @pytest.mark.parametrize("tz", ["dateutil/Europe/London"])
  731. @pytest.mark.parametrize(
  732. "ts_input,fold,value_out",
  733. [
  734. (datetime(2019, 10, 27, 1, 30, 0, 0), 0, 1572136200000000),
  735. (datetime(2019, 10, 27, 1, 30, 0, 0), 1, 1572139800000000),
  736. ],
  737. )
  738. def test_timestamp_constructor_adjust_value_for_fold(tz, ts_input, fold, value_out):
  739. # Test for GH#25057
  740. # Check that we adjust value for fold correctly
  741. # based on timestamps since utc
  742. ts = Timestamp(ts_input, tz=tz, fold=fold)
  743. result = ts._value
  744. expected = value_out
  745. assert result == expected