How organize this function to work correctly? - javascript

I'm working on extending the date filter in my plugin Ideal Forms to allow the user to configure the date format, i.e. dd/mm/yyyy, mm-dd-yyyy... This is what I got so far:
date: {
regex: function (input, value) {
var
// Just grabbing some info from the plugin...
data = input.userOptions.data
? input.userOptions.data.date
: { format: 'mm/dd/yyyy' }, // default format
separator = '\\' + /[^mdy]/.exec(data.format)[0], // extract separator
userFormat = data.format.replace(/[^mdy]/g, ''), // convert to proper format
isDate = function (m, d, y) {
return m > 0 &&
m < 13 &&
y > 0 &&
y < 32768 &&
d > 0 &&
d <= (new Date(y, m, 0)).getDate()
},
n2 = '(\\d{1,2})', // day and month
n4 = '(\\d{4})', // year
format = {
'mmddyyyy': function () {
var re = new RegExp(n2 + separator + n2 + separator + n4),
m = re.exec(value)
return m && isDate(m[1], m[2], m[3])
},
'ddmmyyyy': function () {
var re = new RegExp(n2 + separator + n2 + separator + n4),
m = re.exec(value)
return m && isDate(m[2], m[1], m[3])
},
'yyyymmdd': function () {
var re = new RegExp(n4 + separator + n2 + separator + n2),
m = re.exec(value)
return m && isDate(m[2], m[3], m[1])
},
'yyyyddmm': function () {
var re = new RegExp(n4 + separator + n2 + separator + n2),
m = re.exec(value)
return m && isDate(m[3], m[2], m[1])
}
}
return format[userFormat]() || format['mmddyyyy']()
},
When using formats other that the default mm/dd/yyyy problems come since the function isDate tests the date starting with the month value, so when I pass a custom format like dd-mm-yyyy, the call isDate(m[2], m[1], m[3]) works but it will also validate values like 12-13-1986 but not 13-13-1986.
How can I begin fixing this? Any ideas?

EDIT
I wanted to address your comment regarding the return of isDate, too. The function behaves as expected, the problem is elsewhere. I haven't dissected your code enough to say where the bug is, but isDate is correct: http://jsfiddle.net/nQMYe/
Original Answer
I have had good luck with a variation of the snippet here: http://joey.mazzarelli.com/2008/11/25/easy-date-parsing-with-javascript/
Basically, it implements a fromString method in the Date object. I don't care for that approach, so I've modified my implementation to standalone as a function, and eliminated some of the unnecessary bits. That said, it works great.
The basic idea is to first normalize the input. Since you never know if the user is giving you a format like 1.11.2011 or 3~12~2012, first thing is to just strip away that noise:
data = data.replace(/[^:a-z0-9]/g, '-');
We're discarding all non alpha-numeric chars and dropping in a -, you seem to prefer / -- whatever, just get the input consistent-ish. We keep the alpha so we can deal with March 18, 2012 too.
The snippet then parses through the input, extracting time (if give, uses : to identify), then it establishes a year. As pointed out in the comments, the day and month are next to each other in most reasonable formats, so you're looking to establish what is NOT the year and going from there. It is then a process of elimination to determine the month, then the day.
Not my code, so I don't mean to take credit for the idea, but again, the thing delivers as advertised. You can either use it as-is (BSD license), or read through the source and dissect the concept.
Here is the code, for posterity:
/**
* #author Joey Mazzarelli
* #website http://bitbucket.org/mazzarelli/js-date/
* #website http://joey.mazzarelli.com/2008/11/25/easy-date-parsing-with-javascript/
* #copyright Joey Mazzarelli
* #license BSD license
*/
Date.fromString = (function () {
var defaults = {
order : 'MDY',
strict : false
};
var months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG",
"SEP", "OCT", "NOV", "DEC"];
var abs = ["AM", "PM", "AFTERNOON", "MORNING"];
var mark = function (str, val) {
var lval = val.toLowerCase();
var regex = new RegExp('^' + lval + '|(.*[^:alpha:])' + lval, 'g');
return str.replace(regex, '$1' + val);
};
var normalize = function (str) {
str = str.toLowerCase();
str = str.replace(/[^:a-z0-9]/g, '-');
for (var i=0; i<months.length; i++) str = mark(str, months[i]);
for (var i=0; i<abs.length; i++) str = mark(str, abs[i]);
str = str.replace(/[a-z]/g, '');
str = str.replace(/([0-9])([A-Z])/g, '$1-$2');
str = ('-' + str + '-').replace(/-+/g, '-');
return str;
};
var find_time = function (norm) {
var obj = {date:norm, time:''};
obj.time = norm.replace(
/^.*-(\d\d?(:\d\d){1,2}(:\d\d\d)?(-(AM|PM))?)-.*$/, '$1');
if (obj.time == obj.date)
obj.time = norm.replace(/^.*-(\d\d?-(AM|PM))-.*$/, '$1');
if (obj.time == obj.date) obj.time = '';
obj.date = norm.replace(obj.time, '');
obj.time = ('-' + obj.time + '-').replace(/-+/g, '-');
obj.date = ('-' + obj.date + '-').replace(/-+/g, '-');
return obj;
};
var find_year = function (norm) {
var year = null;
// Check for a 4-digit year
year = norm.replace(/^.*-(\d\d\d\d)-.*$/, '$1');
if (year != norm) return year; else year = null;
// Check for a 2-digit year, over 32.
year = norm.replace(/^.*-((3[2-9])|([4-9][0-9]))-.*$/, '$1');
if (year != norm) return year; else year = null;
// Day is always by month, so check for explicit months in
// first or third spot
year = norm.replace(/^.*-[A-Z]{3}-\d\d?-(\d\d?)-.*$/, '$1');
if (year != norm) return year; else year = null;
year = norm.replace(/^.*-(\d\d?)-\d\d?-[A-Z]{3}-.*$/, '$1');
if (year != norm) return year; else year = null;
// If all else fails, use the setting for the position of the year.
var pos = '$3';
if (defaults.opts.order.charAt(0) == 'Y') pos = '$1';
else if (defaults.opts.order.charAt(1) == 'Y') pos = '$2';
year = norm.replace(/^.*-(\d\d?)-([A-Z]{3}|\d{1,2})-(\d\d?)-.*$/, pos);
if (year != norm) return year; else year = null;
return year;
};
var find_month = function (norm, year) {
// Check for an explicity month
var matches = norm.match(/[A-Z]{3}/);
if (matches && matches.length) return matches[0];
// Remove the year, and unless obviously wrong, use order
// to chose which one to use for month.
var parts = norm.replace(year + '-', '').split('-');
if (parts.length != 4) return null;
var order = defaults.opts.order;
var md = order.indexOf('M') < order.indexOf('D')? 1: 2;
return (parseInt(parts[md], 10) <= 12)? parts[md]: parts[md==1? 2: 1];
};
var find_day = function (norm, year, month) {
return norm.replace(year, '').replace(month, '').replace(/-/g, '');
};
var create_absolute = function (obj) {
var time = obj.time.replace(/[-APM]/g, '');
var parts = time.split(':');
parts[1] = parts[1] || 0;
parts[2] = parts[2] || 0;
parts[3] = parts[3] || 0;
var ihr = parseInt(parts[0], 10);
if (obj.time.match(/-AM-/) && ihr == 12) parts[0] = 0;
else if (obj.time.match(/-PM-/) && ihr < 12) parts[0] = ihr + 12;
parts[0] = ("0" + parts[0]).substring(("0" + parts[0]).length - 2);
parts[1] = ("0" + parts[1]).substring(("0" + parts[1]).length - 2);
parts[2] = ("0" + parts[2]).substring(("0" + parts[2]).length - 2);
time = parts[0] + ":" + parts[1] + ":" + parts[2];
var millisecs = parts[3];
var strict = defaults.opts.strict;
if (!obj.year && !strict) obj.year = (new Date()).getFullYear();
var year = parseInt(obj.year, 10);
if (year < 100) {
year += (year<70? 2000: 1900);
}
if (!obj.month && !strict) obj.month = (new Date()).getMonth() + 1;
var month = String(obj.month);
if (month.match(/[A-Z]{3}/)) {
month = "JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-"
.indexOf(month) / 4 + 1;
}
month = ("0" + month).substring(("0" + month).length - 2);
if (!obj.day && !strict) obj.day = (new Date()).getDate();
var day = ("0" + obj.day).substring(("0" + obj.day).length - 2);
var date = new Date();
date.setTime(Date.parse(year + '/' + month + '/' + day + ' ' + time));
date.setMilliseconds(millisecs);
return date;
};
var parse = function (norm) {
return absolute(norm);
};
var absolute = function (norm) {
var obj = find_time(norm);
obj.norm = norm;
obj.year = find_year(obj.date);
obj.month = find_month(obj.date, obj.year);
obj.day = find_day(obj.date, obj.year, obj.month);
return create_absolute(obj);
};
return function (fuzz, opts) {
defaults.opts = { order: defaults.order, strict: defaults.strict };
if (opts && opts.order) defaults.opts.order = opts.order;
if (opts && opts.strict != undefined) defaults.opts.strict = opts.strict;
var date = parse(normalize(fuzz));
return date;
};
})();

Related

Expected identifier in array variable

I still need my function to work in internet explorer for compatibility reasons. The rest of the browsers support my array variable: var [sHour, sMinute, sSecond] but internet explorer does not. below is my full function.
function time_interval(start, end) {
var [sHour, sMinute, sSecond] = start.split(":");
var [eHour, eMinute, eSecond] = end.split(":");
var s = new Date();
s.setHours(sHour, sMinute, sSecond);
var e = new Date();
e.setHours(eHour, eMinute, eSecond);
var a;
if (s.getTime() < e.getTime()) {
a = e.getTime() - s.getTime();
} else {
e.setDate(e.getDate() + 1);
a = e.getTime() - s.getTime();
}
a = a / 1000;
var h = Math.floor(a / 3600);
var m = Math.floor((a % 3600) / 60);
var s = a % 60;
return (
(h ? h + ' hour ' : '') +
(m ? m + ' minute ' : '') +
(s ? s + ' second ' : '')
).trim();
}
const example = time_interval("10:00:00", "10:30:00");
console.log(example);
an example of the values taken by my array var is for instance, 10:30:00. This is why I added .split. How do I separate the arrays so that it is compatible and remove the Expected identifier error? I tried separating it in single variables but this does not work because of the split.
var sHour
var sMinute
var sSecond
Any help would be appreciated.
It's not the ideal solution, but you could just refactor your code like this:
var splitStart = start.split(":");
var sHour = splitStart[0];
var sMinute = splitStart[1];
var sSecond = splitStart[2];
You could also consider using a function and an object:
function convertTimeArrayToObject(arr) {
return {
hour: arr[0],
minute: arr[1],
second: arr[2]
}
}
var startObject = convertTimeArrayToObject(start.split(":"));
console.log(startObject.hour) // Will print the hour

Javascript convert date to roman date

I have the following code that converts a date input into a roman date:
function romanize (num) {
if (!+num)
return false;
var digits = String(+num).split(""),
key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
"","I","II","III","IV","V","VI","VII","VIII","IX"],
roman = "",
i = 3;
while (i--)
roman = (key[+digits.pop() + (i * 10)] || "") + roman;
return Array(+digits.join("") + 1).join("M") + roman;
}
$(document).on("change",'#date', function() {
var date = new Date($('#date').val());
day = date.getDate();
month = date.getMonth() + 1;
year = date.getFullYear();
var strRomanDate = romanize(month) + " " + romanize(day) + " " + romanize(year);
$('#romandate .date').html(strRomanDate);
});
Now, this is working fine for some dates, for ex:
10/04/2018 --> X IV MMXVIII
But when I want to select a day after 12, so 13, 14,... It returns false false false.
Anyone have an idea what I should change in my code to make it work for every date?

Calculate time difference and sum the difference using Javascript

i am trying to find the difference for end time and start time, followed by adding all the time difference
may i know how can i do so?
the code is as followed
function THcheck() {
var a, s, timeDiff, hr = 0;
var hdate, startTime, endTime, totalTime, timeDiff;
var output = "Date StartTime: EndTime: TimeDiff <br>";
var msg = "";
var DStime, DEtime;
var e = document.getElementsByTagName('input');
for (a = 0; e !== a; a++) {
if (e[a].type == "time" && e[a].name == "THStime[]") {
if (e[a].value && e[a].value !== "") {
startTime = e[a].value;
endTime = e[a + 1].value;
hdate = e[a - 1].value
alert(hdate + " " + startTime + " " + endTime);
timeDiff = endTime - startTime;
alert(timeDiff);
hr = parseInt(timeDiff.asHours());
alert(timeDiff);
totalTime += timeDiff;
alert(totalTime);
output += hdate + " " + startTime + " " + endTime + " " + timeDiff + "<br>";
if (hr >= 24) {
msg = "<br> Exceed 24 hrs! ";
}
}
}
}
alert(output + " Total time: " + totalTime + msg);
return true;
}
thanks in advance for your kind assistance and help on this!
I think you need to parse the hours first, converting from string to date and then convert the dates to milliseconds and use the milliseconds for the difference calculation. After this you convert the difference milliseconds into hours.
Here is some sample code which performs these steps:
const dateRegex = /(\d{2}):(\d{2})/;
function diffDatesInHours(d1Str, d2Str) {
const r1 = dateRegex.exec(d1Str);
const r2 = dateRegex.exec(d2Str);
if (!checkDate(r1)) {
console.log("First date format incorrect: " + d1Str);
return null;
}
if (!checkDate(r2)) {
console.log("Second date format incorrect: " + d2Str);
return null;
}
const d1 = createDateFrom(r1);
const d2 = createDateFrom(r2);
const diff = d1.getTime() - d2.getTime();
return Math.abs(diff) / (1000 * 60 * 60);
}
function checkDate(r) {
if (r === null) {
return null;
}
return r.length > 0;
}
function createDateFrom(r) {
let date = new Date();
date.setHours(r[1], r[2]);
return date;
}
console.log(diffDatesInHours("09:30", "21:00"));
console.log(diffDatesInHours("09:30", "21:"));

Cumbersome time parsing in JavaScript

I need a function to convert time in text from a format with day-part letters to digits.
E.g. 4:15PM -> 16:15, 4:15AM -> 4:15AM. Currently I have the following solution
function formatTime(text){
var find = '([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9] (AM|PM)';
var reg = new RegExp(find, 'g');
pos = 0;
var result;
var formatedText = "";
while((result = reg.exec(text)) !== null) {
if(result[2] == "PM"){
var hours= parseInt(result[0], 10);
hours = hours + 12;
var hoursStr = hours.toString();
var newTime = hoursStr + result[0].substring(result[1].length,result[0].length - 3);
formatedText += newTime;
pos = reg.lastIndex;
} else {
formatedText += text.replace("AM","").substring(pos, reg.lastIndex);
pos = reg.lastIndex;
}
}
if(pos < text.length){
formatedText += text.substring(pos, text.length);
}
return formatedText;
}
console.log(formatTime("Some Text (11:00AM - 1:00PM)"));
I makes nicely cases like
console.log(formatTime("Some Text (11:00AM - 1:00PM)"));
But I strugle to make it process
console.log(formatTime("Some Text (11:00 AM - 1:00 PM)"));
This works for your examples.
I've added \\s? to the regex and made a minor change in the logic of cutting time (-2 instead of -3). Also I've moved variables definition to the beginning of the function to reflect hoisting in JavaScript.
function formatTime(text){
var find = '([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]\\s?(AM|PM)';
var reg = new RegExp(find, 'g');
var pos = 0;
var formatedText = "";
var result, hours, hoursStr, newTime;
while ((result = reg.exec(text)) !== null) {
if (result[2] === "PM") {
hours= parseInt(result[0], 10);
hours = hours + 12;
hoursStr = hours.toString();
newTime = hoursStr + result[0].substring(result[1].length, result[0].length - 2);
formatedText += newTime;
} else {
formatedText += text.replace("AM","").substring(pos, reg.lastIndex);
}
pos = reg.lastIndex;
}
if (pos < text.length) {
formatedText += text.substring(pos, text.length);
}
return formatedText;
}
Here's an easier way to do this: Just use two functions. One to convert the hours, and another to match against PM times along with the replace() function.
Easy does it...
function convertTime12to24(time12h) {
const [time, modifier] = time12h.split(' ');
let [hours, minutes] = time.split(':');
if (hours === '12') {
hours = '00';
}
if (modifier === 'PM') {
hours = parseInt(hours, 10) + 12;
}
return hours + ':' + minutes;
}
function formatTime(i_string) {
console.log(i_string.replace(/([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])(PM)/gi, function newDate(x) {
return convertTime12to24(x.replace("PM", " PM"))
}));
}
formatTime("The time is now 4:15PM");
formatTime("The time is now 12:15PM");
formatTime("The time is now 4:00AM");
formatTime("The time is now 12:00AM");
formatTime("The time is now 11:00PM");

Amending the function to calculate into the new year and not return the value 12/33/2014

I need your help.
It seems that the function this_week('end') is returning a bad date of 12/33/2014 (mm/dd/yyyy) where it should properly read:
01/02/2015
function this_week(x) {
var today, todayNumber, fridayNumber, sundayNumber, monday, friday;
today = new Date();
todayNumber = today.getDay();
mondayNumber = 1 - todayNumber;
fridayNumber = 5 - todayNumber;
if (x === 'start') {
//var start_dd = today.getDate() + mondayNumber
var start_dd = today.getDate()
var start_mm = today.getMonth() + 1
var start_yyyy = today.getFullYear()
return start_mm + '/' + start_dd + '/' + start_yyyy
}
if (x === 'end') {
var end_dd = today.getDate() + fridayNumber
var end_mm = today.getMonth() + 1
var end_yyyy = today.getFullYear()
return end_mm + '/' + end_dd + '/' + end_yyyy
}
}
What needs to be done?
You have to use Date objects when increasing or decreasing the date..
function this_week(x) {
var date, todayNumber, fridayNumber;
date = new Date();
todayNumber = date .getDay();
mondayNumber = 1 - todayNumber;
fridayNumber = 5 - todayNumber;
if (x === 'start') {
date.setDate(date.getDate()+ mondayNumber);
}
else if (x === 'end') {
date.setDate(date.getDate()+ fridayNumber);
}
var end_dd = date.getDate().toString();
end_dd = (end_dd.length == 2)?end_dd:"0"+end_dd;
var end_mm = (date.getMonth() + 1).toString();
end_mm = (end_mm.length == 2)?end_mm:"0"+end_mm;
var end_yyyy = date.getFullYear().toString();
return end_mm + '/' + end_dd + '/' + end_yyyy;
}
document.write(this_week('end'));
Note that the month code for January is 0
For a much simpler version:
function this_week(x,d) {
var d = d || new Date(),
offset = 0;
switch (x){
case 'start':
offset = 1 - d.getDay();
break;
case 'end':
offset = 5 - d.getDay();
break;
}
d.setDate(d.getDate() + offset);
return d;
}
var oE = document.getElementById('o'),
tE = document.getElementById('t');
function $log(t){ oE.innerHTML += (t || '') + "\r\n"; }
function $fmt(d){ return [d.getMonth() + 1, d.getDate(), d.getFullYear() ].map(function(v){ return v < 10 ? '0' + v : v; }).join('/'); }
function c(el){ try { var d = new Date(el.value); tE.innerHTML = 'Start: ' + $fmt(this_week('start',d)) + '; End: ' + $fmt(this_week('end',d)); } catch (e) { tE.innerHTML = 'Invalid Date'; } }
$log( 'Fixed dates' );
var ds = [
new Date(2014, 12 - 1, 29),
new Date(2015, 1 - 1, 1)
];
for (var i = 0; i < ds.length; i++){
$log( $fmt(ds[i]) + ' start » ' + $fmt(this_week('start', ds[i])) );
$log( $fmt(ds[i]) + ' end » ' + $fmt(this_week('end', ds[i])) );
}
$log();
$log( 'Based on today:' );
$log( $fmt(this_week('start')) );
$log( $fmt(this_week('end')) );
$log();
$log('::All dates in mm/dd/yyyy format::');
<pre id="o"></pre>
<hr />
<input type="text" onchange="c(this);" placeholder="try me"><button>Try</button><span id="t"></span>
Assuming that a complete week may start on sunday or on monday, this function covers both:
function this_week(start, givendate, weekStartsOnsunday) {
givendate = givendate && givendate instanceof Date ? givendate : new Date;
var today = givendate.getDay(),
isSunday = !weekStartsOnsunday && today < 1,
diff = !start
? (isSunday ? -2 : (5 - today))
: (isSunday ? -6 : (1 - today));
// set date to begin/end of week and return it formatted
return (givendate.setDate(givendate.getDate() + diff), format(givendate));
}
// format mm/dd/yyyy with leading zero's using an Array and Array.map
function format(date) {
return [ date.getDate(),
date.getMonth()+1,
date.getFullYear()
].map(function (v) {return v <10 ? '0'+v : v;})
.join('/');
}
var log = Helpers.log2Screen;
// today and week starts on monday
log('`this_week()`: ', this_week());
log('`this_week(true)`: ',this_week(true));
// given date is sunday, week starts on monday
log('`this_week(false, new Date(\'2015/01/04\'))`: ',
this_week(false, new Date('2015/01/04')), ' (week ends on sunday)');
log('`this_week(true, new Date(\'2015/01/04\'))`: ',
this_week(true, new Date('2015/01/04')), ' (week ends on sunday)');
// given date is sunday, week starts on sunday
log('`this_week(false, new Date(\'2015/01/04\'), true)`: ',
this_week(false, new Date('2015/01/04'), true), ' (week starts on sunday)')
log('`this_week(true, new Date(\'2015/01/04\'), true)`: ',
this_week(true, new Date('2015/01/04'), true), ' (week starts on sunday)');
<script src="http://kooiinc.github.io/JSHelpers/Helpers-min.js"></script>

Categories