How to get an array of 10 next Mondays in javascript - javascript

Here is my code but this array returns only the same elements, i am trying to create an array which contains 10 elements as the next mondays anyone know please help me
my code:
function getNextDayOfTheWeek(dayName, excludeToday = true, refDate = new Date()) {
const dayOfWeek = ["sun","mon","tue","wed","thu","fri","sat"]
.indexOf(dayName.slice(0,3).toLowerCase());
if (dayOfWeek < 0) return;
refDate.setHours(0,0,0,0);
refDate.setDate(refDate.getDate() + +!!excludeToday +
(dayOfWeek + 7 - refDate.getDay() - +!!excludeToday) % 7);
return refDate;
}
let arr=[]
for(let i=0;i<10;i++){
arr.push(arr[i]=getNextDayOfTheWeek("Monday",false))
}
console.log(arr)

getNextDayOfWeek is being given the same inputs and so will have the same outputs.
You need to:
Establish the base line date and pass it as the third parameter
Pass the resulting date on the subsequent calls so that it advances
Indicate that it should exclude the base line date if it matches the requested date
Insert a new Date into the result array, because Dates are objects and thus passed by reference. If you don't do this, each call of getNextDayOfTheWeek will be making changes to the same object stored in each position of the result array.
Note that your local time might cause the displayed date to appear to be before or after the expected date. You will likely need to decide how to account for local timezone (note that the result might show Z at the end of the time indicating UTC).
let arr=[]
let refDate = new Date()
for(let i=0;i<10;i++){
refDate = getNextDayOfTheWeek("Monday",false, refDate)
arr.push(refDate)
}
function getNextDayOfTheWeek(dayName, excludeToday = true, refDate = new Date()) {
const dayOfWeek = ["sun","mon","tue","wed","thu","fri","sat"]
.indexOf(dayName.slice(0,3).toLowerCase());
if (dayOfWeek < 0) return;
refDate.setHours(0,0,0,0);
refDate.setDate(refDate.getDate() + +!!excludeToday +
(dayOfWeek + 7 - refDate.getDay() - +!!excludeToday) % 7);
return refDate;
}
let arr=[]
let refDate = new Date()
for(let i=0;i<10;i++){
refDate = getNextDayOfTheWeek("Monday", i > 0 ? true : false, refDate)
arr.push(new Date(refDate))
}
console.log(arr)

Related

How to aggregate arrays of days weekly in JS?

For example, take the time range from 05/10/2019 to 05/25/2019.
Dates on this interval need to be aggregated like this (2019 is omitted for brevity):
const result = [
[ '05-10', '05-11', '05-12'], // week 1
['05-13', '05-14', '05-15', '05-16', '05-17', '05-18', '05-19'], // week 2
['05-20', '05-21', '05-22', '05-23', '05-24', '05-25' ], // week 3
];
What is the best way to solve this problem with JS?
Is it possible to implement this by setting the beginning of the week on any day?
Will packages moment and moment-range help in this?
You can go through the dates, and if the day is 1 (Monday), create a new Array in your results:
const startDate = new Date('05-10-2019'),
endDate = new Date('05-25-2019'),
result = [];
function _twoDigits(x) {
return String(x).padStart(2, '0');
}
let tmp = startDate;
do {
if (tmp.getDay() === 1 || result.length === 0) {
// Create a week Array
result.push([]);
}
const str = `${_twoDigits(tmp.getMonth() + 1)}-${_twoDigits(tmp.getDate())}`;
// Add this date to the last week Array
result[result.length - 1].push(str);
// Add 24 hours
tmp = new Date(tmp.getTime() + 86400000);
} while (tmp.getTime() <= endDate.getTime());
console.log(result);
Note: MomentJS may help, but it's a big library. If you only need to do 2 or 3 basic things with dates, I would recommend not using it. If you need to do a lot of work with dates, then yes, it's a powerful library that will save you a lot of time.
Here is one possible implementation if you are interested in moment.js code.
But as blex said it's a large lib.
const start = moment('2019-05-10');
const end = moment('2019-05-25');
const array = [[]];
const from_date = moment(start).startOf('isoWeek');
const to_date = moment(end).endOf('isoWeek');
let j = 0;
let added = 0;
for (let currentDate = moment(from_date); currentDate <= to_date; currentDate.add(1, 'day')) {
if (added === 7) {
array.push([]);
j++;
added = 0;
}
if (currentDate.isBetween(start, end, null, '[]')) {
array[j].push(currentDate.format('MM-DD'));
}
else {
array[j].push('');
}
added++;
}
document.getElementById('output').innerText = JSON.stringify(array);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<p id="output"></p>

