A custom-build HTML Time Input Element

Recently while working on a project, I found that the standard HTML Time Input field (see below) wasn’t sufficient for my needs.

<input type="time" id="setTime" name="setTime" />

Standard HTML time input field
Standard HTML time input field

I needed users to be able to input 24hr time right down to the milliseconds. Something like this:

Custom HTML Time Input Field
Custom HTML Time Input Field

Features

Mobile Input will display the number  pad

Under the hood, each input field is a number. This means that mobile devices should default to the number pad for convenience.

Value retrieval

Values are stored under the name time-<<timeType>> , for example time-hours.

You can loop over your form data and retrieve the names as needed or set a custom ID to the field as you create it dynamically with JavaScript. You can see an example of this in the Example 1: Single time field section.

Automatically moves to the next inputCustom HTML Time Input Field setting field character limits

Setting field character limitsSetting character limits on each time field allows the cursor to automatically move to the next fields.

Client-Side Validation

Removing ‘Accepted’ number input characters that are not numbers

Yeah, yeah, you know you got to validate server-side too, but it’s good to let the user know that if they accidentally put in an accepted number character like e, +, - that it will be removed for them automatically.

Cannot exceed the number range

The max and min number ranges are set by default, but you can always change them manually.

Maybe you want to start with minutes, but as a duration and not a time, have minutes that go all the way up to 10,000. All good, just change the max value in the time-minute number input.

If a user puts in a number greater or less than the default min or max, the number will be replaced by the min or max respectively.

So for example, if the user sets 69 (hur hur hur) minutes but the max minutes is 60 then the field will default to 60.

Likewise, if the user sets the millisecond cell to 2 but your min is 500, then it will default to 500 milliseconds.

This is done with some JavaScript event listeners.

Returning back a tab will clear the field

Returning back a tab by cursor or shift-tab will clear out the field for the user to start afresh.

Prepends Zeros (0) to Any Number Not At Max Character Length

This is just an aesthetic thing, but it makes a difference. When a number’s character length is less than the maximum character length, then additional zeroes will be added to the front of the number.

Quickly add or remove a time input

The values of the time inputs are formatted using a generated CSS method for number inputs within the timeInput class. Further event listeners are looped over this class to allow for fewer or greater number-input elements.

As such, you can add days, months and years or, nanoseconds, microseconds and zeptoseconds. Alternatively, you could remove one of the existing time measures from the field.

The Code for the Custom Time Input field

You can grab a basic sample of the code here:

Example 1: Single time field

In this simple example, we will encapsulate the time input into a form and add a ‘submit’ button. Of course, you can add other form elements to the form as well.

In our script section, we added two functions submitForm() and getFormData() that is called on submit and retrieve all values in the form by their ‘name’ attribute.

I’ve put the submit button outside the form so you can see the logged results. If you wish to refresh the page or move to another page you can add the submit button inside the form.

Custom HTML Time Input Field inside a form with logged values
Custom HTML Time Input Field inside a form with logged values

Check out the updated code:

 

Example 2: Multiple time fields

What if we want to have multiple instances of the custom time input in our HTML?

In this example, we will have a start and end time. Notice that we will need to change the name each time slightly so that the value is stored.

As such, in the example we append -start and -end to the input fields.

Yeap, that’s all you need to do.

Multiple Custom HTML Time Input Fields inside a form with logged values
Multiple Custom HTML Time Input Fields inside a form with logged values

Check out the updated code:

Example 3: Build Multiple HTML Custom Time Input fields dynamically with JavaScript

In this final example, we want to dynamically create time input fields equal to the number of tests we have. We will do this with the createTimeHanlder() function.

Next, we will add the HTML for the custom time input into a template literal (A string with inputs) and then add a name and append a counter to the name tags of each number input element.

Dynamically create Multiple Custom HTML Time Input Fields inside a form with logged values
Dynamically create Multiple Custom HTML Time Input Fields inside a form with logged values

Here’s the updated code:

 

