UNPKG

@technobuddha/library

Version:
163 lines (150 loc) 6.01 kB
import isNil from 'lodash/isNil'; import compact from 'lodash/compact'; import zip from 'lodash/zip'; import build from '../build'; import { month } from '../constants'; function re(template: TemplateStringsArray, ...args: RegExp[]): RegExp { return new RegExp( build( pre.source, compact( zip(template, args.map(a => a.source)).flat() ), post.source ), 'u' ); } const pre = /^\s*/u; const post = /\s*$/u; const sep = /(?:\s*[/.-]?\s*)/u; const mm = /([0][1-9]|[1][012])/u; const mmm = /(jan|january|feb|february|mar|march|apr|april|may|jun|june|jul|july|aug|august|sep|sept|september|oct|october|nov|november|dec|december)/u; const dd = /([0][1-9]|[12][0-9]|[3][01])/u; const yyyy = /(\d{4})/u; const time = /(?:(?:\s+|\s*t\s*)(?:(\d{1,2}):(\d{2})(?:[:](\d{1,2})(?:[.,](\d+))?)?(?:\s*(a|p)(?:m)?)?))?/ui; const zone = /(?:\s*(?:(z|gmt)(?:([+-]\d{1,2})(?:[:](\d{2}))?)?))?/ui; const mdyNumeric = re`${mm}${sep}${dd}${sep}${yyyy}${time}${zone}`; const ymdNumeric = re`${yyyy}${sep}${mm}${sep}${dd}${time}${zone}`; const mdyString = re`${mmm}${sep}${dd}${sep}${yyyy}${time}${zone}`; const dmyString = re`${dd}${sep}${mmm}${sep}${yyyy}${time}${zone}`; const ymdString = re`${yyyy}${sep}${mmm}${sep}${dd}${time}${zone}`; const ydmString = re`${yyyy}${sep}${dd}${sep}${mmm}${time}${zone}`; const mNumeric = re`${mm}`; const myNumeric = re`${mm}${sep}${yyyy}`; const ymNumeric = re`${yyyy}${sep}${mm}`; const mString = re`${mmm}`; const myString = re`${mmm}${sep}${yyyy}`; const ymString = re`${yyyy}${sep}${mmm}`; const yNumeric = re`${yyyy}`; /** * Parse a string into a Date object * * @remarks this is a little more generous about what formats it will take for a date, and if it can't match the input to one of it's supported formats it falls * back to new Date(text) * * @param text The string containing a date * @returns new Date object */ export function parseDate(text: string): Date { const now = new Date(); let dY = 0; let dM = 0; let dD = 0; let tH = 0; let tM = 0; let tS = 0; let tF = 0; let zH = null as number | null; let zM = null as number | null; text = text.toLowerCase(); let match: RegExpExecArray | null; if((match = mdyNumeric.exec(text)) !== null) { dM = Number.parseInt(match[1], 10) - 1; dD = Number.parseInt(match[2], 10); dY = Number.parseInt(match[3], 10); } else if((match = ymdNumeric.exec(text)) !== null) { dM = Number.parseInt(match[2], 10) - 1; dD = Number.parseInt(match[3], 10); dY = Number.parseInt(match[1], 10); } else if((match = mdyString.exec(text)) !== null) { dM = month[match[1]]; dD = Number.parseInt(match[2], 10); dY = Number.parseInt(match[3], 10); } else if((match = dmyString.exec(text)) !== null) { dM = month[match[2]]; dD = Number.parseInt(match[1], 10); dY = Number.parseInt(match[3], 10); } else if((match = ymdString.exec(text)) !== null) { dM = month[match[2]]; dD = Number.parseInt(match[3], 10); dY = Number.parseInt(match[1], 10); } else if((match = ydmString.exec(text)) !== null) { dM = month[match[3]]; dD = Number.parseInt(match[2], 10); dY = Number.parseInt(match[1], 10); } if(isNil(match)) { if((match = mNumeric.exec(text)) !== null) { dM = Number.parseInt(match[1], 10) - 1; dY = 1000; dD = 1; } else if((match = mString.exec(text)) !== null) { dM = month[match[1]]; dY = 1000; dD = 1; } else if((match = myNumeric.exec(text)) !== null) { dM = Number.parseInt(match[1], 10) - 1; dY = Number.parseInt(match[2], 10); dD = 1; } else if((match = ymNumeric.exec(text)) !== null) { dM = Number.parseInt(match[2], 10) - 1; dY = Number.parseInt(match[1], 10); dD = 1; } else if((match = myString.exec(text)) !== null) { dM = month[match[1]]; dY = Number.parseInt(match[2], 10); dD = 1; } else if((match = ymString.exec(text)) !== null) { dM = month[match[2]]; dY = Number.parseInt(match[1], 10); dD = 1; } else if((match = yNumeric.exec(text)) !== null) { dM = 0; dY = Number.parseInt(match[1], 10); dD = 1; } else { //We have tried everything, so default to the built-in date parsing return new Date(Date.parse(text)); } } else { tH = isNil(match[4]) ? 0 : Number.parseInt(match[4], 10); tM = isNil(match[5]) ? 0 : Number.parseInt(match[5], 10); tS = isNil(match[6]) ? 0 : Number.parseInt(match[6], 10); tF = isNil(match[7]) ? 0 : Number.parseFloat(`0.${match[7]}`) * 1000; if(!isNil(match[8]) && match[8].toLowerCase() === 'p' && tH !== 12) tH += 12; else if(!isNil(match[8]) && match[8].toLowerCase() === 'a' && tH === 12) tH -= 12; if(!isNil(match[9])) { zH = isNil(match[10]) ? 0 : Number.parseInt(match[10], 10); zM = isNil(match[11]) ? 0 : Number.parseInt(match[11], 10); } } now.setFullYear(dY); now.setMonth(dM); now.setDate(dD); now.setHours(tH); now.setMinutes(tM); now.setSeconds(tS); now.setMilliseconds(tF); if(!isNil(zH) && !isNil(zM)) { zH += now.getTimezoneOffset() / 60; now.setMinutes( now.getMinutes() - (zH < 0 ? (zH * 60 - zM) : (zH * 60 + zM)) ); //Adjust the time zone } return now; } export default parseDate;