Created
March 11, 2024 11:07
-
-
Save OysteinAmundsen/19b85d8917b05482fab414713e55fdcc to your computer and use it in GitHub Desktop.
Find date format from date string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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