nuVistA/htdocs/fmdatetime.mjs

87 lines
4.7 KiB
JavaScript
Raw Permalink Normal View History

2023-04-24 23:10:19 -04:00
const re_dt_fileman = /(?<dt_fileman>(\d{3})(\d{2})(\d{2})(?:\.(\d{2})?(\d{2})?(\d{2})?)?)/i; // George Timson's format
const re_dt_today = /(?<dt_today>TODAY|T)/i; // today
const re_dt_now = /(?<dt_now>NOW|N)/i; // now
const re_dt_mdy = /(?<dt_mdy>(\d{1,2})[^\w@?]+(\d{1,2})[^\w@?]+(\d{4}|\d{2})\s*)/i; // m/d/yy, m/d/yyyy
const re_dt_ymd = /(?<dt_ymd>(\d{4})[^\w@?]+(\d{1,2})[^\w@?]+(\d{1,2})\s*)/i; // yyyy/m/d
const re_dt_yyyymmdd = /(?<dt_yyyymmdd>(\d{4})(\d{2})(\d{2}))/i; // yyyymmdd
const re_dt_Mdy = /(?<dt_Mdy>([A-Z]{3,})[^\w@?]+(\d{1,2})[^\w@?]+(\d{4}|\d{2})\s*)/i; // M/d/yy, M/d/yyyy
const re_dt_dMy = /(?<dt_dMy>(\d{1,2})[^\w@?]+([A-Z]{3,})[^\w@?]+(\d{4}|\d{2})\s*)/i; // d/M/yy, d/M/yyyy
const re_dt_md = /(?<dt_md>(\d{1,2})[^\w@?]+(\d{1,2})\s*)/i; // m/d
const re_dt_offset = /(?<offset>([-+]\d+)(H|W|M)?)/i; // +#U
const re_dt_time = /(?:\s?@?(?<time>(\d{1,2})\:?(\d{1,2})(?:\:?(\d{1,2}))?))/i; // time
const re_dt_ext = /(?<ext>[<>])/i; // (nonstandard extension)
const rx_dt = new RegExp(`^${re_dt_fileman.source}\$|^(?:(?:${re_dt_today.source}|${re_dt_now.source}|${re_dt_mdy.source}|${re_dt_ymd.source}|${re_dt_yyyymmdd.source}|${re_dt_Mdy.source}|${re_dt_dMy.source}|${re_dt_md.source})?${re_dt_offset.source}?${re_dt_time.source}?${re_dt_ext.source}?)\$`, 'i');
export function validtime(s) {
return rx_dt.test(s);
}
export function strptime(s) {
// Parse VistA-style datetime strings into Date objects
var m, m1;
if(m = rx_dt.exec(s.replace(/^\s+|\s+$/g, '').toLowerCase())) {
m = m.groups;
if(m.dt_fileman) {
m1 = re_dt_fileman.exec(m.dt_fileman);
return new Date(1700 + +m1[2], +m1[3] - 1, +m1[4], +m1[5] || 0, +m1[6] || 0, +m1[7] || 0);
}
var date = new Date(); date.setHours(0, 0, 0, 0);
if(m.dt_today) ;
else if(m.dt_now) date = new Date();
else if(m.dt_mdy) date.setFullYear(strptime_year(+(m1 = re_dt_mdy.exec(m.dt_mdy))[4], date), +m1[2] - 1, +m1[3]);
else if(m.dt_ymd) date.setFullYear(+(m1 = re_dt_ymd.exec(m.dt_ymd))[2], +m1[3] - 1, +m1[4]);
else if(m.dt_yyyymmdd) date.setFullYear(+(m1 = re_dt_yyyymmdd.exec(m.dt_yyyymmdd))[2], +m1[3] - 1, +m1[4]);
else if(m.dt_Mdy) date.setFullYear(strptime_year(+(m1 = re_dt_Mdy.exec(m.dt_Mdy))[4], date), strptime_month(m1[2]) - 1, +m1[3]);
else if(m.dt_dMy) date.setFullYear(strptime_year(+(m1 = re_dt_dMy.exec(m.dt_dMy))[4], date), strptime_month(m1[3]) - 1, +m1[2]);
else if(m.dt_md) { date.setMonth(+(m1 = re_dt_md.exec(m.dt_md))[2] - 1); date.setDate(+m1[3]); }
if(m.time) {
if(m.dt_now) throw 'cannot specify NOW with time';
date.setHours(+(m1 = re_dt_time.exec(m.time))[2], +m1[3], +m1[4] || 0);
}
if(m.offset) {
m1 = re_dt_offset.exec(m.offset);
if((m1[3] == 'h') && ((m.time) || (m.dt_today))) throw 'cannot specify time or TODAY with H offset'
date = strptime_offset(date, +m1[2], m1[3] || 'd');
}
if(m.ext) {
if(m.ext == '<') date.setHours(0, 0, 0, 0);
else if(m.ext == '>') date.setHours(23, 59, 59, 999);
}
if(date.year < 1800) throw 'cannot specify year before 1800';
return date;
}
}
function strptime_year(y, today) {
// Promote years to 4 digits
return y >= 1000 ? y : (y + 2000) < (today.getFullYear() + 20) ? (y + 2000) : (y + 1900);
}
const strptime_month_mapping = {'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6, 'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12};
function strptime_month(m) {
// Convert en-US month names to integers
return strptime_month_mapping[m.substring(0, 3)];
}
const strptime_offset_mapping = {'h': 60*60*1000, 'd': 24*60*60*1000, 'w': 7*24*60*60*1000, 'm': null};
function strptime_offset(base, offset, suffix) {
// Apply datetime offset
return suffix != 'm' ? new Date(base.getTime() + offset*strptime_offset_mapping[suffix]) : (base = new Date(base), base.setMonth(base.getMonth() + offset), base);
}
export function strftime(date) {
// Convert Date objects into conventional FileMan/Timson format
var d = '' + (date.getFullYear() - 1700) + ('00' + (date.getMonth() + 1)).slice(-2) + ('00' + date.getDate()).slice(-2);
var t = '' + ('00' + date.getHours()).slice(-2) + ('00' + date.getMinutes()).slice(-2) + ('00' + date.getSeconds()).slice(-2);
return t == '000000' ? d : (d + '.' + t);
}
export function datefloat(date) {
// Convert Python datetime.datetime objects into floating point FileMan/Timson format
var d = 10000*(date.getFullYear() - 1700) + 100*(date.getMonth() + 1) + date.getDate();
var t = date.getHours()/100 + date.getMinutes()/10000 + date.getSeconds()/1000000 + date.getMilliseconds()/1000000000;
return t == 0.0 ? d : (d + t);
}
export default window.fmdatetime = { validtime, strptime, strftime, datefloat };