Skip to content

Commit 8b86e62

Browse files
authored
Fix how zero Date/DateTimes look to other formulas (#1995)
## Context The date 1970-01-01 is incorrectly cast as a float in formula columns. See #1994 for more details. Resolves #1994 ## Proposed solution Date/DateTime values are stored as floats. To check if it should be presented as a date/datetime object, we should check if we have a float rather than if the value is truthy (as that incorrectly interprets zeros as non-dates). ## Has this been tested? - [x] 👍 yes, I added tests to the test suite - [ ] 💭 no, because this PR is a draft and still needs work - [ ] 🙅 no, because this is not relevant here - [ ] 🙋 no, because I need help <!-- Detail how we can help you -->
1 parent 3e25abe commit 8b86e62

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

sandbox/grist/column.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ class DateColumn(NumericColumn):
289289
to midnight of specific UTC dates. Accessing them yields date objects.
290290
"""
291291
def _make_rich_value(self, typed_value):
292-
return typed_value and moment.ts_to_date(typed_value)
292+
return moment.ts_to_date(typed_value) if isinstance(typed_value, float) else typed_value
293293

294294
def sample_value(self):
295295
return _sample_date
@@ -304,7 +304,8 @@ def __init__(self, table, col_id, col_info):
304304
self._timezone = col_info.type_obj.timezone
305305

306306
def _make_rich_value(self, typed_value):
307-
return typed_value and moment.ts_to_dt(typed_value, self._timezone)
307+
return (moment.ts_to_dt(typed_value, self._timezone)
308+
if isinstance(typed_value, float) else typed_value)
308309

309310
def sample_value(self):
310311
return _sample_datetime

sandbox/grist/test_date_types.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Test that Date/DateTimes produce correct types as seen by other formulas.
3+
"""
4+
import datetime
5+
import testutil
6+
import test_engine
7+
import moment
8+
9+
def D(year, month, day):
10+
return moment.date_to_ts(datetime.date(year, month, day))
11+
12+
class TestDateTypes(test_engine.EngineTestCase):
13+
def test_date_types(self):
14+
date1 = D(2025, 12, 6)
15+
datetime1 = D(2025, 12, 6) + (9 * 60 + 30) * 60 # Make it 9:30 on that date.
16+
dateZero = D(1970, 1, 1) # This should just be 0
17+
datetimeZero = D(1970, 1, 1) # This should just be 0
18+
self.load_sample(testutil.parse_test_sample({
19+
"SCHEMA": [
20+
[1, "Test", [
21+
[1, "DateCol", "Date", False],
22+
[2, "DateColType", "Any", True, "type($DateCol).__name__"],
23+
[3, "DTCol", "DateTime:UTC", False],
24+
[4, "DTColType", "Any", True, "type($DTCol).__name__"],
25+
]]
26+
],
27+
"DATA": {
28+
"Test": [
29+
["id", "DateCol", "DTCol"],
30+
[ 1, date1, datetime1],
31+
[ 2, dateZero, datetimeZero],
32+
[ 3, 0, 0],
33+
[ 5, None, None],
34+
[ 6, "n/a", "unknown"],
35+
]
36+
}
37+
}))
38+
39+
self.apply_user_action(["CreateViewSection", 1, 0, "record", [1], None])
40+
self.assertTableData('Test', cols="all", data=[
41+
["id", "DateCol", "DTCol", "DateColType", "DTColType"],
42+
[ 1, date1, datetime1, "date", "datetime"],
43+
[ 2, dateZero, datetimeZero, "date", "datetime"],
44+
[ 3, 0, 0, "date", "datetime"],
45+
[ 5, None, None, "NoneType", "NoneType"],
46+
[ 6, "n/a", "unknown", "AltText", "AltText"],
47+
])

0 commit comments

Comments
 (0)