Sebbie
Sebbie

Reputation: 117

moment.js: Return the first and last day of each month within an interval

I am trying to return an array that would give me the first and last day of each month, taking into account the start and end dates for the first and last month of the interval.

I can't seem to get get my head around it. I'm only able to do separate bits :'(

Any charitable soul out there to help me understand?

var startDate = moment('2021-08-23');
var endDate = moment('2022-03-22');

var months = [];

if (endDate.isBefore(startDate)) {
    throw "End date must be greater than start date."
}      

while (startDate.isBefore(endDate)) {
    months.push(startDate.format("YYYY-MM-01"));
    startDate.add(1, 'month');
}

console.log(months);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Here, I'm getting

2021-08-01,
2021-09-01,
2021-10-01,
2021-11-01,
2021-12-01,
2022-01-01,
2022-02-01

When I'm really trying to get

[
[2021-08-23, 2021-08-31],
[2021-09-01, 2021-09-30],
[2021-10-01, 2021-10-31],
[2021-11-01, 2021-11-30],
[2021-12-01, 2021-12-31],
[2022-01-01, 2022-01-31],
[2022-02-01, 2022-02-29],
[2022-03-01, 2022-03-31]
]

Thanks!!!

Upvotes: 0

Views: 1783

Answers (1)

AlTheLazyMonkey
AlTheLazyMonkey

Reputation: 1242

In to subarray that you push in main array you forgot to calculate the date for the month end. It's better to use start and end Of in this case, without became crazy to calculate the correct number of day of month

const startDate = moment('2021-08-23');
const endDate = moment('2022-03-22');

const months = [];

if (endDate.isBefore(startDate)) {
  throw Error('End date must be greater than start date.');
}

while (startDate.isBefore(endDate)) {
  months.push([
    startDate.startOf('month').format('YYYY-MM-DD'),
    startDate.endOf('month').format('YYYY-MM-DD')
  ]);
  startDate.add(1, 'month');
}

console.log(months);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

UPDATE: I you want delimiter the start date and the end date using startDateand endDate you can add a controll in every cycle.

In this snip I use a [Ternary operator](Conditional (ternary) operator) for the check (I don't know if you saw that yet).

And a very important thing I done is the .clone() of moment for to do editing operarions like .endOf() and .startOf().

const startDate = moment('2021-08-23');
const endDate = moment('2022-03-22');

const months = [];

if (endDate.isBefore(startDate)) {
  throw Error('End date must be greater than start date.');
}

const cursor = startDate.clone();

while (cursor.isSameOrBefore(endDate, 'month')) {
  const firstDay = cursor.startOf('month').isBefore(startDate) ? startDate : cursor.clone().startOf('month');
  const lastDay = cursor.endOf('month').isAfter(endDate) ? endDate : cursor.clone().endOf('month');

  months.push([firstDay.format('YYYY-MM-DD'), lastDay.format('YYYY-MM-DD')]);

  cursor.add(1, 'month');
}

console.log(months);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Upvotes: 1

Related Questions