Check if date overlaps inside array JS - javascript

I have an array which contains a set of start/end date objects (time included)
i.e.
results["records"] =
[0] -[startDate,endDate]
[1] -[startDate, endDate]
I also have another two date objects stored locally as JS variables.
How do I check if these variables i.e. startDateObj && endDateObj OVERLAP with ANY record in the array, by that I mean crossover with any time between and including any start date or end date.
Thank you in advance
Initial attempt below
$(results['records']).each(function() {
console.log('end:' + this[1])
console.log('start:' + this[0])
if(startDateObj < this[1].end && endDateObj > this[0].start) {
alert('this overlaps')
}
});
EDIT: Answer added below
Have a great day!

I'm assuming this structure in your "dateArray" because to check overlaps you need to define a range of date and time.
dateArray: [{start: Date, end: Date}];
dateArray.forEach(date => {
if(startDateObj < date.end && endDateObj > date.start) {
//this is an overlap
}
});

The answer was the full date objects in the array where being treated as a string
so to convert and fix
function toDateString(date)
{
var formatedDate = new Date(date);
return formatedDate;
}
$(results['records']).each(function() {
if(startDateObj < toDateString(this[1]) && endDateObj > toDateString(this[0]))
{
//overlaps
}

Related

How can i get the first nearest date in the past?

I have this arrays
const datesToBeChecked = ['2020-07-03','2020-07-06', '2020-07-13', '2020-07-20']
const dateToCheckFor = '2020-07-12';
I need to get the first nearest date in the past - so when the date is 2020-07-12 i need to get
2020-07-06 from datesToBeChecked.
WHAT I TRIED
I tried this code
datesToBeChecked.forEach(date => {
let diff = moment(dateToCheckFor).diff(moment(date), 'days');
console.log(diff);
if (diff > 0) {
if (nearestDate) {
if (moment(date).diff(moment(nearestDate), 'days') < 0) {
nearestDate = date;
}
} else {
nearestDate = date;
}
}
});
but that gives me the earliest date in the array - 2020-07-03. But i need the first BEFORE THE DATE I CHECK FOR
Actually your logic is almost there. You don't need the nested if conditional. In essense, what you want is to cache the difference, and compare the current difference with the cached difference. If the cached difference is smaller, then we know the current date is the nearest one. Otherwise, we continue for the search.
This solution will work even if the dates are not sorted in chronological order (oldest to newest):
const datesToBeChecked = ['2020-07-03', '2020-07-06', '2020-07-13', '2020-07-20']
const dateToCheckFor = '2020-07-12';
let nearestDate;
let cachedDiff = Infinity;
datesToBeChecked.forEach(date => {
let diff = moment(dateToCheckFor).diff(moment(date), 'days');
if (diff > 0 && diff < cachedDiff) {
cachedDiff = diff;
nearestDate = date;
}
});
console.log(nearestDate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
The first element is the closest date in the past (at least yesterday, today results won't show up).
If empty then dateToCheckFor elements does not contain any date in past.
const mappedDates = dateToCheckFor
.map(d => moment(dateToCheckFor).diff(moment(d), 'days'))
.filter(diff => diff <= -1)
.sort()
.reverse();
You could try sorting all of the dates in a hash table first. So you would have a hash table:
{
date1: difference,
date2: difference,
...
}
then you would sort the objects values, such as here: Sorting object property by values
then take the first date from that, which is before the dateToCheckFor
I hope this is not too inefficient for you.
Here's one way with good ole vanilla js. Moment.js weighs 230+kb
const datesToBeChecked = ['2020-07-03', '2020-07-06', '2020-07-13', '2020-07-20']
const dateToCheckFor = '2020-07-12';
dateToCheckFor_d = new Date(dateToCheckFor).getTime();
let possibilities = datesToBeChecked.filter(dt => {
return (new Date(dt).getTime() < dateToCheckFor_d)
})
possibilities.sort().reverse()
console.log(possibilities[0])
In your code just update the below line
if (moment(date).diff(moment(nearestDate), 'days') < 0
to
if (moment(date).diff(moment(nearestDate), 'days') > 0

Javascript Cannot use .now() on date string

So I wanted to compare two dates inside a post object. I tried to compare the date objects, but that returned NaN. Then I tried converting it to milliseconds since 1970 by using .now() on these dates, but it returned the following error:
It happens: TypeError: a.date.now is not a function
I tried typeof a.date and this returned string. I don't know why I can't use the .now() method. Can someone help me?
the whole function inside of angular service
getPosts(section) {
return this.http.get(url + '/forum/getPosts/' + section )
.map( (posts: any) => {
// posts should be ordened based on latest replies. If there are no replies yet, we compare it to the date
// of the original post
posts.obj.sort((a, b) => {
const aHasReplies = a.replies.length !== 0;
const bHasReplies = b.replies.length !== 0;
if (aHasReplies && bHasReplies ) {
return a.replies.slice(-1, 1)[0].date - b.replies.slice(-1, 1)[0].date;
} else if ( aHasReplies && !bHasReplies) {
return a.replies.slice(-1, 1)[0].date - b.date;
} else if ( !aHasReplies && bHasReplies) {
return a.date - b.replies.slice(-1, 1)[0].date;
} else {
console.log(a.date.now());
return a.date - b.date;
}
});
return posts;
});
}
It should be object, not string, if that's what you meant, because there is no "date string".
Other than that try:
new Date(a.date).getTime()
Because .now is a static method, you always use it as Date.now()
This means, that Date.now() always returns milliseconds elapsed since the UNIX epoch.
For converting to unix time use getTime.
If you want to compare them, compare two dates without conversion.
But keep in mind, that unix time is in seconds, and javascript method return in milliseconds. If you need exactly unix time, divide by 1000.
You can compare two dates in the year-month-day format (yyyy-mm-dd) using regular javascript comparators such as < and > etc
I suggest use moment.js library (https://momentjs.com/docs/) to parse Date from String.
So you can have some thing like
let date = moment(a.date)

Determine if current time is within an array of time ranges

For a website blocking/productivity app written in javascript, I'd like to have a user input a series of time ranges available for free time (in his local time). Example:
06:00-06:30
12:30-13:00
23:45-00:15
24 format is not required (I'm just assuming it will be easier)
The program should then check the specified free time ranges against the current time to determine whether block mode is on or off.
My rough idea is to use an inbuilt Javascript function to grab the current DateTime, and convert it to 24 hour format if necessary. I think the time ranges will be in an array. I'm not sure how to check if the current date is within a range in the array.
The logic must also be able to handle the crossover from 23:00 to 0:00.
Anyways that is my line of thought. Thanks for any suggestions including ones that take a different path.
Anyways that is my line of thought. Thanks for any suggestions including ones that take a different path.
If you want to check if current time is in range then the range should be DATE + TIME as current time is DATE + TIME
Possible solution
You can convert all three datetimes to moment instances and just use
start.isBefore(current)
&& current.isBefore(end)
Moment docs on isBefore and isAfter : https://momentjs.com/
"I'm not sure how to check if the current date is within a range in the array."
You'd loop through the array and compare. I'd suggest storing the ranges as an array of objects where each individual range is something like {start: "10:15", end: "10:45"}.
JavaScript doesn't have time objects, only Date that includes date and time information. So I think it would be easiest to convert the current time to the "hh:mm" format as a string and then just do simple string compares against your range values, rather than worrying about converting the range values to date objects. So:
var timeRanges = [
{ start: "06:00", stop: "06:30" },
{ start: "12:30", stop: "13:00" },
{ start: "23:45", stop: "00:15" }
]
function isTimeInRange(time) {
for (var i = 0; i < timeRanges.length; i++) {
var range = timeRanges[i]
if ((time > range.start && time < range.stop)
|| (range.start > range.stop && (time > range.start || time < range.stop))) {
return true
}
}
return false
}
But you can make the code neater, and shorter, using the array .some() method, with or without arrow functions:
var timeRanges = [
{ start: "06:00", stop: "06:30" },
{ start: "12:30", stop: "13:00" },
{ start: "23:45", stop: "00:15" }
]
function isTimeInRange(time) {
return timeRanges.some(range =>
(time > range.start && time < range.stop)
|| (range.start > range.stop && (time > range.start || time < range.stop))
)
}
function pad(d) {
return ("0" + d).slice(-2)
}
function getCurrentTime() {
var now = new Date()
return pad(now.getHours()) + ":" + pad(now.getMinutes())
}
console.log("Current time in range? " + isTimeInRange(getCurrentTime()))
// test some other times
console.log(isTimeInRange("06:15")) // true
console.log(isTimeInRange("12:35")) // true
console.log(isTimeInRange("13:30")) // false
console.log(isTimeInRange("23:50")) // true
console.log(isTimeInRange("00:14")) // true
Obviously you can change < and > to <= and >= if desired.
Try it
start = "10:10";
end = "16:30";
function isInRange(start, end, current){
start = convertTimeToMinute(start);
end = convertTimeToMinute(end);
current = convertTimeToMinute(current);
return start <= current && current <= end;
}
function convertTimeToMinute(time){
return +time.slice(0,1)*60 + +time.slice(3,4);
}
console.log(isInRange(start,end, "15:20"));
console.log(isInRange(start,end, "20:20"));

How can I get actual date in this format?

I want to compare the actual date to a format like this that I'm receiving from a server:
item.expires_date.slice
"2016-11-28 22:10:57 Etc/GMT"
In javascript how could this be possible? specially for the part Etc/GMT
In the case I just wanted to compare 2016-11-28
how can I achieve this:
var today = new Date().toISOString().slice(0, 10);
if(item.expires_date.slice(0, 10) > today) {
console.log("This item have expired");
} else {
console.log("this item has not expired" );
}
}
it does not work because it brings to item has not expired comparing dates:
2016-11-28 - 2016-12-28
Thanks!
Since "Etc/GMT" is the same as "GMT+00:00", you can remove it and create a Date object from the string:
var s = "2016-11-28 22:10:57 Etc/GMT";
var d = new Date(Date.parse(s.replace("Etc/", "")));
console.log(d.toString());
Then you can compare d to the current date.

Trying to remove all the passed dates

I have an array with many dates, they are not in the date type but string like: "2016-08-12" for example. Then what I would like to do is to remove all dates that we already have passed. So therefor im trying to compare them to todays date and then remove it if its passed. Using typescript by the way.
my array, named datoArray, looks like this:
["2016-08-02", "2016-08-11", "2016-08-22", "2016-09-10"]
just with a lot more of the same...
then here's what I try to do:
for(var i = 0; i < this.datoArray.length; i++){
this.skoleAar = parseInt(this.datoArray[i].slice(0,4))
this.skoleMaaned = parseInt(this.datoArray[i].slice(5,8))
this.skoleDag = parseInt(this.datoArray[i].slice(8,10))
if(this.skoleAar < dagensAar){
this.datoArray.splice(i, 1);
}
if(this.skoleAar == dagensAar && this.skoleMaaned < dagensMaaned){
this.datoArray.splice(i, 1);
}
if(this.skoleAar == dagensAar && this.skoleMaaned == dagensMaaned && this.skoleDag < dagensDag){
this.datoArray.splice(i, 1);
}
}
the "dagensAar", "dagensMaaned" and "dagensDag" variables im getting from another function that works. If i "console.log" the variables it prints out int values like 2016 for the year and 8 for the month if i take from the start of the array, and for the "dagensAar", "dagensMaaned" and "dagensDag" it prints 2016 11 20, which is todays year, month and day. all is in Int type, so what im not getting here is why my "if" doesnt work? It seems like there is something wrong with the way i compare the, but i thought this was the way to compare int values?
If the dates are in ISO-8601 format then you can simply filter using Date.parse().
var dates = ["2016-08-02", "2016-08-11", "2016-08-22", "2016-09-10", "2016-12-15"];
function removePastDates(data) {
var today = new Date();
console.log('Initial state: ' + data);
var modified = dates.filter(function(dateString) {
return Date.parse(dateString) >= today;
});
console.log('Final state: ' + modified);
return modified;
}
var newDates = removePastDates(dates);
Your dates seem to be RFC compliant, meaning they can be directly fed into a new Date object. Simply compare to today and filter by that:
var today = new Date()
var futureDates = this.datoArray.filter(d => new Date(d) >= today)
(pre-ECMA6:)
var today = new Date()
var futureDates = this.datoArray.filter(function (d) {
return new Date(d) >= today;
})
I think the problem is not related to the dates.
I think the problem is that you are removing items from the array while looping the same exact array.
You should maybe try looping from the end of the array to the beginning or just save the indexes that you need to remove and later do the actual removing.
Keep in mind that when you remove an item you change the index of every item in the remaining of the array - maybe you should start removing from the greatest index so it will not confuse you.

Categories

Resources