moment JS get number of weeks in a month - javascript

I am trying to calculate number of weeks in a month using moment js. But I am getting wrong results for some months like May 2015 and August 2015.
I am using this code.
var start = moment().startOf('month').format('DD');
var end = moment().endOf('month').format('DD');
var weeks = (end-start+1)/7;
weeks = Math.ceil(weeks);
Is there any prebuilt method in moment JS for getting number of weeks.

I have created this gist that finds all the weeks in a given month and year. By calculated the length of calendar, you will know the number of weeks.
https://gist.github.com/guillaumepiot/095b5e02b4ca22680a50
# year and month are variables
year = 2015
month = 7 # August (0 indexed)
startDate = moment([year, month])
# Get the first and last day of the month
firstDay = moment(startDate).startOf('month')
endDay = moment(startDate).endOf('month')
# Create a range for the month we can iterate through
monthRange = moment.range(firstDay, endDay)
# Get all the weeks during the current month
weeks = []
monthRange.by('days', (moment)->
if moment.week() not in weeks
weeks.push(moment.week())
)
# Create a range for each week
calendar = []
for week in weeks
# Create a range for that week between 1st and 7th day
firstWeekDay = moment().week(week).day(1)
lastWeekDay = moment().week(week).day(7)
weekRange = moment.range(firstWeekDay, lastWeekDay)
# Add to the calendar
calendar.push(weekRange)
console.log calendar

Can be easily done using raw javascript:
function getNumWeeksForMonth(year,month){
date = new Date(year,month-1,1);
day = date.getDay();
numDaysInMonth = new Date(year, month, 0).getDate();
return Math.ceil((numDaysInMonth + day) / 7);
}
You get the day index of the first day, add it to the number of days to compensate for the number of days lost in the first week, divide by 7 and use ceil to add 1 for the simplest overflow in the next week

It display the list of weeks in a month with 'moment.js'.
It has been written in typescript with angular 6+.
Install moment with 'npm i moment'
Inside the ts file.
weeks_in_month() {
let year = 2019; // change year
let month = 4; // change month here
let startDate = moment([year, month - 1])
let endDate = moment(startDate).endOf('month');
var dates = [];
var weeks = [];
var per_week = [];
var difference = endDate.diff(startDate, 'days');
per_week.push(startDate.toDate())
let index = 0;
let last_week = false;
while (startDate.add(1, 'days').diff(endDate) < 0) {
if (startDate.day() != 0) {
per_week.push(startDate.toDate())
}
else {
if ((startDate.clone().add(7, 'days').month() == (month - 1))) {
weeks.push(per_week)
per_week = []
per_week.push(startDate.toDate())
}
else if (Math.abs(index - difference) > 0) {
if (!last_week) {
weeks.push(per_week);
per_week = [];
}
last_week = true;
per_week.push(startDate.toDate());
}
}
index += 1;
if ((last_week == true && Math.abs(index - difference) == 0) ||
(Math.abs(index - difference) == 0 && per_week.length == 1)) {
weeks.push(per_week)
}
dates.push(startDate.clone().toDate());
}
console.log(weeks);
}
Result:
Array of date moments.
[Array(6), Array(7), Array(7), Array(7), Array(3)]
0: (6) [Mon Apr 01 2019 00:00:00 GMT+0530 (India Standard Time),
Tue Apr 02 2019 00:00:00 GMT+0530 (India Standard Time),
Wed Apr 03 2019 00:00:00 GMT+0530 (India Standard Time),
Thu Apr 04 2019 00:00:00 GMT+0530 (India Standard Time),
Fri Apr 05 2019 00:00:00 GMT+0530 (India Standard Time),
Sat Apr 06 2019 00:00:00 GMT+0530 (India Standard Time)]
1: (7) [Sun Apr 07 2019 00:00:00 GMT+0530 (India Standard Time),
Mon Apr 08 2019 00:00:00 GMT+0530 (India Standard Time),
Tue Apr 09 2019 00:00:00 GMT+0530 (India Standard Time),
Wed Apr 10 2019 00:00:00 GMT+0530 (India Standard Time),
Thu Apr 11 2019 00:00:00 GMT+0530 (India Standard Time),
Fri Apr 12 2019 00:00:00 GMT+0530 (India Standard Time),
Sat Apr 13 2019 00:00:00 GMT+0530 (India Standard Time)]
2: (7) [Sun Apr 14 2019 00:00:00 GMT+0530 (India Standard Time),
Mon Apr 15 2019 00:00:00 GMT+0530 (India Standard Time),
Tue Apr 16 2019 00:00:00 GMT+0530 (India Standard Time),
Wed Apr 17 2019 00:00:00 GMT+0530 (India Standard Time),
Thu Apr 18 2019 00:00:00 GMT+0530 (India Standard Time),
Fri Apr 19 2019 00:00:00 GMT+0530 (India Standard Time),
Sat Apr 20 2019 00:00:00 GMT+0530 (India Standard Time)]
3: (7) [Sun Apr 21 2019 00:00:00 GMT+0530 (India Standard Time),
Mon Apr 22 2019 00:00:00 GMT+0530 (India Standard Time),
Tue Apr 23 2019 00:00:00 GMT+0530 (India Standard Time),
Wed Apr 24 2019 00:00:00 GMT+0530 (India Standard Time),
Thu Apr 25 2019 00:00:00 GMT+0530 (India Standard Time),
Fri Apr 26 2019 00:00:00 GMT+0530 (India Standard Time),
Sat Apr 27 2019 00:00:00 GMT+0530 (India Standard Time)]
4: (3) [Sun Apr 28 2019 00:00:00 GMT+0530 (India Standard Time),
Mon Apr 29 2019 00:00:00 GMT+0530 (India Standard Time),
Tue Apr 30 2019 00:00:00 GMT+0530 (India Standard Time)]

