Skip to content

Instantly share code, notes, and snippets.

@kamiaka
Last active June 28, 2021 23:16
Show Gist options
  • Save kamiaka/6f828d3319b81a6d67167c27fc43aa07 to your computer and use it in GitHub Desktop.
Save kamiaka/6f828d3319b81a6d67167c27fc43aa07 to your computer and use it in GitHub Desktop.
Convert time durations on TypeScript (JavaScript)
export class DurationUnit {
constructor(public readonly value: number, public readonly name: string) {}
}
export const nanoSecond = new DurationUnit(1, 'ns');
export const microSecond = new DurationUnit(1000 * nanoSecond.value, 'µs');
export const milliSecond = new DurationUnit(1000 * microSecond.value, 'ms');
export const second = new DurationUnit(1000 * milliSecond.value, 's');
export const minute = new DurationUnit(60 * second.value, 'm');
export const hour = new DurationUnit(60 * minute.value, 'h');
export const day = new DurationUnit(24 * hour.value, 'd');
export interface DurationObject {
days: number;
hours: number;
minutes: number;
seconds: number;
}
export class Duration {
public readonly value: number;
public readonly unit: DurationUnit;
constructor(value: number, unit: DurationUnit = nanoSecond) {
this.value = Math.round(value * unit.value) / unit.value;
this.unit = unit;
}
to(unit: DurationUnit, isFloor: boolean = false) {
const v = this.value ? Math.round(this.value * this.unit.value) / unit.value : 0;
return isFloor ? Math.floor(v) : v;
}
add(v: number, unit?: DurationUnit): Duration;
add(v: Duration): Duration;
add(v: number | Duration, unit: DurationUnit = nanoSecond): Duration {
if (typeof v === 'number') {
v = new Duration(v, unit);
}
return new Duration(this.value + v.to(this.unit), this.unit);
}
sub(v: number, unit?: DurationUnit): Duration;
sub(v: Duration): Duration;
sub(v: number | Duration, unit: DurationUnit = nanoSecond) {
if (typeof v === 'number') {
v = new Duration(v, unit);
}
return new Duration(this.value - v.to(this.unit), this.unit);
}
toString() {
return `${this.value}${this.unit.name}`;
}
toObject() {
const ns = Math.round(this.to(nanoSecond));
return {
days: Math.floor(ns / day.value),
hours: Math.floor(ns % day.value / hour.value),
minutes: Math.floor(ns % day.value % hour.value / minute.value),
seconds: ns % day.value % hour.value % minute.value / second.value,
};
}
valueOf() {
return this.to(nanoSecond);
}
static since(d: Date, current: Date = new Date()) {
return new Duration(current.getTime() - d.getTime(), milliSecond);
}
static until(d: Date, current: Date = new Date()) {
return new Duration(d.getTime() - current.getTime(), milliSecond);
}
static fromObject(obj: Partial<DurationObject>) {
return new Duration(obj.days || 0, day)
.add(new Duration(obj.hours || 0, hour))
.add(new Duration(obj.minutes || 0, minute))
.add(new Duration(obj.seconds || 0, second));
}
}
console.log(new Duration(123456.789, second).toObject()); // { days: 1, hours: 10, minutes: 17, seconds: 36.789 }
console.log(new Duration(2, hour).toString()); // 2h
console.log(new Duration(3, microSecond).valueOf()); // 3000
console.log(new Duration(10, day).to(minute)); // 14400
console.log(new Duration(1.5, hour).to(minute)); // 90
console.log(new Duration(3, day).to(second)); // 259200
console.log(
new Duration(3, day)
.add(12, hour)
.add(34, minute)
.add(56, second)
.add(new Duration(12345, microSecond))
.to(second)
); // 304496.012345
console.log(Duration.fromObject({
days: 1,
hours: 10,
minutes: 17,
seconds: 36.789,
}).to(second)); // 123456.789
const now = new Date('2021-06-25');
console.log(Duration.since(new Date('2021-01-01'), now).to(day)); // 175
console.log(Duration.until(new Date('2021-12-31'), now).to(day)); // 189
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment