Development

Time Travel in Vanilla JavaScript

In one of our internal projects for learning tools and techniques, the team was using Jest and Enzyme to test drive the creation of a React app. We wanted to provide an interface to move forward or backward by one day and decided to tackle it using vanilla javascript.

3 min
January 12, 2018
Gabi Procell

## Exploring the pains of date and time manipulation.

In one of our internal projects for learning tools and techniques, the team was using [Jest](https://facebook.github.io/jest/) and [Enzyme](https://github.com/airbnb/enzyme) to test drive the creation of a React app. We wanted to provide an interface to move forward or backward by one day and decided to tackle it using vanilla javascript. However, there is a lot of pomp and circumstance that comes along with changing a date by one day in js!

The app displays tasks for the current day by default, and when a task is added the task's date is set to new Date() which returns a date/time object like so: 2017-11-16T01:27:29.427Z. This was definitely the simplest part of the date handling.

## Finding tomorrow and yesterday the painful way

Finding the next and previous dates required a bit of math. In order to add time to the date, one must first convert the date object into milliseconds (Essentially, the Date instance returns a value that is equal to the number of milliseconds since January 1, 1970 UTC). The getTime() method will return the value of a given date in milliseconds:


   -- CODE line-numbers language-js --
   <!--
   const date = new Date();
   => 2017-11-16T01:27:29.427Z     // Our date-time object

   const dateInMS = date.getTime();
   => 10795649427                 // A lot of milliseconds'
   -->


Next, we do some math to find how many milliseconds there are in a day.

* There are 86,400 seconds in a day.
* 1 millisecond = 0.0001 seconds
* ms/day = 86,400 sec * 0.001 sec

Therefore, calculating yesterday or tomorrow would involve adding or subtracting the total milliseconds in a day to or from the number of milliseconds from a given date.

For example:


   -- CODE line-numbers language-js --
   <!--
    const tomorrow = date.getTime() + (86400 * 1000);
    => 1510882049427 ms

    const yesterday = date.getTime() - (86400 * 1000);
    => 1510709249427 ms
   -->


## Converting milliseconds into dates

After getting the time of the date we are looking for, we then need to create a new instance of Date and use the setTime() method to set our Date object to the time that we calculated in milliseconds since January 1, 1970.


   -- CODE line-numbers language-js --
   <!--
   const yesterday = new Date(date.setTime(date.getTime() - (86400 * 1000)))
   => 2017-11-15T01:27:29.427Z

   const tomorrow = new Date(date.setTime(date.getTime() + (86400 * 1000)))
   => 2017-11-17T01:27:29.427Z
   -->


After finding today's, tomorrow's, and yesterday's dates, we also needed to be able to display the date and any tasks that were created on that date. For display purposes, dates were converted to strings.


   -- CODE line-numbers language-js --
   <!--
   const tasks = this.state.tasks.filter(item =>
       item.date.toDateString() === date.toDateString();
       );
       =>  Returns item with date formatted as such : Tue Nov 14 2017
   -->


More issues arose with testing that our dates and tasks would return as expected when a user clicked the Tomorrow or Yesterday buttons. A roadblock when testing this appeared in the form of a type error that calling the toDateString() method was not a function. What wasn't it a function of? That turned out to be an empty array. If our task list was free of tasks, our filter method wanted nothing to do with that. We would then have to account for this edge case in our code, along with multiple transformations of our data in order to perform a seemingly mundane task.

## Less painful ways of handling time

In comparison, many members of our team have handled date and time with Rails' Active Support Extensions via the DateTime class. According to the Rails documentation, DateTime comes with all of the methods that pair with the Date class, except they will always return dateTimes. Some of these methods include:

* yesterday
* tomorrow
* advance
* weeks_ago
* years_since

Those are just a few of the many helpful methods that perform the same functions that we are trying to do with our buttons in vanilla Javascript but without the headache of calculating dates and times.

While it is nice to maintain a slim figure with your application and not relying heavily on importing libraries and tools, there is something to be said for considering if the effort of a task (such as finding the value of the next or previous day) is worth more of your time in the end. In this case, we ended up using Moment.js as it was more useful and intuitive in the long run. Testing became easier when we didn't have to transform our date object multiple times. Quite frankly, it also reads nicely in the end, and other devs who touch your code may even thank you for it later.

For more information, check out the following links:

<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date" target = "_blank" >MDN Web Docs on Javascript's Date Instance</a>

<a href="http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-date" target = "_blank" >Ruby on Rails Guide to Active Support Extension to Date</a>

<a href="https://momentjs.com/" target = "_blank" >Moment.js, our Lord and Savior</a>

Actionable UX audit kit

  • Guide with Checklist
  • UX Audit Template for Figma
  • UX Audit Report Template for Figma
  • Walkthrough Video
By filling out this form you agree to receive our super helpful design newsletter and announcements from the Headway design crew.

Create better products in just 10 minutes per week

Learn how to launch and grow products less chaos.

See what our crew shares inside our private slack channels to stay on top of industry trends.

By filling out this form you agree to receive a super helpful weekly newsletter and announcements from the Headway crew.