I have two dates: Startdate and enddate
startdate = "10/10/2018" enddate = "03/09/2019"
I am trying to create an array of dates between those 2 dates. I have the following code.
function getDateArray (start, end) {
var arr = [];
var startDate = new Date(start);
var endDate = new Date(end);
endDate.setMonth( endDate.getMonth());
while (startDate <= endDate) {
arr.push(new Date(startDate));
startDate.setMonth(startDate.getMonth() + 1);
}
return arr;
}
Then calculate the number of days between those months in between.
10/10/2018 to 11/10/2018 = 30 days
11/10/2019 to 12/10/2018 = 30 days or so depending on number of days between the 2 dates and then create an array of the dates.
[30,30,31....till end date]
function daysBetween(date1, date2 )
{
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
var dayDifference = Math.ceil(timeDiff / (1000 * 3600 * 24));
return dayDifference;
}
I tried the following code and it's returning the array of number of dates however, it's not accurate. It keeps returning 32 days in October. The output it's giving right now is as follows. I am not sure what i am doing wrong here but it looks like it's only going till February and displaying the result.
Any help will be appreciated. Thank you.
Output: [32,30,31,31,28]
var dateArr = getDateArray(z, y);
console.log(dateArr);
var dayCounts = "";
for (var x = 0; x < dateArr.length-1; x++)
{
dayCounts += daysBetween(dateArr[x], dateArr[x+1]);
}
console.log("datearrlength" + dateArr.length);
console.log(dayCounts);
i think this will work for you,
Date.prototype.addDay= function(days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}
function getDateBwStartandEnd(sdate, edate) {
var dateArray = new Array();
var currentDate = sdate;
while (currentDate <= edate) {
dateArray.push(new Date (currentDate));
currentDate = currentDate.addDay(1);
}
return dateArray;
}
** Shamelessly copied from web, but this works fine for me.
While the following doesn't answer your question it is an alternative approach to the overall problem you are attempting to solve.
One approach would be to simply get the time difference between the two dates and then divide by the number of microseconds in a day. As you will notice though it is not exact and so a floor is used to get the days. There are other concerns with this approach as well such as date ranges before the epoch but it is a very simplistic approach and might work depending on your needs.
const startDate = '10/10/2018';
const endDate = '03/09/2019';
const start = (new Date(startDate)).valueOf();
const end = (new Date(endDate)).valueOf();
const timeBetween = end - start;
console.log({timeBetween, days: Math.floor(timeBetween/86400000)});
A slightly more robust is to essentially use a counter that increments itself by adding 1 day to the counter and the start date while the start date is less than the end date. Again, there are some concerns with this approach but that also depends on your needs.
const startDate = '10/10/2018';
const endDate = '03/09/2019';
let start = new Date(startDate);
const end = (new Date(endDate)).valueOf();
let daysBetween = 0;
while (start.valueOf() < end) {
daysBetween++;
start.setDate(start.getDate() + 1);
}
console.log(daysBetween);
Finally, a more robust solution to avoid the variety of issues with manipulating and working with dates is to use a library like momentjs. Using its difference method would look like the following.
const start = moment([2018, 10, 10]);
const end = moment([2019, 3, 9]);
console.log(end.diff(start, 'days'));
<script src="http://momentjs.com/downloads/moment.min.js"></script>
Using the following code worked for me. I added 1 extra month to my end date and it gives the proper date range. Also, instead of Math.ceil, i used Math.round and it gives the right number of date.
function getDateArray (start, end) {
var arr = [];
var startDate = new Date(start);
var endDate = new Date(end);
endDate.setMonth( endDate.getMonth());
while (startDate <= endDate) {
arr.push(new Date(startDate));
startDate.setMonth(startDate.getMonth() + 1);
}
return arr;
}
Related
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
this code already gets the days until x date but it keeps counting when x date reaches the same date, how can I zero it out to stop counting?
const counters = this.state.counters.map((counters, i) => {
let untildate = counters.date
let diffDays1=(function(){
let oneDay = 24*60*60*1000 // hours*minutes*seconds*milliseconds
let secondDate = new Date(untildate);
let firstDate = new Date();
return (`${Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)))} Days`)
})();
If the input date is 2019-04-05T20:00:00.782Z the out put should be 0
Use Math.max to return the larger of two values. In your case, you want to return the number of days remaining only if that number is greater than 0, otherwise you want to return 0:
const counters = this.state.counters.map((counters, i) => {
let untildate = counters.date
let diffDays1=(function(){
let oneDay = 24*60*60*1000 // hours*minutes*seconds*milliseconds
let secondDate = new Date(untildate);
let firstDate = new Date();
return (`${Math.max(0, Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay))))} Days`)
})();
There are many answers for how to get the difference between two dates in days, like this.
Your code seems overly convoluted. Assuming the input dates are in a format like 2019-05-10 and you're using the built-in parser, you can work in UTC and avoid any daylight saving issues.
Just test the difference in days, if it's 0 or less, return zero. Otherwise, return the difference. E.g.
var dates = ['2019-01-01','2019-05-10','2019-05-20'];
var counters = dates.map(date => {
let diffDays = (new Date(date) - new Date().setUTCHours(0,0,0,0))/8.64e7;
return diffDays > 0? diffDays : 0;
});
console.log(counters)
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);
I am trying to get the date for the next instance of a weekday after a given date. The weekday may be any day from Monday through Sunday. I am using the Moment.js library but there doesn't seem to be a simple way to achieve what I am after.
This is what I have so far but it's not returning the date I want:
// competition.startDate = 2016-02-10 (Wednesday)
var startDate = moment(competition.startDate);
...
for (m = 0; m < matchesPerRound; m++) {
var date;
...
// matchTime[m].day = 3 (Wednesday)
date = startDate.startOf('week').add(7, 'days').subtract(matchTime[m].day, 'days');
console.log(date.format('YYYY-MM-DD'));
// Actual Output = 2016-02-11
// Expected Output = 2016-02-10
...
}
With the example above, I need it returning 2016-02-15 as this is the next Monday after 2016-02-10. This is no problem, and I can get that date. My problem is that I need something more dynamic, as matchTime[m].day could be any weekday number. For example, if matchTime[m].day = 3 // Wednesday, it should just return the same startDate 2016-02-10 as this is a Wednesday.
I'm trying to avoid conditional statements if possible, but I am wondering if Moment.js has the functionality out of the box to produce these results.
UPDATE
I've come up with a solution, and it's working with my requirements, but I feel it's very messy. Does someone else have a cleaner, more concise solution?
var date;
var startDate = moment(competition.startDate);
var proposedDate = moment(startDate).startOf('isoweek').add(matchTimes[0].day - 1, 'd');
if ( startDate.isAfter(proposedDate) ) {
date = startDate.startOf('isoweek').add(7 + Number(matchTimes[0].day) - 1, 'd');
} else {
date = startDate.startOf('isoweek').add(matchTimes[0].day - 1, 'd');
}
I don't know about moment.js, but it seems rather complex for something rather simple.
function firstMatchingDayOfWeek(day, date) {
var delta = date.getDay() - day,
result = new Date(date);
if (delta) {
result.setDate(result.getDate() + ((7 - delta) % 7));
}
return result;
}
I think the code is rather self-explanatory (don't we all ;-) ), but in order to clarify the steps:
firstMatchingDayOfWeek(day, date) > call the function specifying the day of week (0-6) and a date object
delta = date.getDay() - day > calculate how many days the date needs to shift in order to reach the same day of week
result = new Date(date) > create a new Date instance based on the input (so you get to preserve the original date)
result.setDate(result.getDate() + ((7 - delta) % 7)) > set the date part (day of month) to a week minus the delta, modulo a week (as delta can be negative and you want the first occurrence of the same day)
function firstMatchingDayOfWeek(day, date) {
var delta = date.getDay() - day,
result = new Date(date);
if (delta) {
result.setDate(result.getDate() + ((7 - delta) % 7));
}
return result;
}
// tests
for (var i = 1; i < 28; ++i){
var check = new Date('2016-02-' + ('00' + i).substr(-2)),
output = document.querySelector('#out')
.appendChild(document.createElement('pre')),
log = [];
log.push('input: ' + check);
for (var day = 0; day <= 6; ++day) {
var next = firstMatchingDayOfWeek(day, check);
log.push(day + ' > ' + next);
}
output.innerText = log.join('\n');
}
pre {
border: 1px solid gold;
}
<div id="out"></div>
Here's a possible answer too using momentjs (assumes match days will be 0 (sunday) - 6):
var startDate = moment(competition.startDate);
var matchDay = Number(matchTimes[0].day);
var daysToAdd = Math.ceil((startDate.day() - matchDay) / 7) * 7 + matchDay;
var proposedDate = moment(startDate).startOf('week').add(daysToAdd, 'd');
This is a pure JS version:
Logic
Find current day.
Find days to add to get to start of next week.
Get day number for the day to find date.
Compute date with this date.
JSFiddle.
function claculateNextDate() {
var date = new Date();
var nextDay = document.getElementById("dayOfWeek").value;
var day = date.getDay();
var noOfDaysToAdd = (7 - day) + parseInt(nextDay);
date.setDate(date.getDate() + noOfDaysToAdd);
document.getElementById("result").innerHTML = date.toDateString();
}
<select id="dayOfWeek">
<option value="0">Sunday</option>
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
<option value="6">Saturday</option>
</select>
<button onclick="claculateNextDate()">Calculate Next Date</button>
<p id="result"></p>
My solution
var weekDayToFind = moment().day('Monday').weekday() //change monday to searched day name
var givenDate = moment('2016-02-10') // pass the given date
var searchDate = moment(givenDate)
while (searchDate.weekday() !== weekDayToFind){
searchDate.add(1, 'day');
}
Given two Date() objects, where one is less than the other, how do I loop every day between the dates?
for(loopDate = startDate; loopDate < endDate; loopDate += 1)
{
}
Would this sort of loop work? But how can I add one day to the loop counter?
Thanks!
Here's a way to do it by making use of the way adding one day causes the date to roll over to the next month if necessary, and without messing around with milliseconds. Daylight savings aren't an issue either.
var now = new Date();
var daysOfYear = [];
for (var d = new Date(2012, 0, 1); d <= now; d.setDate(d.getDate() + 1)) {
daysOfYear.push(new Date(d));
}
Note that if you want to store the date, you'll need to make a new one (as above with new Date(d)), or else you'll end up with every stored date being the final value of d in the loop.
Based on Tom GullenĀ“s answer.
var start = new Date("02/05/2013");
var end = new Date("02/10/2013");
var loop = new Date(start);
while(loop <= end){
alert(loop);
var newDate = loop.setDate(loop.getDate() + 1);
loop = new Date(newDate);
}
I think I found an even simpler answer, if you allow yourself to use Moment.js:
// cycle through last five days, today included
// you could also cycle through any dates you want, mostly for
// making this snippet not time aware
const currentMoment = moment().subtract(4, 'days');
const endMoment = moment().add(1, 'days');
while (currentMoment.isBefore(endMoment, 'day')) {
console.log(`Loop at ${currentMoment.format('YYYY-MM-DD')}`);
currentMoment.add(1, 'days');
}
<script src="https://cdn.jsdelivr.net/npm/moment#2/moment.min.js"></script>
If startDate and endDate are indeed date objects you could convert them to number of milliseconds since midnight Jan 1, 1970, like this:
var startTime = startDate.getTime(), endTime = endDate.getTime();
Then you could loop from one to another incrementing loopTime by 86400000 (1000*60*60*24) - number of milliseconds in one day:
for(loopTime = startTime; loopTime < endTime; loopTime += 86400000)
{
var loopDay=new Date(loopTime)
//use loopDay as you wish
}
Here simple working code, worked for me
var from = new Date(2012,0,1);
var to = new Date(2012,1,20);
// loop for every day
for (var day = from; day <= to; day.setDate(day.getDate() + 1)) {
// your day is here
console.log(day)
}
var start = new Date("2014-05-01"); //yyyy-mm-dd
var end = new Date("2014-05-05"); //yyyy-mm-dd
while(start <= end){
var mm = ((start.getMonth()+1)>=10)?(start.getMonth()+1):'0'+(start.getMonth()+1);
var dd = ((start.getDate())>=10)? (start.getDate()) : '0' + (start.getDate());
var yyyy = start.getFullYear();
var date = dd+"/"+mm+"/"+yyyy; //yyyy-mm-dd
alert(date);
start = new Date(start.setDate(start.getDate() + 1)); //date increase by 1
}
As a function,
function getDatesFromDateRange(from, to) {
const dates = [];
for (let date = from; date <= to; date.setDate(date.getDate() + 1)) {
const cloned = new Date(date.valueOf());
dates.push(cloned);
}
return dates;
}
const start = new Date(2019, 11, 31);
const end = new Date(2020, 1, 1);
const datesArray = getDatesFromDateRange(start, end);
console.dir(datesArray);
Based on Tabare's Answer,
I had to add one more day at the end, since the cycle is cut before
var start = new Date("02/05/2013");
var end = new Date("02/10/2013");
var newend = end.setDate(end.getDate()+1);
var end = new Date(newend);
while(start < end){
alert(start);
var newDate = start.setDate(start.getDate() + 1);
start = new Date(newDate);
}
Didn't want to store the result in an array, so maybe using yield?
/**
* #param {object} params
* #param {Date} params.from
* #param {Date} params.to
* #param {number | undefined} params.incrementBy
* #yields {Date}
*/
function* iterateDate(params) {
const increaseBy = Math.abs(params.incrementBy ?? 1);
for(let current = params.from; current.getTime() <= params.to.getTime(); current.setDate(current.getDate() + increaseBy)) {
yield new Date(current);
}
}
for (const d of iterateDate({from: new Date(2021,0,1), to: new Date(2021,0,31), incrementBy: 1})) {
console.log(d.toISOString());
}
If you want an efficient way with milliseconds:
var daysOfYear = [];
for (var d = begin; d <= end; d = d + 86400000) {
daysOfYear.push(new Date(d));
}
Let us assume you got the start date and end date from the UI and stored it in the scope variable in the controller.
Then declare an array which will get reset on every function call so that on the next call for the function the new data can be stored.
var dayLabel = [];
Remember to use new Date(your starting variable) because if you dont use the new date and directly assign it to variable the setDate function will change the origional variable value in each iteration`
for (var d = new Date($scope.startDate); d <= $scope.endDate; d.setDate(d.getDate() + 1)) {
dayLabel.push(new Date(d));
}
Based on Jayarjo's answer:
var loopDate = new Date();
loopDate.setTime(datFrom.valueOf());
while (loopDate.valueOf() < datTo.valueOf() + 86400000) {
alert(loopDay);
loopDate.setTime(loopDate.valueOf() + 86400000);
}