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
JavaScript
/**
* 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