UNPKG

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.

710 lines 26.2 kB
/** * Copyright(c) 2014 ABB Switzerland Ltd. * * Time duration */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isDuration = exports.Duration = exports.milliseconds = exports.seconds = exports.minutes = exports.hours = exports.days = exports.months = exports.years = void 0; var assert_1 = require("./assert"); var basics_1 = require("./basics"); var basics = require("./basics"); var strings = require("./strings"); /** * Construct a time duration * @param n Number of years (may be fractional or negative) * @return A duration of n years * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function years(n) { return Duration.years(n); } exports.years = years; /** * Construct a time duration * @param n Number of months (may be fractional or negative) * @return A duration of n months * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function months(n) { return Duration.months(n); } exports.months = months; /** * Construct a time duration * @param n Number of days (may be fractional or negative) * @return A duration of n days * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function days(n) { return Duration.days(n); } exports.days = days; /** * Construct a time duration * @param n Number of hours (may be fractional or negative) * @return A duration of n hours * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function hours(n) { return Duration.hours(n); } exports.hours = hours; /** * Construct a time duration * @param n Number of minutes (may be fractional or negative) * @return A duration of n minutes * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function minutes(n) { return Duration.minutes(n); } exports.minutes = minutes; /** * Construct a time duration * @param n Number of seconds (may be fractional or negative) * @return A duration of n seconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function seconds(n) { return Duration.seconds(n); } exports.seconds = seconds; /** * Construct a time duration * @param n Number of milliseconds (may be fractional or negative) * @return A duration of n milliseconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function milliseconds(n) { return Duration.milliseconds(n); } exports.milliseconds = milliseconds; /** * Time duration which is represented as an amount and a unit e.g. * '1 Month' or '166 Seconds'. The unit is preserved through calculations. * * It has two sets of getter functions: * - second(), minute(), hour() etc, singular form: these can be used to create string representations. * These return a part of your string representation. E.g. for 2500 milliseconds, the millisecond() part would be 500 * - seconds(), minutes(), hours() etc, plural form: these return the total amount represented in the corresponding unit. */ var Duration = /** @class */ (function () { /** * Constructor implementation */ function Duration(i1, unit) { /** * Allow not using instanceof */ this.kind = "Duration"; if (typeof i1 === "number") { // amount+unit constructor var amount = i1; (0, assert_1.default)(Number.isFinite(amount), "Argument.Amount", "amount should be finite: %d", amount); this._amount = amount; this._unit = (typeof unit === "number" ? unit : basics_1.TimeUnit.Millisecond); (0, assert_1.default)(Number.isInteger(this._unit) && this._unit >= 0 && this._unit < basics_1.TimeUnit.MAX, "Argument.Unit", "Invalid time unit %d", this._unit); } else if (typeof i1 === "string") { // string constructor var s = i1; var trimmed = s.trim(); if (trimmed.match(/^-?\d\d?(:\d\d?(:\d\d?(.\d\d?\d?)?)?)?$/)) { var sign = 1; var hours_1 = 0; var minutes_1 = 0; var seconds_1 = 0; var milliseconds_1 = 0; var parts = trimmed.split(":"); (0, assert_1.default)(parts.length > 0 && parts.length < 4, "Argument.S", "Not a proper time duration string: \"" + trimmed + "\""); if (trimmed.charAt(0) === "-") { sign = -1; parts[0] = parts[0].substr(1); } if (parts.length > 0) { hours_1 = +parts[0]; } if (parts.length > 1) { minutes_1 = +parts[1]; } if (parts.length > 2) { var secondParts = parts[2].split("."); seconds_1 = +secondParts[0]; if (secondParts.length > 1) { milliseconds_1 = +strings.padRight(secondParts[1], 3, "0"); } } var amountMsec = sign * Math.round(milliseconds_1 + 1000 * seconds_1 + 60000 * minutes_1 + 3600000 * hours_1); // find lowest non-zero number and take that as unit if (milliseconds_1 !== 0) { this._unit = basics_1.TimeUnit.Millisecond; } else if (seconds_1 !== 0) { this._unit = basics_1.TimeUnit.Second; } else if (minutes_1 !== 0) { this._unit = basics_1.TimeUnit.Minute; } else if (hours_1 !== 0) { this._unit = basics_1.TimeUnit.Hour; } else { this._unit = basics_1.TimeUnit.Millisecond; } this._amount = amountMsec / basics.timeUnitToMilliseconds(this._unit); } else { var split = trimmed.toLowerCase().split(" "); (0, assert_1.default)(split.length === 2, "Argument.S", "Invalid time string '%s'", s); var amount = parseFloat(split[0]); (0, assert_1.default)(Number.isFinite(amount), "Argument.S", "Invalid time string '%s', cannot parse amount", s); this._amount = amount; this._unit = basics.stringToTimeUnit(split[1]); } } else if (i1 === undefined && unit === undefined) { // default constructor this._amount = 0; this._unit = basics_1.TimeUnit.Millisecond; } else { (0, assert_1.default)(false, "Argument.Amount", "invalid constructor arguments"); } } /** * Construct a time duration * @param amount Number of years (may be fractional or negative) * @return A duration of n years * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.years = function (amount) { return new Duration(amount, basics_1.TimeUnit.Year); }; /** * Construct a time duration * @param amount Number of months (may be fractional or negative) * @return A duration of n months * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.months = function (amount) { return new Duration(amount, basics_1.TimeUnit.Month); }; /** * Construct a time duration * @param amount Number of days (may be fractional or negative) * @return A duration of n days * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.days = function (amount) { return new Duration(amount, basics_1.TimeUnit.Day); }; /** * Construct a time duration * @param amount Number of hours (may be fractional or negative) * @return A duration of n hours * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.hours = function (amount) { return new Duration(amount, basics_1.TimeUnit.Hour); }; /** * Construct a time duration * @param amount Number of minutes (may be fractional or negative) * @return A duration of n minutes * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.minutes = function (amount) { return new Duration(amount, basics_1.TimeUnit.Minute); }; /** * Construct a time duration * @param amount Number of seconds (may be fractional or negative) * @return A duration of n seconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.seconds = function (amount) { return new Duration(amount, basics_1.TimeUnit.Second); }; /** * Construct a time duration * @param amount Number of milliseconds (may be fractional or negative) * @return A duration of n milliseconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.milliseconds = function (amount) { return new Duration(amount, basics_1.TimeUnit.Millisecond); }; /** * @return another instance of Duration with the same value. * @throws nothing */ Duration.prototype.clone = function () { return new Duration(this._amount, this._unit); }; /** * Returns this duration expressed in different unit (positive or negative, fractional). * This is precise for Year <-> Month and for time-to-time conversion (i.e. Hour-or-less to Hour-or-less). * It is approximate for any other conversion * @throws nothing */ Duration.prototype.as = function (unit) { if (this._unit === unit) { return this._amount; } else if (this._unit >= basics_1.TimeUnit.Month && unit >= basics_1.TimeUnit.Month) { var thisMonths = (this._unit === basics_1.TimeUnit.Year ? 12 : 1); var reqMonths = (unit === basics_1.TimeUnit.Year ? 12 : 1); return this._amount * thisMonths / reqMonths; } else { var thisMsec = basics.timeUnitToMilliseconds(this._unit); var reqMsec = basics.timeUnitToMilliseconds(unit); return this._amount * thisMsec / reqMsec; } }; /** * Convert this duration to a Duration in another unit. You always get a clone even if you specify * the same unit. * This is precise for Year <-> Month and for time-to-time conversion (i.e. Hour-or-less to Hour-or-less). * It is approximate for any other conversion * @throws nothing */ Duration.prototype.convert = function (unit) { return new Duration(this.as(unit), unit); }; /** * The entire duration in milliseconds (negative or positive) * For Day/Month/Year durations, this is approximate! * @throws nothing */ Duration.prototype.milliseconds = function () { return this.as(basics_1.TimeUnit.Millisecond); }; /** * The millisecond part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 400 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.millisecond = function () { return this._part(basics_1.TimeUnit.Millisecond); }; /** * The entire duration in seconds (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 1500 milliseconds duration * @throws nothing */ Duration.prototype.seconds = function () { return this.as(basics_1.TimeUnit.Second); }; /** * The second part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 3 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.second = function () { return this._part(basics_1.TimeUnit.Second); }; /** * The entire duration in minutes (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 90000 milliseconds duration * @throws nothing */ Duration.prototype.minutes = function () { return this.as(basics_1.TimeUnit.Minute); }; /** * The minute part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 2 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.minute = function () { return this._part(basics_1.TimeUnit.Minute); }; /** * The entire duration in hours (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 5400000 milliseconds duration * @throws nothing */ Duration.prototype.hours = function () { return this.as(basics_1.TimeUnit.Hour); }; /** * The hour part of a duration. This assumes that a day has 24 hours (which is not the case * during DST changes). * @throws nothing */ Duration.prototype.hour = function () { return this._part(basics_1.TimeUnit.Hour); }; /** * The hour part of the duration (always positive). * Note that this part can exceed 23 hours, because for * now, we do not have a days() function * For Day/Month/Year durations, this is approximate! * @return e.g. 25 for a -25:02:03.400 duration * @throws nothing */ Duration.prototype.wholeHours = function () { return Math.floor(basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount) / 3600000); }; /** * The entire duration in days (negative or positive, fractional) * This is approximate if this duration is not in days! * @throws nothing */ Duration.prototype.days = function () { return this.as(basics_1.TimeUnit.Day); }; /** * The day part of a duration. This assumes that a month has 30 days. * @throws nothing */ Duration.prototype.day = function () { return this._part(basics_1.TimeUnit.Day); }; /** * The entire duration in days (negative or positive, fractional) * This is approximate if this duration is not in Months or Years! * @throws nothing */ Duration.prototype.months = function () { return this.as(basics_1.TimeUnit.Month); }; /** * The month part of a duration. * @throws nothing */ Duration.prototype.month = function () { return this._part(basics_1.TimeUnit.Month); }; /** * The entire duration in years (negative or positive, fractional) * This is approximate if this duration is not in Months or Years! * @throws nothing */ Duration.prototype.years = function () { return this.as(basics_1.TimeUnit.Year); }; /** * Non-fractional positive years * @throws nothing */ Duration.prototype.wholeYears = function () { if (this._unit === basics_1.TimeUnit.Year) { return Math.floor(Math.abs(this._amount)); } else if (this._unit === basics_1.TimeUnit.Month) { return Math.floor(Math.abs(this._amount) / 12); } else { return Math.floor(basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount) / basics.timeUnitToMilliseconds(basics_1.TimeUnit.Year)); } }; /** * Amount of units (positive or negative, fractional) * @throws nothing */ Duration.prototype.amount = function () { return this._amount; }; /** * The unit this duration was created with * @throws nothing */ Duration.prototype.unit = function () { return this._unit; }; /** * Sign * @return "-" if the duration is negative * @throws nothing */ Duration.prototype.sign = function () { return (this._amount < 0 ? "-" : ""); }; /** * Approximate if the durations have units that cannot be converted * @return True iff (this < other) * @throws nothing */ Duration.prototype.lessThan = function (other) { return this.milliseconds() < other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return True iff (this <= other) * @throws nothing */ Duration.prototype.lessEqual = function (other) { return this.milliseconds() <= other.milliseconds(); }; /** * Similar but not identical * Approximate if the durations have units that cannot be converted * @return True iff this and other represent the same time duration * @throws nothing */ Duration.prototype.equals = function (other) { var converted = other.convert(this._unit); return this._amount === converted.amount() && this._unit === converted.unit(); }; /** * Similar but not identical * Returns false if we cannot determine whether they are equal in all time zones * so e.g. 60 minutes equals 1 hour, but 24 hours do NOT equal 1 day * * @return True iff this and other represent the same time duration * @throws nothing */ Duration.prototype.equalsExact = function (other) { if (this._unit === other._unit) { return (this._amount === other._amount); } else if (this._unit >= basics_1.TimeUnit.Month && other.unit() >= basics_1.TimeUnit.Month) { return this.equals(other); // can compare months and years } else if (this._unit < basics_1.TimeUnit.Day && other.unit() < basics_1.TimeUnit.Day) { return this.equals(other); // can compare milliseconds through hours } else { return false; // cannot compare days to anything else } }; /** * Same unit and same amount * @throws nothing */ Duration.prototype.identical = function (other) { return this._amount === other.amount() && this._unit === other.unit(); }; /** * Returns true if this is a non-zero length duration */ Duration.prototype.nonZero = function () { return this._amount !== 0; }; /** * Returns true if this is a zero-length duration */ Duration.prototype.zero = function () { return this._amount === 0; }; /** * Approximate if the durations have units that cannot be converted * @return True iff this > other * @throws nothing */ Duration.prototype.greaterThan = function (other) { return this.milliseconds() > other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return True iff this >= other * @throws nothing */ Duration.prototype.greaterEqual = function (other) { return this.milliseconds() >= other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return The minimum (most negative) of this and other * @throws nothing */ Duration.prototype.min = function (other) { if (this.lessThan(other)) { return this.clone(); } return other.clone(); }; /** * Approximate if the durations have units that cannot be converted * @return The maximum (most positive) of this and other * @throws nothing */ Duration.prototype.max = function (other) { if (this.greaterThan(other)) { return this.clone(); } return other.clone(); }; /** * Multiply with a fixed number. * Approximate if the durations have units that cannot be converted * @return a new Duration of (this * value) * @throws nothing */ Duration.prototype.multiply = function (value) { return new Duration(this._amount * value, this._unit); }; Duration.prototype.divide = function (value) { if (typeof value === "number") { (0, assert_1.default)(Number.isFinite(value) && value !== 0, "Argument.Value", "cannot divide by %d", value); return new Duration(this._amount / value, this._unit); } else { (0, assert_1.default)(value.amount() !== 0, "Argument.Value", "cannot divide by 0"); return this.milliseconds() / value.milliseconds(); } }; /** * Add a duration. * @return a new Duration of (this + value) with the unit of this duration * @throws nothing */ Duration.prototype.add = function (value) { return new Duration(this._amount + value.as(this._unit), this._unit); }; /** * Subtract a duration. * @return a new Duration of (this - value) with the unit of this duration * @throws nothing */ Duration.prototype.sub = function (value) { return new Duration(this._amount - value.as(this._unit), this._unit); }; /** * Return the absolute value of the duration i.e. remove the sign. * @throws nothing */ Duration.prototype.abs = function () { if (this._amount >= 0) { return this.clone(); } else { return this.multiply(-1); } }; /** * String in [-]hhhh:mm:ss.nnn notation. All fields are always present except the sign. * @throws nothing */ Duration.prototype.toFullString = function () { return this.toHmsString(true); }; /** * String in [-]hhhh:mm[:ss[.nnn]] notation. * @param full If true, then all fields are always present except the sign. Otherwise, seconds and milliseconds * are chopped off if zero * @throws nothing */ Duration.prototype.toHmsString = function (full) { if (full === void 0) { full = false; } var result = ""; if (full || this.millisecond() > 0) { result = "." + strings.padLeft(this.millisecond().toString(10), 3, "0"); } if (full || result.length > 0 || this.second() > 0) { result = ":" + strings.padLeft(this.second().toString(10), 2, "0") + result; } if (full || result.length > 0 || this.minute() > 0) { result = ":" + strings.padLeft(this.minute().toString(10), 2, "0") + result; } return this.sign() + strings.padLeft(this.wholeHours().toString(10), 2, "0") + result; }; /** * String in ISO 8601 notation e.g. 'P1M' for one month or 'PT1M' for one minute * @throws nothing */ Duration.prototype.toIsoString = function () { switch (this._unit) { case basics_1.TimeUnit.Millisecond: { return "P" + (this._amount / 1000).toFixed(3) + "S"; } case basics_1.TimeUnit.Second: { return "P" + this._amount.toString(10) + "S"; } case basics_1.TimeUnit.Minute: { return "PT" + this._amount.toString(10) + "M"; // note the "T" to disambiguate the "M" } case basics_1.TimeUnit.Hour: { return "P" + this._amount.toString(10) + "H"; } case basics_1.TimeUnit.Day: { return "P" + this._amount.toString(10) + "D"; } case basics_1.TimeUnit.Week: { return "P" + this._amount.toString(10) + "W"; } case basics_1.TimeUnit.Month: { return "P" + this._amount.toString(10) + "M"; } case basics_1.TimeUnit.Year: { return "P" + this._amount.toString(10) + "Y"; } /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { throw new Error("Unknown time unit."); // programming error } } }; /** * String representation with amount and unit e.g. '1.5 years' or '-1 day' * @throws nothing */ Duration.prototype.toString = function () { return this._amount.toString(10) + " " + basics.timeUnitToString(this._unit, this._amount); }; /** * The valueOf() method returns the primitive value of the specified object. * @throws nothing */ Duration.prototype.valueOf = function () { return this.milliseconds(); }; /** * Return this % unit, always positive * @throws nothing */ Duration.prototype._part = function (unit) { var nextUnit; // note not all units are used here: Weeks and Years are ruled out switch (unit) { case basics_1.TimeUnit.Millisecond: nextUnit = basics_1.TimeUnit.Second; break; case basics_1.TimeUnit.Second: nextUnit = basics_1.TimeUnit.Minute; break; case basics_1.TimeUnit.Minute: nextUnit = basics_1.TimeUnit.Hour; break; case basics_1.TimeUnit.Hour: nextUnit = basics_1.TimeUnit.Day; break; case basics_1.TimeUnit.Day: nextUnit = basics_1.TimeUnit.Month; break; case basics_1.TimeUnit.Month: nextUnit = basics_1.TimeUnit.Year; break; default: return Math.floor(Math.abs(this.as(basics_1.TimeUnit.Year))); } var msecs = (basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount)) % basics.timeUnitToMilliseconds(nextUnit); return Math.floor(msecs / basics.timeUnitToMilliseconds(unit)); }; return Duration; }()); exports.Duration = Duration; /** * Checks if a given object is of type Duration. Note that it does not work for sub classes. However, use this to be robust * against different versions of the library in one process instead of instanceof * @param value Value to check * @throws nothing */ function isDuration(value) { return typeof value === "object" && value !== null && value.kind === "Duration"; } exports.isDuration = isDuration; //# sourceMappingURL=duration.js.map