zol-datetime
Version:
SQL Date/Time functionality for Zol
394 lines (387 loc) • 13.9 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('js-joda'), require('zol')) :
typeof define === 'function' && define.amd ? define(['exports', 'js-joda', 'zol'], factory) :
(factory((global.zolDatetime = {}),global.jsJoda,global.zol));
}(this, (function (exports,jsJoda,zol) { 'use strict';
// Ported from <https://github.com/bendrucker/postgres-date>
var DATE_TIME = /^(\d{1,})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d{1,})?/;
var DATE = /^(\d{1,})-(\d{2})-(\d{2})$/;
var TIME = /^(\d{2}):(\d{2}):(\d{2})(\.\d{1,})?$/;
var TIME_ZONE = /([Z+-])(\d{2})?:?(\d{2})?:?(\d{2})?$/;
function parseZonedDateTime(isoDate) {
var matches = DATE_TIME.exec(isoDate);
if (matches === null) {
throw new Error("Error parsing date: " + isoDate);
}
var year = parseInt(matches[1], 10);
var month = parseInt(matches[2], 10);
var day = parseInt(matches[3], 10);
var hour = parseInt(matches[4], 10);
var minute = parseInt(matches[5], 10);
var second = parseInt(matches[6], 10);
var ss = matches[7];
var nanos = (ss !== undefined) ? Math.floor(1000000000 * parseFloat(ss)) : 0;
var offset = timeZoneOffset(isoDate);
if (offset !== null) {
return jsJoda.ZonedDateTime.of(year, month, day, hour, minute, second, nanos, jsJoda.ZoneOffset.ofTotalSeconds(offset));
}
else {
return jsJoda.ZonedDateTime.of(year, month, day, hour, minute, second, nanos, jsJoda.ZoneOffset.UTC);
}
}
function parseLocalDate(isoDate) {
var matches = DATE.exec(isoDate);
if (matches === null) {
throw new Error("Error parsing date: " + isoDate);
}
var year = parseInt(matches[1], 10);
var month = parseInt(matches[2], 10);
var day = parseInt(matches[3], 10);
return jsJoda.LocalDate.of(year, month, day);
}
function parseLocalTime(isoTime) {
var matches = TIME.exec(isoTime);
if (matches === null) {
throw new Error("Error parsing time: " + isoTime);
}
var hour = parseInt(matches[1], 10);
var minute = parseInt(matches[2], 10);
var second = parseInt(matches[3], 10);
var ss = matches[4];
var nanos = (ss !== undefined) ? Math.floor(1000000000 * parseFloat(ss)) : 0;
return jsJoda.LocalTime.of(hour, minute, second, nanos);
}
// match timezones:
// Z (UTC)
// -05
// +06:30
function timeZoneOffset(isoDate) {
var zone = TIME_ZONE.exec(isoDate.split(" ")[1]);
if (zone === null) {
return null;
}
var type = zone[1];
if (type === "Z") {
return 0;
}
var sign = type === "-" ? -1 : 1;
var offset = parseInt(zone[2], 10) * 3600;
if (zone[3] !== undefined) {
offset += parseInt(zone[3], 10) * 60;
}
if (zone[4] !== undefined) {
offset += parseInt(zone[4], 10);
}
return offset * sign;
}
/**
* years, months, days, hours, minutes, seconds, nanos
*/
function intervalParser(interval) {
var parts = interval.split(" ");
var years = 0;
var months = 0;
var days = 0;
var hours = 0;
var minutes = 0;
var seconds = 0;
var nanos = 0;
var numNamed = Math.floor(parts.length / 2);
for (var i = 0; i < numNamed; ++i) {
var v = parseInt(parts[i * 2], 10);
var unit = parts[i * 2 + 1];
if (unit.startsWith("year")) {
years = v;
}
else if (unit.startsWith("mon")) {
months = v;
}
else if (unit.startsWith("day")) {
days = v;
}
else {
throw new Error("Unknown unit \"" + unit + "\" parsing interval \"" + interval + "\"");
}
}
if (parts.length % 2 === 1) {
var time = parts[parts.length - 1];
var negativeTime = false;
if (time.charAt(0) === "-") {
negativeTime = true;
time = time.substring(1);
}
else if (time.charAt(0) === "+") {
time = time.substring(1);
}
// This part looks exactly like a TIME
var matches = TIME.exec(time);
if (matches === null) {
throw new Error("Error parsing time component \"" + time + "\" parsing interval \"" + interval + "\"");
}
hours = parseInt(matches[1], 10);
minutes = parseInt(matches[2], 10);
seconds = parseInt(matches[3], 10);
var ss = matches[4];
nanos = (ss !== undefined) ? Math.floor(1000000000 * parseFloat(ss)) : 0;
if (negativeTime) {
hours = -hours;
minutes = -minutes;
seconds = -seconds;
nanos = -nanos;
}
}
return [years, months, days, hours, minutes, seconds, nanos];
}
function localDateTimeCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "TIMESTAMP", localDateTimeParser);
}
function localDateTimeParser(val) {
var t = parseZonedDateTime(val);
return t.toLocalDateTime();
}
function instantCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "TIMESTAMPTZ", instantParser);
}
function instantParser(val) {
var t = parseZonedDateTime(val);
return t.toInstant();
}
function localDateCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "DATE", localDateParser);
}
function localDateParser(val) {
return parseLocalDate(val);
}
function localTimeCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "TIME", localTimeParser);
}
function localTimeParser(val) {
return parseLocalTime(val);
}
function durationCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "INTERVAL", durationParser);
}
/**
* This should be used with great care, or ideally avoided
*/
function durationParser(interval) {
var _a = intervalParser(interval), years = _a[0], months = _a[1], days = _a[2], hours = _a[3], minutes = _a[4], seconds = _a[5], nanos = _a[6];
// PostgreSQL uses conversion factors 1 month = 30 days and 1 day = 24 hours.
// It doesn't specify what a year is, but 365 feels right.
// <https://www.postgresql.org/docs/current/static/datatype-datetime.html>
return jsJoda.Duration.ofDays(years * 365 + months * 30 + days).plusHours(hours).plusMinutes(minutes).plusSeconds(seconds).plusNanos(nanos);
}
function periodCol(val) {
return zol.Unsafe.unsafeCast(zol.textCol(val.toString()), "INTERVAL", periodParser);
}
/**
* Warning: This is lossy. Only use if you really know what you doing
*/
function periodParser(interval) {
var _a = intervalParser(interval), years = _a[0], months = _a[1], days = _a[2];
// hours, minutes, seconds, nanos: they get dropped! :(
return jsJoda.Period.of(years, months, days);
}
/**
* When instant occurred, what time did the clocks on the wall located in timezone show?
* (Or what do we predict them to show, if instant is in the future?)
*
* SQL equivilent: `TIMEZONE`
*/
function instantToLocalDateTime(instant, timezone) {
var asTimestamptz = zol.Unsafe.unsafeCast(instant, "TIMESTAMPTZ", instantParser);
return zol.Unsafe.unsafeFun2("TIMEZONE", timezone, asTimestamptz, localDateTimeParser);
}
/**
* When the clocks in timezone showed the given time, what was the instant?
* (Or what do we predict it to be, if the clocks haven't yet showed this time)
*
* Note: If due to daylight savings time, the clocks in timezone showed the given
* time on two seperate instances, then PostgreSQL sill arbitrarily pick one.
* Similarly, if the clocks in timezone never showed the given time, then PostgreSQL
* will pick an appropriately close instant.
*
* SQL equivilent: `TIMEZONE`
*/
function localDateTimeToInstant(localDateTime, timezone) {
var asTimestamp = zol.Unsafe.unsafeCast(localDateTime, "TIMESTAMP", localDateTimeParser);
return zol.Unsafe.unsafeFun2("TIMEZONE", timezone, asTimestamp, instantParser);
}
/**
* The duration between two Instants.
*
* SQL equivilent: `-`
*/
function durationBetween(startInclusive, endExclusive) {
var start = zol.Unsafe.unsafeCast(startInclusive, "TIMESTAMPTZ", instantParser);
var end = zol.Unsafe.unsafeCast(endExclusive, "TIMESTAMPTZ", instantParser);
return zol.Unsafe.unsafeCast(zol.e(end, "-", start), "INTERVAL", durationParser);
}
/**
* SQL equivilent: `+`
*/
function durationPlus(lhs, rhs) {
return zol.Unsafe.unsafeCast(zol.e(lhs, "+", rhs), "INTERVAL", durationParser);
}
/**
* SQL equivilent: `-`
*/
function durationMinus(lhs, rhs) {
return zol.Unsafe.unsafeCast(zol.e(lhs, "-", rhs), "INTERVAL", durationParser);
}
/**
* SQL equivilent: `*`
*/
function durationMultiply(lhs, rhs) {
return zol.Unsafe.unsafeCast(zol.e(rhs, "*", lhs), "INTERVAL", durationParser);
}
/**
* SQL equivilent: `/`
*/
function durationDivide(lhs, rhs) {
return zol.Unsafe.unsafeCast(zol.e(lhs, "/", rhs), "INTERVAL", durationParser);
}
/**
* Add a Duration to an Instant
*
* SQL equivilent: `+`
*/
function instantAdd(instant, duration) {
var lhs = zol.Unsafe.unsafeCast(instant, "TIMESTAMPTZ", instantParser);
return zol.Unsafe.unsafeCast(zol.e(lhs, "+", duration), "TIMESTAMPTZ", instantParser);
}
/**
* Subtract a Duration from an Instant
*
* SQL equivilent: `-`
*/
function instantSubtract(instant, duration) {
var lhs = zol.Unsafe.unsafeCast(instant, "TIMESTAMPTZ", instantParser);
return zol.Unsafe.unsafeCast(zol.e(lhs, "-", duration), "TIMESTAMPTZ", instantParser);
}
function localDateTimeAdd(localDateTime, t) {
var lhs = zol.Unsafe.unsafeCast(localDateTime, "TIMESTAMP", localDateTimeParser);
return zol.Unsafe.unsafeCast(zol.e(lhs, "+", t), "TIMESTAMP", localDateTimeParser);
}
function localDateTimeSubtract(localDateTime, t) {
var lhs = zol.Unsafe.unsafeCast(localDateTime, "TIMESTAMP", localDateTimeParser);
return zol.Unsafe.unsafeCast(zol.e(lhs, "-", t), "TIMESTAMP", localDateTimeParser);
}
/**
* Convert a LocalDateTime to a LocalDate (discarding the time portion)
*
* SQL equivilent: `CAST`
*/
function truncateToLocalDate(localDateTime) {
return zol.Unsafe.unsafeCast(localDateTime, "DATE", localDateParser);
}
/**
* Convert a LocalDate to a LocalDateTime. The time will be set to "00:00:00"
*
* SQL equivilent: `CAST`
*/
function expandTolocalDateTime(localDate) {
return zol.Unsafe.unsafeCast(localDate, "TIMESTAMP", localDateTimeParser);
}
/**
* Add n days to a LocalDate.
*
* This is similar to [[localDateAdd]], but can be more convenient when the
* days you want to add is from some other column, or is a computed value.
*
* SQL equivilent: `+` (INTEGER)
*/
function localDateAddDays(localDate, days) {
var rhs = zol.Unsafe.unsafeCast(days, "INT", zol.SqlType.intParser);
return zol.Unsafe.unsafeCast(zol.e(localDate, "+", rhs), "DATE", localDateParser);
}
/**
* Subtract n days from a LocalDate.
*
* This is similar to [[localDateSubtract]], but can be more convenient when
* the days you want to subtract is from some other column, or is a computed
* value.
*
* SQL equivilent: `-` (INTEGER)
*/
function localDateSubtractDays(localDate, days) {
var rhs = zol.Unsafe.unsafeCast(days, "INT", zol.SqlType.intParser);
return zol.Unsafe.unsafeCast(zol.e(localDate, "-", rhs), "DATE", localDateParser);
}
/**
* Add a Period to a LocalDate
*
* SQL equivilent: `+`
*/
function localDateAdd(localDate, period) {
return zol.Unsafe.unsafeCast(zol.e(localDate, "+", period), "DATE", localDateParser);
}
/**
* Subtract a Period from a LocalDate
*
* SQL equivilent: `-`
*/
function localDateSubtract(localDate, period) {
return zol.Unsafe.unsafeCast(zol.e(localDate, "-", period), "DATE", localDateParser);
}
/**
* Add a Duration to a LocalTime. If the LocalTime overflows (goes past
* midnight) then the result will wrap around.
*
* SQL equivilent: `+`
*/
function localTimeAdd(localTime, duration) {
return zol.Unsafe.unsafeCast(zol.e(localTime, "+", duration), "TIME", localTimeParser);
}
/**
* Subtract a Duration from a LocalTime. If the LocalTime overflows (goes
* before midnight) then the result will wrap around.
*
* SQL equivilent: `-`
*/
function localTimeSubtract(localTime, duration) {
return zol.Unsafe.unsafeCast(zol.e(localTime, "-", duration), "TIME", localTimeParser);
}
/**
* The Period between two LocalDates.
*
* SQL equivilent: `age`
*/
function periodBetween(startDate, endDate) {
return zol.Unsafe.unsafeFun2("age", endDate, startDate, periodParser);
}
exports.instantCol = instantCol;
exports.instantParser = instantParser;
exports.localDateTimeCol = localDateTimeCol;
exports.localDateTimeParser = localDateTimeParser;
exports.localDateCol = localDateCol;
exports.localDateParser = localDateParser;
exports.localTimeCol = localTimeCol;
exports.localTimeParser = localTimeParser;
exports.durationCol = durationCol;
exports.durationParser = durationParser;
exports.periodCol = periodCol;
exports.periodParser = periodParser;
exports.instantToLocalDateTime = instantToLocalDateTime;
exports.localDateTimeToInstant = localDateTimeToInstant;
exports.durationBetween = durationBetween;
exports.durationMinus = durationMinus;
exports.durationMultiply = durationMultiply;
exports.durationDivide = durationDivide;
exports.durationPlus = durationPlus;
exports.instantAdd = instantAdd;
exports.instantSubtract = instantSubtract;
exports.localDateTimeAdd = localDateTimeAdd;
exports.localDateTimeSubtract = localDateTimeSubtract;
exports.truncateToLocalDate = truncateToLocalDate;
exports.expandTolocalDateTime = expandTolocalDateTime;
exports.localDateAdd = localDateAdd;
exports.localDateSubtract = localDateSubtract;
exports.localDateAddDays = localDateAddDays;
exports.localDateSubtractDays = localDateSubtractDays;
exports.localTimeAdd = localTimeAdd;
exports.localTimeSubtract = localTimeSubtract;
exports.periodBetween = periodBetween;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=zol-datetime.umd.js.map