Conclusion

That’s it. I would love to hear how you used this in your own projects and what modifications you made. Let me know in the comments.

I am actually using this for a project for a Google Workspace Add-on using Google Apps Script along with an accompanying hosted private site using Golang, SQLite, temple and HTMX.

Have fun!

If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.

Extracting the Valid Workdays Between Two Dates in JavaScript

Given a start date, end date, weekends and, holidays we will extract the valid workdays between two dates in JavaScript in this tutorial.

Sometimes we need to work backward from a date range and extract all the valid workdays within that range. Of course, we will need to exclude holidays and also days off for this period too so it is not just a simple case of subtracting the end date from the start date and adding one.

The best way to illustrate what we want to accomplish is by sharing some example data.

If you are looking to get the end work date given a start date and number of workdays, check out this tutorial: 

Calculate the Workday End Date in JavaScript

The Example

For our example, we will need to prepare a list of date ranges, holiday periods and weekly days off (weekends).

We’ll say for convenience that we will work Monday to Friday and take Saturday and Sunday off. In JavaScirpt-land weekdays are represented as zero-based numbers with the USA-style start of the week occurring on Sunday. In this case, Sunday is zero (0) and Saturday is (6).

Let’s add in some holidays to give ourselves a well-earned break:

  • 15 Sep 2024
  • 31 Oct 2024  🎃🦇👻
  • 24 Dec 2024
  • 25 Dec 2024
  • 01 Jan 2025

This could also be drawn from a regional API that provides dates for holidays in your area.

Finally, we will provide a small sample list of date ranges that we can check, but keep in mind that you can iterate over a much larger list at relatively good speed here.

  1. 10 Sep 2024 – 23 Sep 2024.
    End day for work project JavaScript example range 1
  2. 26 Oct 2024 – 4 Nov 2024.
    End day for work project JavaScript example range 2
  3. 22 Dec 2025 – 16 Jan 2024.
    End day for work project JavaScript example range 3

The blue represents the actual workdays, while the white section indicates the actual date range. Orange bold and underlined days are holidays that don’t fall on weekends. Light red days are weekly days off (in our case, weekends).

Across the top of the dates are the days of the week as a JavaScript day running from 0 (Sunday) to 8 (Saturday).

 

The Video Tutorial

 

To the video tutorial

Releases 8 Oct 2024

The Code

The runsies() function

The runsies() function is the main test function. It contains the 3 different variables that we will send to the getWorkdays() function to generate our list of days.

We’re using the year-month-date (YYYY-MM-DD) format favoured by computer nerds like me.

Once we get the list of days back from the getWordays() function we will then map our existing testRanges array of objects and add the valid days as a property and the total count of valid days.

Finally, we will stringify the array object to make it pretty for logging.

Running the script will display these results:

The getWorkdays() function

Parameters

This function takes three arguments:

  1. workperiod: This is the array object containing the start date and end date for each of the sample periods.
  2. weekends: The array of designated weekends as a number. For example, Saturday and Sunday would look like this: [0,6]
  3. holidays: An array of holidays as date strings.

Function Variables and UTC dates

In this section, we’ll prepare our dates for efficient comparison by converting them into milliseconds so that we can extract our valid dates.

Calculating a Whole Day in Milliseconds (Line 16):

      • We start by calculating the duration of a whole day in milliseconds. This will allow us to iterate over each day and check if it is a valid date.

Handling Timezone and Daylight Saving (Lines 22-29):

    • To avoid any timezone-related quirks or issues with daylight-saving events, we’ll convert our date periods to Coordinated Universal Time (UTC). We’ll create a small private method at the top of our function to handle this conversion.
    • Note: We’ll encounter UTC conversions multiple times in our code, so having a dedicated method simplifies things.

Converting the Array of Holiday Dates to UTC Time (Line 32):

    • Finally, we’ll convert our holiday array of dates to UTC time in milliseconds so that we can directly reference them against the currently iterated day.

