Date format fixer (#1319)

* attmept to figure out what date format the user is inputting w/ burnettk

* reverted default date config w/ burnettk

* added tests for the new date formatter function

* fixed outdated comment

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-04-01 20:39:29 +00:00 committed by GitHub
parent cef93033e8
commit b507f45fb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 135 additions and 3 deletions

View File

@ -6,10 +6,15 @@ import {
StrictRJSFSchema, StrictRJSFSchema,
WidgetProps, WidgetProps,
} from '@rjsf/utils'; } from '@rjsf/utils';
import { parse } from 'date-fns';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useDebouncedCallback } from 'use-debounce'; import { useDebouncedCallback } from 'use-debounce';
import { DATE_FORMAT_CARBON, DATE_FORMAT_FOR_DISPLAY } from '../../../config'; import {
DATE_FORMAT,
DATE_FORMAT_CARBON,
DATE_FORMAT_FOR_DISPLAY,
} from '../../../config';
import DateAndTimeService from '../../../services/DateAndTimeService'; import DateAndTimeService from '../../../services/DateAndTimeService';
import { getCommonAttributes } from '../../helpers'; import { getCommonAttributes } from '../../helpers';
@ -73,8 +78,12 @@ export default function BaseInputTemplate<
); );
const addDebouncedOnChangeDate = useDebouncedCallback( const addDebouncedOnChangeDate = useDebouncedCallback(
(target: React.ChangeEvent<HTMLInputElement>) => { (fullObject: React.ChangeEvent<HTMLInputElement>) => {
_onChange(target); fullObject.target.value =
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
fullObject.target.value
);
_onChange(fullObject);
}, },
// delay in ms // delay in ms
1000 1000
@ -93,6 +102,8 @@ export default function BaseInputTemplate<
// it should in be y-m-d when it gets here. // it should in be y-m-d when it gets here.
let dateValue: string | null = value; let dateValue: string | null = value;
if (value || value === 0) { if (value || value === 0) {
// it would be good if we could compare against the length of the desired format but that doesn't work in all cases and causes some issues.
// 10 seems to be a good value check against.
if (value.length < 10) { if (value.length < 10) {
dateValue = value; dateValue = value;
} else { } else {

View File

@ -5,6 +5,7 @@ test('it can keep the correct date when converting seconds to date', () => {
DateAndTimeService.convertSecondsToFormattedDateString(1666325400); DateAndTimeService.convertSecondsToFormattedDateString(1666325400);
expect(dateString).toEqual('2022-10-21'); expect(dateString).toEqual('2022-10-21');
}); });
test('it can properly format a duration', () => { test('it can properly format a duration', () => {
expect(DateAndTimeService.formatDurationForDisplay('0')).toEqual('0s'); expect(DateAndTimeService.formatDurationForDisplay('0')).toEqual('0s');
expect(DateAndTimeService.formatDurationForDisplay('60')).toEqual('1m'); expect(DateAndTimeService.formatDurationForDisplay('60')).toEqual('1m');
@ -20,3 +21,82 @@ test('it can properly format a duration', () => {
'365d 12m 45s' '365d 12m 45s'
); );
}); });
test('it can get the correct date format from string', () => {
const expectedDateString = '2024-03-04';
const newDateFormat = 'dd-MMM-yyyy';
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
expectedDateString
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'03-04-2024'
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'March 4, 2024'
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'mar-4-2024'
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'03/04/2024'
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'03.04.2024'
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'04-03-2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'March 4, 2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'4-mar-2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'4 March 2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'04/03/2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
'04.03.2024',
newDateFormat
)
).toEqual(expectedDateString);
expect(
DateAndTimeService.attemptToConvertUnknownDateStringFormatToKnownFormat(
expectedDateString,
newDateFormat
)
).toEqual(expectedDateString);
});

View File

@ -147,6 +147,46 @@ const secondsToDuration = (secNum: number) => {
return duration; return duration;
}; };
const attemptToConvertUnknownDateStringFormatToKnownFormat = (
dateString: string,
targetDateFormat?: string
) => {
let dateFormat = targetDateFormat;
if (!dateFormat) {
dateFormat = DATE_FORMAT;
}
let newDateString = dateString;
// if the date starts with 4 digits then assume in y-m-d format and avoid all of this
if (dateString.length >= 10 && !dateString.match(/^\d{4}/)) {
// if the date format should contain month names or abbreviations but does not have letters
// then attempt to parse in the same format but with digit months instead of letters
if (!dateString.match(/[a-zA-Z]+/) && dateFormat.match(/MMM/)) {
const numericalDateFormat = dateFormat.replaceAll(/MMM*/g, 'MM');
const dateFormatRegex = new RegExp(
numericalDateFormat
.replace('dd', '\\d{2}')
.replace('MM', '\\d{2}')
.replace('yyyy', '\\d{4}')
);
const normalizedDateString = dateString.replaceAll(/[.-/]+/g, '-');
if (normalizedDateString.match(dateFormatRegex)) {
const newDate = parse(
normalizedDateString,
dateFormat.replaceAll(/MMM*/g, 'MM'),
new Date()
);
newDateString = convertDateObjectToFormattedString(newDate) || '';
}
} else {
// NOTE: do not run Date.parse with y-m-d formats since it returns dates in a different timezone from other formats
const newDate = new Date(Date.parse(`${dateString}`));
newDateString = convertDateObjectToFormattedString(newDate) || '';
}
}
return newDateString;
};
const formatDurationForDisplay = (value: any) => { const formatDurationForDisplay = (value: any) => {
if (value === undefined) { if (value === undefined) {
return undefined; return undefined;
@ -193,6 +233,7 @@ const DateAndTimeService = {
REFRESH_INTERVAL_SECONDS, REFRESH_INTERVAL_SECONDS,
REFRESH_TIMEOUT_SECONDS, REFRESH_TIMEOUT_SECONDS,
attemptToConvertUnknownDateStringFormatToKnownFormat,
convertDateAndTimeStringsToDate, convertDateAndTimeStringsToDate,
convertDateAndTimeStringsToSeconds, convertDateAndTimeStringsToSeconds,
convertDateObjectToFormattedHoursMinutes, convertDateObjectToFormattedHoursMinutes,