Skip to content

Commit 133541d

Browse files
authored
Fix!: to_datetime now only accepts millis and not epoch seconds (#1540)
this solves an issue where dates between 1970 and 1972 are ambiguous.
1 parent 7176087 commit 133541d

File tree

3 files changed

+14
-18
lines changed

3 files changed

+14
-18
lines changed

sqlmesh/utils/cron.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ def interval_seconds(self) -> int:
2727
to substitute for the cron call.
2828
"""
2929
if self._interval_seconds is None:
30-
seconds = set()
30+
deltas = set()
3131
curr = self.curr
3232

3333
for _ in range(self.ESTIMATE_SAMPLES_NUM):
3434
prev = curr
35-
curr = to_datetime(croniter(self.cron, curr).get_next())
36-
seconds.add(curr - prev)
35+
curr = to_datetime(croniter(self.cron, curr).get_next() * 1000)
36+
deltas.add(curr - prev)
3737

38-
if len(seconds) == 1:
39-
self._interval_seconds = int(first(seconds).total_seconds())
38+
if len(deltas) == 1:
39+
self._interval_seconds = int(first(deltas).total_seconds())
4040
else:
4141
self._interval_seconds = 0
4242

@@ -46,12 +46,12 @@ def get_next(self, estimate: bool = False) -> datetime:
4646
if estimate and self.interval_seconds:
4747
self.curr = self.curr + timedelta(seconds=self.interval_seconds)
4848
else:
49-
self.curr = to_datetime(croniter(self.cron, self.curr).get_next())
49+
self.curr = to_datetime(croniter(self.cron, self.curr).get_next() * 1000)
5050
return self.curr
5151

5252
def get_prev(self, estimate: bool = False) -> datetime:
5353
if estimate and self.interval_seconds:
5454
self.curr = self.curr - timedelta(seconds=self.interval_seconds)
5555
else:
56-
self.curr = to_datetime(croniter(self.cron, self.curr).get_prev())
56+
self.curr = to_datetime(croniter(self.cron, self.curr).get_prev() * 1000)
5757
return self.curr

sqlmesh/utils/date.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
UTC = timezone.utc
2020
TimeLike = t.Union[date, datetime, str, int, float]
21-
MILLIS_THRESHOLD = time.time() + 100 * 365 * 24 * 3600
2221
DATE_INT_FMT = "%Y%m%d"
2322

2423
if t.TYPE_CHECKING:
@@ -122,8 +121,7 @@ def to_datetime(value: TimeLike, relative_base: t.Optional[datetime] = None) ->
122121
"""Converts a value into a UTC datetime object.
123122
124123
Args:
125-
value: A variety of date formats. If the value is number-like, it is assumed to be millisecond epochs
126-
if it is larger than MILLIS_THRESHOLD.
124+
value: A variety of date formats. If the value is number-like, it is assumed to be millisecond epochs.
127125
relative_base: The datetime to reference for time expressions that are using relative terms
128126
129127
Raises:
@@ -154,9 +152,7 @@ def to_datetime(value: TimeLike, relative_base: t.Optional[datetime] = None) ->
154152
try:
155153
dt = datetime.strptime(str(value), DATE_INT_FMT)
156154
except ValueError:
157-
dt = datetime.fromtimestamp(
158-
epoch / 1000.0 if epoch > MILLIS_THRESHOLD else epoch, tz=UTC
159-
)
155+
dt = datetime.fromtimestamp(epoch / 1000.0, tz=UTC)
160156

161157
if dt is None:
162158
raise ValueError(f"Could not convert `{value}` to datetime.")
@@ -169,8 +165,7 @@ def to_datetime(value: TimeLike, relative_base: t.Optional[datetime] = None) ->
169165
def to_date(value: TimeLike, relative_base: t.Optional[datetime] = None) -> date:
170166
"""Converts a value into a UTC date object
171167
Args:
172-
value: A variety of date formats. If the value is number-like, it is assumed to be millisecond epochs
173-
if it is larger than MILLIS_THRESHOLD.
168+
value: A variety of date formats. If the value is number-like, it is assumed to be millisecond epochs.
174169
relative_base: The datetime to reference for time expressions that are using relative terms
175170
176171
Raises:

tests/utils/test_date.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ def test_to_datetime() -> None:
1919
assert to_datetime("2020-01-01T05:00:00+05:00") == target
2020
assert to_datetime("2020-01-01") == target
2121
assert to_datetime(datetime(2020, 1, 1)) == target
22-
assert to_datetime("1577836800") == target
23-
assert to_datetime(1577836800) == target
24-
assert to_datetime(1577836800.0) == target
2522
assert to_datetime(1577836800000) == target
2623
assert to_datetime(20200101) == target
2724
assert to_datetime("20200101") == target
2825
assert to_datetime("0") == datetime(1970, 1, 1, tzinfo=UTC)
2926

27+
target = datetime(1971, 1, 1).replace(tzinfo=UTC)
28+
assert to_datetime("1971-01-01") == target
29+
assert to_datetime("31536000000") == target
30+
3031

3132
@pytest.mark.parametrize(
3233
"expression, result",

0 commit comments

Comments
 (0)