universal-common
Version:
Library that provides useful missing base class library functionality.
469 lines (468 loc) • 19.3 kB
TypeScript
/**
* Represents a time of day, as would be read from a clock, within the range 00:00:00 to 23:59:59.9999999.
*
* TimeOnly provides time-only functionality without date components, making it ideal
* for scenarios where only the time portion is relevant (schedules, opening hours, etc.).
*
* @example
* // Create TimeOnly instances
* const morning = new TimeOnly(9, 30); // 09:30:00
* const precise = new TimeOnly(14, 15, 30, 500); // 14:15:30.500
* const fromTicks = new TimeOnly(450000000000); // From ticks
*
* // Time arithmetic
* const later = morning.addHours(2.5); // 12:00:00
* const duration = later.subtract(morning); // 2:30:00 TimeSpan
*
* // Comparisons and ranges
* console.log(morning.isBetween(new TimeOnly(8, 0), new TimeOnly(17, 0))); // true
*
* // Formatting
* console.log(morning.toString()); // "09:30:00"
* console.log(precise.toString()); // "14:15:30.5"
*/
export default class TimeOnly {
/** @private @type {bigint} Minimum time ticks (midnight) */
private static "__#6@#MIN_TIME_TICKS";
/** @private @type {bigint} Maximum time ticks (23:59:59.9999999) */
private static "__#6@#MAX_TIME_TICKS";
/**
* Converts time components to ticks.
*
* @private
* @param {number} hour - Hour component (0-23)
* @param {number} minute - Minute component (0-59)
* @param {number} second - Second component (0-59)
* @param {number} millisecond - Millisecond component (0-999)
* @returns {bigint} Total ticks representing the time
* @throws {RangeError} If any component is out of valid range
*/
private static "__#6@#timeToTicks";
/**
* Constructs a TimeOnly object from a TimeSpan representing the time elapsed since midnight.
*
* @param {TimeSpan} timeSpan - The time interval measured since midnight. This value has to be positive and not exceeding 24 hours
* @returns {TimeOnly} A TimeOnly object representing the time elapsed since midnight using the timeSpan value
* @throws {TypeError} If timeSpan is not a TimeSpan instance
* @throws {RangeError} If timeSpan is negative or exceeds 24 hours
*
* @example
* const span = TimeSpan.fromHours(14.5); // 14 hours 30 minutes
* const time = TimeOnly.fromTimeSpan(span);
* console.log(time.toString()); // "14:30:00"
*/
static fromTimeSpan(timeSpan: TimeSpan): TimeOnly;
/**
* Constructs a TimeOnly object from a DateTime representing the time of the day in this DateTime object.
*
* @param {DateTime} dateTime - The DateTime object to extract the time of the day from
* @returns {TimeOnly} A TimeOnly object representing time of the day specified in the DateTime object
* @throws {TypeError} If dateTime is not a DateTime instance
*
* @example
* const dateTime = new DateTime(2024, 12, 25, 14, 30, 45);
* const timeOnly = TimeOnly.fromDateTime(dateTime);
* console.log(timeOnly.toString()); // "14:30:45"
*/
static fromDateTime(dateTime: DateTime): TimeOnly;
/**
* Gets the smallest possible value of TimeOnly (00:00:00.0000000).
*
* @type {TimeOnly}
* @readonly
* @static
*
* @example
* const minTime = TimeOnly.minValue;
* console.log(minTime.toString()); // "00:00:00"
*/
static readonly get minValue(): TimeOnly;
/**
* Gets the largest possible value of TimeOnly (23:59:59.9999999).
*
* @type {TimeOnly}
* @readonly
* @static
*
* @example
* const maxTime = TimeOnly.maxValue;
* console.log(maxTime.toString()); // "23:59:59.9999999"
*/
static readonly get maxValue(): TimeOnly;
/**
* Compares two TimeOnly values and returns an indication of their relative values.
*
* @param {TimeOnly} t1 - The first TimeOnly
* @param {TimeOnly} t2 - The second TimeOnly
* @returns {number} -1 if t1 is earlier than t2, 0 if equal, 1 if t1 is later than t2
*
* @example
* const morning = new TimeOnly(9, 0, 0);
* const evening = new TimeOnly(17, 0, 0);
*
* console.log(TimeOnly.compare(morning, evening)); // -1
* console.log(TimeOnly.compare(evening, morning)); // 1
* console.log(TimeOnly.compare(morning, morning)); // 0
*/
static compare(t1: TimeOnly, t2: TimeOnly): number;
/**
* Parses a string representation of a time and returns a TimeOnly instance.
*
* The string can be in various formats:
* - "HH:mm" (e.g., "14:30")
* - "HH:mm:ss" (e.g., "14:30:45")
* - "HH:mm:ss.fff" (e.g., "14:30:45.123")
* - "HH:mm:ss.fffffff" (e.g., "14:30:45.1234567")
*
* @param {string} s - The string to parse
* @returns {TimeOnly} A TimeOnly instance representing the parsed time
* @throws {TypeError} If the input is not a string
* @throws {ArgumentError} If the string format is invalid
* @throws {RangeError} If the time components are out of valid range
*
* @example
* const time1 = TimeOnly.parse("14:30"); // 14:30:00
* const time2 = TimeOnly.parse("09:15:30"); // 09:15:30
* const time3 = TimeOnly.parse("16:45:30.500"); // 16:45:30.5
*/
static parse(s: string): TimeOnly;
/**
* Attempts to parse a string representation of a time and returns the result.
*
* Unlike parse(), this method does not throw exceptions on invalid input.
*
* @param {string} s - The string to parse
* @returns {{success: boolean, value: TimeOnly|null}}
* An object containing:
* - success: true if parsing succeeded, false otherwise
* - value: The parsed TimeOnly instance if successful, null otherwise
*
* @example
* const result1 = TimeOnly.tryParse("14:30:45");
* if (result1.success) {
* console.log(result1.value.toString()); // "14:30:45"
* }
*
* const result2 = TimeOnly.tryParse("invalid-time");
* console.log(result2.success); // false
* console.log(result2.value); // null
*/
static tryParse(s: string): {
success: boolean;
value: TimeOnly | null;
};
/**
* Creates a new TimeOnly instance.
*
* @constructor
* @param {...number} args - Constructor arguments in various formats:
* - (ticks) - 100-nanosecond intervals since midnight
* - (hour, minute) - Hour and minute components
* - (hour, minute, second) - Hour, minute, and second components
* - (hour, minute, second, millisecond) - With milliseconds
* - (hour, minute, second, millisecond, microsecond) - With microseconds
*
* @throws {ArgumentError} If invalid number of arguments provided
* @throws {RangeError} If time components are out of valid range
*
* @example
* // From ticks
* const time1 = new TimeOnly(450000000000); // 12:30:00
*
* // From hour and minute
* const time2 = new TimeOnly(14, 30); // 14:30:00
*
* // From hour, minute, second
* const time3 = new TimeOnly(9, 15, 45); // 09:15:45
*
* // With milliseconds
* const time4 = new TimeOnly(16, 30, 0, 500); // 16:30:00.500
*/
constructor(...args: number[]);
/**
* Gets the hour component of the time represented by this instance (0-23).
*
* @type {number}
* @readonly
* @example
* const time = new TimeOnly(14, 30, 45);
* console.log(time.hour); // 14
*/
readonly get hour(): number;
/**
* Gets the minute component of the time represented by this instance (0-59).
*
* @type {number}
* @readonly
* @example
* const time = new TimeOnly(14, 30, 45);
* console.log(time.minute); // 30
*/
readonly get minute(): number;
/**
* Gets the second component of the time represented by this instance (0-59).
*
* @type {number}
* @readonly
* @example
* const time = new TimeOnly(14, 30, 45);
* console.log(time.second); // 45
*/
readonly get second(): number;
/**
* Gets the millisecond component of the time represented by this instance (0-999).
*
* @type {number}
* @readonly
* @example
* const time = new TimeOnly(14, 30, 45, 500);
* console.log(time.millisecond); // 500
*/
readonly get millisecond(): number;
/**
* Gets the microsecond component of the time represented by this instance (0-999).
*
* @type {number}
* @readonly
* @example
* const time = new TimeOnly(14, 30, 45, 500, 250);
* console.log(time.microsecond); // 250
*/
readonly get microsecond(): number;
/**
* Gets the nanosecond component of the time represented by this instance (0-900).
* Note: Resolution is limited to 100-nanosecond intervals.
*
* @type {number}
* @readonly
*/
readonly get nanosecond(): number;
/**
* Gets the number of ticks that represent the time of this instance.
*
* @type {number}
* @readonly
*/
readonly get ticks(): number;
/**
* Returns a new TimeOnly that adds the value of the specified TimeSpan to the value of this instance.
*
* @param {TimeSpan} value - A positive or negative time interval
* @returns {TimeOnly} An object whose value is the sum of the time represented by this instance and the time interval represented by value
* @throws {TypeError} If value is not a TimeSpan
*
* @example
* const morning = new TimeOnly(9, 0, 0);
* const duration = TimeSpan.fromHours(2.5);
* const later = morning.add(duration); // 11:30:00
*/
add(value: TimeSpan): TimeOnly;
/**
* Returns a new TimeOnly that adds the value of the specified TimeSpan to the value of this instance.
* If the result wraps past the end of the day, this method will return the number of excess days.
*
* @param {TimeSpan} value - A positive or negative time interval
* @returns {{time: TimeOnly, wrappedDays: number}} Object containing the new time and wrapped days
* @throws {TypeError} If value is not a TimeSpan
*
* @example
* const evening = new TimeOnly(22, 0, 0);
* const duration = TimeSpan.fromHours(4);
* const result = evening.addWithWrappedDays(duration);
* console.log(result.time.toString()); // "02:00:00"
* console.log(result.wrappedDays); // 1
*/
addWithWrappedDays(value: TimeSpan): {
time: TimeOnly;
wrappedDays: number;
};
/**
* Returns a new TimeOnly that adds the specified number of hours to the value of this instance.
*
* @param {number} value - A number of whole and fractional hours. The value parameter can be negative or positive
* @returns {TimeOnly} An object whose value is the sum of the time represented by this instance and the number of hours represented by value
*
* @example
* const time = new TimeOnly(10, 30, 0);
* const later = time.addHours(2.5); // 13:00:00
*/
addHours(value: number): TimeOnly;
/**
* Returns a new TimeOnly that adds the specified number of hours to the value of this instance.
* If the result wraps past the end of the day, this method will return the number of excess days.
*
* @param {number} value - A number of whole and fractional hours. The value parameter can be negative or positive
* @returns {{time: TimeOnly, wrappedDays: number}} Object containing the new time and wrapped days
*
* @example
* const time = new TimeOnly(22, 0, 0);
* const result = time.addHoursWithWrappedDays(4);
* console.log(result.time.toString()); // "02:00:00"
* console.log(result.wrappedDays); // 1
*/
addHoursWithWrappedDays(value: number): {
time: TimeOnly;
wrappedDays: number;
};
/**
* Returns a new TimeOnly that adds the specified number of minutes to the value of this instance.
*
* @param {number} value - A number of whole and fractional minutes. The value parameter can be negative or positive
* @returns {TimeOnly} An object whose value is the sum of the time represented by this instance and the number of minutes represented by value
*
* @example
* const time = new TimeOnly(10, 30, 0);
* const later = time.addMinutes(45); // 11:15:00
*/
addMinutes(value: number): TimeOnly;
/**
* Returns a new TimeOnly that adds the specified number of minutes to the value of this instance.
* If the result wraps past the end of the day, this method will return the number of excess days.
*
* @param {number} value - A number of whole and fractional minutes. The value parameter can be negative or positive
* @returns {{time: TimeOnly, wrappedDays: number}} Object containing the new time and wrapped days
*
* @example
* const time = new TimeOnly(23, 30, 0);
* const result = time.addMinutesWithWrappedDays(45);
* console.log(result.time.toString()); // "00:15:00"
* console.log(result.wrappedDays); // 1
*/
addMinutesWithWrappedDays(value: number): {
time: TimeOnly;
wrappedDays: number;
};
/**
* Determines if a time falls within the range provided.
* Supports both "normal" ranges such as 10:00-12:00, and ranges that span midnight such as 23:00-01:00.
*
* @param {TimeOnly} start - The starting time of day, inclusive
* @param {TimeOnly} end - The ending time of day, exclusive
* @returns {boolean} True, if the time falls within the range, false otherwise
* @throws {TypeError} If start or end is not a TimeOnly instance
*
* @example
* const workStart = new TimeOnly(9, 0, 0);
* const workEnd = new TimeOnly(17, 0, 0);
* const currentTime = new TimeOnly(14, 30, 0);
*
* console.log(currentTime.isBetween(workStart, workEnd)); // true
*
* // Midnight-spanning range
* const nightStart = new TimeOnly(22, 0, 0);
* const nightEnd = new TimeOnly(6, 0, 0);
* const lateNight = new TimeOnly(1, 0, 0);
*
* console.log(lateNight.isBetween(nightStart, nightEnd)); // true
*/
isBetween(start: TimeOnly, end: TimeOnly): boolean;
/**
* Determines whether two specified instances of TimeOnly are equal.
*
* @param {TimeOnly} other - The other TimeOnly to compare with
* @returns {boolean} true if left and right represent the same time; otherwise, false
*
* @example
* const time1 = new TimeOnly(14, 30, 0);
* const time2 = new TimeOnly(14, 30, 0);
* const time3 = new TimeOnly(14, 30, 1);
*
* console.log(time1.equals(time2)); // true
* console.log(time1.equals(time3)); // false
*/
equals(other: TimeOnly): boolean;
/**
* Compares this instance to a specified TimeOnly value and indicates whether this instance is earlier than, the same as, or later than the specified TimeOnly value.
*
* @param {TimeOnly} other - The object to compare to the current instance
* @returns {number}
* - Less than zero if this instance is earlier than value
* - Zero if this instance is the same as value
* - Greater than zero if this instance is later than value
* @throws {TypeError} If other is not a TimeOnly instance
*
* @example
* const time1 = new TimeOnly(9, 0, 0);
* const time2 = new TimeOnly(17, 0, 0);
*
* console.log(time1.compareTo(time2)); // -1 (time1 is earlier)
* console.log(time2.compareTo(time1)); // 1 (time2 is later)
* console.log(time1.compareTo(time1)); // 0 (same time)
*/
compareTo(other: TimeOnly): number;
/**
* Gives the elapsed time between two points on a circular clock, which will always be a positive value.
*
* @param {TimeOnly} other - The other TimeOnly instance
* @returns {TimeSpan} The elapsed time between this and other
* @throws {TypeError} If other is not a TimeOnly instance
*
* @example
* const morning = new TimeOnly(9, 0, 0);
* const evening = new TimeOnly(17, 0, 0);
*
* const duration = evening.subtract(morning);
* console.log(duration.toString()); // "08:00:00"
*
* // Circular clock behavior - always positive
* const reverseDuration = morning.subtract(evening);
* console.log(reverseDuration.toString()); // "16:00:00" (going forward around the clock)
*/
subtract(other: TimeOnly): TimeSpan;
/**
* Converts the value of the current TimeOnly object to its equivalent string representation.
*
* @returns {string} A string representation of the TimeOnly in HH:mm:ss format, with fractional seconds if present
*
* @example
* const time1 = new TimeOnly(9, 30, 0);
* console.log(time1.toString()); // "09:30:00"
*
* const time2 = new TimeOnly(14, 15, 30, 500);
* console.log(time2.toString()); // "14:15:30.5"
*
* const time3 = new TimeOnly(23, 59, 59, 999, 999);
* console.log(time3.toString()); // "23:59:59.999999"
*/
toString(): string;
/**
* Converts the value of the current TimeOnly object to its equivalent long time string representation.
*
* @returns {string} A string that contains the long time string representation of the current TimeOnly object
*/
toLongTimeString(): string;
/**
* Converts the value of the current TimeOnly object to its equivalent short time string representation.
*
* @returns {string} A string that contains the short time string representation of the current TimeOnly object
*/
toShortTimeString(): string;
/**
* Convert the current TimeOnly instance to a TimeSpan object.
*
* @returns {TimeSpan} A TimeSpan object spanning to the time specified in the current TimeOnly object
*
* @example
* const time = new TimeOnly(14, 30, 45);
* const span = time.toTimeSpan();
* console.log(span.toString()); // "14:30:45"
*/
toTimeSpan(): TimeSpan;
/**
* Returns the primitive value of this TimeOnly (ticks).
*
* This method is called automatically when the TimeOnly is used in contexts
* that require a primitive value, such as arithmetic operations or comparisons.
*
* @returns {number} The ticks value representing this time
*
* @example
* const time = new TimeOnly(12, 0, 0);
* console.log(+time); // Outputs the ticks value
* console.log(time.valueOf()); // Same as above
*/
valueOf(): number;
#private;
}
import TimeSpan from "./TimeSpan.js";
import DateTime from "./DateTime.js";