newbie question: How to resolve competing priorities when calculating dates?

Hi Observable.

Another newbie question for you: How can I ensure that a variable remains constant?

I am trying to add in a new calculation to add 45 days to a start_date value (a report deadline). I try doing this by noting the value should remain constant:

report_due_gen = {

const date = start_date; 
date.setDate(date.getDate() + 45);

  return date
}   

However, adding in this calculation changes anther calculation also based on the start date, namely:

${start_date.toLocaleString(
   undefined, {timeZone: "utc", month: "long", day: "numeric", year: "numeric"}
 )}

The console isn’t returning any errors. Any pointers on how to debug?

Here’s the notebook:

Thanks in advance for your time and guidance!

Hi Aaron.

It looks like you’re calling date.setDate() … which in JavaScript mutates the value of the original start_date object, changing it in an undesired way.

Try returning a new Date() from report_due_gen instead…

return new Date(start_date.getDate() + 45);
1 Like

Thank you Jeremy! All these little hiccups… but I am getting there.

Thanks for Observable! It’s amazing.

Oh no! This works to separate out the date, but it also seems to decouple the calculation from the start date? I get thrown back to 1969 and +45 is adding milliseconds :sweat_smile:

EDIT: Got it! Thank you!! :heart:

I remain confused. This almost worked, but the solution I though was there appears to have been wrong, and the values keep mutating…

To get around the issue of being in 1969 and having the value update in miliseconds, I did this:

report_due_gen = {
 return new Date(report_start.setDate(report_start.getDate() + 365));
}

But if I call report_start, this approach still mutates value!?

report_start // now returns 2018-11-13T19:00

… I guess this means I can’t use +365, but instead need a full conversion: (365 * 24 * 60 * 60 * 1000)?

Nope. It’s that you’re calling setDate() again.

You don’t want to do that. It mutates (changes) the value of report_start, making it different the next time you look at it…

Thanks. So I see that now… and yet I can’t work out the missing piece.

report_due_gen = {
 return new Date(start_date.getDate() + 365);
}

yields: 1969-12-31T19:00:00.379, as does my attempted work-around:

report_due_gen = {
 const due = start_date
 return new Date(due.getDate() + 365);
}

Any further clues?

Apologies, Aaron. I was missing the forest for the trees (seeing the mutation, but missing the point of what you were trying to do).

You can’t just add a raw number to getDate() like that in JS, and get something meaningful back (unfortunately). For date manipulation, I’d recommend using a library like Moment to make things a little easier.

moment = require("moment")

Then, if you still want to add 45 days to your start date, the definition would be:

report_due_gen = moment(start_date).add(45, "days").toDate()

The full Moment documentation is available here: https://momentjs.com/docs/#/displaying/as-javascript-date/

1 Like

Cool, this works well!

I had come across moment before when I was first working on that ‘working days’ calendar a couple weeks ago. On the encouragement of @Job @bgchen and others, I’ve been trying to limit my reliance on anything other than ‘vanilla’ JS, so as to try to master the basics before moving too much further. With dates especially, however, a bit of help is appreciated!

Alternatively, if you don’t care about leap seconds, you can convert your date to a UNIX timestamp and add the days as milliseconds:

new Date(+start_date + 1000*60*60*24*45).getDate()

To break it down:

  • +start_date casts your date object to a timestamp (×1000, because JS timestamps have a resolution in milliseconds instead of seconds)
  • + 1000*60*60*24*45 adds 1000 ms/second × 60 seconds/minute × 60 minutes/hour × 24 hours/day × 45 days
  • new Date(...) creates a new date object from the timestamp.
1 Like

Cool, @mootari! This is a great solution in that it looks like I might also be able to integrate it with the ‘calculate holidays’ function that I was working on in the notebook.

I was playing around today with moment.js and with its plug-in moment-business-days. I haven’t, however, gotten past the require for the plug-in. Since you and Bryan have already helped me with this issue, I figured I’d dig more into d3-require before raising it again. The patterns you and Bryan provided aren’t working :frowning:

 moment = require('moment@2.24.0/moment.js', 'moment-business-days@1.1.3')

and

moment = require.alias({'moment-business-days': 'moment'})('moment@2.24.0/moment.js', 'moment-business-days@1.1.3')

both return moment = Ne: invalid module

… so much more to learn! but this is tremendous fun, as I feel a world opening up to me each day.

Thank you and everyone for being so welcoming and patient with me!!

My recommendation:

{
  var copy = new Date(date);
  copy.setDate(copy.getDate() + 45);
  return copy;
}
2 Likes

Nice! Looks even more simple. Thanks Mike!!!