EDIT:
NEW and hopefully very correct implementation:
function calcWeeksInMonth(date: Moment) {
const dateFirst = moment(date).date(1);
const dateLast = moment(date).date(date.daysInMonth());
const startWeek = dateFirst.isoWeek();
const endWeek = dateLast.isoWeek();
if (endWeek < startWeek) {
// Yearly overlaps, month is either DEC or JAN
if (dateFirst.month() === 0) {
// January
return endWeek + 1;
} else {
// December
if (dateLast.isoWeekday() === 7) {
// Sunday is last day of year
return endWeek - startWeek + 1;
} else {
// Sunday is NOT last day of year
return dateFirst.isoWeeksInYear() - startWeek + 1;
}
}
} else {
return endWeek - startWeek + 1;
}
}
Outputs the following values for the following dates:
calcWeeksInMonth(moment("2016-12-01")); // 5
calcWeeksInMonth(moment("2017-01-01")); // 6
calcWeeksInMonth(moment("2017-02-01")); // 5
calcWeeksInMonth(moment("2017-03-01")); // 5
calcWeeksInMonth(moment("2017-04-01")); // 5
calcWeeksInMonth(moment("2017-05-01")); // 5
calcWeeksInMonth(moment("2017-06-01")); // 5
calcWeeksInMonth(moment("2017-07-01")); // 6
calcWeeksInMonth(moment("2017-08-01")); // 5
calcWeeksInMonth(moment("2017-09-01")); // 5
calcWeeksInMonth(moment("2017-10-01")); // 6
calcWeeksInMonth(moment("2017-11-01")); // 5
calcWeeksInMonth(moment("2017-12-01")); // 5
calcWeeksInMonth(moment("2018-01-01")); // 5
OLD and very incorrect implementation:
calcWeeksInMonth(date) {
const dateFirst = moment(date).date(1)
const dateLast = moment(date).date(date.daysInMonth())
const startWeek = dateFirst.week()
const endWeek = dateLast.week()
if (endWeek < startWeek) {
return dateFirst.weeksInYear() - startWeek + 1 + endWeek
} else {
return endWeek - startWeek + 1
}
}
This seems to output correct results, feedback welcome if there is something I missed!

function getWeekNums(momentObj) {
var clonedMoment = moment(momentObj), first, last;
// get week number for first day of month
first = clonedMoment.startOf('month').week();
// get week number for last day of month
last = clonedMoment.endOf('month').week();
// In case last week is in next year
if( first > last) {
last = first + last;
}
return last - first + 1;
}

javaScript version here
var year = 2021
var month = 6
var startDate = moment([year, month])
//Get the first and last day of the month
var firstDay = moment(startDate).startOf('month')
var endDay = moment(startDate).endOf('month')
//Create a range for the month we can iterate through
var monthRange = moment.range(firstDay, endDay)
//Get all the weeks during the current month
var weeks = []
var indexOf = [].indexOf;
monthRange.by('days', function (moment) {
var ref;
if (ref = moment.week(), indexOf.call(weeks, ref) < 0) {
return weeks.push(moment.week());
}
});
var calendar, firstWeekDay, i, lastWeekDay, len, week, weekRange;
calendar = [];
for (i = 0, len = weeks.length; i < len; i++) {
week = weeks[i];
// Create a range for that week between 1st and 7th day
firstWeekDay = moment().week(week).day(0);
lastWeekDay = moment().week(week).day(6);
weekRange = moment.range(firstWeekDay, lastWeekDay);
// Add to the calendar
calendar.push(weekRange);
}

This is the best way out , works well
moment.relativeTime.dd = function (number) {
// round to the closest number of weeks
var weeks = Math.round(number / 7);
if (number < 7) {
// if less than a week, use days
return number + " days";
} else {
// pluralize weeks
return weeks + " week" + (weeks === 1 ? "" : "s");
}
}
Source:How to get duration in weeks with Moment.js?

I have not seen a solution that works in all circumstances. I tried all of these but they all are flawed in one way or another. Ditto with several moment.js github threads. This was my crack at it:
getNumberOfWeeksInMonth = (momentDate) => {
const monthStartWeekNumber = momentDate.startOf('month').week();
const distinctWeeks = {
[monthStartWeekNumber]: true
};
let startOfMonth = momentDate.clone().startOf('month');
let endOfMonth = momentDate.clone().endOf('month');
// this is an 'inclusive' range -> iterates through all days of a month
for (let day = startOfMonth.clone(); !day.isAfter(endOfMonth); day.add(1, 'days')) {
distinctWeeks[day.week()] = true
}
return Object.keys(distinctWeeks).length;
}

