timezonecomplete
Version:
DateTime, TimeZone, Duration and Period library aimed at providing a consistent and complete date-time interface, away from the original JavaScript Date class.
1,130 lines (1,128 loc) • 959 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.tc = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
/**
* Copyright(c) 2016 ABB Switzerland Ltd.
*/
"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
var error_1 = require("./error");
/**
* Throws an Assertion error if the given condition is falsy
* @param condition
* @param name error name
* @param format error message with percent-style placeholders
* @param args arguments for error message format string
* @throws [name] if `condition` is falsy
*/
function assert(condition, name, format) {
var args = [];
for (var _i = 3; _i < arguments.length; _i++) {
args[_i - 3] = arguments[_i];
}
if (!condition) {
error_1.throwError.apply(void 0, __spreadArray([name, format], args, false));
}
}
exports.default = assert;
},{"./error":5}],2:[function(require,module,exports){
/**
* Copyright(c) 2014 ABB Switzerland Ltd.
*
* Olsen Timezone Database container
*/
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.binaryInsertionIndex = exports.TimeStruct = exports.secondOfDay = exports.weekDayNoLeapSecs = exports.timeToUnixNoLeapSecs = exports.unixToTimeNoLeapSecs = exports.weekNumber = exports.weekDayInstanceInMonth = exports.calendarWeekInMonth = exports.weekOfMonth = exports.weekDayOnOrBefore = exports.weekDayOnOrAfter = exports.nthWeekDayOfMonth = exports.firstWeekDayOfMonth = exports.lastWeekDayOfMonth = exports.dayOfYear = exports.daysInMonth = exports.daysInYear = exports.isLeapYear = exports.stringToTimeUnit = exports.timeUnitToString = exports.timeUnitToMilliseconds = exports.TimeUnit = exports.WeekDay = void 0;
var assert_1 = require("./assert");
var error_1 = require("./error");
var javascript_1 = require("./javascript");
var math = require("./math");
var strings = require("./strings");
/**
* Day-of-week. Note the enum values correspond to JavaScript day-of-week:
* Sunday = 0, Monday = 1 etc
*/
var WeekDay;
(function (WeekDay) {
WeekDay[WeekDay["Sunday"] = 0] = "Sunday";
WeekDay[WeekDay["Monday"] = 1] = "Monday";
WeekDay[WeekDay["Tuesday"] = 2] = "Tuesday";
WeekDay[WeekDay["Wednesday"] = 3] = "Wednesday";
WeekDay[WeekDay["Thursday"] = 4] = "Thursday";
WeekDay[WeekDay["Friday"] = 5] = "Friday";
WeekDay[WeekDay["Saturday"] = 6] = "Saturday";
})(WeekDay || (exports.WeekDay = WeekDay = {}));
/**
* Time units
*/
var TimeUnit;
(function (TimeUnit) {
TimeUnit[TimeUnit["Millisecond"] = 0] = "Millisecond";
TimeUnit[TimeUnit["Second"] = 1] = "Second";
TimeUnit[TimeUnit["Minute"] = 2] = "Minute";
TimeUnit[TimeUnit["Hour"] = 3] = "Hour";
TimeUnit[TimeUnit["Day"] = 4] = "Day";
TimeUnit[TimeUnit["Week"] = 5] = "Week";
TimeUnit[TimeUnit["Month"] = 6] = "Month";
TimeUnit[TimeUnit["Year"] = 7] = "Year";
/**
* End-of-enum marker, do not use
*/
TimeUnit[TimeUnit["MAX"] = 8] = "MAX";
})(TimeUnit || (exports.TimeUnit = TimeUnit = {}));
/**
* Approximate number of milliseconds for a time unit.
* A day is assumed to have 24 hours, a month is assumed to equal 30 days
* and a year is set to 360 days (because 12 months of 30 days).
*
* @param unit Time unit e.g. TimeUnit.Month
* @returns The number of milliseconds.
* @throws timezonecomplete.Argument.Unit for invalid unit
*/
function timeUnitToMilliseconds(unit) {
switch (unit) {
case TimeUnit.Millisecond: return 1;
case TimeUnit.Second: return 1000;
case TimeUnit.Minute: return 60 * 1000;
case TimeUnit.Hour: return 60 * 60 * 1000;
case TimeUnit.Day: return 86400000;
case TimeUnit.Week: return 7 * 86400000;
case TimeUnit.Month: return 30 * 86400000;
case TimeUnit.Year: return 12 * 30 * 86400000;
default:
return (0, error_1.throwError)("Argument.Unit", "unknown time unit %d", unit);
}
}
exports.timeUnitToMilliseconds = timeUnitToMilliseconds;
/**
* Time unit to lowercase string. If amount is specified, then the string is put in plural form
* if necessary.
* @param unit The unit
* @param amount If this is unequal to -1 and 1, then the result is pluralized
* @throws timezonecomplete.Argument.Unit for invalid time unit
*/
function timeUnitToString(unit, amount) {
if (amount === void 0) { amount = 1; }
if (!Number.isInteger(unit) || unit < 0 || unit >= TimeUnit.MAX) {
return (0, error_1.throwError)("Argument.Unit", "invalid time unit %d", unit);
}
var result = TimeUnit[unit].toLowerCase();
if (amount === 1 || amount === -1) {
return result;
}
else {
return result + "s";
}
}
exports.timeUnitToString = timeUnitToString;
/**
* Convert a string to a numeric TimeUnit. Case-insensitive; time units can be singular or plural.
* @param s
* @throws timezonecomplete.Argument.S for invalid string
*/
function stringToTimeUnit(s) {
var trimmed = s.trim().toLowerCase();
for (var i = 0; i < TimeUnit.MAX; ++i) {
var other = timeUnitToString(i, 1);
if (other === trimmed || (other + "s") === trimmed) {
return i;
}
}
return (0, error_1.throwError)("Argument.S", "Unknown time unit string '%s'", s);
}
exports.stringToTimeUnit = stringToTimeUnit;
/**
* @return True iff the given year is a leap year.
* @throws timezonecomplete.Argument.Year if year is not integer
*/
function isLeapYear(year) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Invalid year %d", year);
// from Wikipedia:
// if year is not divisible by 4 then common year
// else if year is not divisible by 100 then leap year
// else if year is not divisible by 400 then common year
// else leap year
if (year % 4 !== 0) {
return false;
}
else if (year % 100 !== 0) {
return true;
}
else if (year % 400 !== 0) {
return false;
}
else {
return true;
}
}
exports.isLeapYear = isLeapYear;
/**
* The days in a given year
* @throws timezonecomplete.Argument.Year if year is not integer
*/
function daysInYear(year) {
// rely on validation by isLeapYear
return (isLeapYear(year) ? 366 : 365);
}
exports.daysInYear = daysInYear;
/**
* @param year The full year
* @param month The month 1-12
* @return The number of days in the given month
* @throws timezonecomplete.Argument.Year if year is not integer
* @throws timezonecomplete.Argument.Month for invalid month number
*/
function daysInMonth(year, month) {
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 2:
return (isLeapYear(year) ? 29 : 28);
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return (0, error_1.throwError)("Argument.Month", "Invalid month: %d", month);
}
}
exports.daysInMonth = daysInMonth;
/**
* Returns the day of the year of the given date [0..365]. January first is 0.
*
* @param year The year e.g. 1986
* @param month Month 1-12
* @param day Day of month 1-31
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
*/
function dayOfYear(year, month, day) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range");
var yearDay = 0;
for (var i = 1; i < month; i++) {
yearDay += daysInMonth(year, i);
}
yearDay += (day - 1);
return yearDay;
}
exports.dayOfYear = dayOfYear;
/**
* Returns the last instance of the given weekday in the given month
*
* @param year The year
* @param month the month 1-12
* @param weekDay the desired week day 0-6
* @return the last occurrence of the week day in the month
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.WeekDay for invalid week day
*/
function lastWeekDayOfMonth(year, month, weekDay) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: %d", weekDay);
var endOfMonth = new TimeStruct({ year: year, month: month, day: daysInMonth(year, month) });
var endOfMonthWeekDay = weekDayNoLeapSecs(endOfMonth.unixMillis);
var diff = weekDay - endOfMonthWeekDay;
if (diff > 0) {
diff -= 7;
}
return endOfMonth.components.day + diff;
}
exports.lastWeekDayOfMonth = lastWeekDayOfMonth;
/**
* Returns the first instance of the given weekday in the given month
*
* @param year The year
* @param month the month 1-12
* @param weekDay the desired week day
* @return the first occurrence of the week day in the month
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.WeekDay for invalid week day
*/
function firstWeekDayOfMonth(year, month, weekDay) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: %d", weekDay);
var beginOfMonth = new TimeStruct({ year: year, month: month, day: 1 });
var beginOfMonthWeekDay = weekDayNoLeapSecs(beginOfMonth.unixMillis);
var diff = weekDay - beginOfMonthWeekDay;
if (diff < 0) {
diff += 7;
}
return beginOfMonth.components.day + diff;
}
exports.firstWeekDayOfMonth = firstWeekDayOfMonth;
/**
* Returns the nth instance of the given weekday in the given month; throws if not found
*
* @param year The year
* @param month the month 1-12
* @param weekDay the desired week day
* @param dayInstance the desired week day instance, n
* @return the first occurrence of the week day in the month
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.WeekDay for invalid week day
* @throws timezonecomplete.Arugment.DayInstance for invalid day instance (not 1-5)
* @throws timezonecomplete.NotFound if the month has no such instance (i.e. 5th instance, where only 4 exist)
*/
function nthWeekDayOfMonth(year, month, weekDay, dayInstance) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: %d", weekDay);
(0, assert_1.default)(Number.isInteger(dayInstance) && dayInstance >= 1 && dayInstance <= 5, "Argument.DayInstance", "dayInstance out of range: %d", dayInstance);
var beginOfMonth = new TimeStruct({ year: year, month: month, day: 1 });
var beginOfMonthWeekDay = weekDayNoLeapSecs(beginOfMonth.unixMillis);
var diff = weekDay - beginOfMonthWeekDay;
if (diff < 0) {
diff += 7;
}
diff += (dayInstance - 1) * 7;
(0, assert_1.default)(beginOfMonth.components.day + diff <= daysInMonth(year, month), "NotFound", "The given month has no such day");
return beginOfMonth.components.day + diff;
}
exports.nthWeekDayOfMonth = nthWeekDayOfMonth;
/**
* Returns the day-of-month that is on the given weekday and which is >= the given day; throws if not found
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
* @throws timezonecomplete.Argument.WeekDay for invalid week day
* @throws timezonecomplete.NotFound if the month has no such day
*/
function weekDayOnOrAfter(year, month, day, weekDay) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range");
(0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: %d", weekDay);
var start = new TimeStruct({ year: year, month: month, day: day });
var startWeekDay = weekDayNoLeapSecs(start.unixMillis);
var diff = weekDay - startWeekDay;
if (diff < 0) {
diff += 7;
}
(0, assert_1.default)(start.components.day + diff <= daysInMonth(year, month), "NotFound", "The given month has no such weekday");
return start.components.day + diff;
}
exports.weekDayOnOrAfter = weekDayOnOrAfter;
/**
* Returns the day-of-month that is on the given weekday and which is <= the given day.
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
* @throws timezonecomplete.Argument.WeekDay for invalid week day
* @throws timezonecomplete.NotFound if the month has no such day
*/
function weekDayOnOrBefore(year, month, day, weekDay) {
(0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: %d", year);
(0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: %d", month);
(0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range");
(0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: %d", weekDay);
var start = new TimeStruct({ year: year, month: month, day: day });
var startWeekDay = weekDayNoLeapSecs(start.unixMillis);
var diff = weekDay - startWeekDay;
if (diff > 0) {
diff -= 7;
}
(0, assert_1.default)(start.components.day + diff >= 1, "NotFound", "The given month has no such weekday");
return start.components.day + diff;
}
exports.weekDayOnOrBefore = weekDayOnOrBefore;
/**
* The week of this month. There is no official standard for this, but we assume the same rules for the weekNumber:
* week 1 is the week that has the 4th day of the month in it
*
* @param year The year
* @param month The month [1-12]
* @param day The day [1-31]
* @return Week number [1-5]
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
*/
function weekOfMonth(year, month, day) {
// rely on year/month validation in firstWeekDayOfMonth
(0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range");
var firstThursday = firstWeekDayOfMonth(year, month, WeekDay.Thursday);
var firstMonday = firstWeekDayOfMonth(year, month, WeekDay.Monday);
// Corner case: check if we are in week 1 or last week of previous month
if (day < firstMonday) {
if (firstThursday < firstMonday) {
// Week 1
return 1;
}
else {
// Last week of previous month
if (month > 1) {
// Default case
return weekOfMonth(year, month - 1, daysInMonth(year, month - 1));
}
else {
// January
return weekOfMonth(year - 1, 12, 31);
}
}
}
var lastMonday = lastWeekDayOfMonth(year, month, WeekDay.Monday);
var lastThursday = lastWeekDayOfMonth(year, month, WeekDay.Thursday);
// Corner case: check if we are in last week or week 1 of previous month
if (day >= lastMonday) {
if (lastMonday > lastThursday) {
// Week 1 of next month
return 1;
}
}
// Normal case
var result = Math.floor((day - firstMonday) / 7) + 1;
if (firstThursday < 4) {
result += 1;
}
return result;
}
exports.weekOfMonth = weekOfMonth;
/**
* The week of this month, based on counting calendar weeks. Unlike weekOfMonth() the first day of the month is
* always week 1, and no days count as the last week of the previous month. The week number returned can be from 1-6,
* as a month can span up to 6 different weeks on the calendar. The first day of the week, i.e. when the week number
* increases, is customizable, and defaults to Monday.
*
* @param year The year
* @param month The month [1-12]
* @param day The day [1-31]
* @param weekStartDay The week day to use as the start of the week
* @return Week number [1-6]
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
*/
function calendarWeekInMonth(year, month, day, weekStartDay) {
if (weekStartDay === void 0) { weekStartDay = WeekDay.Monday; }
// rely on year/month validation in weekDayOnOrAfter
(0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range");
var firstFullWeekStartDay = weekDayOnOrAfter(year, month, 1, weekStartDay);
var result = Math.floor((day - firstFullWeekStartDay + 7) / 7);
if (firstFullWeekStartDay > 1) {
result++;
}
return result;
}
exports.calendarWeekInMonth = calendarWeekInMonth;
/**
* Returns the weekday instance number in the month for the given date
*
* @param year The year
* @param month The month [1-12]
* @param day The day [1-31]
* @return Instance number [1-5]
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
*/
function weekDayInstanceInMonth(year, month, day) {
// rely on year/month validation in firstWeekDayOfMonth
var weekDay = weekDayNoLeapSecs(new TimeStruct({ year: year, month: month, day: day }).unixMillis);
var firstInstanceOfDay = firstWeekDayOfMonth(year, month, weekDay);
var result = ((day - firstInstanceOfDay) / 7) + 1;
return result;
}
exports.weekDayInstanceInMonth = weekDayInstanceInMonth;
/**
* Returns the day-of-year of the Monday of week 1 in the given year.
* Note that the result may lie in the previous year, in which case it
* will be (much) greater than 4
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
*/
function getWeekOneDayOfYear(year) {
// relay on weekDayOnOrAfter for year validation
// first monday of January, minus one because we want day-of-year
var result = weekDayOnOrAfter(year, 1, 1, WeekDay.Monday) - 1;
if (result > 3) { // greater than jan 4th
result -= 7;
if (result < 0) {
result += exports.daysInYear(year - 1);
}
}
return result;
}
/**
* The ISO 8601 week number for the given date. Week 1 is the week
* that has January 4th in it, and it starts on Monday.
* See https://en.wikipedia.org/wiki/ISO_week_date
*
* @param year Year e.g. 1988
* @param month Month 1-12
* @param day Day of month 1-31
* @return Week number 1-53
* @throws timezonecomplete.Argument.Year for invalid year (non-integer)
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
*/
function weekNumber(year, month, day) {
var doy = dayOfYear(year, month, day);
// check end-of-year corner case: may be week 1 of next year
if (doy >= dayOfYear(year, 12, 29)) {
var nextYearWeekOne = getWeekOneDayOfYear(year + 1);
if (nextYearWeekOne > 4 && nextYearWeekOne <= doy) {
return 1;
}
}
// check beginning-of-year corner case
var thisYearWeekOne = getWeekOneDayOfYear(year);
if (thisYearWeekOne > 4) {
// week 1 is at end of last year
var weekTwo = thisYearWeekOne + 7 - daysInYear(year - 1);
if (doy < weekTwo) {
return 1;
}
else {
return Math.floor((doy - weekTwo) / 7) + 2;
}
}
// Week 1 is entirely inside this year.
if (doy < thisYearWeekOne) {
// The date is part of the last week of prev year.
return weekNumber(year - 1, 12, 31);
}
// normal cases; note that week numbers start from 1 so +1
return Math.floor((doy - thisYearWeekOne) / 7) + 1;
}
exports.weekNumber = weekNumber;
/**
* Convert a unix milli timestamp into a TimeT structure.
* This does NOT take leap seconds into account.
* @throws timezonecomplete.Argument.UnixMillis for non-integer `unixMillis` parameter
*/
function unixToTimeNoLeapSecs(unixMillis) {
(0, assert_1.default)(Number.isInteger(unixMillis), "Argument.UnixMillis", "unixMillis should be an integer number");
var temp = unixMillis;
var result = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, milli: 0 };
var year;
var month;
if (unixMillis >= 0) {
result.milli = math.positiveModulo(temp, 1000);
temp = Math.floor(temp / 1000);
result.second = math.positiveModulo(temp, 60);
temp = Math.floor(temp / 60);
result.minute = math.positiveModulo(temp, 60);
temp = Math.floor(temp / 60);
result.hour = math.positiveModulo(temp, 24);
temp = Math.floor(temp / 24);
year = 1970;
while (temp >= daysInYear(year)) {
temp -= daysInYear(year);
year++;
}
result.year = year;
month = 1;
while (temp >= daysInMonth(year, month)) {
temp -= daysInMonth(year, month);
month++;
}
result.month = month;
result.day = temp + 1;
}
else {
// Note that a negative number modulo something yields a negative number.
// We make it positive by adding the modulo.
result.milli = math.positiveModulo(temp, 1000);
temp = Math.floor(temp / 1000);
result.second = math.positiveModulo(temp, 60);
temp = Math.floor(temp / 60);
result.minute = math.positiveModulo(temp, 60);
temp = Math.floor(temp / 60);
result.hour = math.positiveModulo(temp, 24);
temp = Math.floor(temp / 24);
year = 1969;
while (temp < -daysInYear(year)) {
temp += daysInYear(year);
year--;
}
result.year = year;
month = 12;
while (temp < -daysInMonth(year, month)) {
temp += daysInMonth(year, month);
month--;
}
result.month = month;
result.day = temp + 1 + daysInMonth(year, month);
}
return result;
}
exports.unixToTimeNoLeapSecs = unixToTimeNoLeapSecs;
/**
* Fill you any missing time component parts, defaults are 1970-01-01T00:00:00.000
* @throws timezonecomplete.Argument.Year for invalid year
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
* @throws timezonecomplete.Argument.Hour for invalid hour
* @throws timezonecomplete.Argument.Minute for invalid minute
* @throws timezonecomplete.Argument.Second for invalid second
* @throws timezonecomplete.Argument.Milli for invalid milliseconds
*/
function normalizeTimeComponents(components) {
var input = {
year: typeof components.year === "number" ? components.year : 1970,
month: typeof components.month === "number" ? components.month : 1,
day: typeof components.day === "number" ? components.day : 1,
hour: typeof components.hour === "number" ? components.hour : 0,
minute: typeof components.minute === "number" ? components.minute : 0,
second: typeof components.second === "number" ? components.second : 0,
milli: typeof components.milli === "number" ? components.milli : 0,
};
(0, assert_1.default)(Number.isInteger(input.year), "Argument.Year", "invalid year %d", input.year);
(0, assert_1.default)(Number.isInteger(input.month) && input.month >= 1 && input.month <= 12, "Argument.Month", "invalid month %d", input.month);
(0, assert_1.default)(Number.isInteger(input.day) && input.day >= 1 && input.day <= daysInMonth(input.year, input.month), "Argument.Day", "invalid day %d", input.day);
(0, assert_1.default)(Number.isInteger(input.hour) && input.hour >= 0 && input.hour <= 23, "Argument.Hour", "invalid hour %d", input.hour);
(0, assert_1.default)(Number.isInteger(input.minute) && input.minute >= 0 && input.minute <= 59, "Argument.Minute", "invalid minute %d", input.minute);
(0, assert_1.default)(Number.isInteger(input.second) && input.second >= 0 && input.second <= 59, "Argument.Second", "invalid second %d", input.second);
(0, assert_1.default)(Number.isInteger(input.milli) && input.milli >= 0 && input.milli <= 999, "Argument.Milli", "invalid milli %d", input.milli);
return input;
}
function timeToUnixNoLeapSecs(a, month, day, hour, minute, second, milli) {
var components = (typeof a === "number" ? { year: a, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli } : a);
var input = normalizeTimeComponents(components);
return input.milli + 1000 * (input.second + input.minute * 60 + input.hour * 3600 + dayOfYear(input.year, input.month, input.day) * 86400 +
(input.year - 1970) * 31536000 + Math.floor((input.year - 1969) / 4) * 86400 -
Math.floor((input.year - 1901) / 100) * 86400 + Math.floor((input.year - 1900 + 299) / 400) * 86400);
}
exports.timeToUnixNoLeapSecs = timeToUnixNoLeapSecs;
/**
* Return the day-of-week.
* This does NOT take leap seconds into account.
* @throws timezonecomplete.Argument.UnixMillis for invalid `unixMillis` argument
*/
function weekDayNoLeapSecs(unixMillis) {
(0, assert_1.default)(Number.isInteger(unixMillis), "Argument.UnixMillis", "unixMillis should be an integer number");
var epochDay = WeekDay.Thursday;
var days = Math.floor(unixMillis / 1000 / 86400);
return math.positiveModulo(epochDay + days, 7);
}
exports.weekDayNoLeapSecs = weekDayNoLeapSecs;
/**
* N-th second in the day, counting from 0
* @throws timezonecomplete.Argument.Hour for invalid hour
* @throws timezonecomplete.Argument.Minute for invalid minute
* @throws timezonecomplete.Argument.Second for invalid second
*/
function secondOfDay(hour, minute, second) {
(0, assert_1.default)(Number.isInteger(hour) && hour >= 0 && hour <= 23, "Argument.Hour", "invalid hour %d", hour);
(0, assert_1.default)(Number.isInteger(minute) && minute >= 0 && minute <= 59, "Argument.Minute", "invalid minute %d", minute);
(0, assert_1.default)(Number.isInteger(second) && second >= 0 && second <= 61, "Argument.Second", "invalid second %d", second);
return (((hour * 60) + minute) * 60) + second;
}
exports.secondOfDay = secondOfDay;
/**
* Basic representation of a date and time
*/
var TimeStruct = /** @class */ (function () {
/**
* Constructor implementation
*/
function TimeStruct(a) {
if (typeof a === "number") {
(0, assert_1.default)(Number.isInteger(a), "Argument.UnixMillis", "invalid unix millis %d", a);
this._unixMillis = a;
}
else {
(0, assert_1.default)(typeof a === "object" && a !== null, "Argument.Components", "invalid components object");
this._components = normalizeTimeComponents(a);
}
}
/**
* Returns a TimeStruct from the given year, month, day etc
*
* @param year Year e.g. 1970
* @param month Month 1-12
* @param day Day 1-31
* @param hour Hour 0-23
* @param minute Minute 0-59
* @param second Second 0-59 (no leap seconds)
* @param milli Millisecond 0-999
* @throws timezonecomplete.Argument.Year for invalid year
* @throws timezonecomplete.Argument.Month for invalid month
* @throws timezonecomplete.Argument.Day for invalid day of month
* @throws timezonecomplete.Argument.Hour for invalid hour
* @throws timezonecomplete.Argument.Minute for invalid minute
* @throws timezonecomplete.Argument.Second for invalid second
* @throws timezonecomplete.Argument.Milli for invalid milliseconds
*/
TimeStruct.fromComponents = function (year, month, day, hour, minute, second, milli) {
return new TimeStruct({ year: year, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli });
};
/**
* Create a TimeStruct from a number of unix milliseconds
* (backward compatibility)
* @throws timezonecomplete.Argument.UnixMillis for non-integer milliseconds
*/
TimeStruct.fromUnix = function (unixMillis) {
return new TimeStruct(unixMillis);
};
/**
* Create a TimeStruct from a JavaScript date
*
* @param d The date
* @param df Which functions to take (getX() or getUTCX())
* @throws nothing
*/
TimeStruct.fromDate = function (d, df) {
if (df === javascript_1.DateFunctions.Get) {
return new TimeStruct({
year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate(),
hour: d.getHours(), minute: d.getMinutes(), second: d.getSeconds(), milli: d.getMilliseconds()
});
}
else {
return new TimeStruct({
year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate(),
hour: d.getUTCHours(), minute: d.getUTCMinutes(), second: d.getUTCSeconds(), milli: d.getUTCMilliseconds()
});
}
};
/**
* Returns a TimeStruct from an ISO 8601 string WITHOUT time zone
* @throws timezonecomplete.Argument.S if `s` is not a proper iso string
*/
TimeStruct.fromString = function (s) {
try {
var year = 1970;
var month = 1;
var day = 1;
var hour = 0;
var minute = 0;
var second = 0;
var fractionMillis = 0;
var lastUnit = TimeUnit.Year;
// separate any fractional part
var split = s.trim().split(".");
(0, assert_1.default)(split.length >= 1 && split.length <= 2, "Argument.S", "Empty string or multiple dots.");
// parse main part
var isBasicFormat = (s.indexOf("-") === -1);
if (isBasicFormat) {
(0, assert_1.default)(split[0].match(/^((\d)+)|(\d\d\d\d\d\d\d\dT(\d)+)$/), "Argument.S", "ISO string in basic notation may only contain numbers before the fractional part");
// remove any "T" separator
split[0] = split[0].replace("T", "");
(0, assert_1.default)([4, 8, 10, 12, 14].indexOf(split[0].length) !== -1, "Argument.S", "Padding or required components are missing. Note that YYYYMM is not valid per ISO 8601");
if (split[0].length >= 4) {
year = parseInt(split[0].substr(0, 4), 10);
lastUnit = TimeUnit.Year;
}
if (split[0].length >= 8) {
month = parseInt(split[0].substr(4, 2), 10);
day = parseInt(split[0].substr(6, 2), 10); // note that YYYYMM format is disallowed so if month is present, day is too
lastUnit = TimeUnit.Day;
}
if (split[0].length >= 10) {
hour = parseInt(split[0].substr(8, 2), 10);
lastUnit = TimeUnit.Hour;
}
if (split[0].length >= 12) {
minute = parseInt(split[0].substr(10, 2), 10);
lastUnit = TimeUnit.Minute;
}
if (split[0].length >= 14) {
second = parseInt(split[0].substr(12, 2), 10);
lastUnit = TimeUnit.Second;
}
}
else {
(0, assert_1.default)(split[0].match(/^\d\d\d\d(-\d\d-\d\d((T)?\d\d(\:\d\d(:\d\d)?)?)?)?$/), "Argument.S", "Invalid ISO string");
var dateAndTime = [];
if (s.indexOf("T") !== -1) {
dateAndTime = split[0].split("T");
}
else if (s.length > 10) {
dateAndTime = [split[0].substr(0, 10), split[0].substr(10)];
}
else {
dateAndTime = [split[0], ""];
}
(0, assert_1.default)([4, 10].indexOf(dateAndTime[0].length) !== -1, "Argument.S", "Padding or required components are missing. Note that YYYYMM is not valid per ISO 8601");
if (dateAndTime[0].length >= 4) {
year = parseInt(dateAndTime[0].substr(0, 4), 10);
lastUnit = TimeUnit.Year;
}
if (dateAndTime[0].length >= 10) {
month = parseInt(dateAndTime[0].substr(5, 2), 10);
day = parseInt(dateAndTime[0].substr(8, 2), 10); // note that YYYYMM format is disallowed so if month is present, day is too
lastUnit = TimeUnit.Day;
}
if (dateAndTime[1].length >= 2) {
hour = parseInt(dateAndTime[1].substr(0, 2), 10);
lastUnit = TimeUnit.Hour;
}
if (dateAndTime[1].length >= 5) {
minute = parseInt(dateAndTime[1].substr(3, 2), 10);
lastUnit = TimeUnit.Minute;
}
if (dateAndTime[1].length >= 8) {
second = parseInt(dateAndTime[1].substr(6, 2), 10);
lastUnit = TimeUnit.Second;
}
}
// parse fractional part
if (split.length > 1 && split[1].length > 0) {
var fraction = parseFloat("0." + split[1]);
switch (lastUnit) {
case TimeUnit.Year:
fractionMillis = daysInYear(year) * 86400000 * fraction;
break;
case TimeUnit.Day:
fractionMillis = 86400000 * fraction;
break;
case TimeUnit.Hour:
fractionMillis = 3600000 * fraction;
break;
case TimeUnit.Minute:
fractionMillis = 60000 * fraction;
break;
case TimeUnit.Second:
fractionMillis = 1000 * fraction;
break;
}
}
// combine main and fractional part
year = math.roundSym(year);
month = math.roundSym(month);
day = math.roundSym(day);
hour = math.roundSym(hour);
minute = math.roundSym(minute);
second = math.roundSym(second);
var unixMillis = timeToUnixNoLeapSecs({ year: year, month: month, day: day, hour: hour, minute: minute, second: second });
unixMillis = math.roundSym(unixMillis + fractionMillis);
return new TimeStruct(unixMillis);
}
catch (e) {
if ((0, error_1.errorIs)(e, [
"Argument.S", "Argument.Year", "Argument.Month", "Argument.Day", "Argument.Hour",
"Argument.Minute", "Argument.Second", "Argument.Milli"
])) {
return (0, error_1.throwError)("Argument.S", "Invalid ISO 8601 string: \"%s\": %s", s, e.message);
}
else {
throw e; // programming error
}
}
};
Object.defineProperty(TimeStruct.prototype, "unixMillis", {
get: function () {
if (this._unixMillis === undefined) {
this._unixMillis = timeToUnixNoLeapSecs(this._components);
}
return this._unixMillis;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "components", {
get: function () {
if (!this._components) {
this._components = unixToTimeNoLeapSecs(this._unixMillis);
}
return this._components;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "year", {
get: function () {
return this.components.year;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "month", {
get: function () {
return this.components.month;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "day", {
get: function () {
return this.components.day;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "hour", {
get: function () {
return this.components.hour;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "minute", {
get: function () {
return this.components.minute;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "second", {
get: function () {
return this.components.second;
},
enumerable: false,
configurable: true
});
Object.defineProperty(TimeStruct.prototype, "milli", {
get: function () {
return this.components.milli;
},
enumerable: false,
configurable: true
});
/**
* The day-of-year 0-365
* @throws nothing
*/
TimeStruct.prototype.yearDay = function () {
return dayOfYear(this.components.year, this.components.month, this.components.day);
};
/**
* Equality function
* @param other
* @throws TypeError if other is not an Object
*/
TimeStruct.prototype.equals = function (other) {
return this.valueOf() === other.valueOf();
};
/**
* @throws nothing
*/
TimeStruct.prototype.valueOf = function () {
return this.unixMillis;
};
/**
* @throws nothing
*/
TimeStruct.prototype.clone = function () {
if (this._components) {
return new TimeStruct(this._components);
}
else {
return new TimeStruct(this._unixMillis);
}
};
/**
* Validate a timestamp. Filters out non-existing values for all time components
* @returns true iff the timestamp is valid
* @throws nothing
*/
TimeStruct.prototype.validate = function () {
if (this._components) {
return this.components.month >= 1 && this.components.month <= 12
&& this.components.day >= 1 && this.components.day <= daysInMonth(this.components.year, this.components.month)
&& this.components.hour >= 0 && this.components.hour <= 23
&& this.components.minute >= 0 && this.components.minute <= 59
&& this.components.second >= 0 && this.components.second <= 59
&& this.components.milli >= 0 && this.components.milli <= 999;
}
else {
return true;
}
};
/**
* ISO 8601 string YYYY-MM-DDThh:mm:ss.nnn
* @throws nothing
*/
TimeStruct.prototype.toString = function () {
return strings.padLeft(this.components.year.toString(10), 4, "0")
+ "-" + strings.padLeft(this.components.month.toString(10), 2, "0")
+ "-" + strings.padLeft(this.components.day.toString(10), 2, "0")
+ "T" + strings.padLeft(this.components.hour.toString(10), 2, "0")
+ ":" + strings.padLeft(this.components.minute.toString(10), 2, "0")
+ ":" + strings.padLeft(this.components.second.toString(10), 2, "0")
+ "." + strings.padLeft(this.components.milli.toString(10), 3, "0");
};
return TimeStruct;
}());
exports.TimeStruct = TimeStruct;
/**
* Binary search
* @param array Array to search
* @param compare Function that should return < 0 if given element is less than searched element etc
* @returns The insertion index of the element to look for
* @throws TypeError if arr is not an array
* @throws whatever `compare()` throws
*/
function binaryInsertionIndex(arr, compare) {
var minIndex = 0;
var maxIndex = arr.length - 1;
var currentIndex;
var currentElement;
// no array / empty array
if (!arr) {
return 0;
}
if (arr.length === 0) {
return 0;
}
// out of bounds
if (compare(arr[0]) > 0) {
return 0;
}
if (compare(arr[maxIndex]) < 0) {
return maxIndex + 1;
}
// element in range
while (minIndex <= maxIndex) {
currentIndex = Math.floor((minIndex + maxIndex) / 2);
currentElement = arr[currentIndex];
if (compare(currentElement) < 0) {
minIndex = currentIndex + 1;
}
else if (compare(currentElement) > 0) {
maxIndex = currentIndex - 1;
}
else {
return currentIndex;
}
}
return maxIndex;
}
exports.binaryInsertionIndex = binaryInsertionIndex;
},{"./assert":1,"./error":5,"./javascript":8,"./math":10,"./strings":13}],3:[function(require,module,exports){
/**
* Copyright(c) 2014 ABB Switzerland Ltd.
*
* Date+time+timezone representation
*/
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDateTime = exports.DateTime = exports.now = exports.nowUtc = exports.nowLocal = void 0;
var assert_1 = require("./assert");
var basics = require("./basics");
var basics_1 = require("./basics");
var duration_1 = require("./duration");
var error_1 = require("./error");
var format = require("./format");
var javascript_1 = require("./javascript");
var math = require("./math");
var parseFuncs = require("./parse");
var timesource_1 = require("./timesource");
var timezone_1 = require("./timezone");
var tz_database_1 = require("./tz-database");
/**
* Current date+time in local time
* @throws nothing
*/
function nowLocal() {
return DateTime.nowLocal();
}
exports.nowLocal = nowLocal;
/**
* Current date+time in UTC time
* @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database
*/
function nowUtc() {
return DateTime.nowUtc();
}
exports.nowUtc = nowUtc;
/**
* Current date+time in the given time zone
* @param timeZone The desired time zone (optional, defaults to UTC).
* @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database
*/
function now(timeZone) {
if (timeZone === void 0) { timeZone = timezone_1.TimeZone.utc(); }
return DateTime.now(timeZone);
}
exports.now = now;
/**
*
* @param localTime
* @param fromZone
* @throws nothing
*/
function convertToUtc(localTime, fromZone) {
if (fromZone) {
var offset = fromZone.offsetForZone(localTime);
return new basics_1.TimeStruct(localTime.unixMillis - offset * 60000);
}
else {
return localTime.clone();
}
}
/**
*
* @param utcTime
* @param toZone
* @throws nothing
*/
function convertFromUtc(utcTime, toZone) {
/* istanbul ignore else */
if (toZone) {
var offset = toZone.offsetForUtc(utcTime);
return toZone.normalizeZoneTime(new basics_1.TimeStruct(utcTime.unixMillis + offset * 60000));
}
else {
return utcTime.clone();
}
}
/**
* DateTime class which is time zone-aware
* and which can be mocked for testing purposes.
*/
var DateTime = /** @class */ (function () {
/**
* Constructor implementation, @see overrides
*/
function DateTime(a1, a2, a3, h, m, s, ms, timeZone) {
/**
* Allow not using instanceof
*/
this.kind = "DateTime";
switch (typeof (a1)) {
case "number":
{
if (typeof a2 !== "number") {
(0, assert_1.default)(a3 === undefined && h === undefined && m === undefined
&& s === undefined && ms === undefined && timeZone === undefined, "Argument.A3", "for unix timestamp datetime constructor, third through 8th argument must be undefined");
(0, assert_1.default)(a2 === undefined || a2 === null || isTimeZone(a2), "Argument.TimeZone", "DateTime.DateTime(): second arg should be a TimeZone object.");
// unix timestamp constructor
this._zone = (typeof (a2) === "object" && isTimeZone(a2) ? a2 : undefined);
var unixMillis = (0, error_1.convertError)("Argument.UnixMillis", function () { return math.roundSym(a1); });
if (this._zone) {
this._zoneDate = this._zone.normalizeZoneTime(new basics_1.TimeStruct(unixMillis));
}
else {
this._zoneDate = new basics_1.TimeStruct(unixMillis);
}
}
else {
// year month day constructor
(0, assert_1.default)(typeof (a2) === "number", "Argument.Year", "DateTime.DateTime(): Expect month to be a number.");
(0, assert_1.default)(typeof (a3) === "number", "Argument.Month", "DateTime.DateTime(): Expect day to be a number.");
(0, assert_1.default)(timeZone === undefined || timeZone === null || isTimeZone(timeZone), "Argument.TimeZone", "DateTime.DateTime(): eighth arg should be a TimeZone object.");
var year_1 = a1;
var month_1 = a2;
var day_1 = a3;
var hour_1 = (typeof (h) === "number" ? h : 0);
var minute_1 = (typeof (m) === "number" ? m : 0);
var second_1 = (typeof (s) === "number" ? s : 0);
var milli_1 = (typeof (ms) === "number" ? ms : 0);
year_1 = (0, error_1.convertError)("Argument.Year", function () { return math.roundSym(year_1); });
month_1 = (0, error_1.convertError)("Argument.Month", function () { return math.roundSym(month_1); });
day_1 = (0, error_1.convertError)("Argument.Day", function () { return math.roundSym(day_1); });
hour_1 = (0, error_1.convertError)("Ar