JavaScript Array - all index over 0 are empty after loop

I have an array of date/timestamps saved as seconds, I'm looking to count the number of items that are between two timestamps (all times are assumed to be at midnight). I've cut down a larger function to the section that the problem seems to reside, let me know if you need any additional code.
var fullDay = 86399;
var end = parseInt(dataArray[0]) + parseInt(fullDay);
for (var i = 0; i < numberOfDays; i++) {
dataSegments[i] = sensorEventTotal(dataArray, end, previousEnd);
previousEnd = end;
end = parseInt(end) + parseInt(fullDay);
}
console.log(dataSegments.toString());
SensorEventTotal:
function sensorEventTotal (dataArray, end, previousEnd){
var counter = 0;
$.each(dataArray, function(i, item) {
if (parseInt(item) < end && parseInt(item) > previousEnd) {
counter++;
}
});
previousEnd = end;
return counter;
}
What I'm trying to do is to take the first date/time stamp and add 24 hours (fullDay value is 24 hours in seconds), I'm then looking to use that "end time" as the start point for the next loop with another 24 hours added onto that and so on.
In the end I'd want an array where each index stores the number of occurrences for each day e.g. dataSegments = [23,123,32,34] - so 23 events on day one, 123 events on day two etc.
At the moment this is the result I'm getting for dataSegments:
115,0,0,0,0,0
EDIT:
Sample of data in dataArray:
1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956
Full array:
1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956,1496072955,1496072951,1496072950,1496072949,1496072948,1496072809,1496072805,1496072804,1496072803,1495815090,1495815089,1495815088,1495807282,1495807281,1495807280,1495807279,1495807277,1495807276,1495807275,1495807274,1495807273,1495807267,1495807266,1495807265,1495805409,1495805408,1495805407,1495805406,1495805381,1495805380,1495805379,1495803061,1495803060,1495803059,1495803059,1495803000,1495802999,1495802998,1495786283,1495786282,1495786281,1495728263,1495728262,1495728261,1495728258,1495728257,1495728256,1495727698,1495727697,1495727696,1495727695,1495727694,1495727693,1495727491,1495727490,1495727489,1495727486,1495727485,1495727484,1495724286,1495724285,1495724284,1495724279,1495724278,1495724277,1495720363,1495720358,1495720357,1495720356,1495719373,1495719372,1495719368,1495719367,1495719366,1495717302,1495717301,1495717299,1495717298,1495717297,1495717296,1495713310,1495713309,1495713308,1495713305,1495713304,1495713303,1495713303,1495707902,1495707901,1495707897,1495707896,1495707895,1495707615,1495707611,1495707610,1495707609,1495707608,1495704627,1495704626,1495704625,1495704623,1495704622,1495704621,1495704133,1495704132,1495704128,1495704127,1495704126
This is what I managed to come up with. I hope code is clear just from variable names alone, given that the logic is very similar to yours.
const SECONDS_IN_DAY = 24 * 3600;
let events = [1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956,1496072955,1496072951,1496072950,1496072949,1496072948,1496072809,1496072805,1496072804,1496072803,1495815090,1495815089,1495815088,1495807282,1495807281,1495807280,1495807279,1495807277,1495807276,1495807275,1495807274,1495807273,1495807267,1495807266,1495807265,1495805409,1495805408,1495805407,1495805406,1495805381,1495805380,1495805379,1495803061,1495803060,1495803059,1495803059,1495803000,1495802999,1495802998,1495786283,1495786282,1495786281,1495728263,1495728262,1495728261,1495728258,1495728257,1495728256,1495727698,1495727697,1495727696,1495727695,1495727694,1495727693,1495727491,1495727490,1495727489,1495727486,1495727485,1495727484,1495724286,1495724285,1495724284,1495724279,1495724278,1495724277,1495720363,1495720358,1495720357,1495720356,1495719373,1495719372,1495719368,1495719367,1495719366,1495717302,1495717301,1495717299,1495717298,1495717297,1495717296,1495713310,1495713309,1495713308,1495713305,1495713304,1495713303,1495713303,1495707902,1495707901,1495707897,1495707896,1495707895,1495707615,1495707611,1495707610,1495707609,1495707608,1495704627,1495704626,1495704625,1495704623,1495704622,1495704621,1495704133,1495704132,1495704128,1495704127,1495704126];
events = events.reverse();
let midnight = events[0] - events[0] % SECONDS_IN_DAY; // midnight before the first event
const eventsPerDay = []; // results array
const nrDays = 7; // lets count events for one week
let daysCounted = 0, eventsChecked = 0;
while (daysCounted < nrDays) {
midnight += SECONDS_IN_DAY;
let currentEvent = events[eventsChecked];
let eventsInThisDay = 0;
while (currentEvent < midnight) {
eventsInThisDay++;
eventsChecked++;
currentEvent = events[eventsChecked];
}
eventsPerDay[daysCounted] = eventsInThisDay;
daysCounted++;
}
console.log(eventsPerDay);
Notice that I reverse the sample array before running my execution. That is because your sample starts at May 29 and ends at May 25, so it's running backwards in time.
I encourage you to try your own code on a reversed array, might very well be the case that your solution is correct.
If you do not want to reverse the array, you could "reverse the counting" by going from the latest midnight to the first midnight, subtracting 1 day on each iteration.
In my opininion (and coming example), you can do it a bit simpler. Also, I've noticed a little problem in your function: if your dataArray and number of days (let's call them N) were big, you would have to iterate over the data array N number of times. It could become inefficient. Luckily you can do it in one loop iteration:
let sensorEventTotal = (data, start, daysNum) => {
// We create array of length daysNum filled with 0's.
let days = new Array(daysNum);
days.fill(0);
for(let entry of data) {
// If below the start timestamp, continue loop.
if(entry < start) continue;
// We calculate which day it is.
let index = parseInt((entry - start) / fullDay);
// We check if the entry is not from days we do not count.
if(index < daysNum)
days[index]++;
}
return days;
}
Code with working examples: http://jsbin.com/lekiboruki/edit?js,console.
EDIT: You didn't mention if your dataArray is sorted. My answer would also work on unsorted arrays.

