@tai-kun/surrealdb
Version:
The SurrealDB SDK for JavaScript
87 lines (74 loc) • 2.28 kB
text/typescript
import type { DataItem } from "@tai-kun/surrealdb/cbor";
import { defineAsDatetime } from "../_internals/define";
// See: https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
// SurrealDB では日時にタグ 100, 1, 1004 を使っていない模様
export type DatetimeSource =
// Tag 0 (, 100)
| DataItem.Utf8String.FixedLength["value"]
// Tag (1, 1004)
// | DataItem.UnsignedInteger["value"]
// | DataItem.NegativeInteger["value"]
// SurrealDB 独自
| readonly [
// i64
seconds:
| DataItem.UnsignedInteger["value"]
| DataItem.NegativeInteger["value"],
// u32
nanoseconds:
| DataItem.UnsignedInteger.Tiny["value"]
| DataItem.UnsignedInteger.OneByte["value"]
| DataItem.UnsignedInteger.TwoBytes["value"]
| DataItem.UnsignedInteger.FourBytes["value"],
];
const MILLISECONDS_PER_SECOND = 1e3;
const NANOSECONDS_PER_MILLISECOND = 1e6;
const NANOSECONDS_PER_SECOND = 1e9;
const MAX_DATE_SECONDS = 8_640_000_000_000;
const MIN_DATE_SECONDS = -8_640_000_000_000;
/**
* [API Reference](https://tai-kun.github.io/surrealdb.js/v2/api/data/datetime)
*/
export default class Datetime {
/**
* -(2^53-1) ~ 2^53-1, NaN
*/
readonly seconds: number;
/**
* 0 ~ 999_999_999, NaN
*/
readonly nanoseconds: number;
constructor(source: DatetimeSource) {
let s: number, ns: number;
if (typeof source === "string") {
const msTime = Date.parse(source);
if (msTime === msTime) {
s = Math.trunc(msTime / MILLISECONDS_PER_SECOND);
ns = Math.abs(
(msTime % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND,
);
if (s <= 0 && ns > 0) {
if (s <= MIN_DATE_SECONDS) {
s = ns = NaN; // Underflow
} else {
s -= 1;
ns = NANOSECONDS_PER_SECOND - ns;
}
}
} else {
s = ns = NaN;
}
} else {
ns = source[1];
s = Number(source[0]) + Math.trunc(ns / NANOSECONDS_PER_SECOND);
if (s >= MIN_DATE_SECONDS && s <= MAX_DATE_SECONDS) {
ns %= NANOSECONDS_PER_SECOND;
} else {
s = ns = NaN;
}
}
this.seconds = s === 0 ? 0 : s;
this.nanoseconds = ns === 0 ? 0 : ns;
defineAsDatetime(this);
}
}