newbie questions on calculating working days (date range minus weekends & holidays)

Hi Observable.

We have a snow day here in Washington DC, which prompted me to ask how one would remove holidays from a date range [check out Mike’s recent tool: How many days since?].

Scouring the Internet, I find several articles and examples using jquery and moment.js, but I’d like to avoid using anything but pure JS, or, if anything, to use d3.js.

As a pure JavaScript, lsmith’s addBusinessDays script has several examples with relatively little code.

EDIT: As noted below, this is perhaps not the best example, as it appears not to calculate dates within a range. Here’s another StackOverflow example, which Ii have been similarly unable to get working, but for different reasons

In playing around with these examples, there are a few concepts that continue to challenge me. In the lsmith examples, The code seems to do this by extending the the core function with some additional parameters after a . [e.g. functionName.otherParams]. I believe that these extensions reference back to the main code if one is to separate them out into independent cells, but I get different errors depending on if I run a cell after manipulating it vs. when refreshing the notebook. If I just paste in the entire code block and flank the cell in curly brackets { }, I get only undefined.

In the stack overflow example that I added with this edit, I can’t get the dates variable to work because of what appears to be a syntax error. I’ve tried some different formatting options on the dates, but to no avail.

Here’s where I’m at:

https://beta.observablehq.com/d/b1365ed431f917cd - as a general playground with a few working examples at the bottom, and my attempts breaking down codes with ‘subsections’ at the top, and

https://beta.observablehq.com/d/369a4c679257d641 - which reflects the errors I am getting with data formatting.

Any pointers on how to take the next step? Insights into how to understand the ‘main’ part of a function and it’s ‘subsections’, and how to appropriately connect them? Sorry that I don’t really know the terminology for this…

Thanks in advance for your time and insights!

Hmm… seems like I made a mistake with lsmith’s addBusinessDays, is the comments in the code suggest that it does not exclude holidays within the range. :frowning:

EDIT: Another bit of searching led me to this Stack Overflow answer, which basically solves my questions about how to implement a ‘days since’ function in pure JavaScript, but I’d still appreciate any insights / information about what these ‘extensions’ / ‘sub-functions’ are doing and how they work in Observable. @bgchen helped me before to explain a bit about variables and when (and when now) to bind them together with functions using curly brackets, yet must admit I’m still not fully understanding this, as I seem to constantly hit errors like assignment to constant variable when keeping variables within a function, or unexpected token when trying to separate them out.

I’d be happy for any further pointers or resources about how to understand these aspects of composing or extending functions.

Thanks for any help!

Some additional oddities:

When using the same sort of input as in make’s example: `

viewof start_date = html`<input type=date value=2019-01-01>`

start_date alone in a cell will return 2018-12-31 (i.e. one day before)

Also, if I add a label into the view of, it will break, e…g `

viewof start_date = html`Start Date: <input type=date value=2019-01-01>`

Here’s a working implementation of the StackOverflow example mentioned above:

Note that the values returned are different than the inputs dates by one day, and that don’t try to label the inputs.

For anyone following this (or other newbies), a few notes:

javascript, dates are expressed in milliseconds, which becomes important when trying to add or subtract dates.

the dates captured in the dateinput are stored as UTC values - as the zeroth second of the day. calling the name of the dateinput function, however, appears to referencing one’s local system time, which creates a disparity between the date input value and how that value is reproduced when calling that value by the name of the function. mike gets around this in his How many days since? tool by explicitly formatting the date as UTC with this bit of code: .toLocaleString(undefined, {timeZone: "utc", month: "long", day: "numeric", year: "numeric"})

… for all the date to line up, each date must be formatted.


I haven’t figured out what’s going on with the inputs breaking when adding additional HTML, but I’ll update once I do. I also haven’t found a good reference to explain these ‘subcomponent’ bits of the function and how they work across cells (probably because I haven’t figured out what they should be called yet), but I’ll update once I do. I’ll also see if I can figure out why some ‘complex’ functions will return a value, others return function information, and others come through as ‘undefined’, but I’ll keep reading… of course, I welcome tips and pointers!

It’s quite weird (frustrating) that <input type=date> gives you dates on UTC midnight as input.valueAsDate, rather than midnight local time. Thus, if you want to format the date as a string consistently with the input, you either need to convert it to local time or format it in UTC time.

For example, given a UTC date:

utc = new Date("2012-01-02")

To convert UTC to local time:

local = new Date(+utc + utc.getTimezoneOffset() * 1000 * 60)

This can then be formatted in local time:

local.toLocaleString(undefined, {month: "long", day: "numeric", year: "numeric"})

To format a UTC date in UTC time:

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

Thanks for the clarification, Mike!

As regards some of my other stumbling blocks, a few more notes:

the function.subfunction pattern that was confusing me at the outset has to do with object ‘properties’. As explained by the folks at Mozilla:

When trying to access a property of an object, the property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.

… to really get my head around this, I’ll need to do more reading about the notation someObject.[[Prototype]] and the fundamentals of inheritance. The Mozilla team also has a good primer on functions to help clarify some basic concepts.

1 Like