LCOV - code coverage report
Current view: top level - pkg/lib - timeformat.ts Coverage Total Hit
Test: cockpit Lines: 94.6 % 37 35
Test Date: 2026-07-13 10:00:01

            Line data    Source code
       1              : // SPDX-License-Identifier: LGPL-2.1-or-later
       2              : /* Wrappers around Intl.DateTimeFormat which use Cockpit's current locale, and define a few standard formats.
       3              :  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
       4              :  *
       5              :  * Time stamps are given in milliseconds since the epoch.
       6              :  */
       7          346 : import cockpit from "cockpit";
       8              : 
       9          346 : const _ = cockpit.gettext;
      10              : 
      11              : // this needs to be dynamic, as some pages don't initialize cockpit.language right away
      12          257 : export const dateFormatLang = (): string => cockpit.language.replace('_', '-');
      13              : 
      14              : type Time = Date | number;
      15              : 
      16              : // general Intl.DateTimeFormat formatter object
      17          257 : export const formatter = (options?: Intl.DateTimeFormatOptions) => new Intl.DateTimeFormat(dateFormatLang(), options);
      18              : 
      19              : // common formatters; try to use these as much as possible, for UI consistency
      20              : // 07:41 AM
      21          127 : export const time = (t: Time): string => formatter({ timeStyle: "short" }).format(t);
      22              : // 7:41:26 AM
      23            0 : export const timeSeconds = (t: Time): string => formatter({ timeStyle: "medium" }).format(t);
      24              : // June 30, 2021
      25          139 : export const date = (t: Time): string => formatter({ dateStyle: "long" }).format(t);
      26              : // 06/30/2021
      27              : export const dateShort = (t: Time): string => formatter().format(t);
      28              : // Jun 30, 2021, 7:41 AM
      29           49 : export const dateTime = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "short" }).format(t);
      30              : // Jun 30, 2021, 7:41 AM if `t` is in UTC format
      31           92 : export const dateTimeUTC = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "short", timeZone: "UTC" }).format(t);
      32              : // Jun 30, 2021, 7:41:23 AM
      33            5 : export const dateTimeSeconds = (t: Time): string => formatter({ dateStyle: "medium", timeStyle: "medium" }).format(t);
      34              : // Jun 30, 7:41 AM
      35           76 : export const dateTimeNoYear = (t: Time): string => formatter({ month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }).format(t);
      36              : // Wednesday, June 30, 2021
      37           11 : export const weekdayDate = (t: Time): string => formatter({ dateStyle: "full" }).format(t);
      38              : 
      39              : // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/format
      40          346 : const units: { name: Intl.RelativeTimeFormatUnit, max: number }[] = [
      41          346 :     { name: "second", max: 60 },
      42          346 :     { name: "minute", max: 3600 },
      43          346 :     { name: "hour", max: 86400 },
      44          346 :     { name: "day", max: 86400 * 7 },
      45          346 :     { name: "week", max: 86400 * 30 },
      46          346 :     { name: "month", max: 86400 * 365 },
      47          346 :     { name: "year", max: Infinity },
      48          346 : ];
      49              : 
      50              : // "1 hour ago" for past times, "in 1 hour" for future times
      51          118 : export function distanceToNow(t: Time): string {
      52              :     // Calculate the difference in seconds between the given date and the current date
      53           20 :     const t_timestamp = t?.valueOf() ?? t;
      54          118 :     const secondsDiff = Math.round((t_timestamp - Date.now()) / 1000);
      55              : 
      56              :     // special case for < 1 minute, like date-fns
      57              :     // we don't constantly re-render pages and there are delays, so seconds is too precise
      58          116 :     if (secondsDiff <= 0 && secondsDiff > -60)
      59           74 :         return _("less than a minute ago");
      60           22 :     if (secondsDiff > 0 && secondsDiff < 60)
      61           22 :         return _("in less than a minute");
      62              : 
      63              :     // find the appropriate unit based on the seconds difference
      64           58 :     const unitIndex = units.findIndex(u => u.max > Math.abs(secondsDiff));
      65              :     // get the divisor to convert seconds to the appropriate unit
      66           20 :     const divisor = unitIndex ? units[unitIndex - 1].max : 1;
      67              : 
      68          118 :     const formatter = new Intl.RelativeTimeFormat(dateFormatLang(), { numeric: "auto" });
      69          118 :     return formatter.format(Math.round(secondsDiff / divisor), units[unitIndex].name);
      70          118 : }
      71              : 
      72              : /***
      73              :  * sorely missing from Intl: https://github.com/tc39/ecma402/issues/6
      74              :  * based on https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/weekData.json#L59
      75              :  * However, we don't have translations for most locales, and cockpit.language does not even contain
      76              :  * the country in most cases, so this is just an approximation.
      77              :  * Most locales start the week on Monday (day 1), so default to that and enumerate the others.
      78              :  */
      79              : 
      80          163 : const first_dow_sun = ['en', 'ja', 'ko', 'pt', 'pt_BR', 'sv', 'zh_CN', 'zh_TW'];
      81              : 
      82            5 : export function firstDayOfWeek(): number {
      83            0 :     return first_dow_sun.indexOf(cockpit.language) >= 0 ? 0 : 1;
      84            5 : }
        

Generated by: LCOV version 2.0-1