Map an array of workdays

Next, we need to map our array of found workdays for each sample date range (Line 35). To do this we will use the JavaScirpt map method that takes a function as an argument.

Map Variables

We will need to iterate through each day within our date range checking if the date is not a weekend or a holiday and then record that date. To do this, we will need to set a few variables.

Get start and end days as UTC time in milliseconds (Lines 37-38)

  • Both the start date and end date will need to be converted to UTC dates using our private getUTC() method.

Set Mutable Variables ( Lines 41-42)

  • When we look at each date we need to check that day’s day of the week. To determine the starting day of the week of our range of dates we use the JavaScirpt getDay() method.  This will update for each new day we check.
  • Next, we need to set our first day to check as a day.

Store Valid Wordays (Line 44)

  • Here we store our valid workdays in the validWorkday array.

Iterating over the days in the range

Our main task now is to iterate over each day in the range.

Not a Weekend or a Holiday (Line 49-52)

  • First, we check if the current day of the week is not included in the weekends array and the current day in UTC format does not exist in the holidayUTC array.
  • If both of these conditions are met, then the day is a valid workday and we add it to our validWorkay array.

Preparing for the Next Day (Lines 54-55)

  • Now we need to prepare for the next day check by:
    • Updating the day  by another day using the dayMilliseconds variable.
    • Getting the next day of the week. Here, we need to keep in mind that if the next day of the week is equal to seven then it will go back to the start of the week which will be zero.

Returning it all back

Once we have our valid workday for the selected range, we return that array to generate our mapped array of workdays.

Finally, we return the workdays array back to the calling function.

 

 

If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.

That’s all there is to get a list of valid workdays in a range in JavaScript. I use this function often when providing analysis tools for clients who want to see aggregate workdays over a period of days.

I’d love to hear what you would use this function for.

 

~Yagi

Calculate the Workday End Date in JavaScript

Given a start date, number of days, and holidays, this script calculates the end date of a workday period using JavaScript.

If you are looking to get a list of workdays in a range, then check out this tutorial:

Extract Workdays From a Date Range in JavaScript

Continue reading “Calculate the Workday End Date in JavaScript”

Extracting Overlapping date ranges between 2 Date Ranges with JavaScript

I recently had a project where I had to extract the date range between two sets of overlapping date ranges in JavaScript*.

Let’s say our user wanted to see any overlapping date ranges between "2024-09-01" and "2024-09-16". For the following set of date ranges:

  1. "29 August 2024" – "18 September 2024"
  2. "3 September 2024" – " 10 September 2024"
  3. "3 September 2024" – "18 September 2024"
  4. "29 August 2024""10 September 2024"
  5. "20 August 2024" – "29 August 2024"
  6. "18 September 2024" – "25 September 2024"

Here’s a more visual example:

Extracting overlapping date ranges between a target range of dates and a series of date ranges JavaScript
Extracting overlapping date ranges between a target range of dates and a series of date ranges JavaScript

In my project, this represented many thousands of ranges to search, but we have a good sample here for testing.

Our expected returned results should only provide overlapping ranges that fit inside the target range, chopping off any excess dates. So the results would look a little like this:

  1. 1 Sep 2024 – 16 Sep 2024
  2. 3 Sep 2024 – 10 Sep 2024
  3. 3 Sep 2024 – 16 Sep 2024
  4. 1 Sep 2024 – 10 Sep 2024
  5. null
  6. null

*Well… It was actually a Google Apps Script project, but same-same 😉.


The Video

To the video tutorial. 

Releases 24 Sep 2024

The Code

The following code provides a sample set of date ranges called dates that are compared against a target start (tgtStart) and end (tgtEnd) date range.

The script then iterates over the dates running the getDateRangeOverLap() function to compare the currently iterated date ranges against the target ranges.

If there is an overlap, then the overlapping date range is returned. If there is no overlap, then null is returned.

Finally, the script logs the response from the function displaying the current range and the newly updated overlap range, or null.

