A Duration holds a length of time as a whole number of nanoseconds, and maps to the SurrealDB duration type in both directions. This page documents how to make a Duration, how to read it in other units, and how to convert a datetime.timedelta, which the SDK does not send.
from surrealdb import DurationSource: duration.py
Constructor
Duration(elapsed=0)Parameter | Type | Description |
|---|---|---|
elapsed | int | The length of time in nanoseconds. Defaults to 0. |
length = Duration(5_000_000_000)
print(length.seconds, length)5 5sSurrealDB has no negative durations, so sending a Duration with a negative elapsed raises ValueError.
Fields
Duration is a dataclass with one field.
| Field | Type | Description |
|---|---|---|
elapsed | int | The length of time in nanoseconds. |
Duration.parse()
Duration.parse() builds a Duration from SurrealQL duration text, or from a whole number of seconds.
Duration.parse(value, nanoseconds=0)Parameter | Type | Description |
|---|---|---|
value | str | int | Text made of one or more parts, each a whole number and a unit, such as "1h30m". An intis a number of seconds. |
nanoseconds | int | Nanoseconds to add to the result. Defaults to 0. |
Returns: Duration
The units are the ones SurrealQL uses, in lower case:
| Unit | Meaning |
|---|---|
ns | Nanoseconds |
us or µs | Microseconds |
ms | Milliseconds |
s | Seconds |
m | Minutes |
h | Hours |
d | Days |
w | Weeks |
y | Years of 365 days |
parse() accepts the same text as the server. Spaces around the text are ignored, but text with a fraction ("1.5s"), a sign ("-1s"), an exponent ("1e3s") or an upper-case unit ("1H") raises InvalidDurationError, and so does a negative int.
print(Duration.parse("1h30m").minutes)
print(Duration.parse("500ms").milliseconds)
print(Duration.parse("2d12h").hours)
print(Duration.parse(90))
print(Duration.parse(90, nanoseconds=500).nanoseconds)90
500
60
1m30s
90000000500Duration.parse("1.5s")surrealdb.errors.InvalidDurationError: Invalid duration format: 1.5sProperties
Each unit property gives the number of whole units in the duration as an int, rounded down. Duration.parse("1h30m").hours is 1, not 1.5.
| Property | Type | Description |
|---|---|---|
nanoseconds | int | The whole duration in nanoseconds, the same value as elapsed. |
microseconds | int | Whole microseconds. |
milliseconds | int | Whole milliseconds. |
seconds | int | Whole seconds. |
minutes | int | Whole minutes. |
hours | int | Whole hours. |
days | int | Whole days. |
weeks | int | Whole weeks. |
years | int | Whole years of 365 days. |
For a fraction of a unit, divide nanoseconds by the length of the unit in nanoseconds.
length = Duration.parse("2h30m")
print(length.hours, length.minutes, length.seconds)
print(length.nanoseconds / 3_600_000_000_000)2 150 9000
2.5Methods
to_string()
to_string() returns the duration as SurrealQL duration text, with the largest units first. str(duration) gives the same text, and a zero duration gives 0ns.
duration.to_string()Returns: str
print(Duration.parse("90m").to_string())
print(Duration(1_500_000_000).to_string())
print(Duration().to_string())1h30m
1s500ms
0ns to_compact()
to_compact() returns a list that holds the number of whole seconds. The part of a second is not included.
duration.to_compact()Returns: list[int]
print(Duration(1_500_000_000).to_compact())[1] get_seconds_and_nano()
get_seconds_and_nano() returns the whole seconds and the nanoseconds left over, which are the two parts that SurrealDB stores.
duration.get_seconds_and_nano()Returns: tuple[int, int]
print(Duration(1_500_000_000).get_seconds_and_nano())(1, 500000000)Equality and hashing
Two Duration values are equal when they hold the same number of nanoseconds, however they were written. A Duration is hashable, so it can be a dict key or a member of a set. repr() shows the nanoseconds.
print(Duration.parse("90m") == Duration.parse("1h30m"))
print(repr(Duration.parse("90m")))True
Duration(elapsed=5400000000000)Converting a timedelta
The SDK does not send a datetime.timedelta, and raises TypeError for one. Convert it to a Duration first. Integer division by one microsecond keeps the value exact:
import datetime as dt
from surrealdb import Duration
timeout = dt.timedelta(minutes=1, seconds=30)
length = Duration((timeout // dt.timedelta(microseconds=1)) * 1000)
print(length)1m30sTo go the other way, use dt.timedelta(microseconds=length.nanoseconds // 1000). A timedelta holds microseconds, so the nanoseconds below one microsecond are dropped.
Usage
A Duration can be a field value or a query variable, and a duration that the server returns reads back as a Duration.
from surrealdb import Duration, RecordID, Surreal
with Surreal("ws://localhost:8000") as db:
db.signin({"username": "root", "password": "secret"})
db.use("surrealdb", "docs")
db.create(RecordID("account", "tobie"), {
"session_timeout": Duration.parse("30m"),
})
account = db.select(RecordID("account", "tobie")).execute()
print(repr(account["session_timeout"]))
sql = "RETURN d'2025-01-01T00:00:00Z' + $after"
print(db.query(sql, {"after": Duration.parse("6h")}).first())Duration(elapsed=1800000000000)
2025-01-01 06:00:00+00:00See also
Python values for every value class
Datetime for instants in time
Dates, times and intervals for calendar intervals in SurrealDB 4.0
Durations in SurrealQL