Time types
Create and use timestamps, time spans, time ranges, and rates with nanosecond precision in the Python and TypeScript clients.
Synnax stores each timestamp as a 64-bit integer: the number of nanoseconds since the Unix epoch, 1970-01-01 00:00:00 UTC. The clients give you four types that keep this precision:
Methods such as read and write take a time type, or any value that its constructor
takes, such as a datetime in Python or a Date in TypeScript.
TimeStamp
Create a timestamp
Python
TypeScript
from datetime import datetime, timezone
import pandas as pd
import synnax as sy
now = sy.TimeStamp.now()
# From a datetime. A datetime with no time zone is in local time.
start = sy.TimeStamp(datetime(2026, 10, 3, 12, 0, tzinfo=timezone.utc))
# From a pandas Timestamp.
start = sy.TimeStamp(pd.Timestamp("2026-10-03 12:00:00", tz="UTC"))
# From nanoseconds since the Unix epoch.
start = sy.TimeStamp(1_791_028_800_000_000_000)The Python client does not parse strings: sy.TimeStamp("2026-10-03") raises a
ValueError. Parse the string with datetime.fromisoformat or pandas first.
import { TimeSpan, TimeStamp } from "@synnaxlabs/client";
const now = TimeStamp.now();
// From an ISO 8601 string. A string with no time zone is in UTC.
const start = new TimeStamp("2026-10-03T12:00:00Z");
// From a Date.
const fromDate = new TimeStamp(new Date("2026-10-03T12:00:00Z"));
// From nanoseconds since the Unix epoch.
const fromNanoseconds = new TimeStamp(1_791_028_800_000_000_000n);A number is also nanoseconds: new TimeStamp(1_000_000_000) is one second after the
epoch. To read a string in local time, pass "local" as the second argument.
Add, subtract, and compare
Python
TypeScript
later = start + sy.TimeSpan.MINUTE
print(later - start) # 1m
print(later > start) # True
print(later.after_eq(start)) # TrueSubtracting two timestamps returns the time between them as a TimeSpan. Add or
subtract a TimeSpan, not a bare number: start + 5 raises a TypeError.
const later = start.add(TimeSpan.MINUTE);
console.log(later.span(start).toString()); // 1m
// 2026-10-03T12:00:30.000Z
console.log(later.sub(TimeSpan.seconds(30)).toString());
console.log(later.after(start)); // true
console.log(later.afterEq(start)); // truebefore and beforeEq compare in the other direction.
Convert a timestamp
Python
TypeScript
print(start.datetime(tz=timezone.utc)) # 2026-10-03 12:00:00+00:00
print(start.datetime()) # The same time, in the local time zone.
print(int(start)) # 1791028800000000000console.log(start.date()); // 2026-10-03T12:00:00.000Z
console.log(start.toString()); // 2026-10-03T12:00:00.000Z
console.log(start.valueOf()); // 1791028800000000000nTimeSpan
Python
TypeScript
from datetime import timedelta
timeout = sy.TimeSpan.MILLISECOND * 250
print(timeout) # 250ms
print(timeout.seconds) # 0.25
print(sy.TimeSpan.from_seconds(1.5)) # 1s 500ms
print(sy.TimeSpan(timedelta(minutes=2))) # 2m
print(timeout / 2) # 125ms
print(sy.TimeSpan.MINUTE / sy.TimeSpan.SECOND) # 60.0The constants are NANOSECOND, MICROSECOND, MILLISECOND, SECOND, MINUTE,
HOUR, and DAY. The properties seconds, milliseconds, and the other units return
floats, and timedelta returns a Python timedelta.
const timeout = TimeSpan.milliseconds(250);
console.log(timeout.toString()); // 250ms
console.log(timeout.seconds); // 0.25
console.log(TimeSpan.SECOND.mult(5).toString()); // 5s
console.log(TimeSpan.parse("2h 30m").toString()); // 2h 30mThe static methods are nanoseconds, microseconds, milliseconds, seconds,
minutes, hours, and days, and each has a constant such as TimeSpan.SECOND.
TimeRange
A time range includes its start and excludes its end. A sample at the end of a time range belongs to the next time range, so time ranges that touch never hold the same sample:
Python
TypeScript
end = start + sy.TimeSpan.HOUR
tr = sy.TimeRange(start, end)
print(tr.span) # 1h
print(tr.contains(start)) # True
print(tr.contains(end)) # False
# Other ways to make the same range.
tr = start.range(end)
tr = start.span_range(sy.TimeSpan.HOUR)contains also takes a TimeRange, and returns true when the whole time range is
inside, ends included.
import { TimeRange } from "@synnaxlabs/client";
const end = start.add(TimeSpan.HOUR);
const tr = new TimeRange(start, end);
console.log(tr.span.toString()); // 1h
console.log(tr.contains(start)); // true
console.log(tr.contains(end)); // false
// Ranges overlap when they share any time.
const next = new TimeRange(end, end.add(TimeSpan.HOUR));
console.log(tr.overlapsWith(next)); // false
// Other ways to make the same range.
const fromObject = new TimeRange({ start, end });
const fromSpan = start.spanRange(TimeSpan.HOUR);contains also takes a TimeRange. It returns true only when the other time range
starts at or after this time range and ends before this time range ends, so
tr.contains(tr) is false.
Rate
A rate is a frequency in hertz.
Python
TypeScript
rate = sy.Rate.HZ * 100
print(rate) # 100.0 Hz
print(rate.period) # 10mssy.Rate(100) is the same rate. The constants are HZ, KHZ, and MHZ. Hardware task
configurations take a Rate or a number of hertz for sample_rate and stream_rate.
import { Rate } from "@synnaxlabs/client";
const rate = Rate.hz(100);
console.log(rate.toString()); // 100 Hz
console.log(rate.period.toString()); // 10msRate.khz(1) is 1000 Hz. Hardware task configurations take a number of hertz for
sampleRate and streamRate, not a Rate.
Precision
The time types keep every nanosecond. The native types of each language keep less, so a conversion can lose precision:
Python
TypeScript
A datetime keeps microseconds. TimeStamp.datetime rounds to the nearest microsecond:
ts = sy.TimeStamp(1_609_459_200_123_456_789)
print(ts.datetime(tz=timezone.utc)) # 2021-01-01 00:00:00.123457+00:00A Date keeps milliseconds, and TimeStamp.date drops the rest. A number holds
integers exactly only up to 2^53, so keep nanoseconds as the bigint that valueOf
returns:
const ts = new TimeStamp(1_609_459_200_123_456_789n);
console.log(ts.date()); // 2021-01-01T00:00:00.123Z
console.log(ts.valueOf()); // 1609459200123456789n