mirror of
https://github.com/cpvalente/ontime.git
synced 2026-07-26 10:38:55 +00:00
committed by
GitHub
parent
0966659596
commit
8b0e03e980
@@ -13,11 +13,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"luxon": "^3.4.4",
|
||||
"nanoid": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/luxon": "^3.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"eslint": "^8.53.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { dayInMs } from '../timeConstants';
|
||||
import { MILLIS_PER_HOUR } from './conversionUtils';
|
||||
import { millisToString, removeLeadingZero } from './timeFormatting';
|
||||
import { formatFromMillis, millisToString, removeLeadingZero } from './timeFormatting';
|
||||
|
||||
describe('millisToString()', () => {
|
||||
it('returns fallback if millis is null', () => {
|
||||
@@ -61,3 +61,159 @@ describe('removeLeadingZero()', () => {
|
||||
expect(removeLeadingZero('-00:08:47')).toBe('-8:47');
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatFromMillis()', () => {
|
||||
it('milliseconds', () => {
|
||||
const millis = 76211123; // Jan 1, 1970 21:10:11.123 UTC
|
||||
const format = 'S';
|
||||
const expectedResult = '123';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('seconds (no padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 's';
|
||||
const expectedResult = '11';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('seconds (padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'ss';
|
||||
const expectedResult = '11';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('minute (no padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'm';
|
||||
const expectedResult = '10';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('minute (padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'mm';
|
||||
const expectedResult = '10';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 12 (no padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'h';
|
||||
const expectedResult = '9';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 12 (padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'hh';
|
||||
const expectedResult = '09';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 24 (no padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'H';
|
||||
const expectedResult = '21';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 24 (padding)', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'HH';
|
||||
const expectedResult = '21';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('formatted time HH:mm:ss', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'HH:mm:ss';
|
||||
const expectedResult = '21:10:11';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('formatted time hh:mm a', () => {
|
||||
const millis = 76211123;
|
||||
const format = 'hh:mm a';
|
||||
const expectedResult = '09:10 PM';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('milliseconds', () => {
|
||||
const millis = 29167345; // 08:06:08.345
|
||||
const format = 'S';
|
||||
const expectedResult = '345';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('seconds (no padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 's';
|
||||
const expectedResult = '7';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('seconds (padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'ss';
|
||||
const expectedResult = '07';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('minute (no padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'm';
|
||||
const expectedResult = '6';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('minute (padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'mm';
|
||||
const expectedResult = '06';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 12 (no padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'h';
|
||||
const expectedResult = '8';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 12 (padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'hh';
|
||||
const expectedResult = '08';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 24 (no padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'H';
|
||||
const expectedResult = '8';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('hour - 24 (padding)', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'HH';
|
||||
const expectedResult = '08';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('formatted time HH:mm:ss', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'HH:mm:ss';
|
||||
const expectedResult = '08:06:07';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
|
||||
it('formatted time hh:mm a', () => {
|
||||
const millis = 29167345;
|
||||
const format = 'hh:mm a';
|
||||
const expectedResult = '08:06 AM';
|
||||
expect(formatFromMillis(millis, format)).toBe(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DateTime } from 'luxon';
|
||||
import type { MaybeNumber } from 'ontime-types';
|
||||
|
||||
import { millisToHours, millisToMinutes, millisToSeconds } from './conversionUtils.js';
|
||||
@@ -71,11 +70,60 @@ export function removeSeconds(timer: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description utility function to format a date in milliseconds using luxon
|
||||
* @param {number} millis
|
||||
* @param {string} format
|
||||
* @return {string}
|
||||
* Formats a given date into a custom string format based on UTC time.
|
||||
*
|
||||
* @param millis - The number of milliseconds.
|
||||
* @param format - A string specifying the desired output format.
|
||||
* For example, 'ss' will format the millis as '07' seconds.
|
||||
*
|
||||
* @returns The formatted date as a string according to the provided `format` string.
|
||||
* If input `millis` is smaller than zero, it returns undefined.
|
||||
*
|
||||
*/
|
||||
export function formatFromMillis(millis: number, format: string): string {
|
||||
return DateTime.fromMillis(millis).toUTC().toFormat(format);
|
||||
export function formatFromMillis(millis: number, format: string): string | undefined {
|
||||
if (millis < 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const date: Date = new Date(millis);
|
||||
|
||||
const hour24Padded = date.getUTCHours().toString().padStart(2, '0');
|
||||
const hour24 = date.getUTCHours().toString();
|
||||
const minutePadded = date.getUTCMinutes().toString().padStart(2, '0');
|
||||
const minute = date.getUTCMinutes().toString();
|
||||
const secondPadded = date.getUTCSeconds().toString().padStart(2, '0');
|
||||
const second = date.getUTCSeconds().toString();
|
||||
const milliseconds = date.getUTCMilliseconds().toString().padStart(3, '0');
|
||||
const hour12 = ((date.getUTCHours() % 12) || 12).toString();
|
||||
const hour12Padded = hour12.padStart(2, '0');
|
||||
const amPm = date.getUTCHours() >= 12 ? 'PM' : 'AM';
|
||||
|
||||
const replacements: Record<string, string> = {
|
||||
'HH': hour24Padded,
|
||||
'H': hour24,
|
||||
'hh': hour12Padded,
|
||||
'h': hour12,
|
||||
'mm': minutePadded,
|
||||
'm': minute,
|
||||
'ss': secondPadded,
|
||||
's': second,
|
||||
'S': milliseconds,
|
||||
'a': amPm
|
||||
};
|
||||
|
||||
return applyReplacements(format, replacements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies replacements to a template string based on a dictionary of tokens and their corresponding values.
|
||||
*
|
||||
* @param {string} template - The format template string containing tokens to be replaced.
|
||||
* @param {Record<string, string>} replacements - A record of tokens and their corresponding values.
|
||||
* @returns {string} The formatted string with all tokens replaced by their values.
|
||||
*/
|
||||
function applyReplacements(template: string, replacements: Record<string, string>): string {
|
||||
return Object.keys(replacements).reduce((result, token) => {
|
||||
const regex = new RegExp(`\\b${token}\\b`, 'g');
|
||||
return result.replace(regex, replacements[token]);
|
||||
}, template);
|
||||
}
|
||||
|
||||
Generated
+113
-16
@@ -391,16 +391,10 @@ importers:
|
||||
deepmerge-ts:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0
|
||||
luxon:
|
||||
specifier: ^3.4.4
|
||||
version: 3.4.4
|
||||
nanoid:
|
||||
specifier: ^5.0.4
|
||||
version: 5.0.4
|
||||
devDependencies:
|
||||
'@types/luxon':
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^6.10.0
|
||||
version: 6.10.0(@typescript-eslint/parser@6.10.0)(eslint@8.53.0)(typescript@5.4.3)
|
||||
@@ -430,7 +424,7 @@ importers:
|
||||
version: 5.4.3
|
||||
vitest:
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2(@types/node@18.11.18)(jsdom@21.1.0)(sass@1.57.1)
|
||||
version: 1.2.2
|
||||
|
||||
packages:
|
||||
|
||||
@@ -3312,10 +3306,6 @@ packages:
|
||||
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
|
||||
dev: false
|
||||
|
||||
/@types/luxon@3.4.0:
|
||||
resolution: {integrity: sha512-PEVoA4MOfSsFNaPrZjIUGUZujBDxnO/tj2A2N9KfzlR+pNgpBdDuk0TmRvSMAVUP5q4q8IkMEZ8UOp3MIr+QgA==}
|
||||
dev: true
|
||||
|
||||
/@types/mime@3.0.1:
|
||||
resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==}
|
||||
dev: true
|
||||
@@ -7060,11 +7050,6 @@ packages:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/luxon@3.4.4:
|
||||
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/lz-string@1.4.4:
|
||||
resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==}
|
||||
hasBin: true
|
||||
@@ -9239,6 +9224,27 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/vite-node@1.2.2:
|
||||
resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
vite: 5.1.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vite-node@1.2.2(@types/node@18.11.18)(sass@1.57.1):
|
||||
resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -9301,6 +9307,41 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/vite@5.1.0:
|
||||
resolution: {integrity: sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.4.0
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
lightningcss:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
esbuild: 0.19.10
|
||||
postcss: 8.4.35
|
||||
rollup: 4.9.1
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vite@5.1.0(@types/node@18.11.18)(sass@1.57.1):
|
||||
resolution: {integrity: sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -9338,6 +9379,62 @@ packages:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vitest@1.2.2:
|
||||
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
'@vitest/browser': ^1.0.0
|
||||
'@vitest/ui': ^1.0.0
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
'@edge-runtime/vm':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
'@vitest/ui':
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vitest/expect': 1.2.2
|
||||
'@vitest/runner': 1.2.2
|
||||
'@vitest/snapshot': 1.2.2
|
||||
'@vitest/spy': 1.2.2
|
||||
'@vitest/utils': 1.2.2
|
||||
acorn-walk: 8.3.2
|
||||
cac: 6.7.14
|
||||
chai: 4.3.10
|
||||
debug: 4.3.4
|
||||
execa: 8.0.1
|
||||
local-pkg: 0.5.0
|
||||
magic-string: 0.30.5
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
std-env: 3.6.0
|
||||
strip-literal: 1.3.0
|
||||
tinybench: 2.5.1
|
||||
tinypool: 0.8.2
|
||||
vite: 5.1.0
|
||||
vite-node: 1.2.2
|
||||
why-is-node-running: 2.2.2
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vitest@1.2.2(@types/node@18.11.18)(jsdom@21.1.0)(sass@1.57.1):
|
||||
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
|
||||
Reference in New Issue
Block a user