@technobuddha/library
Version:
A large library of useful functions
153 lines (152 loc) • 5.66 kB
JavaScript
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, ...args) {
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) {
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;
let zM = null;
text = text.toLowerCase();
let match;
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;