Skip to content

Commit d84aa84

Browse files
committed
fix hightime accuracy and add femtosecond test
1 parent fa2a2bb commit d84aa84

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

generated/nidaqmx/_time.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@ def _convert_to_desired_timezone(
2222
# use ZoneInfo here to account for daylight savings
2323
if isinstance(tzinfo, ZoneInfo):
2424
localized_time = expected_time_utc.replace(tzinfo=tzinfo)
25-
desired_expected_time = tzinfo.fromutc(localized_time)
26-
return desired_expected_time # type: ignore[return-value] # https://github.com/ni/nidaqmx-python/issues/860
25+
std_datetime_result = tzinfo.fromutc(localized_time)
26+
desired_expected_time = ht_datetime(
27+
std_datetime_result.year,
28+
std_datetime_result.month,
29+
std_datetime_result.day,
30+
std_datetime_result.hour,
31+
std_datetime_result.minute,
32+
std_datetime_result.second,
33+
std_datetime_result.microsecond,
34+
std_datetime_result.femtosecond,
35+
tzinfo=std_datetime_result.tzinfo
36+
)
37+
return desired_expected_time
2738

2839
# if the tzinfo passed in is a timedelta function, then we don't need to consider daylight savings # noqa: W505 - doc line too long (102 > 100 characters) (auto-generated noqa)
2940
elif tzinfo.utcoffset(None) is not None:

src/handwritten/_time.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@ def _convert_to_desired_timezone(
2222
# use ZoneInfo here to account for daylight savings
2323
if isinstance(tzinfo, ZoneInfo):
2424
localized_time = expected_time_utc.replace(tzinfo=tzinfo)
25-
desired_expected_time = tzinfo.fromutc(localized_time)
26-
return desired_expected_time # type: ignore[return-value] # https://github.com/ni/nidaqmx-python/issues/860
25+
std_datetime_result = tzinfo.fromutc(localized_time)
26+
desired_expected_time = ht_datetime(
27+
std_datetime_result.year,
28+
std_datetime_result.month,
29+
std_datetime_result.day,
30+
std_datetime_result.hour,
31+
std_datetime_result.minute,
32+
std_datetime_result.second,
33+
std_datetime_result.microsecond,
34+
std_datetime_result.femtosecond,
35+
tzinfo=std_datetime_result.tzinfo,
36+
)
37+
return desired_expected_time
2738

2839
# if the tzinfo passed in is a timedelta function, then we don't need to consider daylight savings # noqa: W505 - doc line too long (102 > 100 characters) (auto-generated noqa)
2940
elif tzinfo.utcoffset(None) is not None:

tests/unit/test_lib_time.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from hightime import datetime as ht_datetime
88

99
from nidaqmx._lib_time import AbsoluteTime as LibTimestamp
10+
from nidaqmx._time import _convert_to_desired_timezone
1011
from tests.unit._time_utils import (
1112
JAN_01_1850_DATETIME,
1213
JAN_01_1850_HIGHTIME,
@@ -106,6 +107,37 @@ def test___utc_datetime___convert_to_timestamp_with_dst___is_reversible(date):
106107
assert astimezone_date == roundtrip_dt
107108

108109

110+
@pytest.mark.parametrize(
111+
"base_dt, femtosecond, subseconds",
112+
[
113+
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 0, 0),
114+
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 1, 0x480F),
115+
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 0, 0),
116+
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 1, 0x480F),
117+
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 0, 0),
118+
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 1, 0x480F),
119+
],
120+
)
121+
def test___datetime_with_dst_and_femtoseconds___convert_to_timestamp___is_reversible(
122+
base_dt, femtosecond, subseconds
123+
):
124+
target_timezone = ZoneInfo("America/Los_Angeles")
125+
from_dt = base_dt.replace(femtosecond=femtosecond)
126+
expected_la_time = _convert_to_desired_timezone(from_dt, target_timezone)
127+
128+
ts = LibTimestamp.from_datetime(from_dt)
129+
roundtrip_dt = ts.to_datetime(tzinfo=target_timezone)
130+
131+
assert ts.msb == LibTimestamp.from_datetime(expected_la_time).msb
132+
assert ts.lsb == subseconds
133+
# comparison is tricky since imprecision in the conversion to NI-BTF are
134+
# caught by the higher precision values in hightime, so we round here.
135+
roundtrip_dt_femtosecond = roundtrip_dt.femtosecond
136+
if roundtrip_dt.yoctosecond > LibTimestamp.MAX_YS / 2:
137+
roundtrip_dt_femtosecond += 1
138+
assert roundtrip_dt_femtosecond == femtosecond
139+
140+
109141
@pytest.mark.parametrize(
110142
"datetime_cls, tzinfo, expected_offset",
111143
[

0 commit comments

Comments
 (0)