Created
November 3, 2016 06:13
-
-
Save jasonsperske/d4e6b35dd2bcb1aaf0206e8f6e615b7f to your computer and use it in GitHub Desktop.
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
function Parser() { | |
var int = function(n) { | |
//keep code readable | |
return parseInt(n, 10); | |
}; | |
var def = function(field, source, defaults) { | |
return source[field] ? source[field] : (defaults ? defaults[field] : undefined); | |
}; | |
var pad = function(number) { | |
if (number < 10) { | |
return '0' + number; | |
} | |
return number; | |
}; | |
var military_hour = function(hour, meridian) { | |
if(meridian === 'PM' && hour < 12) { | |
return hour + 12; | |
} else if(meridian === 'AM' && hour === 12) { | |
return 0; | |
} else { | |
return hour; | |
} | |
}; | |
var months = { | |
"JAN": 1, | |
"FEB": 2, | |
"MAR": 3, | |
"APR": 4, "API": 4, | |
"MAY": 5, | |
"JUN": 6, | |
"JUL": 7, | |
"AUG": 8, | |
"SEP": 9, | |
"OCT": 10, | |
"NOV": 11, | |
"DEC": 12 | |
}; | |
//Data extracted from: https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations | |
//"ACT" defies reason and was omitted, | |
var timezones = { | |
"ACDT": 10.5, | |
"ACST": 9.5, | |
"ADT": -3, | |
"AEDT": 11, | |
"AEST": 10, | |
"AFT": 4.5, | |
"AKDT": -8, | |
"AKST": -9, | |
"AMST": -3, | |
"AMT": 4, | |
"ART": -3, | |
"AST": -4, | |
"AWST": 8, | |
"AZOST": 0, | |
"AZOT": -1, | |
"AZT": 4, | |
"BDT": 8, | |
"BIOT": 6, | |
"BIT": -12, | |
"BOT": -4, | |
"BRST": -2, | |
"BRT": -3, | |
"BST": 1, | |
"BTT": 6, | |
"CAT": 2, | |
"CCT": 6.5, | |
"CDT": -4, | |
"CEST": 2, | |
"CET": 1, | |
"CHADT": 13.75, | |
"CHAST": 12.75, | |
"CHOT": 8, | |
"CHOST": 9, | |
"CHST": 10, | |
"CHUT": 10, | |
"CIST": -8, | |
"CIT": 8, | |
"CKT": -10, | |
"CLST": -3, | |
"CLT": -4, | |
"COST": -4, | |
"COT": -5, | |
"CST": -5, | |
"CT": 8, | |
"CVT": -1, | |
"CWST": 8.75, | |
"CXT": 7, | |
"DAVT": 7, | |
"DDUT": 10, | |
"DFT": 1, | |
"EASST": -5, | |
"EAST": -6, | |
"EAT": 3, | |
"ECT": -5, | |
"EDT": -4, | |
"EEST": 3, | |
"EET": 2, | |
"EGST": 0, | |
"EGT": -1, | |
"EIT": 9, | |
"EST": -5, | |
"FET": 3, | |
"FJT": 12, | |
"FKST": -3, | |
"FKT": -4, | |
"FNT": -2, | |
"GALT": -6, | |
"GAMT": -9, | |
"GET": 4, | |
"GFT": -3, | |
"GILT": 12, | |
"GIT": -9, | |
"GMT": 0, | |
"GST": 4, | |
"GYT": -4, | |
"HADT": -9, | |
"HAEC": 2, | |
"HAST": -10, | |
"HKT": 8, | |
"HMT": 5, | |
"HOVST": 8, | |
"HOVT": 7, | |
"ICT": 7, | |
"IDT": 3, | |
"IOT": 3, | |
"IRDT": 4.5, | |
"IRKT": 8, | |
"IRST": 3.5, | |
"IST": 2, | |
"JST": 9, | |
"KGT": 6, | |
"KOST": 11, | |
"KRAT": 7, | |
"KST": 9, | |
"LHST": 11, | |
"LINT": 14, | |
"MAGT": 12, | |
"MART": -9.5, | |
"MAWT": 5, | |
"MDT": -6, | |
"MET": 1, | |
"MEST": 2, | |
"MHT": 12, | |
"MIST": 11, | |
"MIT": -9.5, | |
"MMT": 6.5, | |
"MSK": 3, | |
"MST": -7, | |
"MUT": 4, | |
"MVT": 5, | |
"MYT": 8, | |
"NCT": 11, | |
"NDT": -2.5, | |
"NFT": 11, | |
"NPT": 5.75, | |
"NST": -3.5, | |
"NT": -3.5, | |
"NUT": -11, | |
"NZDT": 13, | |
"NZST": 12, | |
"OMST": 6, | |
"ORAT": 5, | |
"PDT": -7, | |
"PET": -5, | |
"PETT": 12, | |
"PGT": 10, | |
"PHOT": 13, | |
"PKT": 5, | |
"PMDT": -2, | |
"PMST": -3, | |
"PONT": 11, | |
"PST": 8, | |
"PYST": -3, | |
"PYT": -4, | |
"RET": 4, | |
"ROTT": -3, | |
"SAKT": 11, | |
"SAMT": 4, | |
"SAST": 2, | |
"SBT": 11, | |
"SCT": 4, | |
"SGT": 8, | |
"SLST": 5.5, | |
"SRET": 11, | |
"SRT": -3, | |
"SST": 8, | |
"SYOT": 3, | |
"TAHT": -10, | |
"THA": 7, | |
"TFT": 5, | |
"TJT": 5, | |
"TKT": 13, | |
"TLT": 9, | |
"TMT": 5, | |
"TRT": 3, | |
"TOT": 13, | |
"TVT": 12, | |
"ULAST": 9, | |
"ULAT": 8, | |
"USZ1": 2, | |
"UTC": 0, | |
"UYST": -2, | |
"UYT": -3, | |
"UZT": 5, | |
"VET": -4, | |
"VLAT": 10, | |
"VOLT": 4, | |
"VOST": 6, | |
"VUT": 11, | |
"WAKT": 12, | |
"WAST": 2, | |
"WAT": 1, | |
"WEST": 1, | |
"WET": 0, | |
"WIT": 7, | |
"WST": 8, | |
"YAKT": 9, | |
"YEKT": 5 | |
}; | |
var adjust = function(moment, offset) { | |
var adjusted = moment, | |
d; | |
//Timezone offets are never longer than ± 13.75 | |
adjusted.minute = moment.minute + (offset * 60); | |
adjusted.hour = adjusted.hour + Math.floor(adjusted.minute/60); | |
adjusted.minute = adjusted.minute - (Math.floor(adjusted.minute/60) * 60); | |
//the Date object understands leap year and verious details about the | |
//gregorian calendar, so lets take advantage of this | |
d = new Date(Date.UTC(adjusted.year, adjusted.month -1, adjusted.day, adjusted.hour, adjusted.minute, 0)); | |
adjusted.year = d.getUTCFullYear(); | |
adjusted.month = d.getUTCMonth()+1; | |
adjusted.day = d.getUTCDate(); | |
adjusted.hour = d.getUTCHours(); | |
adjusted.minute = d.getUTCMinutes(); | |
return adjusted; | |
}; | |
var patterns = { | |
Val_Val_YYYY: { | |
re: /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/, | |
parse: function(a, b, year) { | |
//We can't tell if it's day/month or month/day | |
if(a > 12) { | |
//A can't be month | |
return { year: int(year), month: int(b), day: int(a) }; | |
} else if (b > 12) { | |
//B can't be month | |
return { year: int(year), month: int(a), day: int(b) }; | |
} else { | |
//Can't tell so pick based US format | |
return { year: int(year), month: int(a), day: int(b) }; | |
} | |
} | |
}, | |
YYYYMMDD: { | |
re: /^(\d{4})(?:\.?)(\d{2})(?:\.?)(\d{2})$/, | |
parse: function(year, month, day) { | |
return { year: int(year), month: int(month), day: int(day) }; | |
} | |
}, | |
Month_DD_YYYY: { | |
re: /(\w+) (\d{1,2})(?:,) (\d{4})$/, | |
parse: function(month, day, year) { | |
return { year: int(year), month: months[(month.substring(0,3).toUpperCase())], day: int(day) }; | |
} | |
}, | |
DD_Month_YYYY: { | |
re: /(\d{1,2}) (\w+) (\d{4})$/, | |
parse: function(day, month, year) { | |
return { year: int(year), month: months[(month.substring(0,3).toUpperCase())], day: int(day) }; | |
} | |
}, | |
Month_YYYY: { | |
re: /^(\w+), (\d{4})$/, | |
parse: function(month, year) { | |
return { year: int(year), month: months[(month.substring(0,3).toUpperCase())] }; | |
} | |
}, | |
Month_DD: { | |
re: /^(\w+) (\d{1,2})$/, | |
parse: function(month, day) { | |
return { day: int(day), month: months[(month.substring(0,3).toUpperCase())] }; | |
} | |
}, | |
HH_MM_SS_meridian: { | |
re: /^(\d{1,2}):(\d{2}):(\d{2}) (AM|PM)$/, | |
parse: function(hour, minute, second, meridian) { | |
return { hour: military_hour(int(hour), meridian.toUpperCase()), minute: int(minute), second: int(second) }; | |
} | |
}, | |
Month_DD_YYYY_HH_MM_SS_meridian: { | |
re: /^(?:\w+)(?:,)? (\w*) (\d{1,2}), (\d{4}) (\d{1,2}):(\d{2})(?::(\d{2}))? (AM|PM)$/, | |
parse: function(month, day, year, hour, minute, second, meridian) { | |
return { day: int(day), month: months[(month.substring(0,3).toUpperCase())], year: int(year), hour: military_hour(int(hour), meridian.toUpperCase()), minute: int(minute), second: int(second) }; | |
} | |
}, | |
DD_Month_YYYY_HH_MM_SS_meridian: { | |
re: /^(?:\w+) (\d{1,2})(?:th|st|nd) of (\w+) (\d{4}) (\d{1,2}):(\d{2})(?::(\d{2}))? (AM|PM)$/, | |
parse: function(day, month, year, hour, minute, second, meridian) { | |
return { day: int(day), month: months[(month.substring(0,3).toUpperCase())], year: int(year), hour: military_hour(int(hour), meridian.toUpperCase()), minute: int(minute), second: int(second) }; | |
} | |
}, | |
MM_DD_YYYY_HH_MM_SS_meridian: { | |
re: /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{2})(?::(\d{2}))? (AM|PM)$/, | |
parse: function(month, day, year, hour, minute, second, meridian) { | |
return { day: int(day), month: int(month), year: int(year), hour: military_hour(int(hour), meridian.toUpperCase()), minute: int(minute), second: int(second) }; | |
} | |
}, | |
YYYY_MM_DD_HH_MM_SS: { | |
re: /^(\d{4})(\d{2})(\d{2}) (\d{1,2}):(\d{2})(?::(\d{2}))?/, | |
parse: function(year, month, day, hour, minute, second) { | |
return { day: int(day), month: int(month), year: int(year), hour: int(hour), minute: int(minute), second: int(second) }; | |
} | |
}, | |
DD_Mon_YYYY_HH_MM_SS_TZabbv: { | |
re: /^(?:\w+), (\d{1,2}) (\w+) (\d{4}) (\d{1,2}):(\d{2})(?::(\d{2}))? (\w+)$/, | |
parse: function(day, month, year, hour, minute, second, tz_abbv) { | |
var moment = { | |
day: int(day), | |
month: months[(month.substring(0,3).toUpperCase())], | |
year: int(year), | |
hour: int(hour), | |
minute: int(minute), | |
second: int(second) | |
}; | |
return adjust(moment, timezones[tz_abbv.toUpperCase()]); | |
} | |
}, | |
DD_Mon_YYYY_HH_MM_SS_TZoffset: { | |
re: /^(?:\w+), (\d{1,2}) (\w+) (\d{4}) (\d{1,2}):(\d{2})(?::(\d{2}))? (-|\+)(\d{2})(\d{2})$/, | |
parse: function(day, month, year, hour, minute, second, tz_direction, tz_offset_hours, tz_offset_minutes) { | |
var moment = { | |
day: int(day), | |
month: months[(month.substring(0,3).toUpperCase())], | |
year: int(year), | |
hour: int(hour), | |
minute: int(minute), | |
second: int(second) | |
}, | |
offset = int(tz_offset_hours); | |
switch (tz_offset_minutes) { | |
case '15': offset += 0.25; break; | |
case '30': offset += 0.5; break; | |
case '45': offset += 0.75; break; | |
} | |
if(tz_direction === '-') { | |
offset = offset * -1; | |
} | |
return adjust(moment, offset); | |
} | |
}, | |
YYYY_DD_MM_HH_MM_SS_TZoffset: { | |
re: /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(-|\+)(\d{2}):(\d{2})$/, | |
parse: function(year, day, month, hour, minute, second, tz_direction, tz_offset_hours, tz_offset_minutes) { | |
var moment = { | |
day: int(day), | |
month: int(month), | |
year: int(year), | |
hour: int(hour), | |
minute: int(minute), | |
second: int(second) | |
}, | |
offset = int(tz_offset_hours); | |
switch (tz_offset_minutes) { | |
case '15': offset += 0.25; break; | |
case '30': offset += 0.5; break; | |
case '45': offset += 0.75; break; | |
} | |
if(tz_direction === '-') { | |
offset = offset * -1; | |
} | |
return adjust(moment, offset); | |
} | |
} | |
}; | |
return function(input, defaults) { | |
for (var pattern in patterns) { | |
if (patterns.hasOwnProperty(pattern)) { | |
if(patterns[pattern].re.test(input)) { | |
var parsed = patterns[pattern].parse.apply(this, patterns[pattern].re.exec(input).splice(1)); | |
//Fill in any missing defaults | |
parsed.year = def('year', parsed, defaults); | |
parsed.month = def('month', parsed, defaults); | |
parsed.day = def('day', parsed, defaults); | |
parsed.hour = def('hour', parsed, defaults); | |
parsed.minute = def('minute', parsed, defaults); | |
parsed.second = def('second', parsed, defaults); | |
parsed.date = new Date(Date.UTC(parsed.year, parsed.month-1, parsed.day, parsed.hour, parsed.minute, parsed.second)); | |
return parsed; | |
} | |
} | |
} | |
}; | |
} | |
var inputs = [//Date Only | |
"3/20/2016", //Val_Val_YYYY | |
"20/03/2016", | |
"20160320", //YYYYMMDD | |
"2016.03.20", | |
"March 20, 2016", //Month_DD_YYYY | |
"Sunday, MAR 20, 2016", | |
"Sunday, March 20, 2016", | |
"20 March 2016", //DD_Month_YYYY | |
//Month/Year Only format | |
"March, 2016", //Month_YYYY | |
//Month/Day Only format | |
"March 20", //Month_DD | |
//Time Only format | |
"4:05:07 PM", //HH_MM_SS_meridian | |
// Full formats | |
"Sunday, March 20, 2016 4:05 PM", //Month_DD_YYYY_HH_MM_SS_meridian | |
"Sunday, March 20, 2016 4:05:07 PM", | |
"Sunday 20th of March 2016 04:05:07 PM",//DD_Month_YYYY_HH_MM_SS_meridian | |
"3/20/2016 4:05 PM", //MM_DD_YYYY_HH_MM_SS_meridian | |
"3/20/2016 4:05:07 PM", | |
"20160320 16:05:07", //YYYY_MM_DD_HH_MM_SS | |
// Full with timezone | |
"Sun, 20 Mar 2016 16:05:07 GMT", //DD_Mon_YYYY_HH_MM_SS_TZabbv | |
"Sun, 20 Mar 2016 4:05:07 MART", //DD_Mon_YYYY_HH_MM_SS_TZabbv | |
"Sun, 20 Mar 2016 16:05:07 -0800", //DD_Mon_YYYY_HH_MM_SS_TZoffset | |
"Sun, 1 Mar 2016 2:05:07 -0800", //DD_Mon_YYYY_HH_MM_SS_TZoffset | |
"2016-20-03T16:05:07-08:00"]; //YYYY_DD_MM_HH_MM_SS_TZoffset | |
var parse = new Parser(); | |
inputs.forEach(function(input) { | |
var now = new Date(), | |
defaults_now = { //Using this exact moment for any missing information | |
year: now.getUTCFullYear(), | |
month: now.getUTCMonth() + 1, | |
day: now.getUTCDate(), | |
hour: now.getUTCHours(), | |
minute: now.getUTCMinutes(), | |
second: now.getUTCSeconds() | |
}, | |
defaults_logical = { //Using this exact moment for any missing information | |
year: now.getUTCFullYear(), | |
month: now.getUTCMonth() + 1, | |
day: 1, | |
hour: 0, | |
minute: 0, | |
second: 0 | |
}, | |
defaults_starwars = { //Using the day Star Wars:A New Hope was released in theaters | |
year: 1977, | |
month: 5, | |
day: 25, | |
hour: 0, | |
minute: 0, | |
second: 0 | |
}; | |
console.log(parse(input, defaults_logical).date.toISOString()+' from "'+input+'"'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment