How to get the start and end time of every month between two dates

How to get the start and end time of every month between two dates

So you can get a list of daily values from an endpoint and maybe you can even specify ‘to’ and ‘from’ times to get values in between certain dates. Fantastic. But what you *really* want to do is group data by months. How do you do it? This is a problem I ran in to recently and I’ll explain how I went about solving it. Firstly, I’ll assume you don’t control the endpoint because that would be the first place to start. On the client side of things, you could manually specify start and end times for all your required months and make a bunch of separate requests but that’s not very efficient or scalable or future proof. Here’s what I did…

Solution in words

We obviously need to have a start date and an end date in mind. We then need to start pulling them apart to get the month and year from said dates.

Once we have our formatted start and end times (really just start month/year and end month/year), we then calculate how many months difference there are between them.

One small but important thing to keep in mind – because timezones are evil often problematic, we also need to make sure all times are UTC (and don’t forget about those pesky zero values when it comes to months where 0 is equal to January and the year ends at month 11 – it often catches me out). If times aren’t consistent, it quickly turns in to a nightmare trying to troubleshoot problems so where possible I always try to make sure all times are UTC times.

Once we figure out how many months there are between our two dates, we then just create an array containing that amount of objects. If there are 11 months between the two dates, we create 11 objects, using a loop. Within the loop, we figure out the start date of the relevant month (by setting the days and hours of that month to zero) and the end date of the relevant month (similar process of setting the day and time), then assign them to an object, then add the object to an array. Anyway, here’s how it all looks and the bit you’re probably interested in…

Solution in code

function monthDiff(startMonth, endMonth) {
   //this function calculates the number of months between dates inclusive of start and end month 
   var months;
   months = (endMonth.getUTCFullYear() - startMonth.getUTCFullYear()) * 12;
   months -= startMonth.getUTCMonth() - 1;
   months += endMonth.getUTCMonth() + 1;
   return months <= 0 ? 0 : months;
}

//specify our start and end dates, in this case 30th May 2018 to present day
var startDate = new Date(2018, 5, 30);
var endDate = new Date();
var theResult = monthDiff(startDate,endDate);
//create array to hold our monthly start & end time objects
var arr = [];

//loop through all months
for (i = 0; i < theResult; i++) { 
   var today = new Date();
   var firstDayOfMonth = Date.UTC(today.getUTCFullYear(), today.getUTCMonth() - i, 1);
   var lastDayOfMonth = Date.UTC(new Date(firstDayOfMonth).getUTCFullYear(), new Date(firstDayOfMonth).getMonth() + 1, 1, 0, 0, -1);
   var time = {};
   //convert times to epoch (just a personal preference)
   time["start"] = (new Date(firstDayOfMonth)).getTime() / 1000;
   time["end"] = (new Date(lastDayOfMonth)).getTime() / 1000;
   arr.push(time);
}
//print the result (which is within our 'arr' array) to console
console.log(arr)

Result

The output should be something like below… an array of objects with the start and end times of each month between your selected dates and including the start month / end month. In the example below, 1559347200 is 1st June 2019 at exactly midnight (UTC). 1561939199 is 30th June 2019 at 11:59:59 pm (UTC). Today is 22nd June 2019 so we now have our start time of month and end time of month for today’s date.

And so it continues backwards every month until our start date which in this case was 30th May 2018.

[
{start: 1559347200, end: 1561939199},
{start: 1556668800, end: 1559347199},
{start: 1554076800, end: 1556668799},
{start: 1551398400, end: 1554076799},
{start: 1548979200, end: 1551398399},
{start: 1546300800, end: 1548979199},
{start: 1543622400, end: 1546300799},
{start: 1541030400, end: 1543622399},
{start: 1538352000, end: 1541030399},
{start: 1535760000, end: 1538351999},
{start: 1533081600, end: 1535759999},
{start: 1530403200, end: 1533081599},
{start: 1527811200, end: 1530403199},
{start: 1525132800, end: 1527811199}
]

In my particular case, I was then able to group other data in to the relevant month if it fell between any of those start and end times. It saved me from making multiple requests to an endpoint which saved time, improved speed and was just far more efficient than making multiple requests to an endpoint.

Leave a Reply