diff --git a/src/v1/index.js b/src/v1/index.js
index 8ddaf0181..8c4c53ace 100644
--- a/src/v1/index.js
+++ b/src/v1/index.js
@@ -29,7 +29,23 @@ import VERSION from '../version';
import {assertString, isEmptyObjectOrNull} from './internal/util';
import urlUtil from './internal/url-util';
import HttpDriver from './internal/http/http-driver';
-import {Point} from './spatial-types';
+import {isPoint, Point} from './spatial-types';
+import {
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ isDate,
+ isDateTimeWithZoneId,
+ isDateTimeWithZoneOffset,
+ isDuration,
+ isLocalDateTime,
+ isLocalTime,
+ isTime,
+ LocalDateTime,
+ LocalTime,
+ Time
+} from './temporal-types';
/**
* @property {function(username: string, password: string, realm: ?string)} basic the function to create a
@@ -196,7 +212,7 @@ function driver(url, authToken, config = {}) {
}
/**
- * Object containing constructors for all graph types.
+ * Object containing constructors for all neo4j types.
*/
const types = {
Node,
@@ -207,7 +223,14 @@ const types = {
Result,
ResultSummary,
Record,
- Point
+ Point,
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ LocalDateTime,
+ LocalTime,
+ Time
};
/**
@@ -248,7 +271,23 @@ const forExport = {
auth,
types,
session,
- error
+ error,
+ Point,
+ isPoint,
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ LocalDateTime,
+ LocalTime,
+ Time,
+ isDuration,
+ isLocalTime,
+ isTime,
+ isDate,
+ isLocalDateTime,
+ isDateTimeWithZoneOffset,
+ isDateTimeWithZoneId
};
export {
@@ -260,6 +299,22 @@ export {
auth,
types,
session,
- error
+ error,
+ Point,
+ isPoint,
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ LocalDateTime,
+ LocalTime,
+ Time,
+ isDuration,
+ isLocalTime,
+ isTime,
+ isDate,
+ isLocalDateTime,
+ isDateTimeWithZoneOffset,
+ isDateTimeWithZoneId
};
export default forExport;
diff --git a/src/v1/integer.js b/src/v1/integer.js
index 7fe006c15..29f6468b7 100644
--- a/src/v1/integer.js
+++ b/src/v1/integer.js
@@ -238,7 +238,9 @@ class Integer {
* @returns {boolean}
* @expose
*/
- notEquals(other) { !this.equals(/* validates */ other); }
+ notEquals(other) {
+ return !this.equals(/* validates */ other);
+ }
/**
* Tests if this Integer's value is less than the specified's.
diff --git a/src/v1/internal/packstream-v2.js b/src/v1/internal/packstream-v2.js
index 05037a3d0..d50c0bdf5 100644
--- a/src/v1/internal/packstream-v2.js
+++ b/src/v1/internal/packstream-v2.js
@@ -19,7 +19,29 @@
import * as v1 from './packstream-v1';
import {isPoint, Point} from '../spatial-types';
+import {
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ Time,
+ isDate,
+ isDateTimeWithZoneId,
+ isDateTimeWithZoneOffset,
+ isDuration,
+ isLocalDateTime,
+ isLocalTime,
+ isTime
+} from '../temporal-types';
import {int} from '../integer';
+import {
+ dateToEpochDay,
+ localDateTimeToEpochSecond,
+ localTimeToNanoOfDay,
+ epochDayToDate,
+ epochSecondAndNanoToLocalDateTime,
+ nanoOfDayToLocalTime
+} from '../internal/temporal-util';
const POINT_2D = 0x58;
const POINT_2D_STRUCT_SIZE = 3;
@@ -27,6 +49,27 @@ const POINT_2D_STRUCT_SIZE = 3;
const POINT_3D = 0x59;
const POINT_3D_STRUCT_SIZE = 4;
+const DURATION = 0x45;
+const DURATION_STRUCT_SIZE = 4;
+
+const LOCAL_TIME = 0x74;
+const LOCAL_TIME_STRUCT_SIZE = 1;
+
+const TIME = 0x54;
+const TIME_STRUCT_SIZE = 2;
+
+const DATE = 0x44;
+const DATE_STRUCT_SIZE = 1;
+
+const LOCAL_DATE_TIME = 0x64;
+const LOCAL_DATE_TIME_STRUCT_SIZE = 2;
+
+const DATE_TIME_WITH_ZONE_OFFSET = 0x46;
+const DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE = 3;
+
+const DATE_TIME_WITH_ZONE_ID = 0x66;
+const DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE = 3;
+
export class Packer extends v1.Packer {
/**
@@ -44,6 +87,20 @@ export class Packer extends v1.Packer {
packable(obj, onError) {
if (isPoint(obj)) {
return () => packPoint(obj, this, onError);
+ } else if (isDuration(obj)) {
+ return () => packDuration(obj, this, onError);
+ } else if (isLocalTime(obj)) {
+ return () => packLocalTime(obj, this, onError);
+ } else if (isTime(obj)) {
+ return () => packTime(obj, this, onError);
+ } else if (isDate(obj)) {
+ return () => packDate(obj, this, onError);
+ } else if (isLocalDateTime(obj)) {
+ return () => packLocalDateTime(obj, this, onError);
+ } else if (isDateTimeWithZoneOffset(obj)) {
+ return () => packDateTimeWithZoneOffset(obj, this, onError);
+ } else if (isDateTimeWithZoneId(obj)) {
+ return () => packDateTimeWithZoneId(obj, this, onError);
} else {
return super.packable(obj, onError);
}
@@ -66,6 +123,20 @@ export class Unpacker extends v1.Unpacker {
return unpackPoint2D(this, structSize, buffer);
} else if (signature == POINT_3D) {
return unpackPoint3D(this, structSize, buffer);
+ } else if (signature == DURATION) {
+ return unpackDuration(this, structSize, buffer);
+ } else if (signature == LOCAL_TIME) {
+ return unpackLocalTime(this, structSize, buffer);
+ } else if (signature == TIME) {
+ return unpackTime(this, structSize, buffer);
+ } else if (signature == DATE) {
+ return unpackDate(this, structSize, buffer);
+ } else if (signature == LOCAL_DATE_TIME) {
+ return unpackLocalDateTime(this, structSize, buffer);
+ } else if (signature == DATE_TIME_WITH_ZONE_OFFSET) {
+ return unpackDateTimeWithZoneOffset(this, structSize, buffer);
+ } else if (signature == DATE_TIME_WITH_ZONE_ID) {
+ return unpackDateTimeWithZoneId(this, structSize, buffer);
} else {
return super._unpackUnknownStruct(signature, structSize, buffer);
}
@@ -121,3 +192,215 @@ function unpackPoint3D(unpacker, structSize, buffer) {
unpacker.unpack(buffer) // z
);
}
+
+function packDuration(value, packer, onError) {
+ const months = int(value.months);
+ const days = int(value.days);
+ const seconds = int(value.seconds);
+ const nanoseconds = int(value.nanoseconds);
+
+ const packableStructFields = [
+ packer.packable(months, onError),
+ packer.packable(days, onError),
+ packer.packable(seconds, onError),
+ packer.packable(nanoseconds, onError),
+ ];
+ packer.packStruct(DURATION, packableStructFields, onError);
+}
+
+function unpackDuration(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('Duration', DURATION_STRUCT_SIZE, structSize);
+
+ const months = unpacker.unpack(buffer);
+ const days = unpacker.unpack(buffer);
+ const seconds = unpacker.unpack(buffer);
+ const nanoseconds = unpacker.unpack(buffer);
+
+ return new Duration(months, days, seconds, nanoseconds);
+}
+
+function packLocalTime(value, packer, onError) {
+ const nanoOfDay = localTimeToNanoOfDay(value);
+
+ const packableStructFields = [
+ packer.packable(nanoOfDay, onError)
+ ];
+ packer.packStruct(LOCAL_TIME, packableStructFields, onError);
+}
+
+function unpackLocalTime(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('LocalTime', LOCAL_TIME_STRUCT_SIZE, structSize);
+
+ const nanoOfDay = unpacker.unpack(buffer);
+ return nanoOfDayToLocalTime(nanoOfDay);
+}
+
+/**
+ * Pack given time.
+ * @param {Time} value the time value to pack.
+ * @param {Packer} packer the packer to use.
+ * @param {function} onError the error callback.
+ */
+function packTime(value, packer, onError) {
+ const nanoOfDay = localTimeToNanoOfDay(value.localTime);
+ const offsetSeconds = int(value.offsetSeconds);
+
+ const packableStructFields = [
+ packer.packable(nanoOfDay, onError),
+ packer.packable(offsetSeconds, onError)
+ ];
+ packer.packStruct(TIME, packableStructFields, onError);
+}
+
+/**
+ * Unpack time value using the given unpacker.
+ * @param {Unpacker} unpacker the unpacker to use.
+ * @param {number} structSize the retrieved struct size.
+ * @param {BaseBuffer} buffer the buffer to unpack from.
+ * @return {Time} the unpacked time value.
+ */
+function unpackTime(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('Time', TIME_STRUCT_SIZE, structSize);
+
+ const nanoOfDay = unpacker.unpack(buffer);
+ const offsetSeconds = unpacker.unpack(buffer);
+
+ const localTime = nanoOfDayToLocalTime(nanoOfDay);
+ return new Time(localTime, offsetSeconds);
+}
+
+/**
+ * Pack given neo4j date.
+ * @param {Date} value the date value to pack.
+ * @param {Packer} packer the packer to use.
+ * @param {function} onError the error callback.
+ */
+function packDate(value, packer, onError) {
+ const epochDay = dateToEpochDay(value);
+
+ const packableStructFields = [
+ packer.packable(epochDay, onError)
+ ];
+ packer.packStruct(DATE, packableStructFields, onError);
+}
+
+/**
+ * Unpack neo4j date value using the given unpacker.
+ * @param {Unpacker} unpacker the unpacker to use.
+ * @param {number} structSize the retrieved struct size.
+ * @param {BaseBuffer} buffer the buffer to unpack from.
+ * @return {Date} the unpacked neo4j date value.
+ */
+function unpackDate(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('Date', DATE_STRUCT_SIZE, structSize);
+
+ const epochDay = unpacker.unpack(buffer);
+ return epochDayToDate(epochDay);
+}
+
+/**
+ * Pack given local date time.
+ * @param {LocalDateTime} value the local date time value to pack.
+ * @param {Packer} packer the packer to use.
+ * @param {function} onError the error callback.
+ */
+function packLocalDateTime(value, packer, onError) {
+ const epochSecond = localDateTimeToEpochSecond(value);
+ const nano = int(value.localTime.nanosecond);
+
+ const packableStructFields = [
+ packer.packable(epochSecond, onError),
+ packer.packable(nano, onError)
+ ];
+ packer.packStruct(LOCAL_DATE_TIME, packableStructFields, onError);
+}
+
+/**
+ * Unpack local date time value using the given unpacker.
+ * @param {Unpacker} unpacker the unpacker to use.
+ * @param {number} structSize the retrieved struct size.
+ * @param {BaseBuffer} buffer the buffer to unpack from.
+ * @return {LocalDateTime} the unpacked local date time value.
+ */
+function unpackLocalDateTime(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('LocalDateTime', LOCAL_DATE_TIME_STRUCT_SIZE, structSize);
+
+ const epochSecond = unpacker.unpack(buffer);
+ const nano = unpacker.unpack(buffer);
+
+ return epochSecondAndNanoToLocalDateTime(epochSecond, nano);
+}
+
+/**
+ * Pack given date time with zone offset.
+ * @param {DateTimeWithZoneOffset} value the date time value to pack.
+ * @param {Packer} packer the packer to use.
+ * @param {function} onError the error callback.
+ */
+function packDateTimeWithZoneOffset(value, packer, onError) {
+ const epochSecond = localDateTimeToEpochSecond(value.localDateTime);
+ const nano = int(value.localDateTime.localTime.nanosecond);
+ const offsetSeconds = int(value.offsetSeconds);
+
+ const packableStructFields = [
+ packer.packable(epochSecond, onError),
+ packer.packable(nano, onError),
+ packer.packable(offsetSeconds, onError)
+ ];
+ packer.packStruct(DATE_TIME_WITH_ZONE_OFFSET, packableStructFields, onError);
+}
+
+/**
+ * Unpack date time with zone offset value using the given unpacker.
+ * @param {Unpacker} unpacker the unpacker to use.
+ * @param {number} structSize the retrieved struct size.
+ * @param {BaseBuffer} buffer the buffer to unpack from.
+ * @return {DateTimeWithZoneOffset} the unpacked date time with zone offset value.
+ */
+function unpackDateTimeWithZoneOffset(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('DateTimeWithZoneOffset', DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE, structSize);
+
+ const epochSecond = unpacker.unpack(buffer);
+ const nano = unpacker.unpack(buffer);
+ const offsetSeconds = unpacker.unpack(buffer);
+
+ const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano);
+ return new DateTimeWithZoneOffset(localDateTime, offsetSeconds);
+}
+
+/**
+ * Pack given date time with zone id.
+ * @param {DateTimeWithZoneId} value the date time value to pack.
+ * @param {Packer} packer the packer to use.
+ * @param {function} onError the error callback.
+ */
+function packDateTimeWithZoneId(value, packer, onError) {
+ const epochSecond = localDateTimeToEpochSecond(value.localDateTime);
+ const nano = int(value.localDateTime.localTime.nanosecond);
+ const zoneId = value.zoneId;
+
+ const packableStructFields = [
+ packer.packable(epochSecond, onError),
+ packer.packable(nano, onError),
+ packer.packable(zoneId, onError)
+ ];
+ packer.packStruct(DATE_TIME_WITH_ZONE_ID, packableStructFields, onError);
+}
+
+/**
+ * Unpack date time with zone id value using the given unpacker.
+ * @param {Unpacker} unpacker the unpacker to use.
+ * @param {number} structSize the retrieved struct size.
+ * @param {BaseBuffer} buffer the buffer to unpack from.
+ * @return {DateTimeWithZoneId} the unpacked date time with zone id value.
+ */
+function unpackDateTimeWithZoneId(unpacker, structSize, buffer) {
+ unpacker._verifyStructSize('DateTimeWithZoneId', DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE, structSize);
+
+ const epochSecond = unpacker.unpack(buffer);
+ const nano = unpacker.unpack(buffer);
+ const zoneId = unpacker.unpack(buffer);
+
+ const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano);
+ return new DateTimeWithZoneId(localDateTime, zoneId);
+}
diff --git a/src/v1/internal/temporal-util.js b/src/v1/internal/temporal-util.js
new file mode 100644
index 000000000..d3fd63b98
--- /dev/null
+++ b/src/v1/internal/temporal-util.js
@@ -0,0 +1,323 @@
+/**
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {int} from '../integer';
+import {Date, LocalDateTime, LocalTime} from '../temporal-types';
+
+/*
+ Code in this util should be compatible with code in the database that uses JSR-310 java.time APIs.
+
+ It is based on a library called ThreeTen (https://github.com/ThreeTen/threetenbp) which was derived
+ from JSR-310 reference implementation previously hosted on GitHub. Code uses `Integer` type everywhere
+ to correctly handle large integer values that are greater than Number.MAX_SAFE_INTEGER
.
+
+ Please consult either ThreeTen or js-joda (https://github.com/js-joda/js-joda) when working with the
+ conversion functions.
+ */
+
+const MINUTES_PER_HOUR = 60;
+const SECONDS_PER_MINUTE = 60;
+const SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+const NANOS_PER_SECOND = 1000000000;
+const NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
+const NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
+const DAYS_0000_TO_1970 = 719528;
+const DAYS_PER_400_YEAR_CYCLE = 146097;
+const SECONDS_PER_DAY = 86400;
+
+/**
+ * Converts given local time into a single integer representing this same time in nanoseconds of the day.
+ * @param {LocalTime} localTime the time to convert.
+ * @return {Integer} nanoseconds representing the given local time.
+ */
+export function localTimeToNanoOfDay(localTime) {
+ const hour = int(localTime.hour);
+ const minute = int(localTime.minute);
+ const second = int(localTime.second);
+ const nanosecond = int(localTime.nanosecond);
+
+ let totalNanos = hour.multiply(NANOS_PER_HOUR);
+ totalNanos = totalNanos.add(minute.multiply(NANOS_PER_MINUTE));
+ totalNanos = totalNanos.add(second.multiply(NANOS_PER_SECOND));
+ return totalNanos.add(nanosecond);
+}
+
+/**
+ * Converts nanoseconds of the day into local time.
+ * @param {Integer|number|string} nanoOfDay the nanoseconds of the day to convert.
+ * @return {LocalTime} the local time representing given nanoseconds of the day.
+ */
+export function nanoOfDayToLocalTime(nanoOfDay) {
+ nanoOfDay = int(nanoOfDay);
+
+ const hour = nanoOfDay.div(NANOS_PER_HOUR);
+ nanoOfDay = nanoOfDay.subtract(hour.multiply(NANOS_PER_HOUR));
+
+ const minute = nanoOfDay.div(NANOS_PER_MINUTE);
+ nanoOfDay = nanoOfDay.subtract(minute.multiply(NANOS_PER_MINUTE));
+
+ const second = nanoOfDay.div(NANOS_PER_SECOND);
+ const nanosecond = nanoOfDay.subtract(second.multiply(NANOS_PER_SECOND));
+
+ return new LocalTime(hour, minute, second, nanosecond);
+}
+
+/**
+ * Converts given local date time into a single integer representing this same time in epoch seconds UTC.
+ * @param {LocalDateTime} localDateTime the local date time value to convert.
+ * @return {Integer} epoch second in UTC representing the given local date time.
+ */
+export function localDateTimeToEpochSecond(localDateTime) {
+ const localDate = localDateTime.localDate;
+ const localTime = localDateTime.localTime;
+
+ const epochDay = dateToEpochDay(localDate);
+ const localTimeSeconds = localTimeToSecondOfDay(localTime);
+ return epochDay.multiply(SECONDS_PER_DAY).add(localTimeSeconds);
+}
+
+/**
+ * Converts given epoch second and nanosecond adjustment into a local date time object.
+ * @param {Integer|number|string} epochSecond the epoch second to use.
+ * @param {Integer|number|string} nano the nanosecond to use.
+ * @return {LocalDateTime} the local date time representing given epoch second and nano.
+ */
+export function epochSecondAndNanoToLocalDateTime(epochSecond, nano) {
+ const epochDay = floorDiv(epochSecond, SECONDS_PER_DAY);
+ const secondsOfDay = floorMod(epochSecond, SECONDS_PER_DAY);
+ const nanoOfDay = secondsOfDay.multiply(NANOS_PER_SECOND).add(nano);
+
+ const localDate = epochDayToDate(epochDay);
+ const localTime = nanoOfDayToLocalTime(nanoOfDay);
+ return new LocalDateTime(localDate, localTime);
+}
+
+/**
+ * Converts given local date into a single integer representing it's epoch day.
+ * @param {Date} date the date to convert.
+ * @return {Integer} epoch day representing the given date.
+ */
+export function dateToEpochDay(date) {
+ const year = int(date.year);
+ const month = int(date.month);
+ const day = int(date.day);
+
+ let epochDay = year.multiply(365);
+
+ if (year.greaterThanOrEqual(0)) {
+ epochDay = epochDay.add(year.add(3).div(4).subtract(year.add(99).div(100)).add(year.add(399).div(400)));
+ } else {
+ epochDay = epochDay.subtract(year.div(-4).subtract(year.div(-100)).add(year.div(-400)));
+ }
+
+ epochDay = epochDay.add(month.multiply(367).subtract(362).div(12));
+ epochDay = epochDay.add(day.subtract(1));
+ if (month.greaterThan(2)) {
+ epochDay = epochDay.subtract(1);
+ if (!isLeapYear(year)) {
+ epochDay = epochDay.subtract(1);
+ }
+ }
+ return epochDay.subtract(DAYS_0000_TO_1970);
+}
+
+/**
+ * Converts given epoch day to a local date.
+ * @param {Integer|number|string} epochDay the epoch day to convert.
+ * @return {Date} the date representing the epoch day in years, months and days.
+ */
+export function epochDayToDate(epochDay) {
+ epochDay = int(epochDay);
+
+ let zeroDay = epochDay.add(DAYS_0000_TO_1970).subtract(60);
+ let adjust = int(0);
+ if (zeroDay.lessThan(0)) {
+ const adjustCycles = zeroDay.add(1).div(DAYS_PER_400_YEAR_CYCLE).subtract(1);
+ adjust = adjustCycles.multiply(400);
+ zeroDay = zeroDay.add(adjustCycles.multiply(-DAYS_PER_400_YEAR_CYCLE));
+ }
+ let year = zeroDay.multiply(400).add(591).div(DAYS_PER_400_YEAR_CYCLE);
+ let dayOfYearEst = zeroDay.subtract(year.multiply(365).add(year.div(4)).subtract(year.div(100)).add(year.div(400)));
+ if (dayOfYearEst.lessThan(0)) {
+ year = year.subtract(1);
+ dayOfYearEst = zeroDay.subtract(year.multiply(365).add(year.div(4)).subtract(year.div(100)).add(year.div(400)));
+ }
+ year = year.add(adjust);
+ let marchDayOfYear = dayOfYearEst;
+
+ const marchMonth = marchDayOfYear.multiply(5).add(2).div(153);
+ const month = marchMonth.add(2).modulo(12).add(1);
+ const day = marchDayOfYear.subtract(marchMonth.multiply(306).add(5).div(10)).add(1);
+ year = year.add(marchMonth.div(10));
+
+ return new Date(year, month, day);
+}
+
+/**
+ * Format given duration to an ISO 8601 string.
+ * @param {Integer|number} months the number of months.
+ * @param {Integer|number} days the number of days.
+ * @param {Integer|number} seconds the number of seconds.
+ * @param {Integer|number} nanoseconds the number of nanoseconds.
+ * @return {string} ISO string that represents given duration.
+ */
+export function durationToIsoString(months, days, seconds, nanoseconds) {
+ const monthsString = formatNumber(months);
+ const daysString = formatNumber(days);
+ const secondsString = formatNumber(seconds);
+ const nanosecondsString = formatNumber(nanoseconds, 9);
+ return `P${monthsString}M${daysString}DT${secondsString}.${nanosecondsString}S`;
+}
+
+/**
+ * Formats given time to an ISO 8601 string.
+ * @param {Integer|number} hour the hour value.
+ * @param {Integer|number} minute the minute value.
+ * @param {Integer|number} second the second value.
+ * @param {Integer|number} nanosecond the nanosecond value.
+ * @return {string} ISO string that represents given time.
+ */
+export function timeToIsoString(hour, minute, second, nanosecond) {
+ const hourString = formatNumber(hour, 2);
+ const minuteString = formatNumber(minute, 2);
+ const secondString = formatNumber(second, 2);
+ const nanosecondString = formatNumber(nanosecond, 9);
+ return `${hourString}:${minuteString}:${secondString}.${nanosecondString}`;
+}
+
+/**
+ * Formats given time zone offset in seconds to string representation like '±HH:MM', '±HH:MM:SS' or 'Z' for UTC.
+ * @param {Integer|number} offsetSeconds the offset in seconds.
+ * @return {string} ISO string that represents given offset.
+ */
+export function timeZoneOffsetToIsoString(offsetSeconds) {
+ offsetSeconds = int(offsetSeconds);
+ if (offsetSeconds.equals(0)) {
+ return 'Z';
+ }
+
+ const isNegative = offsetSeconds.isNegative();
+ if (isNegative) {
+ offsetSeconds = offsetSeconds.multiply(-1);
+ }
+ const signPrefix = isNegative ? '-' : '+';
+
+ const hours = formatNumber(offsetSeconds.div(SECONDS_PER_HOUR), 2);
+ const minutes = formatNumber(offsetSeconds.div(SECONDS_PER_MINUTE).modulo(MINUTES_PER_HOUR), 2);
+ let secondsValue = offsetSeconds.modulo(SECONDS_PER_MINUTE);
+ const seconds = secondsValue.equals(0) ? null : formatNumber(secondsValue, 2);
+
+ return seconds ? `${signPrefix}${hours}:${minutes}:${seconds}` : `${signPrefix}${hours}:${minutes}`;
+}
+
+/**
+ * Formats given date to an ISO 8601 string.
+ * @param {Integer|number} year the date year.
+ * @param {Integer|number} month the date month.
+ * @param {Integer|number} day the date day.
+ * @return {string} ISO string that represents given date.
+ */
+export function dateToIsoString(year, month, day) {
+ year = int(year);
+ const isNegative = year.isNegative();
+ if (isNegative) {
+ year = year.multiply(-1);
+ }
+ let yearString = year.toString().padStart(4, '0');
+ if (isNegative) {
+ yearString = '-' + yearString;
+ }
+
+ const monthString = formatNumber(month, 2);
+ const dayString = formatNumber(day, 2);
+ return `${yearString}-${monthString}-${dayString}`;
+}
+
+/**
+ * Converts given local time into a single integer representing this same time in seconds of the day. Nanoseconds are skipped.
+ * @param {LocalTime} localTime the time to convert.
+ * @return {Integer} seconds representing the given local time.
+ */
+function localTimeToSecondOfDay(localTime) {
+ const hour = int(localTime.hour);
+ const minute = int(localTime.minute);
+ const second = int(localTime.second);
+
+ let totalSeconds = hour.multiply(SECONDS_PER_HOUR);
+ totalSeconds = totalSeconds.add(minute.multiply(SECONDS_PER_MINUTE));
+ return totalSeconds.add(second);
+}
+
+
+/**
+ * Check if given year is a leap year. Uses algorithm described here {@link https://en.wikipedia.org/wiki/Leap_year#Algorithm}.
+ * @param {Integer|number|string} year the year to check. Will be converted to {@link Integer} for all calculations.
+ * @return {boolean} true
if given year is a leap year, false
otherwise.
+ */
+function isLeapYear(year) {
+ year = int(year);
+
+ if (!year.modulo(4).equals(0)) {
+ return false;
+ } else if (!year.modulo(100).equals(0)) {
+ return true;
+ } else if (!year.modulo(400).equals(0)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/**
+ * @param {Integer|number|string} x the divident.
+ * @param {Integer|number|string} y the divisor.
+ * @return {Integer} the result.
+ */
+function floorDiv(x, y) {
+ x = int(x);
+ y = int(y);
+
+ let result = x.div(y);
+ if (x.isPositive() !== y.isPositive() && result.multiply(y).notEquals(x)) {
+ result = result.subtract(1);
+ }
+ return result;
+}
+
+/**
+ * @param {Integer|number|string} x the divident.
+ * @param {Integer|number|string} y the divisor.
+ * @return {Integer} the result.
+ */
+function floorMod(x, y) {
+ x = int(x);
+ y = int(y);
+
+ return x.subtract(floorDiv(x, y).multiply(y));
+}
+
+/**
+ * @param {Integer|number} num the number to format.
+ * @param {number} [stringLength=undefined] the string length to left-pad to.
+ * @return {string} formatted and possibly left-padded number as string.
+ */
+function formatNumber(num, stringLength = undefined) {
+ const result = int(num).toString();
+ return stringLength ? result.padStart(stringLength, '0') : result;
+}
diff --git a/src/v1/temporal-types.js b/src/v1/temporal-types.js
new file mode 100644
index 000000000..3f8b61661
--- /dev/null
+++ b/src/v1/temporal-types.js
@@ -0,0 +1,279 @@
+/**
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {dateToIsoString, durationToIsoString, timeToIsoString, timeZoneOffsetToIsoString} from './internal/temporal-util';
+
+const IDENTIFIER_PROPERTY_ATTRIBUTES = {
+ value: true,
+ enumerable: false,
+ configurable: false
+};
+
+const DURATION_IDENTIFIER_PROPERTY = '__isDuration__';
+const LOCAL_TIME_IDENTIFIER_PROPERTY = '__isLocalTime__';
+const TIME_IDENTIFIER_PROPERTY = '__isTime__';
+const DATE_IDENTIFIER_PROPERTY = '__isDate__';
+const LOCAL_DATE_TIME_IDENTIFIER_PROPERTY = '__isLocalDateTime__';
+const DATE_TIME_WITH_ZONE_OFFSET_IDENTIFIER_PROPERTY = '__isDateTimeWithZoneOffset__';
+const DATE_TIME_WITH_ZONE_ID_IDENTIFIER_PROPERTY = '__isDateTimeWithZoneId__';
+
+/**
+ * Represents an ISO 8601 duration. Contains both date-based values (years, months, days) and time-based values (seconds, nanoseconds).
+ * Created Duration
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class Duration {
+
+ /**
+ * @constructor
+ * @param {Integer|number} months the number of months for the new duration.
+ * @param {Integer|number} days the number of days for the new duration.
+ * @param {Integer|number} seconds the number of seconds for the new duration.
+ * @param {Integer|number} nanoseconds the number of nanoseconds for the new duration.
+ */
+ constructor(months, days, seconds, nanoseconds) {
+ this.months = months;
+ this.days = days;
+ this.seconds = seconds;
+ this.nanoseconds = nanoseconds;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return durationToIsoString(this.months, this.days, this.seconds, this.nanoseconds);
+ }
+}
+
+Object.defineProperty(Duration.prototype, DURATION_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link Duration} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link Duration}, false
otherwise.
+ */
+export function isDuration(obj) {
+ return hasIdentifierProperty(obj, DURATION_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the time of day, but not the date, nor the timezone.
+ * Created LocalTime
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class LocalTime {
+
+ /**
+ * @constructor
+ * @param {Integer|number} hour the hour for the new local time.
+ * @param {Integer|number} minute the minute for the new local time.
+ * @param {Integer|number} second the second for the new local time.
+ * @param {Integer|number} nanosecond the nanosecond for the new local time.
+ */
+ constructor(hour, minute, second, nanosecond) {
+ this.hour = hour;
+ this.minute = minute;
+ this.second = second;
+ this.nanosecond = nanosecond;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return timeToIsoString(this.hour, this.minute, this.second, this.nanosecond);
+ }
+}
+
+Object.defineProperty(LocalTime.prototype, LOCAL_TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link LocalTime} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link LocalTime}, false
otherwise.
+ */
+export function isLocalTime(obj) {
+ return hasIdentifierProperty(obj, LOCAL_TIME_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the time of day, and the timezone offset in seconds, but not the date.
+ * Created Time
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class Time {
+
+ /**
+ * @constructor
+ * @param {LocalTime} localTime the local time for the new time with offset.
+ * @param {Integer|number} offsetSeconds the time zone offset in seconds.
+ */
+ constructor(localTime, offsetSeconds) {
+ this.localTime = localTime;
+ this.offsetSeconds = offsetSeconds;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return this.localTime.toString() + timeZoneOffsetToIsoString(this.offsetSeconds);
+ }
+}
+
+Object.defineProperty(Time.prototype, TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link Time} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link Time}, false
otherwise.
+ */
+export function isTime(obj) {
+ return hasIdentifierProperty(obj, TIME_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the date, but not the time, nor the timezone.
+ * Created Date
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class Date {
+
+ /**
+ * @constructor
+ * @param {Integer|number} year the year for the new local date.
+ * @param {Integer|number} month the month for the new local date.
+ * @param {Integer|number} day the day for the new local date.
+ */
+ constructor(year, month, day) {
+ this.year = year;
+ this.month = month;
+ this.day = day;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return dateToIsoString(this.year, this.month, this.day);
+ }
+}
+
+Object.defineProperty(Date.prototype, DATE_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link Date} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link Date}, false
otherwise.
+ */
+export function isDate(obj) {
+ return hasIdentifierProperty(obj, DATE_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the date and the time, but not the timezone.
+ * Created LocalDateTime
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class LocalDateTime {
+
+ /**
+ * @constructor
+ * @param {Date} localDate the local date part for the new local date-time.
+ * @param {LocalTime} localTime the local time part for the new local date-time.
+ */
+ constructor(localDate, localTime) {
+ this.localDate = localDate;
+ this.localTime = localTime;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return `${this.localDate.toString()}T${this.localTime.toString()}`;
+ }
+}
+
+Object.defineProperty(LocalDateTime.prototype, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link LocalDateTime} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link LocalDateTime}, false
otherwise.
+ */
+export function isLocalDateTime(obj) {
+ return hasIdentifierProperty(obj, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the date, the time and the timezone identifier.
+ * Created DateTimeWithZoneOffset
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class DateTimeWithZoneOffset {
+
+ /**
+ * @constructor
+ * @param {LocalDateTime} localDateTime the local date-time part for the new timezone-aware date-time.
+ * @param {Integer|number} offsetSeconds the timezone offset in seconds for the new timezone-aware date-time.
+ */
+ constructor(localDateTime, offsetSeconds) {
+ this.localDateTime = localDateTime;
+ this.offsetSeconds = offsetSeconds;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return this.localDateTime.toString() + timeZoneOffsetToIsoString(this.offsetSeconds);
+ }
+}
+
+Object.defineProperty(DateTimeWithZoneOffset.prototype, DATE_TIME_WITH_ZONE_OFFSET_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link DateTimeWithZoneOffset} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link DateTimeWithZoneOffset}, false
otherwise.
+ */
+export function isDateTimeWithZoneOffset(obj) {
+ return hasIdentifierProperty(obj, DATE_TIME_WITH_ZONE_OFFSET_IDENTIFIER_PROPERTY);
+}
+
+/**
+ * Represents an instant capturing the date, the time and the timezone identifier.
+ * Created DateTimeWithZoneId
objects are frozen with {@link Object#freeze()} in constructor and thus immutable.
+ */
+export class DateTimeWithZoneId {
+
+ /**
+ * @constructor
+ * @param {LocalDateTime} localDateTime the local date-time part for the new timezone-aware date-time.
+ * @param {string} zoneId the timezone identifier for the new timezone-aware date-time.
+ */
+ constructor(localDateTime, zoneId) {
+ this.localDateTime = localDateTime;
+ this.zoneId = zoneId;
+ Object.freeze(this);
+ }
+
+ toString() {
+ return `${this.localDateTime.toString()}[${this.zoneId}]`;
+ }
+}
+
+Object.defineProperty(DateTimeWithZoneId.prototype, DATE_TIME_WITH_ZONE_ID_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES);
+
+/**
+ * Test if given object is an instance of {@link DateTimeWithZoneId} class.
+ * @param {object} obj the object to test.
+ * @return {boolean} true
if given object is a {@link DateTimeWithZoneId}, false
otherwise.
+ */
+export function isDateTimeWithZoneId(obj) {
+ return hasIdentifierProperty(obj, DATE_TIME_WITH_ZONE_ID_IDENTIFIER_PROPERTY);
+}
+
+function hasIdentifierProperty(obj, property) {
+ return (obj && obj[property]) === true;
+}
diff --git a/test/internal/shared-neo4j.js b/test/internal/shared-neo4j.js
index 50c554560..3bb205264 100644
--- a/test/internal/shared-neo4j.js
+++ b/test/internal/shared-neo4j.js
@@ -109,7 +109,7 @@ const additionalConfig = {
};
const neoCtrlVersionParam = '-e';
-const defaultNeo4jVersion = '3.2.9';
+const defaultNeo4jVersion = '3.3.4';
const defaultNeoCtrlArgs = `${neoCtrlVersionParam} ${defaultNeo4jVersion}`;
function neo4jCertPath(dir) {
diff --git a/test/types/v1/temporal-types.test.ts b/test/types/v1/temporal-types.test.ts
new file mode 100644
index 000000000..95562c15d
--- /dev/null
+++ b/test/types/v1/temporal-types.test.ts
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+ Date,
+ DateTimeWithZoneOffset,
+ Duration,
+ isDate,
+ isDateTimeWithZoneId,
+ isDateTimeWithZoneOffset,
+ isDuration,
+ isLocalDateTime,
+ isLocalTime,
+ isTime,
+ LocalDateTime,
+ LocalTime,
+ Time
+} from "../../../types/v1/temporal-types";
+import Integer, {int} from "../../../types/v1/integer";
+
+const duration1: Duration = new Duration(int(1), int(1), int(1), int(1));
+const months1: Integer = duration1.months;
+const days1: Integer = duration1.days;
+const seconds1: Integer = duration1.seconds;
+const nanoseconds1: Integer = duration1.nanoseconds;
+
+const duration2: Duration = new Duration(1, 1, 1, 1);
+const months2: number = duration2.months;
+const days2: number = duration2.days;
+const seconds2: number = duration2.seconds;
+const nanoseconds2: number = duration2.nanoseconds;
+
+const localTime1: LocalTime = new LocalTime(int(1), int(1), int(1), int(1));
+const localTime1Hour1: Integer = localTime1.hour;
+const localTime1Minute1: Integer = localTime1.minute;
+const localTime1Second1: Integer = localTime1.second;
+const localTime1Nanosecond1: Integer = localTime1.nanosecond;
+
+const localTime2: LocalTime = new LocalTime(1, 1, 1, 1);
+const localTime2Hour1: number = localTime2.hour;
+const localTime2Minute1: number = localTime2.minute;
+const localTime2Second1: number = localTime2.second;
+const localTime2Nanosecond1: number = localTime2.nanosecond;
+
+const time1: Time = new Time(localTime1, int(1));
+const localTime3: LocalTime = time1.localTime;
+const offset1: Integer = time1.offsetSeconds;
+
+const time2: Time = new Time(localTime2, 1);
+const localTime4: LocalTime = time2.localTime;
+const offset2: number = time2.offsetSeconds;
+
+const date1: Date = new Date(int(1), int(1), int(1));
+const date1Year1: Integer = date1.year;
+const date1Month1: Integer = date1.month;
+const date1Day1: Integer = date1.day;
+
+const date2: Date = new Date(1, 1, 1);
+const date2Year1: number = date2.year;
+const date2Month1: number = date2.month;
+const date2Day1: number = date2.day;
+
+const localDateTime1: LocalDateTime = new LocalDateTime(date1, localTime1);
+const date3: Date = localDateTime1.localDate;
+const localTime5: LocalTime = localDateTime1.localTime;
+
+const localDateTime2: LocalDateTime = new LocalDateTime(date2, localTime2);
+const date4: Date = localDateTime2.localDate;
+const localTime6: LocalTime = localDateTime2.localTime;
+
+const dateTime1: DateTimeWithZoneOffset = new DateTimeWithZoneOffset(localDateTime1, int(1));
+const localDateTime3: LocalDateTime = dateTime1.localDateTime;
+const offset3: Integer = dateTime1.offsetSeconds;
+
+const dateTime2: DateTimeWithZoneOffset = new DateTimeWithZoneOffset(localDateTime2, 1);
+const localDateTime4: LocalDateTime = dateTime2.localDateTime;
+const offset4: number = dateTime2.offsetSeconds;
+
+const isDurationValue: boolean = isDuration(duration1);
+const isLocalTimeValue: boolean = isLocalTime(localTime1);
+const isTimeValue: boolean = isTime(time1);
+const isDateValue: boolean = isDate(date1);
+const isLocalDateTimeValue: boolean = isLocalDateTime(localDateTime1);
+const isDateTimeWithZoneOffsetValue: boolean = isDateTimeWithZoneOffset(dateTime1);
+const isDateTimeWithZoneIdValue: boolean = isDateTimeWithZoneId(dateTime2);
diff --git a/test/v1/examples.test.js b/test/v1/examples.test.js
index f76ea7ccf..d63e5023d 100644
--- a/test/v1/examples.test.js
+++ b/test/v1/examples.test.js
@@ -44,7 +44,7 @@ describe('examples', () => {
beforeAll(() => {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
- jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
driverGlobal = neo4j.driver(uri, sharedNeo4j.authToken);
});
diff --git a/test/v1/tck/steps/matchacceptencesteps.js b/test/v1/tck/steps/matchacceptencesteps.js
index b3d5aebfd..c23e364ba 100644
--- a/test/v1/tck/steps/matchacceptencesteps.js
+++ b/test/v1/tck/steps/matchacceptencesteps.js
@@ -155,9 +155,6 @@ module.exports = function () {
var segment;
for (var i = 0; i < segments.length; i++) {
segment = segments[i];
- if (startid.notEquals(segment.start.identity)) {
- throw new Error("Path segment does not make sense")
- }
var relationship = segment.relationship;
var endId = neo4j.int(segment.end.identity.toString());
relationship.identity = neo4j.int(0);
diff --git a/test/v1/temporal-types.test.js b/test/v1/temporal-types.test.js
new file mode 100644
index 000000000..929721846
--- /dev/null
+++ b/test/v1/temporal-types.test.js
@@ -0,0 +1,517 @@
+/**
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import neo4j from '../../src';
+import sharedNeo4j from '../internal/shared-neo4j';
+import {ServerVersion, VERSION_3_4_0} from '../../src/v1/internal/server-version';
+import timesSeries from 'async/timesSeries';
+import _ from 'lodash';
+
+const RANDOM_VALUES_TO_TEST = 2000;
+const MAX_NANO_OF_SECOND = 999999999;
+const MAX_YEAR = 999999999;
+const MIN_YEAR = -MAX_YEAR;
+const MAX_TIME_ZONE_OFFSET = 64800;
+const MIN_TIME_ZONE_OFFSET = -MAX_TIME_ZONE_OFFSET;
+const SECONDS_PER_MINUTE = 60;
+const MIN_ZONE_ID = 'Etc/GMT+12';
+const MAX_ZONE_ID = 'Etc/GMT-14';
+const ZONE_IDS = ['Europe/Zaporozhye', 'America/Argentina/Mendoza', 'Etc/GMT-12', 'Asia/Jayapura', 'Pacific/Auckland', 'America/Argentina/Rio_Gallegos',
+ 'America/Tegucigalpa', 'Europe/Skopje', 'Africa/Lome', 'America/Eirunepe', 'Pacific/Port_Moresby', 'America/Merida', 'Asia/Qyzylorda', 'Hongkong',
+ 'America/Paramaribo', 'Pacific/Wallis', 'Antarctica/Mawson', 'America/Metlakatla', 'Indian/Reunion', 'Asia/Chungking', 'Canada/Central', 'Etc/GMT-6',
+ 'UCT', 'America/Belem', 'Europe/Belgrade', 'Singapore', 'Israel', 'Europe/London', 'America/Yellowknife', 'Europe/Uzhgorod', 'Etc/GMT+7',
+ 'America/Indiana/Winamac', 'Asia/Kuala_Lumpur', 'America/Cuiaba', 'Europe/Sofia', 'Asia/Kuching', 'Australia/Lord_Howe', 'America/Porto_Acre',
+ 'America/Indiana/Indianapolis', 'Africa/Windhoek', 'Atlantic/Cape_Verde', 'Asia/Kuwait', 'America/Barbados', 'Egypt', 'GB-Eire', 'Antarctica/South_Pole',
+ 'America/Kentucky/Louisville', 'Asia/Yangon', 'CET', 'Etc/GMT+11', 'Asia/Dubai', 'Europe/Stockholm'];
+
+describe('temporal-types', () => {
+
+ let originalTimeout;
+ let driver;
+ let session;
+ let serverVersion;
+
+ beforeAll(done => {
+ originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
+
+ driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken);
+ ServerVersion.fromDriver(driver).then(version => {
+ serverVersion = version;
+ done();
+ });
+ });
+
+ afterAll(() => {
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
+
+ if (driver) {
+ driver.close();
+ driver = null;
+ }
+ });
+
+ beforeEach(done => {
+ session = driver.session();
+ session.run('MATCH (n) DETACH DELETE n').then(() => {
+ done();
+ }).catch(error => {
+ done.fail(error);
+ });
+ });
+
+ afterEach(() => {
+ if (session) {
+ session.close();
+ session = null;
+ }
+ });
+
+ it('should receive Duration', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = duration(27, 17, 91, 999);
+ testReceiveTemporalValue('RETURN duration({years: 2, months: 3, days: 17, seconds: 91, nanoseconds: 999})', expectedValue, done);
+ });
+
+ it('should send and receive random Duration', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => {
+ const sign = _.sample([true, false]) ? 1 : -1; // duration can be negative
+ return duration(
+ sign * _.random(0, Number.MAX_SAFE_INTEGER),
+ sign * _.random(0, Number.MAX_SAFE_INTEGER),
+ sign * _.random(0, Number.MAX_SAFE_INTEGER),
+ sign * _.random(0, MAX_NANO_OF_SECOND),
+ );
+ };
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive LocalTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = localTime(22, 59, 10, 999999);
+ testReceiveTemporalValue('RETURN localtime({hour: 22, minute: 59, second: 10, nanosecond: 999999})', expectedValue, done);
+ });
+
+ it('should send and receive max LocalTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxLocalTime = localTime(23, 59, 59, MAX_NANO_OF_SECOND);
+ testSendReceiveTemporalValue(maxLocalTime, done);
+ });
+
+ it('should send and receive min LocalTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minLocalTime = localTime(0, 0, 0, 0);
+ testSendReceiveTemporalValue(minLocalTime, done);
+ });
+
+ it('should send and receive random LocalTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomLocalTime();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive Time', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = time(11, 42, 59, 9999, -30600);
+ testReceiveTemporalValue('RETURN time({hour: 11, minute: 42, second: 59, nanosecond: 9999, timezone:"-08:30"})', expectedValue, done);
+ });
+
+ it('should send and receive max Time', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxTime = time(23, 59, 59, MAX_NANO_OF_SECOND, MAX_TIME_ZONE_OFFSET);
+ testSendReceiveTemporalValue(maxTime, done);
+ });
+
+ it('should send and receive min Time', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minTime = time(0, 0, 0, 0, MIN_TIME_ZONE_OFFSET);
+ testSendReceiveTemporalValue(minTime, done);
+ });
+
+ it('should send and receive random Time', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomTime();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive Date', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = date(1995, 7, 28);
+ testReceiveTemporalValue('RETURN date({year: 1995, month: 7, day: 28})', expectedValue, done);
+ });
+
+ it('should send and receive max Date', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxDate = date(MAX_YEAR, 12, 31);
+ testSendReceiveTemporalValue(maxDate, done);
+ });
+
+ it('should send and receive min Date', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minDate = date(MIN_YEAR, 1, 1);
+ testSendReceiveTemporalValue(minDate, done);
+ });
+
+ it('should send and receive random Date', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomDate();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive LocalDateTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = localDateTime(1869, 9, 23, 18, 29, 59, 12349);
+ testReceiveTemporalValue('RETURN localdatetime({year: 1869, month: 9, day: 23, hour: 18, minute: 29, second: 59, nanosecond: 12349})', expectedValue, done);
+ });
+
+ it('should send and receive max LocalDateTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxLocalDateTime = localDateTime(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND);
+ testSendReceiveTemporalValue(maxLocalDateTime, done);
+ });
+
+ it('should send and receive min LocalDateTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minLocalDateTime = localDateTime(MIN_YEAR, 1, 1, 0, 0, 0, 0);
+ testSendReceiveTemporalValue(minLocalDateTime, done);
+ });
+
+ it('should send and receive random LocalDateTime', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomLocalDateTime();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive DateTimeWithZoneOffset', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = dateTimeWithZoneOffset(1992, 11, 24, 9, 55, 42, 999, 18000);
+ testReceiveTemporalValue('RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "+05:00"})', expectedValue, done);
+ });
+
+ it('should send and receive max DateTimeWithZoneOffset', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxDateTime = dateTimeWithZoneOffset(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND, MAX_TIME_ZONE_OFFSET);
+ testSendReceiveTemporalValue(maxDateTime, done);
+ });
+
+ it('should send and receive min DateTimeWithZoneOffset', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minDateTime = dateTimeWithZoneOffset(MIN_YEAR, 1, 1, 0, 0, 0, 0, MAX_TIME_ZONE_OFFSET);
+ testSendReceiveTemporalValue(minDateTime, done);
+ });
+
+ it('should send and receive random DateTimeWithZoneOffset', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomDateTimeWithZoneOffset();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should receive DateTimeWithZoneId', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const expectedValue = dateTimeWithZoneId(1992, 11, 24, 9, 55, 42, 999, 'Europe/Stockholm');
+ testReceiveTemporalValue('RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "Europe/Stockholm"})', expectedValue, done);
+ });
+
+ it('should send and receive max DateTimeWithZoneId', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const maxDateTime = dateTimeWithZoneId(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND, MAX_ZONE_ID);
+ testSendReceiveTemporalValue(maxDateTime, done);
+ });
+
+ it('should send and receive min DateTimeWithZoneId', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const minDateTime = dateTimeWithZoneId(MIN_YEAR, 1, 1, 0, 0, 0, 0, MIN_ZONE_ID);
+ testSendReceiveTemporalValue(minDateTime, done);
+ });
+
+ it('should send and receive random DateTimeWithZoneId', done => {
+ if (neo4jDoesNotSupportTemporalTypes(done)) {
+ return;
+ }
+
+ const valueGenerator = () => randomDateTimeWithZoneId();
+
+ testSendAndReceiveRandomTemporalValues(valueGenerator, done);
+ });
+
+ it('should convert Duration to ISO string', () => {
+ expect(duration(13, 62, 3, 999111999).toString()).toEqual('P13M62DT3.999111999S');
+ expect(duration(0, 0, 0, 0).toString()).toEqual('P0M0DT0.000000000S');
+ expect(duration(-1, -2, 10, 10).toString()).toEqual('P-1M-2DT10.000000010S');
+ });
+
+ it('should convert LocalTime to ISO string', () => {
+ expect(localTime(12, 19, 39, 111222333).toString()).toEqual('12:19:39.111222333');
+ expect(localTime(3, 59, 2, 17).toString()).toEqual('03:59:02.000000017');
+ expect(localTime(0, 0, 0, 0).toString()).toEqual('00:00:00.000000000');
+ });
+
+ it('should convert Time to ISO string', () => {
+ expect(time(11, 45, 22, 333222111, 9015).toString()).toEqual('11:45:22.333222111+02:30:15');
+ expect(time(23, 2, 1, 10, 0).toString()).toEqual('23:02:01.000000010Z');
+ expect(time(0, 12, 59, 0, -40500).toString()).toEqual('00:12:59.000000000-11:15');
+ expect(time(21, 59, 0, 123, -25200).toString()).toEqual('21:59:00.000000123-07:00');
+ });
+
+ it('should convert Date to ISO string', () => {
+ expect(date(2015, 10, 12).toString()).toEqual('2015-10-12');
+ expect(date(881, 1, 1).toString()).toEqual('0881-01-01');
+ expect(date(-999, 12, 24).toString()).toEqual('-0999-12-24');
+ expect(date(-9, 1, 1).toString()).toEqual('-0009-01-01');
+ });
+
+ it('should convert LocalDateTime to ISO string', () => {
+ expect(localDateTime(1992, 11, 8, 9, 42, 17, 22).toString()).toEqual('1992-11-08T09:42:17.000000022');
+ expect(localDateTime(-10, 7, 15, 8, 15, 33, 500).toString()).toEqual('-0010-07-15T08:15:33.000000500');
+ expect(localDateTime(0, 0, 0, 0, 0, 0, 1).toString()).toEqual('0000-00-00T00:00:00.000000001');
+ });
+
+ it('should convert DateTime with time zone offset to ISO string', () => {
+ expect(dateTimeWithZoneOffset(2025, 9, 17, 23, 22, 21, 999888, 37800).toString()).toEqual('2025-09-17T23:22:21.000999888+10:30');
+ expect(dateTimeWithZoneOffset(1, 2, 3, 4, 5, 6, 7, -49376).toString()).toEqual('0001-02-03T04:05:06.000000007-13:42:56');
+ expect(dateTimeWithZoneOffset(-3, 3, 9, 9, 33, 27, 999000, 15300).toString()).toEqual('-0003-03-09T09:33:27.000999000+04:15');
+ });
+
+ it('should convert DateTime with time zone id to ISO-like string', () => {
+ expect(dateTimeWithZoneId(1949, 10, 7, 6, 10, 15, 15000000, 'Europe/Zaporozhye').toString()).toEqual('1949-10-07T06:10:15.015000000[Europe/Zaporozhye]');
+ expect(dateTimeWithZoneId(-30455, 5, 5, 12, 24, 10, 123, 'Asia/Yangon').toString()).toEqual('-30455-05-05T12:24:10.000000123[Asia/Yangon]');
+ expect(dateTimeWithZoneId(248, 12, 30, 23, 59, 59, 3, 'CET').toString()).toEqual('0248-12-30T23:59:59.000000003[CET]');
+ });
+
+ function testSendAndReceiveRandomTemporalValues(valueGenerator, done) {
+ const asyncFunction = (index, callback) => {
+ const next = () => callback();
+ next.fail = error => callback(error);
+ testSendReceiveTemporalValue(valueGenerator(), next);
+ };
+
+ const doneFunction = error => {
+ if (error) {
+ done.fail(error);
+ } else {
+ done();
+ }
+ };
+
+ timesSeries(RANDOM_VALUES_TO_TEST, asyncFunction, doneFunction);
+ }
+
+ function testReceiveTemporalValue(query, expectedValue, done) {
+ session.run(query).then(result => {
+ const records = result.records;
+ expect(records.length).toEqual(1);
+
+ const value = records[0].get(0);
+ expect(value).toEqual(expectedValue);
+
+ session.close();
+ done();
+ }).catch(error => {
+ done.fail(error);
+ });
+ }
+
+ function testSendReceiveTemporalValue(value, done) {
+ session.run('CREATE (n:Node {value: $value}) RETURN n.value', {value: value}).then(result => {
+ const records = result.records;
+ expect(records.length).toEqual(1);
+
+ const receivedValue = records[0].get(0);
+ expect(receivedValue).toEqual(value);
+
+ session.close();
+ done();
+ }).catch(error => {
+ done.fail(error);
+ });
+ }
+
+ function neo4jDoesNotSupportTemporalTypes(done) {
+ if (serverVersion.compareTo(VERSION_3_4_0) < 0) {
+ done();
+ return true;
+ }
+ return false;
+ }
+
+ function randomDateTimeWithZoneOffset() {
+ return new neo4j.DateTimeWithZoneOffset(
+ randomLocalDateTime(),
+ randomZoneOffsetSeconds()
+ );
+ }
+
+ function randomDateTimeWithZoneId() {
+ return new neo4j.DateTimeWithZoneId(
+ randomLocalDateTime(),
+ randomZoneId()
+ );
+ }
+
+ function randomLocalDateTime() {
+ return new neo4j.LocalDateTime(randomDate(), randomLocalTime());
+ }
+
+ function randomDate() {
+ return new neo4j.Date(
+ randomInt(MIN_YEAR, MAX_YEAR),
+ randomInt(1, 12),
+ randomInt(1, 28)
+ );
+ }
+
+ function randomTime() {
+ return new neo4j.Time(
+ randomLocalTime(),
+ randomZoneOffsetSeconds(),
+ );
+ }
+
+ function randomLocalTime() {
+ return new neo4j.LocalTime(
+ randomInt(0, 23),
+ randomInt(0, 59),
+ randomInt(0, 59),
+ randomInt(0, MAX_NANO_OF_SECOND)
+ );
+ }
+
+ function randomZoneOffsetSeconds() {
+ const randomOffsetWithSeconds = neo4j.int(randomInt(MIN_TIME_ZONE_OFFSET, MAX_TIME_ZONE_OFFSET));
+ return randomOffsetWithSeconds.div(SECONDS_PER_MINUTE).multiply(SECONDS_PER_MINUTE); // truncate seconds
+ }
+
+ function randomZoneId() {
+ return _.sample(ZONE_IDS);
+ }
+
+ function duration(months, days, seconds, nanoseconds) {
+ return new neo4j.Duration(neo4j.int(months), neo4j.int(days), neo4j.int(seconds), neo4j.int(nanoseconds));
+ }
+
+ function localTime(hour, minute, second, nanosecond) {
+ return new neo4j.LocalTime(neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond));
+ }
+
+ function time(hour, minute, second, nanosecond, offsetSeconds) {
+ return new neo4j.Time(localTime(hour, minute, second, nanosecond), neo4j.int(offsetSeconds));
+ }
+
+ function date(year, month, day) {
+ return new neo4j.Date(neo4j.int(year), neo4j.int(month), neo4j.int(day));
+ }
+
+ function localDateTime(year, month, day, hour, minute, second, nanosecond) {
+ return new neo4j.LocalDateTime(date(year, month, day), localTime(hour, minute, second, nanosecond));
+ }
+
+ function dateTimeWithZoneOffset(year, month, day, hour, minute, second, nanosecond, offsetSeconds) {
+ return new neo4j.DateTimeWithZoneOffset(localDateTime(year, month, day, hour, minute, second, nanosecond), neo4j.int(offsetSeconds));
+ }
+
+ function dateTimeWithZoneId(year, month, day, hour, minute, second, nanosecond, zoneId) {
+ return new neo4j.DateTimeWithZoneId(localDateTime(year, month, day, hour, minute, second, nanosecond), zoneId);
+ }
+
+ function randomInt(lower, upper) {
+ return neo4j.int(_.random(lower, upper));
+ }
+});
diff --git a/types/v1/index.d.ts b/types/v1/index.d.ts
index 0a8aab49c..a3c07e9aa 100644
--- a/types/v1/index.d.ts
+++ b/types/v1/index.d.ts
@@ -19,16 +19,26 @@
import Integer, {inSafeRange, int, isInt, toNumber, toString} from "./integer";
import {Node, Path, PathSegment, Relationship, UnboundRelationship} from "./graph-types";
+import {isPoint, Point} from "./spatial-types";
+import {
+ Date,
+ DateTimeWithZoneId,
+ DateTimeWithZoneOffset,
+ Duration,
+ isDate,
+ isDateTimeWithZoneId,
+ isDateTimeWithZoneOffset,
+ isDuration,
+ isLocalDateTime,
+ isLocalTime,
+ isTime,
+ LocalDateTime,
+ LocalTime,
+ Time
+} from "./temporal-types";
import {Neo4jError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from "./error";
import Result, {Observer, StatementResult} from "./result";
-import ResultSummary, {
- Notification,
- NotificationPosition,
- Plan,
- ProfiledPlan,
- ServerInfo,
- StatementStatistic
-} from "./result-summary";
+import ResultSummary, {Notification, NotificationPosition, Plan, ProfiledPlan, ServerInfo, StatementStatistic} from "./result-summary";
import Record from "./record";
import Session from "./session";
import {AuthToken, Config, Driver, EncryptionLevel, READ, SessionMode, TrustStrategy, WRITE} from "./driver";
@@ -54,14 +64,22 @@ declare function driver(url: string,
config?: Config): Driver;
declare const types: {
- Node: typeof Node;
- Relationship: typeof Relationship;
- UnboundRelationship: typeof UnboundRelationship;
- PathSegment: typeof PathSegment;
- Path: typeof Path;
+ Node: Node;
+ Relationship: Relationship;
+ UnboundRelationship: UnboundRelationship;
+ PathSegment: PathSegment;
+ Path: Path;
Result: Result;
ResultSummary: ResultSummary;
- Record: typeof Record;
+ Record: Record;
+ Point: Point;
+ Duration: Duration;
+ LocalTime: LocalTime;
+ Time: Time;
+ Date: Date;
+ LocalDateTime: LocalDateTime;
+ DateTimeWithZoneOffset: DateTimeWithZoneOffset;
+ DateTimeWithZoneId: DateTimeWithZoneId;
};
declare const session: {
@@ -125,6 +143,22 @@ declare const forExport: {
NotificationPosition: NotificationPosition,
Session: Session;
Transaction: Transaction;
+ Point: Point;
+ isPoint: typeof isPoint;
+ Duration: Duration;
+ LocalTime: LocalTime;
+ Time: Time;
+ Date: Date;
+ LocalDateTime: LocalDateTime;
+ DateTimeWithZoneOffset: DateTimeWithZoneOffset;
+ DateTimeWithZoneId: DateTimeWithZoneId;
+ isDuration: typeof isDuration;
+ isLocalTime: typeof isLocalTime;
+ isTime: typeof isTime;
+ isDate: typeof isDate;
+ isLocalDateTime: typeof isLocalDateTime;
+ isDateTimeWithZoneOffset: typeof isDateTimeWithZoneOffset;
+ isDateTimeWithZoneId: typeof isDateTimeWithZoneId;
};
export {
@@ -161,7 +195,23 @@ export {
ServerInfo,
NotificationPosition,
Session,
- Transaction
+ Transaction,
+ Point,
+ isPoint,
+ Duration,
+ LocalTime,
+ Time,
+ Date,
+ LocalDateTime,
+ DateTimeWithZoneOffset,
+ DateTimeWithZoneId,
+ isDuration,
+ isLocalTime,
+ isTime,
+ isDate,
+ isLocalDateTime,
+ isDateTimeWithZoneOffset,
+ isDateTimeWithZoneId
}
export default forExport;
diff --git a/types/v1/temporal-types.d.ts b/types/v1/temporal-types.d.ts
new file mode 100644
index 000000000..dd27cae25
--- /dev/null
+++ b/types/v1/temporal-types.d.ts
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {NumberOrInteger} from './graph-types';
+import Integer from "./integer";
+
+declare class Duration {
+ months: T;
+ days: T;
+ seconds: T;
+ nanoseconds: T;
+
+ constructor(months: T, days: T, seconds: T, nanoseconds: T)
+}
+
+declare class LocalTime {
+ hour: T;
+ minute: T;
+ second: T;
+ nanosecond: T;
+
+ constructor(hour: T, minute: T, second: T, nanosecond: T);
+}
+
+declare class Time {
+
+ localTime: LocalTime;
+ offsetSeconds: T;
+
+ constructor(localTime: LocalTime, offsetSeconds: T);
+}
+
+declare class Date {
+
+ year: T;
+ month: T;
+ day: T;
+
+ constructor(year: T, month: T, day: T);
+}
+
+declare class LocalDateTime {
+
+ localDate: Date;
+ localTime: LocalTime;
+
+ constructor(localDate: Date, localTime: LocalTime);
+}
+
+declare class DateTimeWithZoneOffset {
+
+ localDateTime: LocalDateTime;
+ offsetSeconds: T;
+
+ constructor(localDateTime: LocalDateTime, offsetSeconds: T);
+}
+
+declare class DateTimeWithZoneId {
+
+ localDateTime: LocalDateTime;
+ zoneId: string;
+
+ constructor(localDateTime: LocalDateTime, zoneId: string);
+}
+
+declare function isDuration(obj: object): boolean;
+
+declare function isLocalTime(obj: object): boolean;
+
+declare function isTime(obj: object): boolean;
+
+declare function isDate(obj: object): boolean;
+
+declare function isLocalDateTime(obj: object): boolean;
+
+declare function isDateTimeWithZoneOffset(obj: object): boolean;
+
+declare function isDateTimeWithZoneId(obj: object): boolean;
+
+export {
+ Duration,
+ LocalTime,
+ Time,
+ Date,
+ LocalDateTime,
+ DateTimeWithZoneOffset,
+ DateTimeWithZoneId,
+ isDuration,
+ isLocalTime,
+ isTime,
+ isDate,
+ isLocalDateTime,
+ isDateTimeWithZoneOffset,
+ isDateTimeWithZoneId
+}