function weeksInMonth(date = null){
let firstDay = moment(date).startOf('month');
let endDay = moment(date).endOf('month');
let weeks = [];
for (let i = firstDay.week(); i <= endDay.week(); i++){
weeks.push(i)
}
return weeks;
}

Here is a simple way of doing it (based on a solution posted above):
const calcWeeksInMonth = (momentDate) => {
const dateFirst = moment(momentDate).date(1)
const dateLast = moment(momentDate).date(momentDate.daysInMonth())
const startWeek = dateFirst.isoWeek()
const endWeek = dateLast.isoWeek()
if (endWeek < startWeek) {
// cater to end of year (dec/jan)
return dateFirst.weeksInYear() - startWeek + 1 + endWeek
} else {
return endWeek - startWeek + 1
}
}
As far as I can tell, it works correctly for any date thrown at it, but feedback is always welcome!

Throwing this into the mix
import moment from "moment";
export const calcWeeksInMonth = date => {
let weekMonthEnds = moment(date)
.date(moment(date).daysInMonth())
.week();
let weekMonthStarts = moment(date)
.date(1)
.week();
return weekMonthEnds < weekMonthStarts
? moment(date).isoWeeksInYear() - weekMonthStarts + 1
: weekMonthEnds - weekMonthStarts + 1;
};

var month = moment().month();
var startOfMonth = month.startOf("month");
var endOfMonth = month.endOf("month");
var startWeekNumber = startOfMonth.isoWeek();
var endWeekNumber = endOfMonth.isoWeek();
var numberOfWeeks = (endWeekNumber - startWeekNumber + 1);
console.log(numberOfWeeks);

If you have selectedDate value that is give you opportunity to detect which month is active now:
private calculateNumberOfWeeks(): number {
const end = moment(this.selectedDate).endOf('month');
const startDay = moment(this.selectedDate)
.startOf('month')
.day();
const endDay = end.day();
const endDate = end.date();
return (startDay - 1 + endDate + (endDay === 0 ? 0 : 7 - endDay)) / 7;
}

/UPDATE/
Solution below did not take in consideration jump to the new year.
Here is the improved solution.
const getNumberOfWeeksInAMonth = (currentMoment: moment.Moment) => {
const currentMomentCopy = cloneDeep(currentMoment)
const startOfMonth = currentMomentCopy.startOf('month')
const startOfISOWeek = startOfMonth.startOf('isoWeek')
let numberOfWeeks = 0;
do {
numberOfWeeks++
MomentManager.addWeek(startOfISOWeek)
} while (currentMoment.month() === startOfISOWeek.month())
return numberOfWeeks;
}
I have found another solution with momentjs.
const getNumberOfWeeksInMonth = (moment: moment.Moment) => {
const startWeek = moment.startOf('month').isoWeek()
const endWeek = moment.endOf('month').isoWeek()
return endWeek - startWeek + 1
}

Related

Array Push method inside loop not displaying expected results

I have 2 dates. Date1 = "1/1/2022" and Date2 = "1/3/2022". I want to create an array consisting of ["1/1/2022", "1/2/2022", "1/3/2022"]. Quite straightforward. Not sure why my code is not working. Attached is screenshot image of my code after it runs. The array result it's giving me is ["1/4/2022", "1/4/2022", "1/4/2022"].
function test1() {
var array = []
var date1 = new Date(2022, 0, 1)
var date2 = new Date(2022, 0, 3)
d = date1
while (d <= date2) {
console.log(d)
array.push(d)
d.setDate(d.getDate() + 1)
}
console.log(array)
}
test1();
you are updating the same reference, which is changing values already stored in array.
try this:
while(d <= date2) {
array.push(d)
var copy = new Date()
copy.setTime(d.getTime())
copy.setDate(d.getDate() + 1)
d = copy
}
this will ensure that d is a new object in each iteration.
Try this:
function test1() {
var array = [];
var date1 = new Date(2022, 0, 1);
var date2 = new Date(2022, 0, 3);
d = date1;
while (d.valueOf() <= date2.valueOf()) {
console.log(d);
array.push(new Date(d));
d.setDate(d.getDate() + 1);
}
console.log(array)
}
Execution log
5:49:29 PM Notice Execution started
5:49:29 PM Info Sat Jan 01 2022 00:00:00 GMT-0700 (Mountain Standard Time)
5:49:29 PM Info Sun Jan 02 2022 00:00:00 GMT-0700 (Mountain Standard Time)
5:49:29 PM Info Mon Jan 03 2022 00:00:00 GMT-0700 (Mountain Standard Time)
5:49:29 PM Info [ Sat Jan 01 2022 00:00:00 GMT-0700 (Mountain Standard Time),
Sun Jan 02 2022 00:00:00 GMT-0700 (Mountain Standard Time),
Mon Jan 03 2022 00:00:00 GMT-0700 (Mountain Standard Time) ]
5:49:30 PM Notice Execution completed

How to group by year? (month and day already working)

