klog.js
Version:
A JavaScript implementation of the Klog time tracking file format
136 lines (135 loc) • 4.49 kB
JavaScript
import { Duration } from "./duration.js";
/**
* How a time should be formatted when turned into a string.
*/
export var TimeFormat;
(function (TimeFormat) {
TimeFormat["TwentyFourHour"] = "24h";
TimeFormat["TwelveHour"] = "12h";
})(TimeFormat || (TimeFormat = {}));
/**
* Which day a time should be assigned to.
*/
export var DayShift;
(function (DayShift) {
DayShift[DayShift["Yesterday"] = -1] = "Yesterday";
DayShift[DayShift["Today"] = 0] = "Today";
DayShift[DayShift["Tomorrow"] = 1] = "Tomorrow";
})(DayShift || (DayShift = {}));
/**
* A specific time of day.
*/
export class Time {
hour;
minute;
dayShift;
format;
/**
* Create a new time.
* @throws {Error} The time values are invalid.
*/
constructor(
/** The hour of the time, in 24-hour format. */
hour,
/** The minute of the time. */
minute,
/** If the time belongs to today, tomorrow, or yesterday. */
dayShift = DayShift.Today,
/** The format to use for the time when rendering as a string. */
format = TimeFormat.TwentyFourHour) {
this.hour = hour;
this.minute = minute;
this.dayShift = dayShift;
this.format = format;
if (!Time.isValidValue(hour, minute, dayShift))
throw new Error("Invalid time");
// Special casing for `24:00` times:
// - Accept a time of `24:00` and treat it as `0:00` tomorrow.
// - Accept a time of `<24:00` and treat it as `0:00` today.
// `24:00>` is not representable as Klog only allows shifting time by up to a single day.
if (hour === 24 && minute === 0 && dayShift !== DayShift.Tomorrow) {
this.hour = 0;
this.dayShift += 1;
}
}
/** @internal */
static fromAST = (node) => {
return new this(node.hour, node.minute, node.shift, node.format);
};
/**
* Validates the time values.
* @param hour - The hour to validate.
* @param minute - The minute to validate.
* @param dayShift - The day shift to validate.
* @returns True if the time values are valid, false otherwise.
*/
static isValidValue(hour, minute, dayShift = DayShift.Today) {
if (hour === 24 && minute === 0 && dayShift !== DayShift.Tomorrow)
return true;
else
return hour <= 23 && hour >= 0 && minute <= 59 && minute >= 0;
}
/**
* Check if this time is equal to another time.
* @param other - The time to compare against.
*/
equals(other) {
return this.toMinutesSinceMidnight() === other.toMinutesSinceMidnight();
}
/**
* Check if this time is after or equal to another time.
* @param other - The other time to compare against.
*/
afterOrEquals(other) {
return this.toMinutesSinceMidnight() >= other.toMinutesSinceMidnight();
}
/**
* Render the time as a Klog string.
* @param formatOverride - Optional override for the time format.
*/
toString(formatOverride) {
const shiftPrefix = this.dayShift === DayShift.Yesterday ? "<" : "";
const shiftSuffix = this.dayShift === DayShift.Tomorrow ? ">" : "";
let hour = this.hour;
const minute = this.minute.toString().padStart(2, "0");
let periodSuffix = "";
if ((formatOverride || this.format) === TimeFormat.TwelveHour) {
if (hour === 0) {
hour = 12;
periodSuffix = "am";
}
else if (hour === 12) {
periodSuffix = "pm";
}
else if (hour > 12) {
hour = hour - 12;
periodSuffix = "pm";
}
else {
periodSuffix = "am";
}
}
return `${shiftPrefix}${hour}:${minute}${periodSuffix}${shiftSuffix}`;
}
/**
* Convert the time to a duration starting at midnight.
*/
toDurationSinceMidnight() {
let hour = this.hour;
let minute = this.minute;
if (this.dayShift === DayShift.Yesterday) {
hour = -23 + hour;
minute = -60 + minute;
}
else if (this.dayShift === DayShift.Tomorrow) {
hour += 24;
}
return new Duration(hour, minute);
}
/**
* Convert the time to the amount of minutes since midnight.
*/
toMinutesSinceMidnight() {
return this.toDurationSinceMidnight().toMinutes();
}
}