Skip to content

Commit

Permalink
Add a date/time parsing quick check to escape early if the string doe…
Browse files Browse the repository at this point in the history
…s not look like a date/time value
  • Loading branch information
sequba committed Aug 14, 2023
1 parent 7e9737b commit ca5cb70
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 14 deletions.
38 changes: 29 additions & 9 deletions src/DateTimeDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,28 @@
import {DateTime, SimpleDate, SimpleTime} from './DateTimeHelper'
import {Maybe} from './Maybe'

//const QUICK_CHECK_REGEXP = new RegExp('^[0-9/.\\-:\\s]+[ap]?m?\\s*$', '')
const QUICK_CHECK_REGEXP = new RegExp('^[0-9/.\\-: ]+[ap]?m?$', '')
const WHITESPACE_REGEXP = new RegExp('\\s+')
const DATE_SEPARATOR_REGEXP = new RegExp('[ /.-]')
const TIME_SEPARATOR = ':'

export function defaultParseToDateTime(dateTimeString: string, dateFormat?: string, timeFormat?: string): Maybe<DateTime> {
dateTimeString = dateTimeString.replace(WHITESPACE_REGEXP, ' ').trim().toLowerCase()
let ampmtoken: Maybe<string> = dateTimeString.substring(dateTimeString.length - 2)
if (ampmtoken === 'am' || ampmtoken === 'pm') {
export function defaultParseToDateTime(text: string, dateFormat?: string, timeFormat?: string): Maybe<DateTime> {
let dateTimeString = text.replace(WHITESPACE_REGEXP, ' ').trim().toLowerCase()

if (!doesItLookLikeADateTimeQuickCheck(dateTimeString)) {
return undefined
}

let ampmToken: Maybe<string> = dateTimeString.substring(dateTimeString.length - 2)
if (ampmToken === 'am' || ampmToken === 'pm') {
dateTimeString = dateTimeString.substring(0, dateTimeString.length - 2).trim()
} else {
ampmtoken = dateTimeString.substring(dateTimeString.length - 1)
if (ampmtoken === 'a' || ampmtoken === 'p') {
ampmToken = dateTimeString.substring(dateTimeString.length - 1)
if (ampmToken === 'a' || ampmToken === 'p') {
dateTimeString = dateTimeString.substring(0, dateTimeString.length - 1).trim()
} else {
ampmtoken = undefined
ampmToken = undefined
}
}
const dateItems = dateTimeString.split(DATE_SEPARATOR_REGEXP)
Expand All @@ -29,8 +36,8 @@ export function defaultParseToDateTime(dateTimeString: string, dateFormat?: stri
dateItems.pop()
}
const timeItems = dateItems[dateItems.length - 1].split(TIME_SEPARATOR)
if (ampmtoken !== undefined) {
timeItems.push(ampmtoken)
if (ampmToken !== undefined) {
timeItems.push(ampmToken)
}

if (dateItems.length === 1) {
Expand All @@ -50,6 +57,10 @@ export function defaultParseToDateTime(dateTimeString: string, dateFormat?: stri
}
}

function doesItLookLikeADateTimeQuickCheck(text: string): boolean {
return QUICK_CHECK_REGEXP.test(text)
}

export const secondsExtendedRegexp = /^ss(\.(s+|0+))?$/

function defaultParseToTime(timeItems: string[], timeFormat: Maybe<string>): Maybe<SimpleTime> {
Expand Down Expand Up @@ -166,3 +177,12 @@ function defaultParseToDate(dateItems: string[], dateFormat: Maybe<string>): May
const day = Number(dayString)
return {year, month, day}
}

// Ideas:
// - quick check -> 10% speedup
// - parse formats only once
// - divide string into parts by a regexp [date_regexp]? [time_regexp]? [ampm_regexp]?
// - start by finding the time part, because it is unambiguous '([0-9]+:[0-9:.]+ ?[ap]?m?)$', before it is the date part
// - OR split by spaces - last segment is ampm token, second to last is time (with or without ampm), rest is date
// - date parsing might work differently after these changes but still according to the docs
// - test edge cases like timeFormats: ['hh', 'ss.ss'] etc, string: '01-01-2019 AM', 'PM'
9 changes: 4 additions & 5 deletions src/DateTimeHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,10 @@ export class DateTimeHelper {
}

private parseDateTimeFromFormats(dateTimeString: string, dateFormats: string[], timeFormats: string[]): Partial<{ dateTime: DateTime, dateFormat: string, timeFormat: string }> {
const dateFormatsIterate = dateFormats.length === 0 ? [undefined] : dateFormats
const timeFormatsIterate = timeFormats.length === 0 ? [undefined] : timeFormats
for (const dateFormat of dateFormatsIterate) {
for (const timeFormat of timeFormatsIterate) {
const dateFormatsArray = dateFormats.length === 0 ? [undefined] : dateFormats
const timeFormatsArray = timeFormats.length === 0 ? [undefined] : timeFormats
for (const dateFormat of dateFormatsArray) {
for (const timeFormat of timeFormatsArray) {
const dateTime = this.parseSingleFormat(dateTimeString, dateFormat, timeFormat)
if (dateTime !== undefined) {
return {dateTime, timeFormat, dateFormat}
Expand Down Expand Up @@ -319,4 +319,3 @@ export function timeToNumber(time: SimpleTime): number {
export function toBasisEU(date: SimpleDate): SimpleDate {
return {year: date.year, month: date.month, day: Math.min(30, date.day)}
}

0 comments on commit ca5cb70

Please sign in to comment.