Find date ranges from a collection of dates Javascript - javascript

I know this is similar to this Question, but I need different results and in JavaScript.
I have an string of dates like this, that may not be in order. 03/27/2017,03/28/2017,03/29/2017,04/04/2017,04/05/2017,04/06/2017,04/12/2017,04/13/2017,04/14/2017, 05/02/2017
Date format is mm/dd/yyyy
I need to split this into an array of dates, which I can do. But then I need to loop through all dates and if the dates are connected then it needs to be a date range. If there is a single date, then it would be a single date range.
So I would need these results from the above dates.
[
{'start': 03/27/2017, 'end': 03/29/2017 },
{'start': 04/04/2017, 'end': 04/06/2017},
{'start': 04/12/2017, 'end': 04/14/2017 },
{'start': 05/02/2017, 'end': 05/02/2017}
]
I am doing this app in JavaScript, Typescript, lodash, angular 1.6.
Any help is greatly appreciated.
EDIT
I have a popup calendar that the user can select multiple dates. If the dates are consecutive then that is the date range, if it is a single date then that alone will be the date range. This is needed for the user to select their desired dates off, then these will be inserted into the DB.

Here is how I did it. I converted them to dates, and then did a math calculation to see if the next date was bigger than a day or not. If it was, then I stopped the current date range and started the next one.
let string = '03/27/2017,03/28/2017,03/29/2017,04/04/2017,04/05/2017,04/06/2017,04/12/2017,04/13/2017,04/14/2017, 05/02/2017';
//split them and pull out any white spaces from beginning and end
let dates = string.split(',').map(s=>{
s = s.trim();
let nums = s.split('/');
let d = new Date(nums[2], nums[0], nums[1]);
return {date:d, string: s};
});
let currentStart = dates[0];
let result = [];
for(let i = 1; i < dates.length; i++){
let {date, string} = dates[i];
//If last date, add range
if(i == dates.length -1){
console.log("hello");
result.push({start: currentStart.string ,end: string});
} else {
let prevDate = dates[i-1] || currentStart; //in case prevDate is undefined
let nextDate = dates[i+1];
let diff = nextDate.date.getTime() - date.getTime();
if(diff > (24 * 60 * 60 * 1000)){
result.push({start: currentStart.string ,end: string});
currentStart = nextDate;
}
}
}
console.log(result, 'result');

Related

How to find number of days from given days in js?

I need to find number of days if i enter startDate and endDate.from the start_date to end_date i only want to retrieve weekdays i.e monday to friday along with the offcial_leave variable
for_example:
let numberOfdays;
let startDate = '2022-04-04'; //yy-mm-dd format
let endDate = '2022-04-08';
// Below variable come from db and vary according the start and endate
// eg:- 2022-12-25 will be holiday if we select start and end in december
let holidays = ['2022-04-05', '2022-04-07' ]
numberOfdays => 3
// I want to return number of days to 3
How can i achieve this in in JavaScript
thanks
First convert the startDate and endDate to javascript Date. Then, declare a variable i to store while looping through the date. Also, declare holidayIndex which stores the current index at which holiday date needs to be checked with the current date.
Inside the loop, convert the date to YYYY-MM-DD format (original format) to check if the current date (isoDate) lies between a holiday, i.e., it is not a holiday date. If the holidayIndex is at last index of array, then just check if the current date (isoDate) is not in the holidays array. If not found, then increment numberOfDays variable.
Otherwise, a holiday date is found, hence no need to increment numberOfDays. Just increment holidayIndex to be ready to match the upcoming dates for next holiday date.
Here is the solution:
let numberOfdays = 0;
const startDate = '2022-04-04'; //yy-mm-dd format
const endDate = '2022-04-08';
// Below variable come from db and vary according the start and endate
// eg:- 2022-12-25 will be holiday if we select start and end in december
const holidays = ['2022-04-05', '2022-04-07'];
let holidayIndex = 0;
const start = new Date(startDate);
const end = new Date(endDate);
let i = start;
while (i <= end) {
const isoDate = i.toISOString().split('T')[0];
if (
(holidayIndex < holidays.length - 1 && isoDate < holidays[holidayIndex] && isoDate > holidays[holidayIndex + 1]) ||
formattedDate !== holidays[holidayIndex]
) {
numberOfdays += 1;
} else {
holidayIndex += 1;
}
i.setDate(i.getDate() + 1);
}

