mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-06 16:03:52 +00:00
refactor: extract parseUserTime
This commit is contained in:
committed by
Carlos Valente
parent
9d04954d87
commit
ce910c9cc6
@@ -1,9 +1,8 @@
|
||||
import { KeyboardEvent, useEffect, useRef, useState } from 'react';
|
||||
import { Input, Radio, RadioGroup } from '@chakra-ui/react';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
import { millisToString, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import { useEventAction } from '../../../hooks/useEventAction';
|
||||
import { forgivingStringToMillis } from '../../../utils/dateConfig';
|
||||
|
||||
import style from './DelayInput.module.scss';
|
||||
|
||||
@@ -40,7 +39,7 @@ export default function DelayInput(props: DelayInputProps) {
|
||||
}
|
||||
|
||||
const isNegative = newValue.startsWith('-');
|
||||
let newMillis = forgivingStringToMillis(newValue);
|
||||
let newMillis = parseUserTime(newValue);
|
||||
|
||||
if (isNegative) {
|
||||
newMillis = newMillis * -1;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { FocusEvent, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Input } from '@chakra-ui/react';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
import { millisToString, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import { useEmitLog } from '../../../stores/logger';
|
||||
import { forgivingStringToMillis } from '../../../utils/dateConfig';
|
||||
|
||||
interface TimeInputProps<T extends string> {
|
||||
name: T;
|
||||
@@ -57,7 +56,7 @@ export default function TimeInput<T extends string>(props: TimeInputProps<T>) {
|
||||
submitHandler(name, newValue);
|
||||
}
|
||||
|
||||
const valueInMillis = forgivingStringToMillis(newValue);
|
||||
const valueInMillis = parseUserTime(newValue);
|
||||
if (valueInMillis === time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
getLinkedTimes,
|
||||
getPreviousEventNormal,
|
||||
MILLIS_PER_SECOND,
|
||||
parseUserTime,
|
||||
reorderArray,
|
||||
swapEventData,
|
||||
} from 'ontime-utils';
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
} from '../api/rundown';
|
||||
import { logAxiosError } from '../api/utils';
|
||||
import { useEditorSettings } from '../stores/editorSettings';
|
||||
import { forgivingStringToMillis } from '../utils/dateConfig';
|
||||
|
||||
/**
|
||||
* @description Set of utilities for events //TODO: should this be called useEntryAction and so on
|
||||
@@ -94,15 +94,15 @@ export const useEventAction = () => {
|
||||
}
|
||||
|
||||
if (newEvent.duration === undefined && newEvent.timeEnd === undefined) {
|
||||
newEvent.duration = forgivingStringToMillis(defaultDuration);
|
||||
newEvent.duration = parseUserTime(defaultDuration);
|
||||
}
|
||||
|
||||
if (newEvent.timeDanger === undefined) {
|
||||
newEvent.timeDanger = forgivingStringToMillis(defaultDangerTime);
|
||||
newEvent.timeDanger = parseUserTime(defaultDangerTime);
|
||||
}
|
||||
|
||||
if (newEvent.timeWarning === undefined) {
|
||||
newEvent.timeWarning = forgivingStringToMillis(defaultWarnTime);
|
||||
newEvent.timeWarning = parseUserTime(defaultWarnTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,9 +217,9 @@ export const useEventAction = () => {
|
||||
} else if (value.startsWith('+') || value.startsWith('p+') || value.startsWith('p +')) {
|
||||
// TODO: is this logic solid?
|
||||
const remainingString = value.substring(1);
|
||||
newValMillis = getPreviousEnd() + forgivingStringToMillis(remainingString);
|
||||
newValMillis = getPreviousEnd() + parseUserTime(remainingString);
|
||||
} else {
|
||||
newValMillis = forgivingStringToMillis(value);
|
||||
newValMillis = parseUserTime(value);
|
||||
}
|
||||
|
||||
// dont allow timer values over 23:59:59
|
||||
|
||||
@@ -1,337 +1,4 @@
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from 'ontime-utils';
|
||||
|
||||
import { forgivingStringToMillis, millisToDelayString } from '../dateConfig';
|
||||
|
||||
describe('test forgivingStringToMillis()', () => {
|
||||
describe('function handles time with no separators', () => {
|
||||
const testData = [
|
||||
{ value: '', expect: 0 },
|
||||
{ value: '0', expect: 0 },
|
||||
{ value: '-0', expect: 0 },
|
||||
{ value: '1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '-1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0h0m0s', expect: 0 },
|
||||
{ value: '0h0m1s', expect: MILLIS_PER_SECOND },
|
||||
{ value: '0h1m0s', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '1h0m0s', expect: MILLIS_PER_HOUR },
|
||||
{ value: '23h0m0s', expect: 23 * MILLIS_PER_HOUR },
|
||||
{ value: '12h12m12s', expect: 12 * MILLIS_PER_SECOND + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_HOUR },
|
||||
{ value: '12H12M12S', expect: 12 * MILLIS_PER_SECOND + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_HOUR },
|
||||
{ value: '2m', expect: 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1h5s', expect: MILLIS_PER_HOUR + 5 * MILLIS_PER_SECOND },
|
||||
{ value: '1h2m', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of testData) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(typeof forgivingStringToMillis(s.value)).toBe('number');
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses strings correctly', () => {
|
||||
const ts = [
|
||||
{ value: '1.1.1', expect: MILLIS_PER_HOUR + MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.1.1', expect: 12 * MILLIS_PER_HOUR + MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.55.1', expect: 12 * MILLIS_PER_HOUR + 55 * MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.55.40', expect: 12 * MILLIS_PER_HOUR + 55 * MILLIS_PER_MINUTE + 40 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value} to the left`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('#33 separators are parsed according to doc examples ', () => {
|
||||
const ts = [
|
||||
{ value: '0.1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0 1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0:1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0,1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '2.2.2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2 2 2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2:2:2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2,2,2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2,2,2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '10:', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: ':10', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '120', expect: MILLIS_PER_HOUR + 20 * MILLIS_PER_MINUTE },
|
||||
{ value: '90m', expect: 90 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.2', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.2.3', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '123456', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 56 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses time strings', () => {
|
||||
const ts = [
|
||||
{ value: '1h2m3s', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '1h3s', expect: MILLIS_PER_HOUR + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '1h2m', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '10h', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10m', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10s', expect: 10 * MILLIS_PER_SECOND },
|
||||
{ value: '120h', expect: 120 * MILLIS_PER_HOUR },
|
||||
{ value: '120m', expect: 120 * MILLIS_PER_MINUTE },
|
||||
{ value: '120s', expect: 120 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles am/pm', () => {
|
||||
const ampm = [
|
||||
{ value: '1am', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1pm', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
{ value: '1 am', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1 pm', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
{ value: '1AM', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1PM', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '9am', expect: 9 * MILLIS_PER_HOUR },
|
||||
{ value: '9pm', expect: (12 + 9) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '10am', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10pm', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
{ value: '10 am', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10 pm', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
{ value: '10AM', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10PM', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '12am', expect: 0 * MILLIS_PER_HOUR },
|
||||
{ value: '12pm', expect: 12 * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '1:10am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10 am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10 pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10AM', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10PM', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '9:10am', expect: 9 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '9:10pm', expect: (12 + 9) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '10:10am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10 am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10 pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10AM', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10PM', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '12:10am', expect: 0 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '12:10pm', expect: 12 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '1:10:10am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10 am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10 pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10AM', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10PM', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '9:10:10am', expect: 9 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '9:10:10pm', expect: (12 + 9) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '10:10:10am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10 am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10 pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10AM', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10PM', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '12:10:10am', expect: 0 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '12:10:10pm', expect: 12 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ampm) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('it infers separators when non existent', () => {
|
||||
const testCases = [
|
||||
{ value: '1', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '12', expect: 12 * MILLIS_PER_MINUTE }, // 00:12:00
|
||||
{ value: '123', expect: MILLIS_PER_HOUR + 23 * MILLIS_PER_MINUTE }, // 01:23:00
|
||||
{ value: '1234', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE }, // 12:34:00
|
||||
{ value: '12345', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 5 * MILLIS_PER_SECOND }, // 12:34:05
|
||||
{ value: '123456', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 56 * MILLIS_PER_SECOND }, // 12:34:56
|
||||
];
|
||||
|
||||
for (const s of testCases) {
|
||||
it(`handles basic strings digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const sixDigits = [
|
||||
{ value: '000000', expect: 0 }, // 00:00:00
|
||||
{ value: '000001', expect: MILLIS_PER_SECOND }, // 00:00:01
|
||||
{ value: '000100', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '010000', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '230000', expect: MILLIS_PER_HOUR * 23 }, // 23:00:00
|
||||
{ value: '121212', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_SECOND }, // 12:12:12
|
||||
];
|
||||
|
||||
for (const s of sixDigits) {
|
||||
it(`handles string with 6 digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const fiveDigits = [
|
||||
{ value: '00000', expect: 0 },
|
||||
{ value: '00001', expect: MILLIS_PER_SECOND }, // 00:00:01
|
||||
{ value: '00010', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '00100', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '01000', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '10000', expect: 10 * MILLIS_PER_HOUR }, // 10:00:00
|
||||
{ value: '23000', expect: 23 * MILLIS_PER_HOUR }, // 23:00:00
|
||||
{ value: '12121', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE + 1 * MILLIS_PER_SECOND }, // 12:12:01
|
||||
];
|
||||
|
||||
for (const s of fiveDigits) {
|
||||
it(`handles string with 5 digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const fourDigits = [
|
||||
{ value: '0000', expect: 0 },
|
||||
{ value: '0001', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '0010', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '0100', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '1000', expect: 10 * MILLIS_PER_HOUR }, // 10:00:00
|
||||
{ value: '2300', expect: 23 * MILLIS_PER_HOUR }, // 23:00:00
|
||||
{ value: '1212', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE }, // 12:12:00
|
||||
];
|
||||
|
||||
for (const s of fourDigits) {
|
||||
it(`handles string with 4 digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const threeDigits = [
|
||||
{ value: '000', expect: 0 },
|
||||
{ value: '001', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '010', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '100', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '230', expect: 2 * MILLIS_PER_HOUR + 30 * MILLIS_PER_MINUTE }, // 02:30:00
|
||||
{ value: '121', expect: MILLIS_PER_HOUR + 21 * MILLIS_PER_MINUTE }, // 01:21:00
|
||||
];
|
||||
|
||||
for (const s of threeDigits) {
|
||||
it(`handles string with 3 digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const twoDigits = [
|
||||
{ value: '00', expect: 0 },
|
||||
{ value: '01', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '10', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '23', expect: 23 * MILLIS_PER_MINUTE }, // 00:23:00
|
||||
];
|
||||
|
||||
for (const s of twoDigits) {
|
||||
it(`handles string with 2 digits: ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const singleDigit = [...Array(10).keys()];
|
||||
|
||||
for (const s of singleDigit) {
|
||||
it(`handles string with a single digits ${s}`, () => {
|
||||
expect(forgivingStringToMillis(`${s}`)).toBe(s * 1000 * 60);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles overflows', () => {
|
||||
const ts = [
|
||||
// minutes overflow
|
||||
{ value: '99', expect: 99 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.39.0', expect: 99 * MILLIS_PER_MINUTE },
|
||||
// seconds overflow
|
||||
{ value: '0.0.120', expect: 120 * MILLIS_PER_SECOND },
|
||||
{ value: '0.2.0', expect: 120 * MILLIS_PER_SECOND },
|
||||
{ value: '0.0.99', expect: 99 * MILLIS_PER_SECOND },
|
||||
{ value: '0.1.39', expect: 99 * MILLIS_PER_SECOND },
|
||||
// hours overflow
|
||||
{ value: '25.0.0', expect: 25 * MILLIS_PER_HOUR },
|
||||
// hours overflow
|
||||
{ value: '50.0.0', expect: 50 * MILLIS_PER_HOUR },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value} to the left`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('test fillLeft', () => {
|
||||
describe('function handles separators', () => {
|
||||
const testData = [
|
||||
{ value: '1:2:3:10', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND }, // 01:02:03
|
||||
{ value: '2,10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '2.10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '2 10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of testData) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(typeof forgivingStringToMillis(s.value)).toBe('number');
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses strings correctly', () => {
|
||||
const ts = [
|
||||
{ value: '1.2', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.70', expect: MILLIS_PER_HOUR + 70 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles overflows', () => {
|
||||
const ts = [
|
||||
// minutes overflow
|
||||
{ value: '0.120', expect: 120 * MILLIS_PER_MINUTE },
|
||||
{ value: '0.99', expect: 99 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(forgivingStringToMillis(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
import { millisToDelayString } from '../dateConfig';
|
||||
|
||||
describe('millisToDelayString()', () => {
|
||||
it('returns null for null values', () => {
|
||||
|
||||
@@ -1,179 +1,11 @@
|
||||
import { MaybeNumber } from 'ontime-types';
|
||||
import { formatFromMillis, MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from 'ontime-utils';
|
||||
import { formatFromMillis, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||
|
||||
/**
|
||||
* @description safe parse string to int
|
||||
* @param {string} valueAsString
|
||||
* @return {number}
|
||||
* Parses a value in millis to a string which encodes a delay
|
||||
* @param millis
|
||||
* @param format
|
||||
*/
|
||||
const parse = (valueAsString: string): number => {
|
||||
const parsed = parseInt(valueAsString, 10);
|
||||
if (isNaN(parsed)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.abs(parsed);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Utility function to check if a string contain am/pm indicators
|
||||
* @param {string} value
|
||||
*/
|
||||
function checkAmPm(value: string) {
|
||||
let isPM = false;
|
||||
let isAM = false;
|
||||
if (value.toLowerCase().includes('pm')) {
|
||||
isPM = true;
|
||||
value = value.replace(/pm/i, '');
|
||||
} else if (value.toLowerCase().includes('p')) {
|
||||
isPM = true;
|
||||
value = value.replace(/p/i, '');
|
||||
}
|
||||
|
||||
// we need to remove am, but it doesn't actually change anything
|
||||
if (value.toLowerCase().includes('am')) {
|
||||
isAM = true;
|
||||
value = value.replace(/am/i, '');
|
||||
} else if (value.toLowerCase().includes('a')) {
|
||||
isAM = true;
|
||||
value = value.replace(/a/i, '');
|
||||
}
|
||||
|
||||
return { isAM, isPM, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Utility function to check if a string contain h / m / s indicators
|
||||
* @param {string} value
|
||||
*/
|
||||
function checkMatchers(value: string): number | null {
|
||||
const hoursMatch = /(\d+)h/i.exec(value);
|
||||
const hoursMatchValue = hoursMatch ? parse(hoursMatch[1]) : 0;
|
||||
|
||||
const minutesMatch = /(\d+)m/i.exec(value);
|
||||
const minutesMatchValue = minutesMatch ? parse(minutesMatch[1]) : 0;
|
||||
|
||||
const secondsMatch = /(\d+)s/i.exec(value);
|
||||
const secondsMatchValue = secondsMatch ? parse(secondsMatch[1]) : 0;
|
||||
|
||||
if (hoursMatchValue > 0 || minutesMatchValue > 0 || secondsMatchValue > 0) {
|
||||
return (
|
||||
hoursMatchValue * MILLIS_PER_HOUR + minutesMatchValue * MILLIS_PER_MINUTE + secondsMatchValue * MILLIS_PER_SECOND
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Utility function to infer separators from a whole string
|
||||
* @param {string} value
|
||||
* @param {boolean} isAM
|
||||
* @param {boolean} isPM
|
||||
*/
|
||||
function inferSeparators(value: string, isAM: boolean, isPM: boolean) {
|
||||
const length = value.length;
|
||||
let inferredMillis = 0;
|
||||
let addAM = 0;
|
||||
if (length === 1) {
|
||||
if (isPM || isAM) {
|
||||
inferredMillis = parse(value) * MILLIS_PER_HOUR;
|
||||
if (isAM) {
|
||||
// this ensures we dont add 12 hours in the end
|
||||
addAM = inferredMillis;
|
||||
}
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
} else if (length === 2) {
|
||||
if (isPM || isAM) {
|
||||
if (value === '12' && isAM) {
|
||||
inferredMillis = 0;
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_HOUR;
|
||||
}
|
||||
|
||||
if (isAM || value === '12') {
|
||||
// this ensures we dont add 12 hours in the end
|
||||
addAM = 12;
|
||||
}
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
} else if (length === 3) {
|
||||
inferredMillis = parse(value[0]) * MILLIS_PER_HOUR + parse(value.substring(1)) * MILLIS_PER_MINUTE;
|
||||
} else if (length === 4) {
|
||||
inferredMillis = parse(value.substring(0, 2)) * MILLIS_PER_HOUR + parse(value.substring(2)) * MILLIS_PER_MINUTE;
|
||||
} else if (length >= 5) {
|
||||
const hours = parse(value.substring(0, 2));
|
||||
const minutes = parse(value.substring(2, 4));
|
||||
const seconds = parse(value.substring(4));
|
||||
inferredMillis = hours * MILLIS_PER_HOUR + minutes * MILLIS_PER_MINUTE + seconds * MILLIS_PER_SECOND;
|
||||
}
|
||||
return { inferredMillis, addAM };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Parses a time string to millis, auto-filling to the left
|
||||
* @param {string} value - time string
|
||||
* @returns {number} - time string in millis
|
||||
*/
|
||||
export const forgivingStringToMillis = (value: string): number => {
|
||||
value = value.toLowerCase();
|
||||
|
||||
const { isAM, isPM, value: parsingValue } = checkAmPm(value);
|
||||
const maybeMillisFromMatchers = checkMatchers(parsingValue);
|
||||
if (maybeMillisFromMatchers !== null) {
|
||||
return maybeMillisFromMatchers;
|
||||
}
|
||||
|
||||
// split string at known separators : , .
|
||||
const separatorRegex = /[\s,:.]+/;
|
||||
const [first, second, third] = parsingValue.split(separatorRegex);
|
||||
|
||||
let addTwelve = isPM;
|
||||
|
||||
let millis = 0;
|
||||
|
||||
if (first != null && second != null && third != null) {
|
||||
// if string has three sections, treat as [hours] [minutes] [seconds]
|
||||
let hours = parse(first);
|
||||
if (hours === 12) {
|
||||
if (isAM) {
|
||||
hours = 0;
|
||||
}
|
||||
addTwelve = false;
|
||||
}
|
||||
|
||||
millis = hours * MILLIS_PER_HOUR;
|
||||
millis += parse(second) * MILLIS_PER_MINUTE;
|
||||
millis += parse(third) * MILLIS_PER_SECOND;
|
||||
} else if (first != null && second == null && third == null) {
|
||||
// we only have one section, infer separators
|
||||
const { inferredMillis, addAM } = inferSeparators(first, isAM, isPM);
|
||||
millis = inferredMillis;
|
||||
addTwelve = addAM < 12 && isPM;
|
||||
}
|
||||
if (first != null && second != null && third == null) {
|
||||
// if string has two sections, treat as [hours] [minutes]
|
||||
let hours = parse(first);
|
||||
if (hours === 12) {
|
||||
if (isAM) {
|
||||
hours = 0;
|
||||
}
|
||||
addTwelve = false;
|
||||
}
|
||||
|
||||
millis = hours * MILLIS_PER_HOUR;
|
||||
millis += parse(second) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
|
||||
// Add 12 hours if needed
|
||||
if (addTwelve) {
|
||||
millis += 12 * MILLIS_PER_HOUR;
|
||||
}
|
||||
|
||||
return millis;
|
||||
};
|
||||
|
||||
export function millisToDelayString(millis: MaybeNumber, format: 'compact' | 'expanded' = 'compact'): string {
|
||||
if (millis == null || millis === 0) {
|
||||
return '';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Select, Switch } from '@chakra-ui/react';
|
||||
import { EndAction, TimerType } from 'ontime-types';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { editorSettingsDefaults, useEditorSettings } from '../../../../common/stores/editorSettings';
|
||||
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
export default function EditorSettingsForm() {
|
||||
@@ -15,9 +15,9 @@ export default function EditorSettingsForm() {
|
||||
const setDangerTime = eventSettings.setDangerTime;
|
||||
const setDefaultPublic = eventSettings.setDefaultPublic;
|
||||
|
||||
const durationInMs = forgivingStringToMillis(eventSettings.defaultDuration);
|
||||
const warnTimeInMs = forgivingStringToMillis(eventSettings.defaultWarnTime);
|
||||
const dangerTimeInMs = forgivingStringToMillis(eventSettings.defaultDangerTime);
|
||||
const durationInMs = parseUserTime(eventSettings.defaultDuration);
|
||||
const warnTimeInMs = parseUserTime(eventSettings.defaultWarnTime);
|
||||
const dangerTimeInMs = parseUserTime(eventSettings.defaultDangerTime);
|
||||
|
||||
return (
|
||||
<Panel.Section>
|
||||
|
||||
@@ -2,12 +2,11 @@ import { Tooltip } from '@chakra-ui/react';
|
||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||
import { IoRemove } from '@react-icons/all-files/io5/IoRemove';
|
||||
import { Playback } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_SECOND } from 'ontime-utils';
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_SECOND, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { useLocalStorage } from '../../../../common/hooks/useLocalStorage';
|
||||
import { setPlayback } from '../../../../common/hooks/useSocket';
|
||||
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
|
||||
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||
import TapButton from '../tap-button/TapButton';
|
||||
|
||||
@@ -22,7 +21,7 @@ export default function AddTime(props: AddTimeProps) {
|
||||
const [time, setTime] = useLocalStorage('add-time', 300_000); // 5 minutes
|
||||
|
||||
const handleTimeChange = (_field: string, value: string) => {
|
||||
const newTime = forgivingStringToMillis(value);
|
||||
const newTime = parseUserTime(value);
|
||||
// cap add time to 1 hour
|
||||
setTime(Math.min(newTime, MILLIS_PER_HOUR));
|
||||
};
|
||||
|
||||
@@ -4,10 +4,10 @@ import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
||||
import { Playback, SimpleDirection, SimplePlayback } from 'ontime-types';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { setAuxTimer, useAuxTimerControl, useAuxTimerTime } from '../../../../common/hooks/useSocket';
|
||||
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
|
||||
import TapButton from '../tap-button/TapButton';
|
||||
|
||||
import style from './AuxTimer.module.scss';
|
||||
@@ -64,7 +64,7 @@ function AuxTimerInput() {
|
||||
const { setDuration } = setAuxTimer;
|
||||
|
||||
const handleTimeUpdate = (_field: string, value: string) => {
|
||||
const newTime = forgivingStringToMillis(value);
|
||||
const newTime = parseUserTime(value);
|
||||
setDuration(newTime / 1000); //frontend api is seconds based;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { memo } from 'react';
|
||||
import { Select, Switch } from '@chakra-ui/react';
|
||||
import { EndAction, MaybeString, TimerType, TimeStrategy } from 'ontime-types';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
import { millisToString, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { useEventAction } from '../../../../common/hooks/useEventAction';
|
||||
import { forgivingStringToMillis, millisToDelayString } from '../../../../common/utils/dateConfig';
|
||||
import { millisToDelayString } from '../../../../common/utils/dateConfig';
|
||||
import TimeInputFlow from '../../time-input-flow/TimeInputFlow';
|
||||
|
||||
import style from '../EventEditor.module.scss';
|
||||
@@ -51,7 +51,7 @@ const EventEditorTimes = (props: EventEditorTimesProps) => {
|
||||
}
|
||||
|
||||
if (field === 'timeWarning' || field === 'timeDanger') {
|
||||
const newTime = forgivingStringToMillis(value as string);
|
||||
const newTime = parseUserTime(value as string);
|
||||
updateEvent({ id: eventId, [field]: newTime });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export {
|
||||
removeSeconds,
|
||||
removeTrailingZero,
|
||||
} from './src/date-utils/timeFormatting.js';
|
||||
export { parseUserTime } from './src/date-utils/parseUserTime.js';
|
||||
export { isAlphanumeric } from './src/regex-utils/isAlphanumeric.js';
|
||||
export { isColourHex } from './src/regex-utils/isColourHex.js';
|
||||
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from "./conversionUtils";
|
||||
import { parseUserTime } from "./parseUserTime";
|
||||
|
||||
describe('test parseUserTime()', () => {
|
||||
describe('function handles time with no separators', () => {
|
||||
const testData = [
|
||||
{ value: '', expect: 0 },
|
||||
{ value: '0', expect: 0 },
|
||||
{ value: '-0', expect: 0 },
|
||||
{ value: '1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '-1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0h0m0s', expect: 0 },
|
||||
{ value: '0h0m1s', expect: MILLIS_PER_SECOND },
|
||||
{ value: '0h1m0s', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '1h0m0s', expect: MILLIS_PER_HOUR },
|
||||
{ value: '23h0m0s', expect: 23 * MILLIS_PER_HOUR },
|
||||
{ value: '12h12m12s', expect: 12 * MILLIS_PER_SECOND + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_HOUR },
|
||||
{ value: '12H12M12S', expect: 12 * MILLIS_PER_SECOND + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_HOUR },
|
||||
{ value: '2m', expect: 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1h5s', expect: MILLIS_PER_HOUR + 5 * MILLIS_PER_SECOND },
|
||||
{ value: '1h2m', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of testData) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(typeof parseUserTime(s.value)).toBe('number');
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses strings correctly', () => {
|
||||
const ts = [
|
||||
{ value: '1.1.1', expect: MILLIS_PER_HOUR + MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.1.1', expect: 12 * MILLIS_PER_HOUR + MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.55.1', expect: 12 * MILLIS_PER_HOUR + 55 * MILLIS_PER_MINUTE + MILLIS_PER_SECOND },
|
||||
{ value: '12.55.40', expect: 12 * MILLIS_PER_HOUR + 55 * MILLIS_PER_MINUTE + 40 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value} to the left`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('#33 separators are parsed according to doc examples ', () => {
|
||||
const ts = [
|
||||
{ value: '0.1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0 1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0:1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '0,1', expect: MILLIS_PER_MINUTE },
|
||||
{ value: '2.2.2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2 2 2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2:2:2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2,2,2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '2,2,2', expect: 2 * MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 2 * MILLIS_PER_SECOND },
|
||||
{ value: '10:', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: ':10', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '120', expect: MILLIS_PER_HOUR + 20 * MILLIS_PER_MINUTE },
|
||||
{ value: '90m', expect: 90 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.2', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.2.3', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '123456', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 56 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses time strings', () => {
|
||||
const ts = [
|
||||
{ value: '1h2m3s', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '1h3s', expect: MILLIS_PER_HOUR + 3 * MILLIS_PER_SECOND },
|
||||
{ value: '1h2m', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '10h', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10m', expect: 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10s', expect: 10 * MILLIS_PER_SECOND },
|
||||
{ value: '120h', expect: 120 * MILLIS_PER_HOUR },
|
||||
{ value: '120m', expect: 120 * MILLIS_PER_MINUTE },
|
||||
{ value: '120s', expect: 120 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles am/pm', () => {
|
||||
const ampm = [
|
||||
{ value: '1am', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1pm', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
{ value: '1 am', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1 pm', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
{ value: '1AM', expect: 1 * MILLIS_PER_HOUR },
|
||||
{ value: '1PM', expect: (12 + 1) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '9am', expect: 9 * MILLIS_PER_HOUR },
|
||||
{ value: '9pm', expect: (12 + 9) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '10am', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10pm', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
{ value: '10 am', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10 pm', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
{ value: '10AM', expect: 10 * MILLIS_PER_HOUR },
|
||||
{ value: '10PM', expect: (12 + 10) * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '12am', expect: 0 * MILLIS_PER_HOUR },
|
||||
{ value: '12pm', expect: 12 * MILLIS_PER_HOUR },
|
||||
|
||||
{ value: '1:10am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10 am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10 pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10AM', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '1:10PM', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '9:10am', expect: 9 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '9:10pm', expect: (12 + 9) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '10:10am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10 am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10 pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10AM', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '10:10PM', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '12:10am', expect: 0 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '12:10pm', expect: 12 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
|
||||
{ value: '1:10:10am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10 am', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10 pm', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10AM', expect: 1 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '1:10:10PM', expect: (12 + 1) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '9:10:10am', expect: 9 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '9:10:10pm', expect: (12 + 9) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '10:10:10am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10 am', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10 pm', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10AM', expect: 10 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '10:10:10PM', expect: (12 + 10) * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
|
||||
{ value: '12:10:10am', expect: 0 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
{ value: '12:10:10pm', expect: 12 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE + 10 * MILLIS_PER_SECOND },
|
||||
];
|
||||
|
||||
for (const s of ampm) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('it infers separators when non existent', () => {
|
||||
const testCases = [
|
||||
{ value: '1', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '12', expect: 12 * MILLIS_PER_MINUTE }, // 00:12:00
|
||||
{ value: '123', expect: MILLIS_PER_HOUR + 23 * MILLIS_PER_MINUTE }, // 01:23:00
|
||||
{ value: '1234', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE }, // 12:34:00
|
||||
{ value: '12345', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 5 * MILLIS_PER_SECOND }, // 12:34:05
|
||||
{ value: '123456', expect: 12 * MILLIS_PER_HOUR + 34 * MILLIS_PER_MINUTE + 56 * MILLIS_PER_SECOND }, // 12:34:56
|
||||
];
|
||||
|
||||
for (const s of testCases) {
|
||||
it(`handles basic strings digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const sixDigits = [
|
||||
{ value: '000000', expect: 0 }, // 00:00:00
|
||||
{ value: '000001', expect: MILLIS_PER_SECOND }, // 00:00:01
|
||||
{ value: '000100', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '010000', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '230000', expect: MILLIS_PER_HOUR * 23 }, // 23:00:00
|
||||
{ value: '121212', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE + 12 * MILLIS_PER_SECOND }, // 12:12:12
|
||||
];
|
||||
|
||||
for (const s of sixDigits) {
|
||||
it(`handles string with 6 digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const fiveDigits = [
|
||||
{ value: '00000', expect: 0 },
|
||||
{ value: '00001', expect: MILLIS_PER_SECOND }, // 00:00:01
|
||||
{ value: '00010', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '00100', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '01000', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '10000', expect: 10 * MILLIS_PER_HOUR }, // 10:00:00
|
||||
{ value: '23000', expect: 23 * MILLIS_PER_HOUR }, // 23:00:00
|
||||
{ value: '12121', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE + 1 * MILLIS_PER_SECOND }, // 12:12:01
|
||||
];
|
||||
|
||||
for (const s of fiveDigits) {
|
||||
it(`handles string with 5 digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const fourDigits = [
|
||||
{ value: '0000', expect: 0 },
|
||||
{ value: '0001', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '0010', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '0100', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '1000', expect: 10 * MILLIS_PER_HOUR }, // 10:00:00
|
||||
{ value: '2300', expect: 23 * MILLIS_PER_HOUR }, // 23:00:00
|
||||
{ value: '1212', expect: 12 * MILLIS_PER_HOUR + 12 * MILLIS_PER_MINUTE }, // 12:12:00
|
||||
];
|
||||
|
||||
for (const s of fourDigits) {
|
||||
it(`handles string with 4 digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const threeDigits = [
|
||||
{ value: '000', expect: 0 },
|
||||
{ value: '001', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '010', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '100', expect: MILLIS_PER_HOUR }, // 01:00:00
|
||||
{ value: '230', expect: 2 * MILLIS_PER_HOUR + 30 * MILLIS_PER_MINUTE }, // 02:30:00
|
||||
{ value: '121', expect: MILLIS_PER_HOUR + 21 * MILLIS_PER_MINUTE }, // 01:21:00
|
||||
];
|
||||
|
||||
for (const s of threeDigits) {
|
||||
it(`handles string with 3 digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const twoDigits = [
|
||||
{ value: '00', expect: 0 },
|
||||
{ value: '01', expect: MILLIS_PER_MINUTE }, // 00:01:00
|
||||
{ value: '10', expect: 10 * MILLIS_PER_MINUTE }, // 00:10:00
|
||||
{ value: '23', expect: 23 * MILLIS_PER_MINUTE }, // 00:23:00
|
||||
];
|
||||
|
||||
for (const s of twoDigits) {
|
||||
it(`handles string with 2 digits: ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
|
||||
const singleDigit = [...Array(10).keys()];
|
||||
|
||||
for (const s of singleDigit) {
|
||||
it(`handles string with a single digits ${s}`, () => {
|
||||
expect(parseUserTime(`${s}`)).toBe(s * 1000 * 60);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles overflows', () => {
|
||||
const ts = [
|
||||
// minutes overflow
|
||||
{ value: '99', expect: 99 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.39.0', expect: 99 * MILLIS_PER_MINUTE },
|
||||
// seconds overflow
|
||||
{ value: '0.0.120', expect: 120 * MILLIS_PER_SECOND },
|
||||
{ value: '0.2.0', expect: 120 * MILLIS_PER_SECOND },
|
||||
{ value: '0.0.99', expect: 99 * MILLIS_PER_SECOND },
|
||||
{ value: '0.1.39', expect: 99 * MILLIS_PER_SECOND },
|
||||
// hours overflow
|
||||
{ value: '25.0.0', expect: 25 * MILLIS_PER_HOUR },
|
||||
// hours overflow
|
||||
{ value: '50.0.0', expect: 50 * MILLIS_PER_HOUR },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value} to the left`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('test fillLeft', () => {
|
||||
describe('function handles separators', () => {
|
||||
const testData = [
|
||||
{ value: '1:2:3:10', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE + 3 * MILLIS_PER_SECOND }, // 01:02:03
|
||||
{ value: '2,10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '2.10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
{ value: '2 10', expect: 2 * MILLIS_PER_HOUR + 10 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of testData) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(typeof parseUserTime(s.value)).toBe('number');
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('parses strings correctly', () => {
|
||||
const ts = [
|
||||
{ value: '1.2', expect: MILLIS_PER_HOUR + 2 * MILLIS_PER_MINUTE },
|
||||
{ value: '1.70', expect: MILLIS_PER_HOUR + 70 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('handles overflows', () => {
|
||||
const ts = [
|
||||
// minutes overflow
|
||||
{ value: '0.120', expect: 120 * MILLIS_PER_MINUTE },
|
||||
{ value: '0.99', expect: 99 * MILLIS_PER_MINUTE },
|
||||
];
|
||||
|
||||
for (const s of ts) {
|
||||
it(`handles ${s.value}`, () => {
|
||||
expect(parseUserTime(s.value)).toBe(s.expect);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,174 @@
|
||||
import { MILLIS_PER_HOUR, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from './conversionUtils.js';
|
||||
|
||||
/**
|
||||
* @description Parses a time string to millis, auto-filling to the left
|
||||
* @param {string} value - time string
|
||||
* @returns {number} - time string in millis
|
||||
*/
|
||||
export function parseUserTime(value: string): number {
|
||||
value = value.toLowerCase();
|
||||
|
||||
const { isAM, isPM, value: parsingValue } = checkAmPm(value);
|
||||
const maybeMillisFromMatchers = checkMatchers(parsingValue);
|
||||
if (maybeMillisFromMatchers !== null) {
|
||||
return maybeMillisFromMatchers;
|
||||
}
|
||||
|
||||
// split string at known separators : , .
|
||||
const separatorRegex = /[\s,:.]+/;
|
||||
const [first, second, third] = parsingValue.split(separatorRegex);
|
||||
|
||||
let addTwelve = isPM;
|
||||
|
||||
let millis = 0;
|
||||
|
||||
if (first != null && second != null && third != null) {
|
||||
// if string has three sections, treat as [hours] [minutes] [seconds]
|
||||
let hours = parse(first);
|
||||
if (hours === 12) {
|
||||
if (isAM) {
|
||||
hours = 0;
|
||||
}
|
||||
addTwelve = false;
|
||||
}
|
||||
|
||||
millis = hours * MILLIS_PER_HOUR;
|
||||
millis += parse(second) * MILLIS_PER_MINUTE;
|
||||
millis += parse(third) * MILLIS_PER_SECOND;
|
||||
} else if (first != null && second == null && third == null) {
|
||||
// we only have one section, infer separators
|
||||
const { inferredMillis, addAM } = inferSeparators(first, isAM, isPM);
|
||||
millis = inferredMillis;
|
||||
addTwelve = addAM < 12 && isPM;
|
||||
}
|
||||
if (first != null && second != null && third == null) {
|
||||
// if string has two sections, treat as [hours] [minutes]
|
||||
let hours = parse(first);
|
||||
if (hours === 12) {
|
||||
if (isAM) {
|
||||
hours = 0;
|
||||
}
|
||||
addTwelve = false;
|
||||
}
|
||||
|
||||
millis = hours * MILLIS_PER_HOUR;
|
||||
millis += parse(second) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
|
||||
// Add 12 hours if needed
|
||||
if (addTwelve) {
|
||||
millis += 12 * MILLIS_PER_HOUR;
|
||||
}
|
||||
|
||||
return millis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Utility function to infer separators from a whole string
|
||||
* @param {string} value
|
||||
* @param {boolean} isAM
|
||||
* @param {boolean} isPM
|
||||
*/
|
||||
function inferSeparators(value: string, isAM: boolean, isPM: boolean) {
|
||||
const length = value.length;
|
||||
let inferredMillis = 0;
|
||||
let addAM = 0;
|
||||
if (length === 1) {
|
||||
if (isPM || isAM) {
|
||||
inferredMillis = parse(value) * MILLIS_PER_HOUR;
|
||||
if (isAM) {
|
||||
// this ensures we dont add 12 hours in the end
|
||||
addAM = inferredMillis;
|
||||
}
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
} else if (length === 2) {
|
||||
if (isPM || isAM) {
|
||||
if (value === '12' && isAM) {
|
||||
inferredMillis = 0;
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_HOUR;
|
||||
}
|
||||
|
||||
if (isAM || value === '12') {
|
||||
// this ensures we dont add 12 hours in the end
|
||||
addAM = 12;
|
||||
}
|
||||
} else {
|
||||
inferredMillis = parse(value) * MILLIS_PER_MINUTE;
|
||||
}
|
||||
} else if (length === 3) {
|
||||
inferredMillis = parse(value[0]) * MILLIS_PER_HOUR + parse(value.substring(1)) * MILLIS_PER_MINUTE;
|
||||
} else if (length === 4) {
|
||||
inferredMillis = parse(value.substring(0, 2)) * MILLIS_PER_HOUR + parse(value.substring(2)) * MILLIS_PER_MINUTE;
|
||||
} else if (length >= 5) {
|
||||
const hours = parse(value.substring(0, 2));
|
||||
const minutes = parse(value.substring(2, 4));
|
||||
const seconds = parse(value.substring(4));
|
||||
inferredMillis = hours * MILLIS_PER_HOUR + minutes * MILLIS_PER_MINUTE + seconds * MILLIS_PER_SECOND;
|
||||
}
|
||||
return { inferredMillis, addAM };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Utility function to check if a string contain h / m / s indicators
|
||||
* @param {string} value
|
||||
*/
|
||||
function checkMatchers(value: string): number | null {
|
||||
const hoursMatch = /(\d+)h/i.exec(value);
|
||||
const hoursMatchValue = hoursMatch ? parse(hoursMatch[1]) : 0;
|
||||
|
||||
const minutesMatch = /(\d+)m/i.exec(value);
|
||||
const minutesMatchValue = minutesMatch ? parse(minutesMatch[1]) : 0;
|
||||
|
||||
const secondsMatch = /(\d+)s/i.exec(value);
|
||||
const secondsMatchValue = secondsMatch ? parse(secondsMatch[1]) : 0;
|
||||
|
||||
if (hoursMatchValue > 0 || minutesMatchValue > 0 || secondsMatchValue > 0) {
|
||||
return (
|
||||
hoursMatchValue * MILLIS_PER_HOUR + minutesMatchValue * MILLIS_PER_MINUTE + secondsMatchValue * MILLIS_PER_SECOND
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Utility function to check if a string contain am/pm indicators
|
||||
* @param {string} value
|
||||
*/
|
||||
function checkAmPm(value: string) {
|
||||
let isPM = false;
|
||||
let isAM = false;
|
||||
if (value.toLowerCase().includes('pm')) {
|
||||
isPM = true;
|
||||
value = value.replace(/pm/i, '');
|
||||
} else if (value.toLowerCase().includes('p')) {
|
||||
isPM = true;
|
||||
value = value.replace(/p/i, '');
|
||||
}
|
||||
|
||||
// we need to remove am, but it doesn't actually change anything
|
||||
if (value.toLowerCase().includes('am')) {
|
||||
isAM = true;
|
||||
value = value.replace(/am/i, '');
|
||||
} else if (value.toLowerCase().includes('a')) {
|
||||
isAM = true;
|
||||
value = value.replace(/a/i, '');
|
||||
}
|
||||
|
||||
return { isAM, isPM, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description safe parse string to int
|
||||
* @param {string} valueAsString
|
||||
* @return {number}
|
||||
*/
|
||||
function parse(valueAsString: string): number {
|
||||
const parsed = parseInt(valueAsString, 10);
|
||||
if (isNaN(parsed)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.abs(parsed);
|
||||
}
|
||||
Reference in New Issue
Block a user