Files
2026-04-05 16:14:49 -04:00

576 lines
21 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
exports.normalizeSecondsForDuration = normalizeSecondsForDuration;
exports.normalizeNanosecondsForDuration = normalizeNanosecondsForDuration;
exports.localTimeToNanoOfDay = localTimeToNanoOfDay;
exports.nanoOfDayToLocalTime = nanoOfDayToLocalTime;
exports.localDateTimeToEpochSecond = localDateTimeToEpochSecond;
exports.epochSecondAndNanoToLocalDateTime = epochSecondAndNanoToLocalDateTime;
exports.dateToEpochDay = dateToEpochDay;
exports.epochDayToDate = epochDayToDate;
exports.durationToIsoString = durationToIsoString;
exports.timeToIsoString = timeToIsoString;
exports.timeZoneOffsetToIsoString = timeZoneOffsetToIsoString;
exports.dateToIsoString = dateToIsoString;
exports.totalNanoseconds = totalNanoseconds;
exports.timeZoneOffsetInSeconds = timeZoneOffsetInSeconds;
exports.assertValidYear = assertValidYear;
exports.assertValidMonth = assertValidMonth;
exports.assertValidDay = assertValidDay;
exports.assertValidHour = assertValidHour;
exports.assertValidMinute = assertValidMinute;
exports.assertValidSecond = assertValidSecond;
exports.assertValidNanosecond = assertValidNanosecond;
var _integer = require('../integer');
var _temporalTypes = require('../temporal-types');
var _util = require('./util');
var _error = require('../error');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
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 <code>Number.MAX_SAFE_INTEGER</code>.
Please consult either ThreeTen or js-joda (https://github.com/js-joda/js-joda) when working with the
conversion functions.
*/
/**
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.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.
*/
var ValueRange = function () {
function ValueRange(min, max) {
(0, _classCallCheck3.default)(this, ValueRange);
this._minNumber = min;
this._maxNumber = max;
this._minInteger = (0, _integer.int)(min);
this._maxInteger = (0, _integer.int)(max);
}
(0, _createClass3.default)(ValueRange, [{
key: 'contains',
value: function contains(value) {
if ((0, _integer.isInt)(value)) {
return value.greaterThanOrEqual(this._minInteger) && value.lessThanOrEqual(this._maxInteger);
} else {
return value >= this._minNumber && value <= this._maxNumber;
}
}
}, {
key: 'toString',
value: function toString() {
return '[' + this._minNumber + ', ' + this._maxNumber + ']';
}
}]);
return ValueRange;
}();
var YEAR_RANGE = new ValueRange(-999999999, 999999999);
var MONTH_OF_YEAR_RANGE = new ValueRange(1, 12);
var DAY_OF_MONTH_RANGE = new ValueRange(1, 31);
var HOUR_OF_DAY_RANGE = new ValueRange(0, 23);
var MINUTE_OF_HOUR_RANGE = new ValueRange(0, 59);
var SECOND_OF_MINUTE_RANGE = new ValueRange(0, 59);
var NANOSECOND_OF_SECOND_RANGE = new ValueRange(0, 999999999);
var MINUTES_PER_HOUR = 60;
var SECONDS_PER_MINUTE = 60;
var SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
var NANOS_PER_SECOND = 1000000000;
var NANOS_PER_MILLISECOND = 1000000;
var NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
var NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
var DAYS_0000_TO_1970 = 719528;
var DAYS_PER_400_YEAR_CYCLE = 146097;
var SECONDS_PER_DAY = 86400;
function normalizeSecondsForDuration(seconds, nanoseconds) {
return (0, _integer.int)(seconds).add(floorDiv(nanoseconds, NANOS_PER_SECOND));
}
function normalizeNanosecondsForDuration(nanoseconds) {
return floorMod(nanoseconds, NANOS_PER_SECOND);
}
/**
* Converts given local time into a single integer representing this same time in nanoseconds of the day.
* @param {Integer|number|string} hour the hour of the local time to convert.
* @param {Integer|number|string} minute the minute of the local time to convert.
* @param {Integer|number|string} second the second of the local time to convert.
* @param {Integer|number|string} nanosecond the nanosecond of the local time to convert.
* @return {Integer} nanoseconds representing the given local time.
*/
function localTimeToNanoOfDay(hour, minute, second, nanosecond) {
hour = (0, _integer.int)(hour);
minute = (0, _integer.int)(minute);
second = (0, _integer.int)(second);
nanosecond = (0, _integer.int)(nanosecond);
var 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.
*/
function nanoOfDayToLocalTime(nanoOfDay) {
nanoOfDay = (0, _integer.int)(nanoOfDay);
var hour = nanoOfDay.div(NANOS_PER_HOUR);
nanoOfDay = nanoOfDay.subtract(hour.multiply(NANOS_PER_HOUR));
var minute = nanoOfDay.div(NANOS_PER_MINUTE);
nanoOfDay = nanoOfDay.subtract(minute.multiply(NANOS_PER_MINUTE));
var second = nanoOfDay.div(NANOS_PER_SECOND);
var nanosecond = nanoOfDay.subtract(second.multiply(NANOS_PER_SECOND));
return new _temporalTypes.LocalTime(hour, minute, second, nanosecond);
}
/**
* Converts given local date time into a single integer representing this same time in epoch seconds UTC.
* @param {Integer|number|string} year the year of the local date-time to convert.
* @param {Integer|number|string} month the month of the local date-time to convert.
* @param {Integer|number|string} day the day of the local date-time to convert.
* @param {Integer|number|string} hour the hour of the local date-time to convert.
* @param {Integer|number|string} minute the minute of the local date-time to convert.
* @param {Integer|number|string} second the second of the local date-time to convert.
* @param {Integer|number|string} nanosecond the nanosecond of the local date-time to convert.
* @return {Integer} epoch second in UTC representing the given local date time.
*/
function localDateTimeToEpochSecond(year, month, day, hour, minute, second, nanosecond) {
var epochDay = dateToEpochDay(year, month, day);
var localTimeSeconds = localTimeToSecondOfDay(hour, minute, second);
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.
*/
function epochSecondAndNanoToLocalDateTime(epochSecond, nano) {
var epochDay = floorDiv(epochSecond, SECONDS_PER_DAY);
var secondsOfDay = floorMod(epochSecond, SECONDS_PER_DAY);
var nanoOfDay = secondsOfDay.multiply(NANOS_PER_SECOND).add(nano);
var localDate = epochDayToDate(epochDay);
var localTime = nanoOfDayToLocalTime(nanoOfDay);
return new _temporalTypes.LocalDateTime(localDate.year, localDate.month, localDate.day, localTime.hour, localTime.minute, localTime.second, localTime.nanosecond);
}
/**
* Converts given local date into a single integer representing it's epoch day.
* @param {Integer|number|string} year the year of the local date to convert.
* @param {Integer|number|string} month the month of the local date to convert.
* @param {Integer|number|string} day the day of the local date to convert.
* @return {Integer} epoch day representing the given date.
*/
function dateToEpochDay(year, month, day) {
year = (0, _integer.int)(year);
month = (0, _integer.int)(month);
day = (0, _integer.int)(day);
var 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.
*/
function epochDayToDate(epochDay) {
epochDay = (0, _integer.int)(epochDay);
var zeroDay = epochDay.add(DAYS_0000_TO_1970).subtract(60);
var adjust = (0, _integer.int)(0);
if (zeroDay.lessThan(0)) {
var 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));
}
var year = zeroDay.multiply(400).add(591).div(DAYS_PER_400_YEAR_CYCLE);
var 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);
var marchDayOfYear = dayOfYearEst;
var marchMonth = marchDayOfYear.multiply(5).add(2).div(153);
var month = marchMonth.add(2).modulo(12).add(1);
var day = marchDayOfYear.subtract(marchMonth.multiply(306).add(5).div(10)).add(1);
year = year.add(marchMonth.div(10));
return new _temporalTypes.Date(year, month, day);
}
/**
* Format given duration to an ISO 8601 string.
* @param {Integer|number|string} months the number of months.
* @param {Integer|number|string} days the number of days.
* @param {Integer|number|string} seconds the number of seconds.
* @param {Integer|number|string} nanoseconds the number of nanoseconds.
* @return {string} ISO string that represents given duration.
*/
function durationToIsoString(months, days, seconds, nanoseconds) {
var monthsString = formatNumber(months);
var daysString = formatNumber(days);
var secondsAndNanosecondsString = formatSecondsAndNanosecondsForDuration(seconds, nanoseconds);
return 'P' + monthsString + 'M' + daysString + 'DT' + secondsAndNanosecondsString + 'S';
}
/**
* Formats given time to an ISO 8601 string.
* @param {Integer|number|string} hour the hour value.
* @param {Integer|number|string} minute the minute value.
* @param {Integer|number|string} second the second value.
* @param {Integer|number|string} nanosecond the nanosecond value.
* @return {string} ISO string that represents given time.
*/
function timeToIsoString(hour, minute, second, nanosecond) {
var hourString = formatNumber(hour, 2);
var minuteString = formatNumber(minute, 2);
var secondString = formatNumber(second, 2);
var nanosecondString = formatNanosecond(nanosecond);
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|string} offsetSeconds the offset in seconds.
* @return {string} ISO string that represents given offset.
*/
function timeZoneOffsetToIsoString(offsetSeconds) {
offsetSeconds = (0, _integer.int)(offsetSeconds);
if (offsetSeconds.equals(0)) {
return 'Z';
}
var isNegative = offsetSeconds.isNegative();
if (isNegative) {
offsetSeconds = offsetSeconds.multiply(-1);
}
var signPrefix = isNegative ? '-' : '+';
var hours = formatNumber(offsetSeconds.div(SECONDS_PER_HOUR), 2);
var minutes = formatNumber(offsetSeconds.div(SECONDS_PER_MINUTE).modulo(MINUTES_PER_HOUR), 2);
var secondsValue = offsetSeconds.modulo(SECONDS_PER_MINUTE);
var 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|string} year the date year.
* @param {Integer|number|string} month the date month.
* @param {Integer|number|string} day the date day.
* @return {string} ISO string that represents given date.
*/
function dateToIsoString(year, month, day) {
year = (0, _integer.int)(year);
var isNegative = year.isNegative();
if (isNegative) {
year = year.multiply(-1);
}
var yearString = formatNumber(year, 4);
if (isNegative) {
yearString = '-' + yearString;
}
var monthString = formatNumber(month, 2);
var dayString = formatNumber(day, 2);
return yearString + '-' + monthString + '-' + dayString;
}
/**
* Get the total number of nanoseconds from the milliseconds of the given standard JavaScript date and optional nanosecond part.
* @param {global.Date} standardDate the standard JavaScript date.
* @param {Integer|number|undefined} nanoseconds the optional number of nanoseconds.
* @return {Integer|number} the total amount of nanoseconds.
*/
function totalNanoseconds(standardDate, nanoseconds) {
nanoseconds = nanoseconds || 0;
var nanosFromMillis = standardDate.getMilliseconds() * NANOS_PER_MILLISECOND;
return (0, _integer.isInt)(nanoseconds) ? nanoseconds.add(nanosFromMillis) : nanoseconds + nanosFromMillis;
}
/**
* Get the time zone offset in seconds from the given standard JavaScript date.
* @param {global.Date} standardDate the standard JavaScript date.
* @return {number} the time zone offset in seconds.
*/
function timeZoneOffsetInSeconds(standardDate) {
return standardDate.getTimezoneOffset() * SECONDS_PER_MINUTE;
}
/**
* Assert that the year value is valid.
* @param {Integer|number} year the value to check.
* @return {Integer|number} the value of the year if it is valid. Exception is thrown otherwise.
*/
function assertValidYear(year) {
return assertValidTemporalValue(year, YEAR_RANGE, 'Year');
}
/**
* Assert that the month value is valid.
* @param {Integer|number} month the value to check.
* @return {Integer|number} the value of the month if it is valid. Exception is thrown otherwise.
*/
function assertValidMonth(month) {
return assertValidTemporalValue(month, MONTH_OF_YEAR_RANGE, 'Month');
}
/**
* Assert that the day value is valid.
* @param {Integer|number} day the value to check.
* @return {Integer|number} the value of the day if it is valid. Exception is thrown otherwise.
*/
function assertValidDay(day) {
return assertValidTemporalValue(day, DAY_OF_MONTH_RANGE, 'Day');
}
/**
* Assert that the hour value is valid.
* @param {Integer|number} hour the value to check.
* @return {Integer|number} the value of the hour if it is valid. Exception is thrown otherwise.
*/
function assertValidHour(hour) {
return assertValidTemporalValue(hour, HOUR_OF_DAY_RANGE, 'Hour');
}
/**
* Assert that the minute value is valid.
* @param {Integer|number} minute the value to check.
* @return {Integer|number} the value of the minute if it is valid. Exception is thrown otherwise.
*/
function assertValidMinute(minute) {
return assertValidTemporalValue(minute, MINUTE_OF_HOUR_RANGE, 'Minute');
}
/**
* Assert that the second value is valid.
* @param {Integer|number} second the value to check.
* @return {Integer|number} the value of the second if it is valid. Exception is thrown otherwise.
*/
function assertValidSecond(second) {
return assertValidTemporalValue(second, SECOND_OF_MINUTE_RANGE, 'Second');
}
/**
* Assert that the nanosecond value is valid.
* @param {Integer|number} nanosecond the value to check.
* @return {Integer|number} the value of the nanosecond if it is valid. Exception is thrown otherwise.
*/
function assertValidNanosecond(nanosecond) {
return assertValidTemporalValue(nanosecond, NANOSECOND_OF_SECOND_RANGE, 'Nanosecond');
}
/**
* Check if the given value is of expected type and is in the expected range.
* @param {Integer|number} value the value to check.
* @param {ValueRange} range the range.
* @param {string} name the name of the value.
* @return {Integer|number} the value if valid. Exception is thrown otherwise.
*/
function assertValidTemporalValue(value, range, name) {
(0, _util.assertNumberOrInteger)(value, name);
if (!range.contains(value)) {
throw (0, _error.newError)(name + ' is expected to be in range ' + range + ' but was: ' + value);
}
return value;
}
/**
* Converts given local time into a single integer representing this same time in seconds of the day. Nanoseconds are skipped.
* @param {Integer|number|string} hour the hour of the local time.
* @param {Integer|number|string} minute the minute of the local time.
* @param {Integer|number|string} second the second of the local time.
* @return {Integer} seconds representing the given local time.
*/
function localTimeToSecondOfDay(hour, minute, second) {
hour = (0, _integer.int)(hour);
minute = (0, _integer.int)(minute);
second = (0, _integer.int)(second);
var 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} <code>true</code> if given year is a leap year, <code>false</code> otherwise.
*/
function isLeapYear(year) {
year = (0, _integer.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 = (0, _integer.int)(x);
y = (0, _integer.int)(y);
var 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 = (0, _integer.int)(x);
y = (0, _integer.int)(y);
return x.subtract(floorDiv(x, y).multiply(y));
}
/**
* @param {Integer|number|string} seconds the number of seconds to format.
* @param {Integer|number|string} nanoseconds the number of nanoseconds to format.
* @return {string} formatted value.
*/
function formatSecondsAndNanosecondsForDuration(seconds, nanoseconds) {
seconds = (0, _integer.int)(seconds);
nanoseconds = (0, _integer.int)(nanoseconds);
var secondsString = void 0;
var nanosecondsString = void 0;
var secondsNegative = seconds.isNegative();
var nanosecondsGreaterThanZero = nanoseconds.greaterThan(0);
if (secondsNegative && nanosecondsGreaterThanZero) {
if (seconds.equals(-1)) {
secondsString = '-0';
} else {
secondsString = seconds.add(1).toString();
}
} else {
secondsString = seconds.toString();
}
if (nanosecondsGreaterThanZero) {
if (secondsNegative) {
nanosecondsString = formatNanosecond(nanoseconds.negate().add(2 * NANOS_PER_SECOND).modulo(NANOS_PER_SECOND));
} else {
nanosecondsString = formatNanosecond(nanoseconds.add(NANOS_PER_SECOND).modulo(NANOS_PER_SECOND));
}
}
return nanosecondsString ? secondsString + nanosecondsString : secondsString;
}
/**
* @param {Integer|number|string} value the number of nanoseconds to format.
* @return {string} formatted and possibly left-padded nanoseconds part as string.
*/
function formatNanosecond(value) {
value = (0, _integer.int)(value);
return value.equals(0) ? '' : '.' + formatNumber(value, 9);
}
/**
* @param {Integer|number|string} 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) {
var stringLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
num = (0, _integer.int)(num);
var isNegative = num.isNegative();
if (isNegative) {
num = num.negate();
}
var numString = num.toString();
if (stringLength) {
// left pad the string with zeroes
while (numString.length < stringLength) {
numString = '0' + numString;
}
}
return isNegative ? '-' + numString : numString;
}