Skip to content

Commit da6de99

Browse files
committed
nanosecond utility functions
1 parent 3390675 commit da6de99

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

pyiceberg/utils/datetime.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,20 @@ def time_str_to_nanos(time_str: str) -> int:
9898

9999
def time_to_nanos(t: time) -> int:
100100
"""Convert a datetime.time object to nanoseconds from midnight."""
101-
return (((t.hour * 60 + t.minute) * 60) + t.second) * 1_000_000 + t.microsecond + t.nanosecond
101+
# python datetime and time doesn't have nanoseconds support yet
102+
# https://github.com/python/cpython/issues/59648
103+
return ((((t.hour * 60 + t.minute) * 60) + t.second) * 1_000_000 + t.microsecond) * 1_000
102104

103105

104106
def datetime_to_nanos(dt: datetime) -> int:
105107
"""Convert a datetime to nanoseconds from 1970-01-01T00:00:00.000000000."""
108+
# python datetime and time doesn't have nanoseconds support yet
109+
# https://github.com/python/cpython/issues/59648
106110
if dt.tzinfo:
107111
delta = dt - EPOCH_TIMESTAMPTZ
108112
else:
109113
delta = dt - EPOCH_TIMESTAMP
110-
return (delta.days * 86400 + delta.seconds) * 1_000_000 + delta.microseconds + delta.nanoseconds
114+
return ((delta.days * 86400 + delta.seconds) * 1_000_000 + delta.microseconds) * 1_000
111115

112116

113117
def timestamp_to_nanos(timestamp_str: str) -> int:

tests/utils/test_datetime.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
from datetime import datetime, timezone, tzinfo
17+
from datetime import datetime, time, timezone, tzinfo
1818

1919
import pytest
2020
import pytz
2121

22-
from pyiceberg.utils.datetime import datetime_to_millis, millis_to_datetime
22+
from pyiceberg.utils.datetime import (
23+
datetime_to_millis,
24+
datetime_to_nanos,
25+
millis_to_datetime,
26+
time_str_to_nanos,
27+
time_to_nanos,
28+
timestamp_to_nanos,
29+
)
2330

2431
timezones = [
2532
pytz.timezone("Etc/GMT"),
@@ -71,3 +78,31 @@ def test_datetime_tz_to_millis(tz: tzinfo) -> None:
7178

7279
def test_millis_to_datetime() -> None:
7380
assert millis_to_datetime(1690971805918) == datetime(2023, 8, 2, 10, 23, 25, 918000)
81+
82+
83+
@pytest.mark.parametrize("time_str, nanos", [("00:00:00Z", 0), ("20:21:44.375612-0500", 73304375612000)])
84+
def test_time_str_to_nanos(time_str: str, nanos: int) -> None:
85+
assert nanos == time_str_to_nanos(time_str)
86+
87+
88+
@pytest.mark.parametrize(
89+
"time_, nanos", [(time(0, 0, 0), 0), (time(20, 21, 44, 375612, tzinfo=pytz.timezone("Etc/GMT-5")), 73304375612000)]
90+
)
91+
def test_time_to_nanos(time_: time, nanos: int) -> None:
92+
assert nanos == time_to_nanos(time_)
93+
94+
95+
@pytest.mark.parametrize(
96+
"datetime_, nanos",
97+
[
98+
(datetime(1970, 1, 1, 0, 0, 0), 0),
99+
(datetime(2025, 2, 23, 20, 21, 44, 375612, tzinfo=pytz.timezone("Etc/GMT-5")), 1740324104375612000),
100+
],
101+
)
102+
def test_datetime_to_nanos(datetime_: datetime, nanos: int) -> None:
103+
assert nanos == datetime_to_nanos(datetime_)
104+
105+
106+
@pytest.mark.parametrize("timestamp, nanos", [("1970-01-01T00:00:00", 0), ("2025-02-23T20:21:44.375612", 1740342104375612000)])
107+
def test_timestamp_to_nanos(timestamp: str, nanos: int) -> None:
108+
assert nanos == timestamp_to_nanos(timestamp)

0 commit comments

Comments
 (0)