Add recurring date and time within range(StartDate and EndDate) using momentjs or javascript

I need an array of recurring dates with time for every week within the start date and end date using moment.js or javascript.
For example:
Startdate: 2021-10-04T00:00:00Z
Enddate: 2021-10-31T00:00:00Z
let's say 2021-10-05T00:00:00Z is a recurring date then output will be
["2021-10-05T00:00:00Z", "2021-10-12T00:00:00Z", "2021-10-19T00:00:00Z", "2021-10-26T00:00:00Z"]
We can use Date.getUTCDate() and Date.setUTCDate() to advance a date by a number of days, in this case seven.
We can then use a while loop to populate the result array. I'm returning an array of Date objects here, one could use .toISOString() to convert to strings.
let startDate = '2021-10-05T00:00:00Z';
let endDate = '2021-10-31T00:00:00Z';
function getWeeklyDates(start, end) {
let date = new Date(start);
const endDate = new Date(end);
const result = [];
while (date < endDate) {
result.push(date);
date = new Date(date);
date.setUTCDate(date.getUTCDate() + 7);
}
return result;
}
console.log(getWeeklyDates(startDate, endDate).map(dt => dt.toISOString()))
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with pure js if you remove the "Z" add "+00:00" to all of your strings to make sure your timezone does not break this code.
let start = "2021-10-04T00:00:00+00:00";
let end = "2021-10-31T00:00:00+00:00";
let date = "2021-10-05T00:00:00+00:00";
start = new Date(start);
end = new Date(end);
date = new Date(date);
let dates = [];
if (date < start) {
console.log("bad input")
} else {
while (date.getTime() < end.getTime()) {
dates.push(date.toISOString());
date = new Date(date.getTime() + 604800000); // add a week in milliseconds
}
}
you can do something like:
start at the first recurring date
add a week to the recurring date using .add(1, 'weeks') (see https://momentjs.com/docs/#/manipulating/add/ )
do this while recurring date < end date

Get days using two dates in js

I'm having this trouble where I can only get the days between specified 2 dates. Please see the code below:
var getDaysArray = function(start, end) {
for (var arr = [], dt = start; dt <= end; dt.setDate(dt.getDate() + 1)) {
arr.push(new Date(dt));
}
return arr;
};
var daylist = getDaysArray(new Date('08/13/2018'), new Date('08/17/2018'));
daylist.map((v) => v.toISOString().slice(0, 10)).join("");
console.log(daylist);
The output of the code above is:
Expected output (due to start and end dates 08/13/2018 and 08/17/2018):
0: Date 2018-08-13T16:00:00.000Z
1: Date 2018-08-14T16:00:00.000Z
2: Date 2018-08-15T16:00:00.000Z
3: Date 2018-08-16T16:00:00.000Z
4: Date 2018-08-17T16:00:00.000Z
Note: The code above was from one of the SO answers found somewhere.
toISOString represents the date in UTC format. You are probably in positive timezone offset, that's why the UTC representation of your date objects are a day off. You can use toLocaleString instead to represent your dates in your timezone.
Another issue is that Array.prototype.map retuns a new array, which you forgot to assign to daylist Without that assignment, no changes in daylist will be made.
Below snippet works as per your requirements.
var getDaysArray = function(start, end) {
for (var arr = [], dt = start; dt <= end; dt.setDate(dt.getDate() + 1)) {
arr.push(new Date(dt));
}
return arr;
};
var daylist = getDaysArray(new Date('08/13/2018'), new Date('08/17/2018'));
daylist = daylist.map((v) => v.toLocaleString());
console.log(daylist);

How to get date ranges from an array of static dates in jquery or javascript

I want to create date ranges from statics dates of array.
Here is an example of what I want:
var collDates = [
"2017/01/01",
"2017/01/02",
"2017/01/03",
"2017/01/04",
"2017/01/08",
"2017/01/09"
];
This should be transformed to:
[
{ start_date: "2017/01/01", end_date: "2017/01/04" },
{ start_date: "2017/01/08", end_date: "2017/01/09" }
];
I have resolved the issue and here is an example code.
var staticDates = ["2017/01/01", "2017/01/02", "2017/01/03", "2017/01/04", "2017/01/08", "2017/01/09", "2017/01/10", "2017/01/11", "2017/01/12", "2017/01/13", "2017/01/14", "2017/01/15", "2017/01/16", "2017/01/17", "2017/01/18", "2017/01/19", "2017/01/20", "2017/01/21", "2017/01/22", "2017/01/23", "2017/01/24", "2017/01/25", "2017/01/26", "2017/01/27", "2017/01/28", "2017/01/29"];
var coll_dateIntervals = [];
var arr_temp = [];
var i = 1;
$.each(staticDates, function(index, moment_date){
//Day difference in # of days
var diff = Math.abs(moment(staticDates[index]).diff(staticDates[index + 1], "days"));
arr_temp.push(moment_date);
//Check the date difference in days.
if(diff <= 1 && diff !== undefined){
//If the difference is 1, than add the date to the temporary array
arr_temp.push(moment_date);
//If it's more than 1 day, or the last object
} else if (diff > 1 || diff === undefined){
//Store the interval in an object
console.log(arr_temp[arr_temp.length - 1]);
var obj_dateInterval = { start_date: moment(arr_temp[0], "YYYY/MM/DD").format('YYYY-MM-DD'), end_date: moment(arr_temp[arr_temp.length - 1], "YYYY/MM/DD").format('YYYY-MM-DD')};
coll_dateIntervals.push(obj_dateInterval);
//Empty the array to start the new loop
arr_temp = [];
}
});
console.log(coll_dateIntervals);
Without a library, you just need a couple of simple functions for parsing and formatting. Doesn't do anything with invalid dates, but not difficult to add if required.
Step through the dates to create ranges. Begin with a start date, calculate the next day as current date plus one. When get a date that isn't the next day, end the range and start a new one. Also end when run out of dates.
For single dates, creates a single date range.
/* Parse date in format y/m/d
** #param {string} s - string to parse
** #returns {Date}
*/
function parseYMD(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1] - 1, b[2])
}
/* Collate array of date strings in y/m/d format to ranges
** #param {Array} dateArray - array of dates to parse in y/m/d format
** #returns {Array} ranges in format {start_date: yyyy/mm/dd, end_date: yyyy/mm/dd}
*/
function datesToRanges(dateArray) {
return dateArray.reduce(function(acc, currentDate, index) {
var d = parseYMD(currentDate);
// Start of a processing, initialise accumulator
if (!acc) {
acc = {range: {start_date: currentDate}, ranges: []};
// If not continuing range, end current range, store and start new
} else if (acc.previousDate.setDate(acc.previousDate.getDate() + 1) != +d) {
acc.range.end_date = acc.previousString;
acc.ranges.push(acc.range);
acc.range = {start_date: currentDate};
}
// Keep current values for next iteration
acc.previousDate = d;
acc.previousString = currentDate;
// If at end of dates, end current range
if (index == dateArray.length - 1) {
acc.range.end_date = currentDate;
acc.ranges.push(acc.range);
}
return acc;
}, null).ranges;
}
// Tests
var collDates = [
"2017/01/01", // Start 4 day range
"2017/01/02",
"2017/01/03",
"2017/01/04", // End 4 day range
"2017/01/06", // Zero day range
"2017/01/08", // Start one day range
"2017/01/09", // End one day range
"2017/01/15", // Zero day range
];
console.log(datesToRanges(collDates));
PS
Can't see what this has to do with jQuery. There's no moment.js tag so I haven't used it. ;-)

