Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions generated/nidaqmx/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,23 @@ def _convert_to_desired_timezone(
# use ZoneInfo here to account for daylight savings
if isinstance(tzinfo, ZoneInfo):
localized_time = expected_time_utc.replace(tzinfo=tzinfo)
desired_expected_time = tzinfo.fromutc(localized_time)
return desired_expected_time # type: ignore[return-value] # https://github.com/ni/nidaqmx-python/issues/860
std_datetime_result = tzinfo.fromutc(localized_time)
femtosecond = getattr(expected_time_utc, "femtosecond", 0)
yoctosecond = getattr(expected_time_utc, "yoctosecond", 0)
desired_expected_time = ht_datetime(
std_datetime_result.year,
std_datetime_result.month,
std_datetime_result.day,
std_datetime_result.hour,
std_datetime_result.minute,
std_datetime_result.second,
std_datetime_result.microsecond,
femtosecond,
yoctosecond,
tzinfo=std_datetime_result.tzinfo,
fold=std_datetime_result.fold,
)
return desired_expected_time

# 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)
elif tzinfo.utcoffset(None) is not None:
Expand Down
19 changes: 17 additions & 2 deletions src/handwritten/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,23 @@ def _convert_to_desired_timezone(
# use ZoneInfo here to account for daylight savings
if isinstance(tzinfo, ZoneInfo):
localized_time = expected_time_utc.replace(tzinfo=tzinfo)
desired_expected_time = tzinfo.fromutc(localized_time)
return desired_expected_time # type: ignore[return-value] # https://github.com/ni/nidaqmx-python/issues/860
std_datetime_result = tzinfo.fromutc(localized_time)
femtosecond = getattr(expected_time_utc, "femtosecond", 0)
yoctosecond = getattr(expected_time_utc, "yoctosecond", 0)
desired_expected_time = ht_datetime(
std_datetime_result.year,
std_datetime_result.month,
std_datetime_result.day,
std_datetime_result.hour,
std_datetime_result.minute,
std_datetime_result.second,
std_datetime_result.microsecond,
femtosecond,
yoctosecond,
tzinfo=std_datetime_result.tzinfo,
fold=std_datetime_result.fold,
)
return desired_expected_time

# 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)
elif tzinfo.utcoffset(None) is not None:
Expand Down
58 changes: 58 additions & 0 deletions tests/unit/test_lib_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from hightime import datetime as ht_datetime

from nidaqmx._lib_time import AbsoluteTime as LibTimestamp
from nidaqmx._time import _convert_to_desired_timezone
from tests.unit._time_utils import (
JAN_01_1850_DATETIME,
JAN_01_1850_HIGHTIME,
Expand Down Expand Up @@ -106,6 +107,63 @@ def test___utc_datetime___convert_to_timestamp_with_dst___is_reversible(date):
assert astimezone_date == roundtrip_dt


@pytest.mark.parametrize(
"base_dt, femtosecond, subseconds",
[
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 1, 0x480F),
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 1, 0x480F),
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 1, 0x480F),
],
)
def test___utc_datetime_with_femtoseconds___convert_to_timestamp_with_dst___is_reversible(
base_dt, femtosecond, subseconds
):
target_timezone = ZoneInfo("America/Los_Angeles")
from_dt = base_dt.replace(femtosecond=femtosecond)
expected_la_time = _convert_to_desired_timezone(from_dt, target_timezone)

ts = LibTimestamp.from_datetime(from_dt)
roundtrip_dt = ts.to_datetime(tzinfo=target_timezone)

assert ts.msb == LibTimestamp.from_datetime(expected_la_time).msb
assert ts.lsb == subseconds
assert roundtrip_dt.microsecond == expected_la_time.microsecond
assert roundtrip_dt.femtosecond == expected_la_time.femtosecond
# The yoctosecond field may contain up to 1 NI-BTF tick of rounding error.
assert roundtrip_dt.yoctosecond <= 54210


@pytest.mark.parametrize(
"base_dt, yoctosecond, subseconds",
[
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 3, 12, tzinfo=timezone.utc), 54210, 1),
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 6, 1, tzinfo=timezone.utc), 54210, 1),
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 0, 0),
(ht_datetime(2023, 11, 5, tzinfo=timezone.utc), 54210, 1),
],
)
def test___utc_datetime_with_yoctoseconds___convert_to_timestamp_with_dst___is_reversible(
base_dt, yoctosecond, subseconds
):
target_timezone = ZoneInfo("America/Los_Angeles")
from_dt = base_dt.replace(yoctosecond=yoctosecond)
expected_la_time = _convert_to_desired_timezone(from_dt, target_timezone)

ts = LibTimestamp.from_datetime(from_dt)
roundtrip_dt = ts.to_datetime(tzinfo=target_timezone)

assert ts.msb == LibTimestamp.from_datetime(expected_la_time).msb
assert ts.lsb == subseconds
assert roundtrip_dt.microsecond == expected_la_time.microsecond
assert roundtrip_dt.femtosecond == expected_la_time.femtosecond
assert roundtrip_dt.yoctosecond == expected_la_time.yoctosecond


@pytest.mark.parametrize(
"datetime_cls, tzinfo, expected_offset",
[
Expand Down