Skip to content
Snippets Groups Projects
timely.ts 5.72 KiB
Newer Older
    'none':         Infinity,
    'year':         1000 * 60 * 60 * 24 * 365.2425,
    'month':        1000 * 60 * 60 * 24 * 30,
    'week':         1000 * 60 * 60 * 24 * 7,
    'day':          1000 * 60 * 60 * 24,
    'hour':         1000 * 60 * 60,
    'minute':       1000 * 60,
    'second':       1000,
    'millisecond':  1,
};

type Unit = (keyof typeof UNITS);

function formatAmount(amount: number, base: string): string {
    amount = Math.floor(amount);
    if (amount === 0) {
        return 'zero ' + base + 's';
    } else if (amount === 1) {
        return 'one ' + base;
    } else {
        return amount.toString() + ' ' + base + 's';
    }
}

export function formatDuration(millis: number, precision: Unit = 'minute'): string {
    if (millis >= UNITS[precision]) {
        for (const key of (Object.keys(UNITS) as Unit[])) {
            if (millis >= UNITS[key]) {
                return formatAmount(millis / UNITS[key], key);
            }
        }
    }
    return 'moments';
}

function formatNumber(value: number, places = 2, padding = '0'): string {
    let result = Math.floor(value).toString();
    while (result.length < places) {
        result = padding + result;
    }
    return result;
}

export function formatSimpleDuration(millis: number, hours = false, minutes = true, seconds = true, milliseconds = false): string {
    let result = '';
    if (hours) {
        const hour = Math.floor(millis / UNITS['hour']);
        millis -= hour * UNITS['hour'];
        result += formatNumber(hour);
    }
    if (minutes) {
        if (result.length !== 0) {
            result += ':';
        }
        const min = Math.floor(millis / UNITS['minute']);
        millis -= min * UNITS['minute'];
        result += formatNumber(min);
    }
    if (seconds) {
        if (result.length !== 0) {
            result += ':';
        }
        const sec = Math.floor(millis / UNITS['second']);
        millis -= sec * UNITS['second'];
        result += formatNumber(sec);
    }
    if (milliseconds) {
        if (result.length !== 0) {
            result += '.';
        }
        result += formatNumber(millis, 3);
    }
    return result;
}

function formatOrdinal(value: number): string {
    value = Math.floor(value);
    if (value === 1 || (value % 10 === 1 && value > 20)) {
        return value.toString() + 'st';
    } else if (value === 2 || (value % 10 === 2 && value > 20)) {
        return value.toString() + 'nd';
    } else if (value === 3 || (value % 10 === 3 && value > 20)) {
        return value.toString() + 'rd';
        return value.toString() + 'th';
const MONTHS = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
];

const WEEKDAYS = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
];

export function formatTime(date: Date, precision: Unit = 'minute'): string {
    let result = '';
    if (UNITS[precision] <= UNITS['hour']) {
        result += formatNumber(date.getHours());
        if (UNITS[precision] <= UNITS['minute']) {
            result += ':' + formatNumber(date.getMinutes());
        } else {
            result += ':00';
        }
        if (UNITS[precision] <= UNITS['second']) {
            result += ':' + formatNumber(date.getSeconds())
        }
        if (UNITS[precision] <= UNITS['millisecond']) {
            result += '.' + formatNumber(date.getMilliseconds(), 3);
        }
    }
    return result;
}

export function formatDate(date: Date, precision: Unit = 'day', weekday?: 'short' | 'full', year = true): string {
    let result = '';
    if (weekday === 'short') {
        result += WEEKDAYS[date.getDay()].substr(0, 3);
    } else if (weekday === 'full') {
        result += WEEKDAYS[date.getDay()];
    }
    if (UNITS[precision] <= UNITS['day']) {
        if (result.length !== 0) {
            result += ', ';
        }
        result += formatOrdinal(date.getDate());
    }
    if (UNITS[precision] <= UNITS['month']) {
        if (result.length !== 0) {
            result += ' ';
        }
        result += MONTHS[date.getMonth()];
    }
    if (year && UNITS[precision] <= UNITS['year']) {
        if (result.length !== 0) {
            result += ' ';
        }
        result += date.getFullYear().toString();
    }
    if (UNITS[precision] <= UNITS['hour']) {
        result += ' ' + formatTime(date, precision);
export function formatRelativeTime(target: Date, origin = new Date(), precision?: Unit): string {
    const delta = durationBetween(origin, target);
    if (delta > 0) {
        return 'in ' + formatDuration(delta, precision);
    } else {
        return formatDuration(-delta, precision) + ' ago';
    }
}

export function addTime(date: Date, time: number, unit: Unit): Date {
    if (time === 0) {
        return new Date(date);
    } else if (unit === 'month') {
        const full = Math.floor(time);
        const result = new Date(date);
        result.setMonth(result.getMonth() + full);
        return addTime(result, 30 * (time - full), 'day');
    } else if (unit === 'year') {
        const full = Math.floor(time);
        const result = new Date(date);
        result.setFullYear(result.getFullYear() + full);
        return addTime(result, 12 * (time - full), 'month');
    } else {
        // All other durations are constant
        return new Date(date.getTime() + time * UNITS[unit]);
    }
}

export function subtractTime(date: Date, time: number, unit: Unit): Date {
    return addTime(date, -time, unit);
}

export function durationBetween(from: Date, to: Date): number {
    return to.getTime() - from.getTime();
}

export function currentTime(): Date {
    return new Date();
}