Comparing two dates with javascript or datejs (date difference)

I am trying to compare two dates which are in Finnish time form like this: dd.mm.YYYY or d.m.YYYY or dd.m.YYYY or d.mm.YYYY.
I am having a hard time finding out how to do this, my current code won't work.
<script src="inc/date-fi-FI.js" type="text/javascript"></script>
<script type="text/javascript">
function parseDate() {
var date = $('#date').val();
var parsedDate = Date.parse(date);
alert('Parsed date: '+parsedDate);
}
function jämförMedIdag (datum) {
if (datum == null || datum == "") {
alert('Inget datum!');
return;
}
/*resultat = Date.compare(Datum1,Datum2);
alert(resultat); */
var datum = Date.parse(datum);
var dagar = datum.getDate();
var månader = datum.getMonth();
var år = datum.getYear();
var nyttDatum = new Date();
nyttDatum.setFullYear(år,månader,dagar);
var idag = new Date();
if(nyttDatum>idag) {
var svar = nyttDatum - idag;
svar = svar.toString("dd.MM.yyyy");
alert(svar);
return(svar);
} else {
var svar = idag - nyttDatum;
svar = svar.toString("dd.MM.yyyy");
alert(svar);
return(svar);
}
}
</script>
This code will try to calculate the difference between two dates, one of them being today. No success lolz.
Thanks in advance!
My final code (thanks RobG!):
function dateDiff(a,b,format) {
var milliseconds = toDate(a) - toDate(b);
var days = milliseconds / 86400000;
var hours = milliseconds / 3600000;
var weeks = milliseconds / 604800000;
var months = milliseconds / 2628000000;
var years = milliseconds / 31557600000;
if (format == "h") {
return Math.round(hours);
}
if (format == "d") {
return Math.round(days);
}
if (format == "w") {
return Math.round(weeks);
}
if (format == "m") {
return Math.round(months);
}
if (format == "y") {
return Math.round(years);
}
}
It is not fully accurate, but very close. I ended up adding some addons to it to calculate in day week month year or hour, anyone can freely copy and use this code.
If you are using Datejs, and the optional time.js module, you can run your calculations with the following code by creating a TimeSpan object:
Example
// dd.mm.YYYY or d.m.YYYY
// dd.m.YYYY or d.mm.YYYY
var start = Date.parse("20.09.2011");
var end = Date.parse("28.09.2011");
var span = new TimeSpan(end - start);
span.days; // 8
Of course the above could be simplified down to one line if you really want to be extra terse.
Example
new TimeSpan(Date.parse(end) - Date.parse(start)).days; // pass 'end' and 'start' as strings
Hope this helps.
If your dates are strings in the common form d/m/y or some variation thereof, you can use:
function toDate(s) {
var s = s.split('/');
return new Date(s[2], --s[1], s[0]);
}
You may want to validate the input, or not, depending on how confident you are in the consistency of the supplied data.
Edit to answer comments
To permit different separators (e.g. period (.) or hyphen (-)), the regular expression to split on can be:
var s = s.split(/[/\.-]/);
The date will be split into date, month and year numbers respectively. The parts are passed to the Date constructor to create a local date object for that date. Since javascript months are zero indexed (January is 0, February is 1 and so on) the month number must be reduced by one, hence --s[1].
/Edit
To compare two date objects (i.e get the difference in milliseconds) simply subtract one from the other. If you want the result in days, then divide by the number of milliseconds in a day and round (to allow for any minor differences caused by daylight saving).
So if you want to see how many days are between today and a date, use:
function diffToToday(s) {
var today = new Date();
today.setHours(0,0,0);
return Math.round((toDate(s) - today) / 8.64e7);
}
alert(diffToToday('2/8/2011')); // -1
alert(diffToToday('2/8/2012')); // 365
PS. The "Finnish" data format is the one used by the vast majority of the world that don't use ISO format dates.
Using the Date object:
var today = Date.today();
var dateToday = Date.parse(today.toString('MMMM d, yyyy'));
var prevMonthDate = dateToday.addDays(-30);
var difference = (dateToday - prevMonthDate)/86400000;
console.log(difference); //will give you the difference in days.

Categories