Create array of dates and minutes with JavaScript

How can I create an array of dates with format DD-MM-YYYY from today and 1 ahead?
I guess it's something like
var dates = [];
var date = moment();
while (date <= date.clone().add(1, 'month')) {
dates.push(date.format('DD-MM-YYYY'));
date = date.clone().add(1, 'd');
}
but is this the best way to do it?
And how can I do the same with minutes? I want an array with ['00:00', '00:05', '00:10', ..., '23:50', '23:55'].
I guess it's something like
var minutes = [];
var time = moment('00:00', 'hh:mm');
while (time < time.clone().add(1, 'day')) {
minutes.push(time.format('hh:mm'));
time = time.clone().add(5, 'minutes');
}
It's not important to use moment.js for this, but I guess it's easier.
Since these can be general functionality, you should make them configurable.
Time Array
For Time array, i guess creating moment object and manipulating its values will be a waste of resource. You can do that with normal loops.
Non moment version
function getDoubleDigits(str) {
return ("00" + str).slice(-2);
}
function formatTime(h, m, is24Hr) {
var tmp = "";
if(is24Hr){
tmp =" " + (Math.floor(h/12) ? "p.m." : "a.m.")
h=h%12;
}
return getDoubleDigits(h) + ":" + getDoubleDigits(m) + tmp;;
}
function getTimeByInterval(interval, is24HrFormat) {
var times = []
for (var i = 0; i < 24; i++) {
for (var j = 0; j < 60; j += interval) {
times.push(formatTime(i, j, is24HrFormat))
}
}
return times.slice(0);
}
console.log(getTimeByInterval(5, false))
console.log(getTimeByInterval(5, true))
Date Array
Since you want dates between 2 dates with a specific interval, its better to make them configurable:
Moment version
I have made even format configurable in this version. This can be done in non-moment version as well but I guess that(how to format date in pure JS) goes out of question's scope and so not doing that.
function getDatesInrange(d1, d2, interval, format){
var dates = [];
while(d1.isBefore(d2)){
dates.push(d1.format(format));
d1.add(interval, "days");
}
console.log(dates)
return dates.slice(0)
}
getDatesInrange(moment(), moment().add(1, "month"), 1, "DD-MM-YYYY")
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
Non Moment Version
function getDatesInrange(d1, d2, interval){
var dates = [];
while(+d1 < +d2){
dates.push(formateDate(d1));
d1.setDate(d1.getDate() + interval)
}
console.log(dates)
return dates.slice(0)
}
function formateDate(date){
return [getDoubleDigits(date.getDate()),
getDoubleDigits(date.getMonth() +1),
date.getFullYear()].join('-')
}
var startDate = new Date();
var endDate = new Date();
endDate.setMonth(endDate.getMonth() + 1);
getDatesInrange(startDate, endDate, 1)
function getDoubleDigits(str) {
return ("00" + str).slice(-2);
}
Nothing wrong with your current implementation idea (except that the current code will cause an infinite loop. The ceiling should be declared separately), but since moment.js can take objects for duration, it's also possible to create a single helper function in which the values are calculated. For some cases this may not be the most efficient way (for times without a date, this could be overkill), but it would keep it versatile. e.g. if the range should stay the same but only the format should change to include a date, only one parameter would have to be changed.
The example below uses an ES6 generator, but the same could be easily converted to return an array instead:
function* createRange(start, duration, interval, format){
let dt= start.clone(), target = start.clone().add(duration);
while(dt < target){
yield dt.format(format);
dt.add(interval || {years:1});
}
}
let dates = createRange(moment(),{month:1}, {days:1}, 'DD-MM-YYYY'),
times= createRange(moment('00:00','HH:mm'),{days:1},{minutes:5}, 'HH:mm');
console.log([...dates]);
console.log([...times]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
Of course if certain ranges, such as the month from now, are recurring, they can be put in a separate function which calls the range function.

How to group array of dates to periods startdate-enddate? If one weekday is missing between dates then new period begins in Javascript

20.01.2017
23.01.2017
24.01.2017
25.01.2017
26.01.2017
27.01.2017
31.01.2017
01.02.2017
Lets say i have these dates. All those dates are workdays.
Output should be
20.01.2017-27.01.2017
and
31.01.2017-01.02.2017
Since 30 January is workday and so the first period is not continiuing and new period starts.
What is the best way to approach this.
I was thinking taking first date in array and putting it into a new array. Then comparing next date in array to the previous one if it's next day (ignoring weekends). If it is not nextday then take previous date and put it to array as end date and then start a new array of next period.
Get your first date (I'm supossing you have them ordered, as in your example data they are) and store it on a variable for the start date.
Store the same value also in another variable for the end date.
Now loop through your dates checking if current looped date is the next one after your current end date. If it's, store your current looped date into the end date variable and continue to the next loop. If it isn't return current start and end dates and store your currently looped date as a new period start date, go on until loop ends and return current variables.
This would be my approach, though not the shortest or maybe best way of facing this. Just take it as an idea
var array = [
"20.01.2017",
"23.01.2017",
"24.01.2017",
"25.01.2017",
"26.01.2017",
"27.01.2017",
"31.01.2017",
"01.02.2017"
];
var isNextDay = function(day, nextDay) {
var day1 = new Date(day.slice(3, 6) + day.slice(0, 3) + day.slice(6)); //had to format the date this way to make a valid date
day1.setDate(day1.getDate() + 1); //sets the next day, nextday of 30 or 31(last day of month) is 1
var day2 = new Date(nextDay.slice(3, 6) + nextDay.slice(0, 3) + nextDay.slice(6));
if (day1.getTime() === day2.getTime()) {
return true;
} else {
return false;
}
}
var dateGroup = function(dateStrings) {
var res = [];
var aux = dateStrings[0] + "-";
for (var i = 1; i < dateStrings.length; i++) {
if (!isNextDay(dateStrings[i - 1], dateStrings[i])) {
aux += dateStrings[i - 1];
res.push(aux);
aux = dateStrings[i] + "-";
}
}
aux += dateStrings[dateStrings.length - 1];
res.push(aux); //this is because the last one never gets pushed
return res;
}
var output = dateGroup(array);
You can loop over the dates and calculate what the string for the next date should look like, then compare to see if it's the same. If not, end the previous period and start a new one.
You can use a library to parse and format the dates, but simple functions to do the job are just a couple of lines, e.g.
var dates = ['20.01.2017','23.01.2017','24.01.2017',
'25.01.2017','26.01.2017','27.01.2017',
'31.01.2017','01.02.2017'];
/* Parse date in format D/M/YYYY
** #param {string} s - date to parse lke 23.1.2017
** #returns {Date}
*/
function parseDMY(s) {
var b = s.split(/\D/);
return new Date(b[2], b[1]-1, b[0]);
}
/* Format a date in DD/MM/YYYY with supplied separator
** #param {Date} date - date to format
** #param {string} s - separator, default is /
** #returns {string} date formatted as DD/MM/YYYY with supplied separator
*/
function formatDMY(date, s) {
s = s || '/';
function z(n){return (n<10?'0':'')+n}
return [z(date.getDate()),z(date.getMonth()+1),
date.getFullYear()].join(s);
}
/* Create array of date ranges in DD.MM.YYYY-DD.MM.YYYY format
** #param {Array} data - array of date strings in DD.MM.YYYY format
** #returns {Array} array of range strings in DD.MM.YYYY-DD.MM.YYYY format
*/
function createRanges(data) {
var result = [];
var previous;
data.forEach(function(s, i) {
var previous, previousNext, current, range;
// If on first loop, create a range using first value
if (i == 0) {
result.push(s + '-' + s);
// Otherwise, get end date of last range and add one day
} else {
previous = result[result.length-1].split('-')[1];
previousNext = parseDMY(previous);
previousNext.setDate(previousNext.getDate() + 1);
previousNext = formatDMY(previousNext,'.');
// If current date is same as previousNext, update range.
// Otherwise, start a new range
if (s == previousNext) {
range = result[result.length-1];
result[result.length-1] = range.split('-')[0] + '-' + s;
} else {
result.push(s + '-' + s);
}
}
});
// Remove zero day ranges. Could do this by checking last range
// when creating a new one but seems simpler to do it here
result = result.filter(s=>!(s.split('-')[0] == s.split('-')[1]));
return result;
}
console.log(createRanges(dates));
However, a library like moment.js will help with parsing, formatting and arithmetic.
Same as made by Leandro, but made for an array with Date objects and with using moment.js
function groupDates(dates) {
const res = [];
const isNextDay = (day, nextDay) => moment(day).add(1, 'day').isSame(nextDay, 'day');
const format = "DD.MM.YYYY";
let aux = moment(dates[0]).format(format) + "-";
for (let i = 1; i < dates.length; i++) {
if (!isNextDay(dates[i - 1], dates[i])) {
aux += moment(dates[i - 1]).format(format);
res.push(aux);
aux = moment(dates[i]).format(format) + "-";
}
}
aux += moment(dates[dates.length - 1]).format(format);
res.push(aux);
return res;
}
My solution with Luxon lib
const DateTime = luxon.DateTime;
const test = [
"2022-06-23",
"2022-06-24",
"2022-06-25",
"2022-06-26",
"2022-06-27",
"2022-06-28",
"2022-06-29",
"2022-05-02",
"2022-05-03",
"2022-05-05",
"2022-05-04",
"2022-05-06",
"2022-05-07",
"2022-05-08",
];
function getRanges(datesArr) {
const periods = [];
let ix = 0;
const dates = datesArr.map((d) => DateTime.fromSQL(d));
dates.sort();
dates.forEach((date, index) => {
if (index === 0) {
periods.push([
date,
]);
} else if (date.diff(dates[index - 1], [ 'days' ]).days === 1) {
periods[ix].push(date);
} else {
ix += 1;
periods.push([ date ]);
}
})
return periods;
}
console.log(getRanges(test));
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.4.0/luxon.min.js"></script>
Then you can get first and last elements from each ranges

Find the next closest date in MM/DD/YYYY format JavaScript

I have an array of dates formatted as MM/DD/YYYY. I need to find the next closest date in the future starting from today. Say today was 1/22/2016 then 2/19/2016 would return.
2/3/2015
7/5/2015
1/21/2016
2/19/2016
7/1/2016
I've tried doing substrings to get the month, day, year separate and attempting a sort based off those values but surely there has to be a better way.
There is no need for a sorting algorithm. You only need to iterate once and find the closest date that is greater or equals today.
Pseudocode
closest <- infinity
foreach date in dates:
if (date >= now and date < closest) then
closest <- d
return closest
JavaScript
const dates = [
'2/3/2035',
'7/5/2035',
'1/21/2036',
'2/19/2036',
'7/1/2036',
'10/22/2039',
'08/12/2039',
];
const now = new Date();
let closest = Infinity;
dates.forEach(function(d) {
const date = new Date(d);
if (date >= now && (date < new Date(closest) || date < closest)) {
closest = d;
}
});
console.log(closest);
Personally I would use a library such as the very good Moment.JS library, to handle all the horrible complexity of dates.
It has a difference method:
http://momentjs.com/docs/#/displaying/difference/
e.g.
var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
a.diff(b) // 86400000
It would then be trivial to Math.min() the differences of each date in your list.
There's also a moment.min, which might shortcut this entirely, if all your dates are in the future already:
http://momentjs.com/docs/#/get-set/min/
A naïve implementation would be to parse each date as a string and sort them in ascending order. Then, remove any dates that are in the past, and get the first child of the array of remaining dates. See this jsbin example:
var dates = [
'2/3/2015',
'7/5/2015',
'1/21/2016',
'2/19/2016',
'7/1/2016'
];
// parse each string as a Date object and sort them in ascending order
function sortDates(dates) {
return dates.map(function(date) {
return new Date(date).getTime();
}).sort(function(a, b) {
return a - b;
});
}
var orderedDates = sortDates(dates);
// remove any dates in the past, and get the first child of the array of remaining dates
var nextDate = orderedDates.filter(function(date) {
return (Date.now() - date) > 0;
})[0];
Keep in mind that this depends on the format of the date string that you pass to the Date object (in other words, is 1/12/2015 January 12th, or December 1st? JavaScript will parse it as January 12th.
You can use while loop, new Date()
var dates = ["2/3/2015","7/5/2015","1/21/2016","2/19/2016","7/1/2016"]
, d = "1/22/2016", n = -1, res = null;
while (++n < dates.length && new Date(dates[n]) < new Date(d));
res = dates[n] || d;
console.log(res)
Lots of answers, one more can't hurt.
Date strings should always be manually parsed. A library can help, but if you only have a single format, a simple function is all that's required.
The following uses reduce to loop over the array of dates and finds the closest future date. If no date is in the future, it returns null.
The returned value is the string from the array, not a Date.
function parseMDY(s) {
var b = (s || '').split(/\D/);
return new Date(b[2], b[0]-1, b[1])
}
function getClosestDateToToday(arr) {
var now = new Date();
now.setHours(23,59,59);
return arr.reduce(function (acc, s) {
var d = parseMDY(s);
return d < now? acc : (acc && d > parseMDY(acc)? acc : s);
}, null);
}
var dates = ['2/3/2015', '7/5/2015','1/21/2016',
'2/19/2016','7/1/2016'];
document.write(getClosestDateToToday(dates));
This really depends upon your dates and data structures (the ones shown in original example are not so great for me).
From the other answers...
To take the example from Josh, you could also keep a pointer to which date you are using, or simply shift off of a sorted queue of dates to make it work, but it's really adding noise to your code, disrupting the purpose.
Frederik.L answer is really beautiful code, but it would still have to be executed multiple times, so I cannot recommend it.
Feedback warning
I've been given feedback in comments that Date.parse can behave inconsistently. I'll move to passing a date parsing callback function, and demonstrate Date.UTC usage in the callback for OP-specific date format. Please be careful when defining your own callbacks, and please do not copy-paste.
Suggestion
I'd suggest utilizing Date functions i.e. Date.parse; but also try where possible to get data sources sorted without needing application-level sorting. Then you can store-once and step through the array using array.shift() or similar;
Ideally also YYYY-MM-DD
Four-Digit Year
Two-Digit Month
Two-Digit Day
... (continue from least occurring to most occurring)
sample code
var dates = [
'2/3/2015',
'7/5/2015',
'7/1/2016',
'1/21/2016',
'2/19/2016'
]; // unsorted garbage dates
var DateList = function( dateList, getDate ) {
var sortedDates = dateList.sort( function(a, b) {
return getDate(a) - getDate(b);
});
this.next = function() {
var dt = sortedDates.shift();
sortedDates.push(dt); // comment to remove cyclical nature
return dt;
}
};
// specific implementation parser for this format
var getDisgustingDateFormat = function(dStr) {
var dParts = dStr.split('/');
return new Date(Date.UTC(dParts[2],dParts[0],dParts[1]));
};
var dl = new DateList( dates, getDisgustingDateFormat );
Usage
dl.next(); // "2/3/2015"
dl.next(); // "7/5/2015"
dl.next(); // "1/21/2016"
dl.next(); // "2/19/2016"
dl.next(); // "7/1/2016"
dl.next(); // "2/3/2015"
Hope this helps (Updated for clarity)
What about this version using for of and momentjs:
const getClosestFutureDate = (dates) => {
if (dates.length === 0) {
return null;
}
let minDiff = 0;
for (const date of dates) {
minDiff += minDiff + 30;
var currentDate = moment(date);
if (currentDate.isAfter(moment()) && currentDate.diff(moment(), "days") <= minDiff) {
break;
}
}
return currentDate;
};
Assuming now = 2019-08-21
console.log(getClosestFutureDate(["2019-05-07", "2019-06-01", "2019-07-13", "2019-11-09", "2019-11-10", "2019-11-11"]));
// 2019-11-09
I am fan of momentjs, but this can be easily refactored to use only vanilla Date.
const FindDate = (date, allDate) => {
// moment().diff only works on moment(). Make sure both date and elements in allDate list is in moment
let nearestDate = -1;
allDate.some(d => {
const currentDate = moment(d)
const difference = currentDate.diff(date); // Or date.diff(currentDate) depending on what you're trying to find
if(difference >= 0){
nearestDate = d
}
});
console.log(nearestDate)
}
In Livescript:
x =
* "2/3/2015"
* "7/5/2015"
* "1/21/2016"
* "2/19/2016"
* "7/1/2016"
sim-unix-ts = (date-str) ->
# Simulate unix timestamp like concatenating
# convert "MM/DD/YYYY" to YYYYMMDD (integer)
# so we can simply compare these integers
[MM, DD, YYYY] = date-str.split "/"
MM = "0#{MM}".slice -2 # apply zero padding
DD = "0#{DD}".slice -2 # apply zero padding
parse-int "#{YYYY}#{MM}#{DD}"
today = sim-unix-ts "2/18/2016"
date-list = [sim-unix-ts(..) for x]
# find next date
next-dates = [.. for date-list when .. > today]
next-date = next-dates.0
next-date-orig = x[date-list.index-of next-date]
alert [next-date, next-date-orig]
..in Javascript:
var x, simUnixTs, today, dateList, res$, i$, x$, len$, nextDates, y$, nextDate, nextDateOrig;
x = ["2/3/2015", "7/5/2015", "1/21/2016", "2/19/2016", "7/1/2016"];
simUnixTs = function(dateStr){
var ref$, MM, DD, YYYY;
ref$ = dateStr.toString().split("/"), MM = ref$[0], DD = ref$[1], YYYY = ref$[2];
MM = ("0" + MM).slice(-2);
DD = ("0" + DD).slice(-2);
return parseInt(YYYY + "" + MM + DD);
};
today = simUnixTs("2/18/2016");
res$ = [];
for (i$ = 0, len$ = x.length; i$ < len$; ++i$) {
x$ = x[i$];
res$.push(simUnixTs(x$));
}
dateList = res$;
res$ = [];
for (i$ = 0, len$ = dateList.length; i$ < len$; ++i$) {
y$ = dateList[i$];
if (y$ > today) {
res$.push(y$);
}
}
nextDates = res$;
nextDate = nextDates[0];
nextDateOrig = x[dateList.indexOf(nextDate)];
alert([nextDate, nextDateOrig]);

Categories

Resources