The different date formats are just to illustrate that any JavaScript date format can be used here.

Go ahead and make a copy of the script and give it a run in your favourite IDE.

getDateRangeOverLaps()

Get dates and Dates in milliseconds

Lines 40-49

Our first task is to convert the strings of dates into a proper JavaScirpt Date object format.

We also need to convert this date to a time in milliseconds since the epoch (1970-01-01) with the getTime() method.

Next, we need to check any possible overlap conditions.

Check for no Date Range Overlaps

It is faster for the function to check if there are no overlapping dates between our current date range and our target range rather than to work through the nuances of the different overlap updates we need to do.

Here we check if our current range start epoch is greater than the target end epoch or if the current end epoch is less than the target start epoch. If either of these conditions are met, we return null.

Otherwise, we can run through the other conditions below.

Check if the Current date range encompasses the entire target date range

JavaScript current dates encompasses target date

In this situation, the current date range starts before the target date and ends after the target date. In this case, the overlapping range will be the same as the target date.

Check if the current start and end range fit inside the target range.

JavaScript current dates match within the target date range

Here,  we have a current date range that starts after the target date range and ends before the target date range.

We have a match and that matching date will be the range of the current date so that is what we will return.

Check if the Current date ranges End within the target date

JavaScript dates end with target range

In this condition, we check if the current date range starts before the target range but also ends before the target range. In this case, we return the target start date and the current end date.

Check if the current date range starts within the target date

JavaScript dates starts with target range

For the final condition check we determine if the current range starts within the target range but ends after the target range. If this condition is met, then we return the current start range and the target end range.

 

That’s all there is to it.

I’d love to hear how you applied this or tweaked it for your own projects.

~Yagi.

Is a Year a Leap Year? Gregorian Calendar & JavaScript

Earth doesn’t perfectly orbit the Sun every 365 days. Rather, it irritatingly must make its orbit in oh, I don’t know, roughly 365.242190 days each year.

Due to this inconsiderate behaviour, we must add a leap year into our common calendar known as the Gregorian Calendar.

Like, I presume, many of us, I thought a leap year occurred every four years.

Whether it was a matter of being taught a half-truth from my school teachers many decades ago in School (possible), or simply not paying attention to said teachers (much much more possible), I was wrong on this account.

So, when is a leap year?

According to the very impressively sounding Royal Museum Greenwich, a leaps year must meet the following conditions:

  1. Any year that is a century (e.g. 2000, 2100, 2400, 1900) must be divisible by 400. So 2000 and, 2400 are leap years but 2100 and, 1900 are not.
  2. Any other year must be divisible by 4.

Yeap. It’s that first one, I didn’t know about.

So with this in mind, how would we determine if a year is a leap year in JavaScript?

Enter the JavaScript Modulo Operator

To determine if something is divisible by a number we can use the JavaScript modulo operator (%) to determine the remainder. If the remainder is zero we know it is divisible by a number.

So 12%4 would return 0 because 12 divides perfectly into three lots of four. Whereas 7%3 would have one left over.

Got it? Cool.

The Video

The Video Tutorial

Releases  17 Sep 2024

The Code

Let’s now create a function called isLeapYear() that takes a four-digit number for our target year.

Remember our leap years rules.

We need to:

  1. Check if the year is divisible by 400 (year%400 == 0)
  2. Check if the year is divisible by 4 (year%4 == 0)
    If it is, then:
  3. Check if the year isn’t divisible by 100 (year%100 != 0).

Give it a run to see the results.

Why not just use the Date object?

I actually did this in a previous tutorial to get a list of days of the year a particular weekday (e.g. Monday, Tuesday, Wednesday…etc) falls. You can check it out here:

Get the Day of the Year in JavaScript

However, I would say that a purely numerical approach is always going to significantly beat a multi-step constructor approach.

Check out this benchmark example:

benchmark JavaScript find leap year numerical approach vs Date construtor approachBig difference.

 

~Yagi