Skip to content

Instantly share code, notes, and snippets.

@OysteinAmundsen
Created March 11, 2024 11:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OysteinAmundsen/19b85d8917b05482fab414713e55fdcc to your computer and use it in GitHub Desktop.
Save OysteinAmundsen/19b85d8917b05482fab414713e55fdcc to your computer and use it in GitHub Desktop.
Find date format from date string
import { addDays, getHours, isAfter, isBefore, parse, setHours, startOfDay, subDays } from 'date-fns';
export class dateUtil {
/**
* Find the correct date format, by comparing two consecutive days.
*
* @param date The date string to find the format for
* @param refDate The date string to compare. This should be either the next or previous day.
* This is only needed to determine if the day is before or after the month in the format.
*/
findDateFormat(date: string, refDate: string): string | null {
const [d1, t1] = date.split(' ');
const [d2, t2] = refDate.split(' ');
// Generate all possible date formats
const formats = [
['d', 'dd'],
['M', 'MM'],
['yy', 'yyyy'],
];
const delimiters = ['.', '/', '-', ''].filter(d => d1.includes(d)); // Only apply delimiters that are present in the given date string
let dateFormats = delimiters
.flatMap(delimiter =>
formats[0].flatMap(day =>
formats[1].flatMap(month =>
formats[2].flatMap(year =>
[
[day, month, year],
[month, day, year],
[year, month, day],
].map(order => order.join(delimiter)),
),
),
),
)
.filter(
(format, i, arr) =>
arr.indexOf(format) === i && !format.includes('d.d') && !format.includes('M.M') && !format.includes('y.y'),
);
// Support those formats which does not separate date and time with a space
if (delimiters.length === 1 && t1 == null) {
dateFormats = dateFormats.reduce((acc, f) => {
return [...acc, f, `${f}H`, `${f}HH`];
}, [] as string[]);
}
// Loop through all formats and try to parse the date and reference date
for (const format of dateFormats) {
const date = parse(d1, format, new Date());
const referenceDate = parse(d2, format, new Date());
if (!isNaN(date.getTime()) && !isNaN(referenceDate.getTime())) {
// If the date is one day after the reference date or one day before, this is our format.
const nextDay = setHours(addDays(new Date(referenceDate), 1), getHours(date));
const previousDay = setHours(subDays(new Date(referenceDate), 1), getHours(date));
if (
(isAfter(date, referenceDate) && date.getTime() === nextDay.getTime()) ||
(isBefore(date, referenceDate) && date.getTime() === previousDay.getTime())
) {
if (t1 != null) {
const [hour, minute] = t1.split(':');
return `${format} ${
minute != null
? `H${hour.length > 1 ? 'H' : ''}:m${minute.length > 1 ? 'm' : ''}`
: `H${hour.length > 1 ? 'H' : ''}`
}`;
}
return format;
}
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment