i have an array of user selected days, presented as such:
days_selected[1] = true;
days_selected[2] = false;
days_selected[3] = false;
days_selected[4] = true;
days_selected[5] = true;
days_selected[6] = true;
days_selected[7] = true;
Key presents weekday, and true/false presents if the user checked the day
now, i have the current weekday,
date_now.getDay()
Lets say the current weekday is monday, 1 i need to find the amount of days between monday and the first day which is marked as true;
I know i could simply loop the days, find the current day, and keep looping until i stumble on another true day, and then subtract the values, but how do i count in day 6 being true, while day 7 and day 1 are false, in that case, it would also be 2 days in between, i am horrible at math :-)
passed = false;
day = 0;
$.each( days_selected, function( key, value ) {
if (passed == true && value == true) {
day = key;
return false;
}
if (key == date_now.getDay()) {
passed = true;
}
});
What about this? (assuming indexes starting at 0)
var today = date_now.getDay()
, i = today + 1;
while (i % 7 != today && !days_selected[i % 7]) {
i += 1;
}
var interval = i - today - 1;
Check http://jsbin.com/jozotoke/1/edit
How about something like
function nextTrue(arr, selected, toCheck) {
var first = arr.indexOf(toCheck, selected+1),
res = first > selected ? first : arr.indexOf(toCheck);
return Math.abs(res - selected);
}
to be used as
var diff = nextTrue(days_selected, date_now.getDay(), true);
FIDDLE
Related
I have 2 different times:
var shiftStartTime = "05:48";
var shiftEndTime = "14:29";
And i have another time which is selectedDate ="06:20"(this will change according datetimepicker selection), and i want to check if selectedDate should be between (shiftStartTime and shiftEndTime ).
Can anyone help in this?
Updated Code:
i have 6 different timespan like below
var shift1StartTime = "05:48";
var shift1EndTime = "14:18";
var shift2StartTime = "14:30";
var shift2EndTime = "22:29";
va
r shift3StartTime = "22:30";
var shift3EndTime = "05:47";
using all 6 timespan i want to check the if the given time is between (shift1StartTime and shift1EndTime) return shift1
Or
if the given time is between (shift2StartTime and shift2EndTime) return shift2
Or
if the given time is between (shift3StartTime and shift3EndTime) return shift3
Simply compare the strings like
var shiftStartTime = "05:48"; var shiftEndTime = "14:29";
shiftStartTime > shiftEndTime // false
Here is some JS that does this, although better formatted time would make it a lot easier
function findTotalTime(time) {
hours = parseInt(time.substring(0,2))
mins = parseInt(time.substring(3,5))
return (hours*60) + mins
}
startTime = findTotalTime(shiftStartTime)
endTime = findTotalTime(shiftEndTime)
selectedTime = findTotalTime(selectedDate)
if (selectedTime > startTime && selectedTime < endTime) {
// time is inbetween shifts
}
const date = new Date();
const shiftStartTime = '05:48';
const shiftEndTime = '14:29';
const selectedDate = '14:20';
const start = date.setHours(+shiftStartTime.split(':')[0], +shiftStartTime.split(':')[1], 0, 0);
const end = date.setHours(+shiftEndTime.split(':')[0], +shiftEndTime.split(':')[1], 0, 0);
const selected = date.setHours(+selectedDate.split(':')[0], +selectedDate.split(':')[1], 0, 0);
if (start < selected && selected < end) {
console.log(true);
} else {
console.log(false);
}
Alright, so you got three relative times as strings in the format HH:mm. I'm assuming that your times are given as 24h strings / military time, because otherwise, you'd need an A.M. / P.M. specifier.
It is always useful to have the data you are working with in a well-suited machine-readable format, so you could parse them into a simple object holding the hour and minute as numbers.
A function doing this could look like this.
function parseTimeStr(time) {
// The pattern of your input,
// allows spaces around the `:`
// and single-digit inputs like `8:00`
let re = /([0-9][0-9]?)\s*:\s*([0-9][0-9]?)/;
let result = re.exec(time.trim());
if (result === null) {
throw "No match"
}
let hour = parseInt(result[1], 10);
let minute = parseInt(result[2], 10);
/* handle out of range values here */
return { hour, minute };
}
Alright, so you have these objects now. How do you compare them? There's a pattern for that: Have a function returning whether the first argument is greater (1), equal (0), or less (-1) than the second.
Writing this is simple now that the time is an object:
function cmpDate(date1, date2) {
if (date1.hour > date2.hour) {
return 1;
} else if (date1.hour < date2.hour) {
return -1;
} else if (date1.minute > date2.minute) {
return 1;
} else if (date1.minute < date2.minute) {
return -1;
} else {
return 0;
}
}
Alright, now we can have a helper function checking if the first argument is in the closed interval defined by the last two arguments:
function isInShift(time, shiftStart, shiftEnd) {
// time is greater or equal shiftStart
// and less or equal shiftEnd
return cmpDate(time, shiftStart) !== -1 && cmpDate(time, shiftEnd) !== 1;
}
You can then finally make your comparison by calling isInShift(parseTimeStr(selectedTime), parseTimeStr(shiftStartTime), parseTimeStr(shiftEndTime)). This will return a boolean. You can easily extend this infrastructure for multiple shifts.
Be aware that both reality and your users can be more ... screwy than you'd expect.
The above code does not do error handling for invalid time inputs, neither does it account for overnight shifts, but these are details that you can easily work out, you just have to put some effort into thinking of them.
I have an array with the following values (example):
[
1491408000000,
1491494400000,
1491753600000,
1493222400000,
1493308800000,
1493568000000
]
Where the index is a date time. The date time will always be at 12:00:00 on a date.
In this example, the first 3 dates are consecutive cross weekend (weekend is holiday so count as leave), then another group of 3 dates cross weekend and month.
Now, what I am trying to do is find sequential dates (cross week and month) and put them into an array as follows:
[
1491408000000,
1491494400000,
1491753600000
],
[
1493222400000,
1493308800000,
1493568000000
]
I have tried the following code to get the sequential dates but this cannot cross week and month, how to modify the code to get above result? Any help would be much appreciated!
var timeValue = new Date(dateReview).getTime();
valueCon.push(timeValue);
var k = 0;
sortedValue[k] = [];
valueCon.sort( function ( a, b ){
return +a > +b ? 1 : +a == +b ? 0: -1;
})
.forEach( function( v , i ){
var a = v,b = valueCon[i+1]||0;
sortedValue[k].push( +a );
if ( (+b - +a) > 86400000) {
sortedValue[++k] = []
}
return 1;
});
sortedValue.sort( function ( a,b ){
return a.length > b.length ? -1: 1;
});
This requires help from a function to test if two dates are in the same week. The following goes over the set of time values provided in an array and puts the first value into an array within the array. For each subsequent value, it tests if it's in the same week as the first value in each array within the outer array.
If it's in the same week as the first value in any existing array, it's pushed into that array. Otherwise, it's put in a new array and pushed into the outer array.
There may be a neater way to implement the algorithm, but I'll leave that for others.
Due to time zone differences, they are adjusted to the host time zone based on the original time values representing noon in the source time zone.
// Given 2 dates, return true if they are in the same week (Mon to Sun).
// Otherwise, return false
function sameWeek(a, b){
var e = new Date(+a);
// Week starts at 00:00:00.000 on Monday on or before date
var s = new Date(e.setDate(e.getDate() - ((e.getDay()||7) -1)));
s.setHours(0,0,0,0);
// Week ends at 23:59:59.999 the following Sunday
e.setDate(e.getDate() + 6);
e.setHours(23,59,59,999);
// Test b and return value
return b >= s && b <= e;
}
// Given time value for UTC-0400, adjust to same date and time
// in local time zone and return a date
function adjust(n) {
var d = new Date(n);
d.setMinutes(d.getMinutes() - 240 + d.getTimezoneOffset());
return d;
}
var result = [1491408000000,1491494400000,1491753600000,1493222400000,1493308800000,1493568000000
].reduce(function(acc, n) {
var d = adjust(n);
var used;
if (acc.length != 0) {
used = acc.some(function(arr) {
if (sameWeek(adjust(arr[0]), d)) {
arr.push(n);
return true;
}
});
}
if (!used || acc.length == 0) {
acc.push([n]);
}
return acc;
},[]);
// Result array
console.log(result);
// Printed as date strings adjusted to same host local time
result.forEach(arr => {
arr.forEach(n => console.log(adjust(n).toString()))
console.log('\n');
});
Manipulation of timestamps is a pain. JavaScript has a built-in Date type, as you know, and I would suggest you use it. Date#getUTCDay returns the day of the week as an integer (for reference, 4 is Friday, or the day before a weekend), while Date#setUTCDate and Date#getUTCDate together allow you to adjust the date in day increments (and have it overflow/underflow to the next/previous month). Thus, to determine whether a timestamp b follows "sequentially" (excluding weekends) after a, you can use:
function sequential (a, b) {
a = new Date(a)
return a.setUTCDate(a.getUTCDate() + (a.getUTCDay() === 4 ? 3 : 1)) === b
}
Grouping is just an exercise after that; the code above contains all of the real logic behind this solution.
Example Snippet
var dates = [
1491408000000,
1491494400000,
1491753600000,
1493222400000,
1493308800000,
1493568000000
]
function sequential (a, b) {
a = new Date(a)
return a.setUTCDate(a.getUTCDate() + (a.getUTCDay() === 4 ? 3 : 1)) === b
}
function groupSequential(dates) {
if (dates.length < 2) return [dates.slice()]
dates.sort(function(a, b) { return a - b })
var result = [], group
for (var i = 0; i < dates.length; i++) {
sequential(dates[i - 1], dates[i]) || result.push(group = [])
group.push(dates[i])
}
return result
}
console.log(groupSequential(dates))
I have this string:
002 2.0 (100aa) 95-97
I then want regex the 95-97 portion of it and paste it with relevant two numbers so I get a year.
In example, 96-97 should become 1995-1997, but 00-05 should become 2000-2005 (all numbers between 0 and 16 should be pasted with 20, but all other numbers with 19).
Then, when I have i.e. 1995-1997 I want to check if a year (i.e. 1996) is present inside 1995-1997 interval or not, and return a bolean.
How would one wright such code?
Best Regards
You could use the callback variant of replace:
function parseString(str) {
function padYear(year) {
return year < 30 ? 2000+year :
year < 100 ? 1900+year : year;
}
var result = {};
result.hasCurrentYear = false;
result.str = str.replace(/(\d\d)-(\d\d)$/g, function (match, yr1, yr2) {
yr1 = padYear(+yr1);
yr2 = padYear(+yr2);
var yrNow = (new Date).getFullYear();
result.hasCurrentYear = yrNow >= yr1 && yrNow <= yr2;
return yr1 + '-' + yr2;
});
return result;
}
var str = '002 2.0 (100aa) 95-16';
console.log(parseString(str));
Note that I made the split at year 30, as the solution will become outdated soon if you use 16 as split year.
I suppose there's a much simpler way to check if a certain year is in "range".The solution using String.split, Array.map functions and Number constructor:
var str = "002 2.0 (100aa) 95-97";
function checkYearInRange(str, year) {
year = Number(year);
var range = str.split(" ").pop().split('-').map((v) => Number((Number(v) > 16)? "19"+v : "20"+v));
return (range[0] <= year && year <= range[1]);
}
console.log(checkYearInRange(str, "1996")); // true
console.log(checkYearInRange(str, "2015")); // false
I'm using 4 drop-down lists in an html form. The 2 drop downs, represent the starting and ending month of an activity and the other 2 represent the starting and the ending year of an activity. I'm allowing the user to enter a 3 year history and after completion, I prompt the user to go to the next section. To calculate the 3 year history, I take the difference between the start and ending month and I enter it each time in a counter (note that I am working with numbers and not with the Date object). The values are passed into my arrays, but the counter is not updated. It is just replaced by the new value in the array. Can anyone tell me where is the problem? Here is my code:
var arrMonthStarted = []; //It stores the month that activity started
var arrMonthEnded = []; //It stores the month that activity ended
var arrYearStarted = []; //It stores the year that activity started
var arrYearEnded = []; //It stores the year that activity ended
function validatedropdowns1(){
var monthStarted = document.getElementById('idMonthStarted').value;
var yearStarted = document.getElementById('idYearStarted').value;
var monthEnded = document.getElementById('idMonthEnded').value;
var yearEnded = document.getElementById('idYearEnded').value;
arrMonthStarted.push(monthStarted);
arrMonthEnded.push(monthEnded);
arrYearStarted.push(yearStarted);
arrYearEnded.push(yearEnded);
//Calculating the 3-year history
var count = 0;
if(yearStarted == yearEnded){
if(monthEnded < monthStarted){
var temp = monthEnded;
monthEnded = monthStarted;
monthStarted = temp;
}
var diffmonths = monthEnded - monthStarted;
count = count + diffmonths;
}
//Take the difference between the years.
var subYears = yearEnded - yearStarted;
//If 1, just take the difference on the first 2 lines of the calendar
if(subYears == 1){
var subLine1 = 12 - monthStarted;
var subLine2 = 12 - monthEnded;
var finalLine2 = 12 - subLine2;
var takeresult = subLine1 + finalLine2;
count = count + takeresult;
}
//Follow case 1, but also add 12 months
if(subYears == 2){
var subLine3 = 12 - monthStarted;
var subLine4 = 12 - monthEnded;
var finalLine3 = 12 - subLine4;
var takeresult11 = subLine3 + finalLine4;
var takeresult1 = 12 + takeresult11;
count = count + takeresult1l;
}
//add another 12 months (24 now) on step 1.
if(subYears == 3){
var subLine5 = 12 - monthStarted;
var subLine6 = 12 - monthEnded;
var finalLine5 = 12 - subLine6;
var takeresult22 = subLine5 + finalLine6;
var takeresult2 = 24 + takeresult22;
count = count + takeresult2;
}
var arrCount = []; // array to hold the count var
arrCount.push(count); // push count into arrCount
//print total months
for(var m = 0; m < arrCount.length; m++){
alert("The array now has" + "" + "" + count + "" + "months");
}
if(arrCount == 36){
alert("You have successfuly finished this section. Please go to the next section. Thank you.")
document.getElementById('btnAdd').disable = true;
}
if(arrMonthEnded[arrMonthEnded.length - 1] - arrMonthStarted[arrMonthSarted.length] > 1){
alert("There should not be a gap of more than a month in your 3 year activity. Fill in all the months and select from the list what you were doing each month. Thank you.")
}
}
Also, I was trying to test the gap between the end date and the next start date. For example if I enter 12 2011 as an end date and 03 2012 as the next start date, I would like to see if there is a gap of more than one month. I tried the code below, but it didn't work
if(arrMonthEnded[arrMonthEnded.length - 1] - arrMonthStarted[arrMonthSarted.length] > 1){
alert("There should not be a gap of more than a month in your 3 year activity. Fill in all the months and select from the list what you were doing each month. Thank you.")
}
Thank you in advance (KSFIDDLE http://jsfiddle.net/k4dNb/)
This loop is pointless, as the array will only ever have one item:
for(var m = 0; m < arrCount.length; m++){
Here you are comparing an array to a number, and eventhough that actually works because both will be converted to strings, and the string value of [36] is "36" which is the same as the string value of 36 which is "36", it's done in a confusing way:
if(arrCount == 36){
Typo, you wrote arrMonthSarted instead of arrMonthStarted:
if(arrMonthEnded[arrMonthEnded.length - 1] - arrMonthStarted[arrMonthSarted.length] > 1){
Also, arrMonthStarted[arrMonthStarted.length] will always return undefined, as you are trying to access an item beyond the last item of the array.
Given a string str, how could I check if it is in the dd/mm/yyyy format and contains a legal date ?
Some examples:
bla bla // false
14/09/2011 // true
09/14/2011 // false
14/9/2011 // false
1/09/2011 // false
14/09/11 // false
14.09.2011 // false
14/00/2011 // false
29/02/2011 // false
14/09/9999 // true
Edit: exact solution below
You could do something like this, but with a more accurate algorithm for day validation:
function testDate(str) {
var t = str.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
if(t === null)
return false;
var d = +t[1], m = +t[2], y = +t[3];
// Below should be a more acurate algorithm
if(m >= 1 && m <= 12 && d >= 1 && d <= 31) {
return true;
}
return false;
}
http://jsfiddle.net/aMWtj/
Date validation alg.: http://www.eee.hiflyers.co.uk/ProgPrac/DateValidation-algorithm.pdf
Exact solution: function that returns a parsed date or null, depending exactly on your requirements.
function parseDate(str) {
var t = str.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
if(t !== null){
var d = +t[1], m = +t[2], y = +t[3];
var date = new Date(y, m - 1, d);
if(date.getFullYear() === y && date.getMonth() === m - 1) {
return date;
}
}
return null;
}
http://jsfiddle.net/aMWtj/2/
In case you need the function to return true/false and for a yyyy/mm/dd format
function IsValidDate(pText) {
var isValid = false ;
var t = pText.match(/^(\d{4})\/(\d{2})\/(\d{2})$/);
if (t !== null) {
var y = +t[1], m = +t[2], d = +t[3];
var date = new Date(y, m - 1, d);
isValid = (date.getFullYear() === y && date.getMonth() === m - 1) ;
}
return isValid ;
}
Try -
var strDate = '12/03/2011';
var dateParts = strDate.split("/");
var date = new Date(dateParts[2], (dateParts[1] - 1) ,dateParts[0]);
There's more info in this question - Parse DateTime string in JavaScript (the code in my answer is heavily influenced by linked question)
Demo - http://jsfiddle.net/xW2p8/
EDIT
Updated answer, try -
function isValidDate(strDate) {
if (strDate.length != 10) return false;
var dateParts = strDate.split("/");
var date = new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]);
if (date.getDate() == dateParts[0] && date.getMonth() == (dateParts[1] - 1) && date.getFullYear() == dateParts[2]) {
return true;
}
else return false;
}
This function passes all the test cases. As far as I'm aware, Adam Jurczyk had posted an accurate answer well before I corrected my original wrong answer. He deserves credit for this.
Demo - http://jsfiddle.net/2r6eX/1/
you can use regular exp to validate date .
try like this :
re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
if(form.mydate.value != '' && !form.mydate.value.match(re))
//do something here
note: this will only work for dd/mm/yyyy
for exact match of your requirement use
re = /^\d{2}\/\d{2}\/\d{4}$/;
I'm going to answer a different question, as Misha Moroshko's has already been well-answered: use HTML5. That is, on the assumption that the strings in question arise as user inputs through a Web browser, I propose that the entries be received as
<input type = "date" ...
I recognize that not all browsers likely to be in use will interpret "date" in a way that rigorously enforces validity. It's the right thing to do, though, will certainly improve as time goes on, and might well be good enough in a particular context even now simply to eliminate the need to validate the date-string after the fact.
Personally, I think the best solution would be to modify the UI to use dropdowns for the month and possibly day selections.
Trying to figure out if 1/2/2001 is January 2nd or February 1st based solely on that input string is impossible.
Recent discovery: You can use date.js lib, it adds function Date.parseExact so you can just do Date.parseExact(dateString,"dd/MM/yyyy"). It fails when month is 00, but its still usefull.
for dd/mm/yyyy format only
^(0?[1-9]|[12][0-9]|3[01])[\/](0?[1-9]|1[012])[\/]\d{4}$