This is for a Google Sheet which uses GAS but I was advised to try Javascript Tag.
So I got this script which will read column 1 where I have the dates, and will group all rows by month and within these will group rows by day. This is because within each day I've got a row for every hour or 4 hours or so.
I need this script to also group by year as well. So it goes like:
Year Row -> Month Rows -> Day Rows
Month and day rows are working. I can't get the year grouping to work. Any ideas where to start?
The script:
function groupRow() {
const timeZone = "GMT+1";
const sheet = SpreadsheetApp.getActiveSheet();
const rowStart = 5;
const rows = sheet.getLastRow() - rowStart + 1;
const values = sheet.getRange(rowStart, 1, rows, 1).getValues().flat();
const o = [];
values.forEach((date, i) => {
const [m, d] = Utilities.formatDate(date, timeZone, "yyyyMM,dd").split(",");
if (!o[m]) {
o[m] = [];
}
if (!o[m][d]) {
o[m][d] = [];
}
o[m][d].push(rowStart + i);
});
for (var m in o) {
o[m] = Object.values(o[m]).sort((a,b) => parseInt(a) - parseInt(b));
}
Object.values(o).forEach(m => {
for (const d of m) {
if (d.length === 1) {
continue;
}
const range = `${ d[1] }:${ d.slice(-1)[0] }`;
sheet.getRange(range).shiftRowGroupDepth(1);
}
const a = m.flat();
if (a.length === 1) {
return;
}
const range = `${ a[1] }:${ a.slice(-1)[0] }`;
sheet.getRange(range).shiftRowGroupDepth(1);
});
}
Here's the link for dummy file:
https://docs.google.com/spreadsheets/d/1ExXtmQ8nyuV1o_UtabVJ-TifIbORItFMWjtN6ZlruWc/edit?usp=sharing
Well, it's me again. :) I can't sleep whenever there is some unsolved code.
It seems work to a degree:
function groupRow() {
var timeZone = "GMT+1";
var sheet = SpreadsheetApp.getActiveSheet();
var rowStart = 5;
var rows = sheet.getLastRow() - rowStart + 1;
var values = sheet.getRange(rowStart, 1, rows, 1).getValues().flat();
var o = {};
// make the object {'year': { 'month':[days] } }
values.forEach((date, i) => {
var [y, m, d] = Utilities.formatDate(date, timeZone, "yyyy,MM,dd").split(",");
// console.log(y, m, d);
if (!o[y]) o[y] = {};
if (!o[y][m]) o[y][m] = {};
if (!o[y][m][d]) o[y][m][d] = [];
o[y][m][d].push(rowStart + i);
});
// convert the unordered object {year:{month:[days]}}
// into the ordered 3d-array [year[month[days]]]
const numsort = (a,b) => parseInt(a) - parseInt(b);
var years = Object.keys(o).sort(numsort)
.map(y => Object.keys(o[y]).sort(numsort)
.map(m => Object.values(o[y][m]).sort(numsort)));
// group rows by years
years.forEach(y => shift_rows(y.map(m => m.flat()).flat(),sheet));
// group rows by months
years.flat().forEach(m => shift_rows(m.flat(),sheet));
// group rows by days
years.flat().flat().forEach(d => shift_rows(d.flat(),sheet));
function shift_rows(rows,sheet) {
if (rows.length === 1) return;
var range = `${ rows[1] }:${ rows.slice(-1) }`;
sheet.getRange(range).shiftRowGroupDepth(1);
}
}
But the code is really complicated already. It's need to test and... most likely, to rewrite it from scratch.
This approach to handling row groups tries to focus on readability/maintainability over efficiency, by minimizing array manipulation. If the code runs too slowly, then you can consider performance optimizations - but those can generally make the code harder to read.
It also tries to make the code easier to test by breaking it down into multiple separate functions, where each function tries to do as little logic as possible (I'm sure that could be improved & simplified, even further).
It makes 3 passes over the dates data, one for each type of grouping (year, month, and date). That's the big compromise vs. efficiency.
I've presented it here as a runnable snippet with some hard-coded data, not as a full GAS script, since the core of the logic is pure JavaScript.
var src_data = [
'Thu Aug 26 2021 21:27:26 GMT-0400 (Eastern Daylight Time)',
'Fri Aug 27 2021 21:27:26 GMT-0400 (Eastern Daylight Time)',
'Fri Aug 27 2021 23:51:26 GMT-0400 (Eastern Daylight Time)',
'Sun Aug 29 2021 09:27:26 GMT-0400 (Eastern Daylight Time)',
'Sat Sep 04 2021 07:03:26 GMT-0400 (Eastern Daylight Time)',
'Sat Sep 04 2021 16:39:26 GMT-0400 (Eastern Daylight Time)',
'Fri Sep 17 2021 00:49:02 GMT-0400 (Eastern Daylight Time)',
'Fri Sep 17 2021 03:13:02 GMT-0400 (Eastern Daylight Time)',
'Wed Sep 22 2021 03:13:02 GMT-0400 (Eastern Daylight Time)',
'Tue Sep 28 2021 03:13:02 GMT-0400 (Eastern Daylight Time)',
'Wed Sep 29 2021 11:22:38 GMT-0400 (Eastern Daylight Time)',
'Wed Sep 29 2021 12:34:38 GMT-0400 (Eastern Daylight Time)',
'Mon Oct 11 2021 12:34:38 GMT-0400 (Eastern Daylight Time)',
'Tue Oct 12 2021 19:46:38 GMT-0400 (Eastern Daylight Time)',
'Thu Nov 04 2021 19:46:38 GMT-0400 (Eastern Daylight Time)',
'Mon Nov 29 2021 09:13:02 GMT-0500 (Eastern Standard Time)',
'Thu Dec 23 2021 22:39:26 GMT-0500 (Eastern Standard Time)',
'Mon Jan 17 2022 12:05:50 GMT-0500 (Eastern Standard Time)',
'Fri Feb 11 2022 01:32:14 GMT-0500 (Eastern Standard Time)',
'Mon Mar 07 2022 14:58:38 GMT-0500 (Eastern Standard Time)',
'Mon Mar 07 2022 14:58:39 GMT-0500 (Eastern Standard Time)'
];
var dates = src_data.map(d => new Date(d));
// The starting row of our data in the spreadsheet:
var rowStart = 5;
// We will compare each new date against the previous date to see
// if the period has changed:
var prevDate;
// Build a range of potentially groupable dates, because they share the
// same period. These are the array range start & end positions:
var rangeStart;
var rangeEnd;
// the type of grouping to create:
var groupingPeriod;
//
// entry point:
//
groupDates('year');
groupDates('month');
groupDates('date');
// process the array of dates:
function groupDates(period) {
groupingPeriod = period;
console.log('finding groups by ' + period + ':') ;
dates.forEach((date, idx) => {
// The first date is a special case:
if (idx === 0) {
processInitialDate(date);
} else {
// everything which is not the first date:
processDate(date, idx);
}
} );
}
// Some initial set-up (and we know we cannot create
// a group containing only the first date):
function processInitialDate(date) {
prevDate = date;
rangeStart = 0;
rangeEnd = rangeStart;
}
// All dates except the first one:
function processDate(date, idx) {
if (periodHasChanged(date, prevDate, groupingPeriod)) {
createGroup();
// start a new range:
rangeStart = rangeEnd +1;
rangeEnd = rangeStart;
} else {
// extend the current range:
rangeEnd++;
// the final value in the array is a special case, which
// would otherwise not be processed (because there is no
// "next" date to compare it against):
if (idx === dates.length -1) {
createGroup();
}
}
prevDate = date;
}
function periodHasChanged(currDate, prevDate, period) {
switch(period) {
case 'year':
var currPeriod = currDate.getYear();
var prevPeriod = prevDate.getYear();
break;
case 'month':
var currPeriod = currDate.getMonth();
var prevPeriod = prevDate.getMonth();
break;
case 'date':
var currPeriod = currDate.getDate();
var prevPeriod = prevDate.getDate();
break;
}
return currPeriod !== prevPeriod;
}
function createGroup() {
var rangeGroup = dates.slice(rangeStart, rangeEnd +1);
// only create the group if it contains at least 2 dates:
if (rangeGroup.length > 1) {
// make the group here - but for testing, we just log it to the console:
// TODO - build the sheet range, by adjusting the array rangeStart
// and rangeEnd values, using the rowStart value defined earlier.
//range.shiftRowGroupDepth(1);
console.log( rangeGroup );
}
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
</body>
</html>
Here is the full GAS script I used:
function groupingDemo() {
//const timeZone = "GMT+1";
rowStart = 5;
sheet = SpreadsheetApp.getActiveSheet();
rows = sheet.getLastRow() - rowStart + 1;
dates = sheet.getRange(rowStart, 1, rows, 1).getValues().flat();
groupDates(dates, 'year');
groupDates(dates, 'month');
groupDates(dates, 'date');
}
// spreadsheet items:
var sheet;
var rowStart;
var dates;
// We will compare each new date against the previous date to see
// if the period has changed:
var prevDate;
// Build a range of potentially groupable dates, because they share the
// same period. These are the array range start & end positions:
var rangeStart;
var rangeEnd;
// the type of grouping to create:
var groupingPeriod;
// process the array of dates:
function groupDates(dates, period) {
groupingPeriod = period;
console.log('finding groups by ' + period + ':') ;
dates.forEach((date, idx) => {
// The first date is a special case:
if (idx === 0) {
processInitialDate(date);
} else {
// everything which is not the first date:
processDate(date, idx);
}
} );
}
// Some initial set-up (and we know we cannot create
// a group containing only the first date):
function processInitialDate(date) {
prevDate = date;
rangeStart = 0;
rangeEnd = rangeStart;
}
// All dates except the first one:
function processDate(date, idx) {
if (periodHasChanged(date, prevDate, groupingPeriod)) {
createGroup();
// start a new range:
rangeStart = rangeEnd +1;
rangeEnd = rangeStart;
} else {
// extend the current range:
rangeEnd++;
// the final value in the array is a special case, which
// would otherwise not be processed (because there is no
// "next" date to compare it against):
if (idx === dates.length -1) {
createGroup();
}
}
prevDate = date;
}
function periodHasChanged(currDate, prevDate, period) {
switch(period) {
case 'year':
var currPeriod = currDate.getYear();
var prevPeriod = prevDate.getYear();
break;
case 'month':
var currPeriod = currDate.getMonth();
var prevPeriod = prevDate.getMonth();
break;
case 'date':
var currPeriod = currDate.getDate();
var prevPeriod = prevDate.getDate();
break;
}
return currPeriod !== prevPeriod;
}
function createGroup() {
const sheet = SpreadsheetApp.getActiveSheet();
var rangeGroup = dates.slice(rangeStart, rangeEnd +1);
// only create the group if it contains at least 2 dates:
if (rangeGroup.length > 1) {
// make a new group (we use the "+1" to avoid contiguous groups being merged):
var range = `${ rowStart + rangeStart +1 }:${ rowStart + rangeEnd }`;
sheet.getRange(range).shiftRowGroupDepth(1);
// uncomment these to see what's going on:
//console.log( rangeGroup );
//console.log( 'sheet rows: ' + `${ rowStart + rangeStart +1 }:${ rowStart + rangeEnd }` )
}
}
The results:
And if you un-comment the logging statements, you see the following logs:
finding groups by year:
[ Thu Aug 26 2021 21:27:26 GMT-0400 (Eastern Daylight Time),
Fri Aug 27 2021 21:27:26 GMT-0400 (Eastern Daylight Time),
Fri Aug 27 2021 23:51:26 GMT-0400 (Eastern Daylight Time),
Sun Aug 29 2021 09:27:26 GMT-0400 (Eastern Daylight Time),
Sat Sep 04 2021 07:03:26 GMT-0400 (Eastern Daylight Time),
Sat Sep 04 2021 16:39:26 GMT-0400 (Eastern Daylight Time),
Fri Sep 17 2021 00:49:02 GMT-0400 (Eastern Daylight Time),
Fri Sep 17 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Wed Sep 22 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Tue Sep 28 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Wed Sep 29 2021 11:22:38 GMT-0400 (Eastern Daylight Time),
Wed Sep 29 2021 12:34:38 GMT-0400 (Eastern Daylight Time),
Mon Oct 11 2021 12:34:38 GMT-0400 (Eastern Daylight Time),
Tue Oct 12 2021 19:46:38 GMT-0400 (Eastern Daylight Time),
Thu Nov 04 2021 19:46:38 GMT-0400 (Eastern Daylight Time),
Mon Nov 29 2021 09:13:02 GMT-0500 (Eastern Standard Time),
Thu Dec 23 2021 22:39:26 GMT-0500 (Eastern Standard Time) ]
sheet rows: 6:21
[ Mon Jan 17 2022 12:05:50 GMT-0500 (Eastern Standard Time),
Fri Feb 11 2022 01:32:14 GMT-0500 (Eastern Standard Time),
Mon Mar 07 2022 14:58:38 GMT-0500 (Eastern Standard Time) ]
sheet rows: 23:24
finding groups by month:
[ Thu Aug 26 2021 21:27:26 GMT-0400 (Eastern Daylight Time),
Fri Aug 27 2021 21:27:26 GMT-0400 (Eastern Daylight Time),
Fri Aug 27 2021 23:51:26 GMT-0400 (Eastern Daylight Time),
Sun Aug 29 2021 09:27:26 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 6:8
[ Sat Sep 04 2021 07:03:26 GMT-0400 (Eastern Daylight Time),
Sat Sep 04 2021 16:39:26 GMT-0400 (Eastern Daylight Time),
Fri Sep 17 2021 00:49:02 GMT-0400 (Eastern Daylight Time),
Fri Sep 17 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Wed Sep 22 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Tue Sep 28 2021 03:13:02 GMT-0400 (Eastern Daylight Time),
Wed Sep 29 2021 11:22:38 GMT-0400 (Eastern Daylight Time),
Wed Sep 29 2021 12:34:38 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 10:16
[ Mon Oct 11 2021 12:34:38 GMT-0400 (Eastern Daylight Time),
Tue Oct 12 2021 19:46:38 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 18:18
[ Thu Nov 04 2021 19:46:38 GMT-0400 (Eastern Daylight Time),
Mon Nov 29 2021 09:13:02 GMT-0500 (Eastern Standard Time) ]
sheet rows: 20:20
finding groups by date:
[ Fri Aug 27 2021 21:27:26 GMT-0400 (Eastern Daylight Time),
Fri Aug 27 2021 23:51:26 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 7:7
[ Sat Sep 04 2021 07:03:26 GMT-0400 (Eastern Daylight Time),
Sat Sep 04 2021 16:39:26 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 10:10
[ Fri Sep 17 2021 00:49:02 GMT-0400 (Eastern Daylight Time),
Fri Sep 17 2021 03:13:02 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 12:12
[ Wed Sep 29 2021 11:22:38 GMT-0400 (Eastern Daylight Time),
Wed Sep 29 2021 12:34:38 GMT-0400 (Eastern Daylight Time) ]
sheet rows: 16:16

Strange behavior when using Date.setDate() incremental by day

I am working on a functionality where I'd like to iterate particular dates between Date_A and Date_B.
Problem is when 'DateB' is in next month so the iterating process is overlapping to next month. Please see a line 12 of output. It seems like it starts incrementing months instead of days... Any suggestions, please? :)
iter: 0 , inspectedDate: Mon Apr 22 2019 00:00:00 GMT+0000 (UTC)
iter: 1 , inspectedDate: Tue Apr 23 2019 00:00:00 GMT+0000 (UTC)
iter: 2 , inspectedDate: Wed Apr 24 2019 00:00:00 GMT+0000 (UTC)
iter: 3 , inspectedDate: Thu Apr 25 2019 00:00:00 GMT+0000 (UTC)
iter: 4 , inspectedDate: Fri Apr 26 2019 00:00:00 GMT+0000 (UTC)
iter: 5 , inspectedDate: Sat Apr 27 2019 00:00:00 GMT+0000 (UTC)
iter: 6 , inspectedDate: Sun Apr 28 2019 00:00:00 GMT+0000 (UTC)
iter: 7 , inspectedDate: Mon Apr 29 2019 00:00:00 GMT+0000 (UTC)
iter: 8 , inspectedDate: Tue Apr 30 2019 00:00:00 GMT+0000 (UTC)
iter: 9 , inspectedDate: Wed May 01 2019 00:00:00 GMT+0000 (UTC)
iter: 10 , inspectedDate: Sat Jun 01 2019 00:00:00 GMT+0000 (UTC)
iter: 11 , inspectedDate: Wed Jul 03 2019 00:00:00 GMT+0000 (UTC)
iter: 12 , inspectedDate: Sat Aug 03 2019 00:00:00 GMT+0000 (UTC)
iter: 13 , inspectedDate: Wed Sep 04 2019 00:00:00 GMT+0000 (UTC)
example here: https://repl.it/repls/QuerulousSelfreliantDatabase
const inspectedDate = new Date('2019-04-22');
const today = new Date('2019-04-22');
let intervalCorrection = 0;
for (let dayOffset = 0; dayOffset < requestInterval; dayOffset++) {
inspectedDate.setDate(today.getDate() + dayOffset);
console.log('iter: ' + dayOffset, ', inspectedDate: ' + inspectedDate);
}
Try 'reseting' inspectedDate every iteration. Worked fine for me.
Changes I made to your code snippet:
const requestInterval = 14;
let today = new Date('2019-04-22').getDate();
let intervalCorrection = 0;
for (let dayOffset = 0; dayOffset < requestInterval; dayOffset++) {
const inspectedDate = new Date('2019-04-22');
inspectedDate.setDate(today + dayOffset);
console.log('iter: ' + dayOffset, ', inspectedDate: ' + inspectedDate);
}
The problem is that when you setDate and it's more than the current month's days that changes the month. Adding a bigger number again changes the mongth again:
const date = new Date("2019-02-01");
let day = 31;
let offset = 1;
date.setDate(day + offset); //goes to March
offset++;
console.log(date.toString());
date.setDate(day + offset); //goes to April
offset++;
console.log(date.toString());
Since you add a constant 22 (the value of today.getDate()) each time, you very quickly get to 30 and above which will start rolling over each month.
If you just want each consecutive day, then you don't need to have two dates and do a lot of calculations - just use a single date and increment the day by 1 each time - this will give you each day:
const inspectedDate = new Date('2019-04-22');
const requestInterval = 14;
for (let i = 0; i < requestInterval; i++) {
inspectedDate.setDate(inspectedDate.getDate() + 1); //advance one day
console.log('iter: ' + i, ', inspectedDate: ' + inspectedDate);
}
The problem here lies in that you are storing the date variable in a constant and altering its date using setDate only. This results in its moth getting changed which you are not handling.
On iter 9, it sets the date to 22 + 9, i.e, 31. But the month is 4(Apr) which is a 30 day month. So the date changes to Wed May 01 2019 00:00:00 GMT+0000 (UTC)
On iter 10, it sets the date to 22 + 10, i.e, 32. But the month is now 5(May) which is a 31 day month. So the date changes to Sat Jun 01 2019 00:00:00 GMT+0000 (UTC)
On iter 11, it sets the date to 33. The month is 6(Jun). So the date changes to Wed Jul 03 2019 00:00:00 GMT+0000 (UTC)
and so on...
I can think of 2 ways to avoid it:
First
Create a new variable each time
const requestInterval = 14;
const today = new Date('2019-04-22');
let intervalCorrection = 0;
for (let dayOffset = 0; dayOffset < requestInterval; dayOffset++) {
const inspectedDate = new Date('2019-04-22');
inspectedDate.setDate(today.getDate() + dayOffset);
console.log('iter: ' + dayOffset, ', inspectedDate: ' + inspectedDate);
}
Second
Update the month and year as well before updating date
const requestInterval = 14;
const inspectedDate = new Date('2019-04-22');
const today = new Date('2019-04-22');
let intervalCorrection = 0;
for (let dayOffset = 0; dayOffset < requestInterval; dayOffset++) {
inspectedDate.setMonth(today.getMonth());
inspectedDate.setYear(today.getYear());
inspectedDate.setDate(today.getDate() + dayOffset);
console.log('iter: ' + dayOffset, ', inspectedDate: ' + inspectedDate);
}
Firstly, convert your date to milliseconds.
Secondly, iterate ms in day over your date.
const today = new Date('2019-04-22');
let intervalCorrection = 0;
const millisecsInDay = 1000 * 60 * 60 * 24;
for (let dayOffset = 0; dayOffset < 14; dayOffset++) {
const inspectedDate = new Date(today.getTime() + dayOffset * millisecsInDay);
console.log('iter: ' + dayOffset, ', inspectedDate: ' + inspectedDate);
}

Comparision between two dates

I have a calender and has following two scenarios:
case - 1
current_month = 8 (aug)
end_month = 10 (oct)
current_year = 2017
end_year = 2017
case - 2
current_month = 8 (aug)
end_month = 2 (feb)
current_year = 2017
end_year = 2018
When I click next month it should move only until "end_month". What should be the condition to satisfy both the cases:
if(condition)
alert("Move to next month");
else
alert("condition fail");
I have tried comparing start and end date objects, But I'm able to move one more month extra, which should not happen.
I have used the following conditions:
cal_date = Tue Aug 01 2017 23:58:33 GMT+0530 (India Standard Time)
$scope.edate = Wed Nov 15 2017 00:00:00 GMT+0530 (India Standard Time)
if (cal_date.getMonth() > $scope.edate.getMonth() + 1 || cal_date.getMonth() == $scope.edate.getMonth() || $scope.edate.getFullYear() <= new Date().getFullYear())
if (cal_date.getMonth() > $scope.edate.getMonth() || cal_date.getMonth() == $scope.edate.getMonth())
if (cal_date.getTime() < new Date(new Date($scope.edate) - 1)) {
if (cal_date < $scope.edate) {
Personally I would create Date objects:
var current = new Date(year,month)
var end = new Date(year,month)
and then test:
if ( current<end )
That would probably be the simplest approach.

momentjs add moment object into array

js:
service.search = function (goDate, returnDate) {
var outwardInterval = {};
outwardInterval.start = moment(goDate, 'YYYY-MM-DD').subtract(3, 'day');
outwardInterval.end = moment(goDate, 'YYYY-MM-DD').add(3, 'day');
matrice.outwardDates = buildDateArray(outwardInterval);
}
var buildDateArray = function (interval) {
var array = [];
var currentDate = interval.start;
do {
array.push(currentDate);
currentDate.add(1, 'day');
} while (!currentDate.isAfter(interval.end));
return array;
};
My output:
Why in my array i have the same value ..?
Update:
JSFIDDLE
Extending My comment:
function GetDates(startDate, daysToAdd) {
var aryDates = [];
for(var i = 0; i <= daysToAdd; i++) {
var currentDate = new Date();
currentDate.setDate(startDate.getDate() + i);
aryDates.push(DayAsString(currentDate.getDay()) + ", " + currentDate.getDate() + " " + MonthAsString(currentDate.getMonth()) + " " + currentDate.getFullYear());
}
return aryDates;
}
function MonthAsString(monthIndex) {
var d=new Date();
var month=new Array();
month[0]="Jan";
month[1]="Feb";
month[2]="March";
month[3]="April";
month[4]="May";
month[5]="June";
month[6]="July";
month[7]="Aug";
month[8]="Sep";
month[9]="Oct";
month[10]="Nov";
month[11]="Dec";
return month[monthIndex];
}
function DayAsString(dayIndex) {
var weekdays = new Array(7);
weekdays[0] = "Sun";
weekdays[1] = "Mon";
weekdays[2] = "Tue";
weekdays[3] = "Wed";
weekdays[4] = "Thu";
weekdays[5] = "Fri";
weekdays[6] = "Sat";
return weekdays[dayIndex];
}
var startDate = new Date();
var aryDates = GetDates(startDate, 7);
console.log(aryDates);
Fiddle: http://jsfiddle.net/u93g87qc/2/
Actually you're not getting the same date for every value in the array. You're fighting moment.js here. If you slightly modify your code to execute the toDate method of the moment you'll see that it's working just fine:
var matrice = { };
var service = { };
service.search = function (goDate, returnDate) {
var outwardInterval = {};
outwardInterval.start = moment(goDate, 'YYYY-MM-DD').subtract(3, 'day');
outwardInterval.end = moment(goDate, 'YYYY-MM-DD').add(3, 'day');
matrice.outwardDates = buildDateArray(outwardInterval);
}
var buildDateArray = function (interval) {
console.clear();
console.log('Start: ', interval.start.toDate());
console.log('End: ', interval.end.toDate());
var array = [];
var currentDate = interval.start;
console.log('Initial date: ', currentDate.toDate());
do {
array.push(currentDate.toDate());
currentDate.add(1, 'days');
console.log('Current date: ', currentDate.toDate());
} while (!currentDate.isAfter(interval.end));
return array;
};
service.search('2014-12-25');
Output:
Start: Mon Dec 22 2014 00:00:00 GMT-0700 (Mountain Standard Time)
End: Sun Dec 28 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Initial date: Mon Dec 22 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Tue Dec 23 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Wed Dec 24 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Thu Dec 25 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Fri Dec 26 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Sat Dec 27 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Sun Dec 28 2014 00:00:00 GMT-0700 (Mountain Standard Time)
Current date: Mon Dec 29 2014 00:00:00 GMT-0700 (Mountain Standard Time)

Categories