UNPKG

chronoshift

Version:

A tiny library for shifting time with timezones

184 lines (183 loc) 6.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseSQLDate = parseSQLDate; exports.parseISODate = parseISODate; exports.parseInterval = parseInterval; const date_1 = require("@internationalized/date"); const duration_1 = require("../duration/duration"); const timezone_1 = require("../timezone/timezone"); function parseYear(v) { if (v.length === 2) { const vn = parseInt(v, 10); return (vn < 70 ? 2000 : 1900) + vn; } else if (v.length === 4) { return parseInt(v, 10); } else { throw new Error('Invalid year in date'); } } function parseMonth(v) { const vn = parseInt(v, 10); if (vn <= 0 || 12 < vn) throw new Error('Invalid month in date'); return vn - 1; } function parseDay(v) { const vn = parseInt(v, 10); if (vn <= 0 || 31 < vn) throw new Error('Invalid day in date'); return vn; } function parseHour(v) { const vn = parseInt(v, 10); if (vn < 0 || 24 < vn) throw new Error('Invalid hour in date'); return vn; } function parseMinute(v) { const vn = parseInt(v, 10); if (vn < 0 || 60 < vn) throw new Error('Invalid minute in date'); return vn; } function parseSecond(v) { const vn = parseInt(v, 10); if (vn < 0 || 60 < vn) throw new Error('Invalid second in date'); return vn; } function parseMillisecond(v) { if (!v) return 0; return parseInt(v.substr(0, 3), 10); } function parseSQLDate(type, v) { if (type === 't') throw new Error('time literals are not supported'); let m; let d; if (type === 'ts') { if ((m = /^(\d{2}(?:\d{2})?)(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/.exec(v))) { d = Date.UTC(parseYear(m[1]), parseMonth(m[2]), parseDay(m[3]), parseHour(m[4]), parseMinute(m[5]), parseSecond(m[6])); } else if ((m = /^(\d{2}(?:\d{2})?)[~!@#$%^&*()_+=:.\-\/](\d{1,2})[~!@#$%^&*()_+=:.\-\/](\d{1,2})[T ](\d{1,2})[~!@#$%^&*()_+=:.\-\/](\d{1,2})[~!@#$%^&*()_+=:.\-\/](\d{1,2})(?:\.(\d{1,6}))?$/.exec(v))) { d = Date.UTC(parseYear(m[1]), parseMonth(m[2]), parseDay(m[3]), parseHour(m[4]), parseMinute(m[5]), parseSecond(m[6]), parseMillisecond(m[7])); } else { throw new Error('Invalid timestamp'); } } else { if ((m = /^(\d{2}(?:\d{2})?)(\d{2})(\d{2})$/.exec(v))) { d = Date.UTC(parseYear(m[1]), parseMonth(m[2]), parseDay(m[3])); } else if ((m = /^(\d{2}(?:\d{2})?)[~!@#$%^&*()_+=:.\-\/](\d{1,2})[~!@#$%^&*()_+=:.\-\/](\d{1,2})$/.exec(v))) { d = Date.UTC(parseYear(m[1]), parseMonth(m[2]), parseDay(m[3])); } else { throw new Error('Invalid date'); } } return new Date(d); } const numericKeys = [1, 4, 5, 6, 10, 11]; function parseISODate(date, timezone = timezone_1.Timezone.UTC) { let struct; let minutesOffset = 0; if ((struct = /^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2})(?::?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?)?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?$/.exec(date))) { for (let i = 0, k; (k = numericKeys[i]); ++i) { struct[k] = +struct[k] || 0; } struct[2] = (+struct[2] || 1) - 1; struct[3] = +struct[3] || 1; struct[7] = struct[7] ? +(struct[7] + '00').slice(0, 3) : 0; if ((struct[8] === undefined || struct[8] === '') && (struct[9] === undefined || struct[9] === '') && !timezone_1.Timezone.UTC.equals(timezone || undefined)) { if (timezone === null) { return new Date(struct[1], struct[2], struct[3], struct[4], struct[5], struct[6], struct[7]); } else { const dt = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5], struct[6], struct[7]); const tzd = (0, date_1.fromDate)(new Date(dt), timezone.toString()); return new Date(dt - tzd.offset); } } else { if (struct[8] !== 'Z' && struct[9] !== undefined) { minutesOffset = struct[10] * 60 + struct[11]; if (struct[9] === '+') { minutesOffset = 0 - minutesOffset; } } return new Date(Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7])); } } else { return; } } function parseInterval(str, timezone = timezone_1.Timezone.UTC, now = new Date()) { const parts = str.split('/'); if (parts.length > 2) throw new Error(`Can not parse string ${str}`); let start; let end; let duration; const p0 = parts[0]; if (parts.length === 1) { duration = duration_1.Duration.fromJS(p0); } else { const p1 = parts[1]; if (p0[0] === 'P') { duration = duration_1.Duration.fromJS(p0); end = parseISODate(p1, timezone); if (!end) throw new Error(`can not parse '${p1}' as ISO date`); } else if (p1[0] === 'P') { start = parseISODate(p0, timezone); if (!start) throw new Error(`can not parse '${p0}' as ISO date`); duration = duration_1.Duration.fromJS(p1); } else { start = parseISODate(p0, timezone); if (!start) throw new Error(`can not parse '${p0}' as ISO date`); end = parseISODate(p1, timezone); if (!end) throw new Error(`can not parse '${p1}' as ISO date`); if (end < start) { throw new Error(`start must be <= end in '${str}'`); } } } let computedStart; let computedEnd; if (start) { computedStart = start; if (duration) { computedEnd = duration.shift(computedStart, timezone, 1); } else { computedEnd = end; } } else { computedEnd = end || now; computedStart = duration.shift(computedEnd, timezone, -1); } return { computedStart, computedEnd, start, end, duration, }; }