Skip to content

Commit 69fbb0a

Browse files
authored
Add examples for temporal types for the manual (#616)
This PR also fixes a bug in serialization of times in a timezone with a negative utc offset.
1 parent 1fe9d01 commit 69fbb0a

File tree

3 files changed

+318
-2
lines changed

3 files changed

+318
-2
lines changed

neo4j/time/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2077,7 +2077,7 @@ def now(cls, tz=None):
20772077
"""Get the current date and time.
20782078
20792079
:param tz: timezone. Set to None to create a local :class:`.DateTime`.
2080-
:type tz: datetime.tzinfo` or Non
2080+
:type tz: datetime.tzinfo` or None
20812081
20822082
:rtype: DateTime
20832083

neo4j/time/hydration.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ def dehydrate_time(value):
100100
else:
101101
raise TypeError("Value must be a neo4j.time.Time or a datetime.time")
102102
if value.tzinfo:
103-
return Structure(b"T", nanoseconds, value.tzinfo.utcoffset(value).seconds)
103+
return Structure(b"T", nanoseconds,
104+
int(value.tzinfo.utcoffset(value).total_seconds()))
104105
else:
105106
return Structure(b"t", nanoseconds)
106107

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
4+
# Copyright (c) "Neo4j"
5+
# Neo4j Sweden AB [http://neo4j.com]
6+
#
7+
# This file is part of Neo4j.
8+
#
9+
# Licensed under the Apache License, Version 2.0 (the "License");
10+
# you may not use this file except in compliance with the License.
11+
# You may obtain a copy of the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS,
17+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
# See the License for the specific language governing permissions and
19+
# limitations under the License.
20+
21+
# python -m pytest tests/integration/examples/test_temporal_types_example.py -s -v
22+
23+
24+
def _echo(tx, x):
25+
return tx.run("RETURN $x AS fieldName", x=x).single()
26+
27+
28+
def test_datetime(driver):
29+
# tag::temporal-types-datetime-import[]
30+
from datetime import datetime
31+
32+
from neo4j.time import DateTime
33+
import pytz
34+
# end::temporal-types-datetime-import[]
35+
36+
# tag::temporal-types-datetime[]
37+
# Create datetimes to be used as query parameters
38+
# Python's builtin datetimes works as well. However, they don't support
39+
# the full feature-set of Neo4j's durations: it has no nanosecond precision.
40+
py_dt = datetime(2021, month=11, day=2, hour=7, minute=47, microsecond=4)
41+
py_dt = pytz.timezone("US/Eastern").localize(py_dt)
42+
43+
# A DateTime can be created from a native datetime
44+
dt = DateTime.from_native(py_dt)
45+
# or directly
46+
dt = DateTime(year=2021, month=11, day=2, hour=7, minute=47,
47+
nanosecond=4123)
48+
dt = pytz.timezone("US/Eastern").localize(dt)
49+
# end::temporal-types-datetime[]
50+
51+
in_dt = dt # stored for later assertions
52+
53+
with driver.session() as session:
54+
record = session.read_transaction(_echo, dt)
55+
56+
# tag::temporal-types-datetime[]
57+
58+
# Reading a DateTime from a record
59+
dt = record.get("fieldName") # type: DateTime
60+
str(dt) # '2021-11-02T07:47:09.232260000-04:00'
61+
62+
# converting DateTime to native datetime (lossy)
63+
native = dt.to_native() # type: datetime
64+
# end::temporal-types-datetime[]
65+
66+
assert isinstance(dt, DateTime)
67+
assert str(dt) == "2021-11-02T07:47:00.000004123-04:00"
68+
assert dt == in_dt
69+
assert isinstance(native, datetime)
70+
assert native == py_dt
71+
72+
with driver.session() as session:
73+
record = session.read_transaction(_echo, py_dt)
74+
75+
dt = record.get("fieldName")
76+
assert isinstance(dt, DateTime)
77+
assert dt == in_dt.to_native()
78+
79+
80+
def test_date(driver):
81+
# tag::temporal-types-date-import[]
82+
from datetime import date
83+
84+
from neo4j.time import Date
85+
# end::temporal-types-date-import[]
86+
87+
# tag::temporal-types-date[]
88+
# Create dates to be used as query parameters
89+
# Python's builtin dates works as well.
90+
py_d = date(year=2021, month=11, day=2)
91+
92+
# A Date can be created from a native date
93+
d = Date.from_native(py_d)
94+
# or directly
95+
d = Date(year=2021, month=11, day=2)
96+
# end::temporal-types-date[]
97+
98+
assert d == Date.from_native(py_d)
99+
100+
in_d = d # stored for later assertions
101+
102+
with driver.session() as session:
103+
record = session.read_transaction(_echo, d)
104+
105+
# tag::temporal-types-date[]
106+
107+
# Reading a Date from a record
108+
d = record.get("fieldName") # type: Date
109+
str(d) # '2021-11-02'
110+
111+
# converting Date to native date
112+
native = d.to_native() # type: date
113+
# end::temporal-types-date[]
114+
115+
assert isinstance(d, Date)
116+
assert str(d) == "2021-11-02"
117+
assert d == in_d
118+
assert isinstance(native, date)
119+
assert native == py_d
120+
121+
with driver.session() as session:
122+
record = session.read_transaction(_echo, py_d)
123+
124+
d = record.get("fieldName")
125+
assert isinstance(d, Date)
126+
assert d == in_d.to_native()
127+
128+
129+
def test_time(driver):
130+
# tag::temporal-types-time-import[]
131+
from datetime import time
132+
133+
from neo4j.time import Time
134+
import pytz
135+
# end::temporal-types-time-import[]
136+
137+
# tag::temporal-types-time[]
138+
# Create datetimes to be used as query parameters
139+
# Python's builtin datetimes works as well. However, they don't support
140+
# the full feature-set of Neo4j's durations: it has no nanosecond precision.
141+
py_t = time(hour=7, minute=47, microsecond=4, tzinfo=pytz.FixedOffset(-240))
142+
143+
# A Time can be created from a native time
144+
t = Time.from_native(py_t)
145+
# or directly
146+
t = Time(hour=7, minute=47, nanosecond=4123, tzinfo=pytz.FixedOffset(-240))
147+
# end::temporal-types-time[]
148+
149+
in_t = t # stored for later assertions
150+
151+
with driver.session() as session:
152+
record = session.read_transaction(_echo, t)
153+
154+
# tag::temporal-types-time[]
155+
156+
# Reading a Time from a record
157+
t = record.get("fieldName") # type: Time
158+
str(t) # 'T07:47:09.232260000-04:00'
159+
160+
# converting Time to native time (lossy)
161+
native = t.to_native() # type: time
162+
# end::temporal-types-time[]
163+
164+
assert isinstance(t, Time)
165+
assert str(t) == "07:47:00.000004123-04:00"
166+
assert t == in_t
167+
assert isinstance(native, time)
168+
assert native == py_t
169+
170+
with driver.session() as session:
171+
record = session.read_transaction(_echo, py_t)
172+
173+
t = record.get("fieldName")
174+
assert isinstance(t, Time)
175+
assert t == in_t.to_native()
176+
177+
178+
def test_local_datetime(driver):
179+
# tag::temporal-types-local-datetime-import[]
180+
from datetime import datetime
181+
182+
from neo4j.time import DateTime
183+
import pytz
184+
# end::temporal-types-local-datetime-import[]
185+
186+
# tag::temporal-types-local-datetime[]
187+
# Create datetimes to be used as query parameters
188+
# Python's builtin datetimes works as well. However, they don't support
189+
# the full feature-set of Neo4j's durations: it has no nanosecond precision.
190+
py_dt = datetime(2021, month=11, day=2, hour=7, minute=47, microsecond=4)
191+
192+
# A DateTime can be created from a native datetime
193+
dt = DateTime.from_native(py_dt)
194+
# or directly
195+
dt = DateTime(year=2021, month=11, day=2, hour=7, minute=47,
196+
nanosecond=4123)
197+
# end::temporal-types-local-datetime[]
198+
199+
in_dt = dt # stored for later assertions
200+
201+
with driver.session() as session:
202+
record = session.read_transaction(_echo, dt)
203+
204+
# tag::temporal-types-local-datetime[]
205+
206+
# Reading a DateTime from a record
207+
dt = record.get("fieldName") # type: DateTime
208+
str(dt) # '2021-11-02T07:47:09.232260000'
209+
210+
# converting DateTime to native datetime (lossy)
211+
native = dt.to_native() # type: datetime
212+
# end::temporal-types-local-datetime[]
213+
214+
assert isinstance(dt, DateTime)
215+
assert str(dt) == "2021-11-02T07:47:00.000004123"
216+
assert dt == in_dt
217+
assert isinstance(native, datetime)
218+
assert native == py_dt
219+
220+
with driver.session() as session:
221+
record = session.read_transaction(_echo, py_dt)
222+
223+
dt = record.get("fieldName")
224+
assert isinstance(dt, DateTime)
225+
assert dt == in_dt.to_native()
226+
227+
228+
def test_local_time(driver):
229+
# tag::temporal-types-local-time-import[]
230+
from datetime import time
231+
232+
from neo4j.time import Time
233+
import pytz
234+
# end::temporal-types-local-time-import[]
235+
236+
# tag::temporal-types-local-time[]
237+
# Create datetimes to be used as query parameters
238+
# Python's builtin datetimes works as well. However, they don't support
239+
# the full feature-set of Neo4j's durations: it has no nanosecond precision.
240+
py_t = time(hour=7, minute=47, microsecond=4)
241+
242+
# A Time can be created from a native time
243+
t = Time.from_native(py_t)
244+
# or directly
245+
t = Time(hour=7, minute=47, nanosecond=4123)
246+
# end::temporal-types-local-time[]
247+
248+
in_t = t # stored for later assertions
249+
250+
with driver.session() as session:
251+
record = session.read_transaction(_echo, t)
252+
253+
# tag::temporal-types-local-time[]
254+
255+
# Reading a Time from a record
256+
t = record.get("fieldName") # type: Time
257+
str(t) # 'T07:47:09.232260000'
258+
259+
# converting Time to native time (lossy)
260+
native = t.to_native() # type: time
261+
# end::temporal-types-local-time[]
262+
263+
assert isinstance(t, Time)
264+
assert str(t) == "07:47:00.000004123"
265+
assert t == in_t
266+
assert isinstance(native, time)
267+
assert native == py_t
268+
269+
with driver.session() as session:
270+
record = session.read_transaction(_echo, py_t)
271+
272+
t = record.get("fieldName")
273+
assert isinstance(t, Time)
274+
assert t == in_t.to_native()
275+
276+
277+
def test_duration_example(driver):
278+
# tag::temporal-types-duration-import[]
279+
from datetime import timedelta
280+
281+
from neo4j.time import Duration
282+
# end::temporal-types-duration-import[]
283+
284+
# tag::temporal-types-duration[]
285+
# Creating durations to be used as query parameters
286+
duration = Duration(years=1, days=2, seconds=3, nanoseconds=4)
287+
# Python's builtin timedeltas works as well. However, they don't support
288+
# the full feature-set of Neo4j's durations,
289+
# e.g., no nanoseconds and no months.
290+
py_duration = timedelta(days=2, seconds=3, microseconds=4)
291+
# end::temporal-types-duration[]
292+
293+
in_duration = duration # stored for later assertions
294+
295+
with driver.session() as session:
296+
record = session.read_transaction(_echo, duration)
297+
298+
# tag::temporal-types-duration[]
299+
300+
# Reading a Duration from a record
301+
duration = record.get("fieldName") # type: Duration
302+
str(duration) # 'P1Y2DT3.000000004S'
303+
# end::temporal-types-duration[]
304+
305+
assert isinstance(duration, Duration)
306+
assert str(duration) == 'P1Y2DT3.000000004S'
307+
assert duration == in_duration
308+
309+
with driver.session() as session:
310+
record = session.read_transaction(_echo, py_duration)
311+
312+
duration = record.get("fieldName")
313+
assert isinstance(duration, Duration)
314+
assert str(duration) == 'P2DT3.000004S'
315+
assert Duration() + py_duration == duration

0 commit comments

Comments
 (0)