I’m converting Java 8 code to Typescript. Java 8 introduced a great Duration class that uses ChronoUnit to specify units such as DAYS or HOURS. You then instantiate a duration using that:
Duration can then interact with LocalDateTime objects. To start, it can obtain a Duration from the difference of two times.
elapsed = Duration.between(startTime, endTime);
That gives us two ways to instantiate it. The latter can result in a conceptual combination, such as “3 days, 4 hours and 21 minutes” that the former method doesn’t result in.
We can also compare two durations to see which is greater:
boolean result duration1.compareTo(duration2) >= 0;
So how do we do that in Typescript?
To summarize our requirements from our Java uses:
- Instantiate in time units, such a “6 weeks”. This would likely come from a human interface where a user is specifying a duration or interval.
- Calculate the difference between two dates and represent this in various usable forms, including human.
- Compare two periods to determine which is greater.
As long as we can convert a duration to milliseconds, it is easy to compare. This simplifies our last requirement. Likewise, if we can convert milliseconds to a duration object that has the capabilities we need, that solves requirement #2, since it is easy to calculate the difference of two Date objects:
diff = Math.abs(date1.getTime() - date2.getTime());
The issue we have is that not all human durations are easily translated into milliseconds. A month, for instance, is not a concrete block of time. It conceptually depends on a calendar. A duration of 5 months may simply require adding 5 to the month of a date, so that 5 months from Feb 5th is July 5th.
Leap years are another anomaly depending on the calendar so that not all years have the same number of days.
You really have to decide how these fit into your requirements for your application. I’ve chosen to treat them as bonus features in my case rather than core requirements.
This works great for calculating the difference of two Date objects. You then have the ability to view the result as either a total of any given unit, or as human breakdown, such as:
10y 2m 6d 3h 23m 8s 456ms
Because we can convert to total milliseconds, we can compare two durations.
This solves requirements #2 and #3, but does not provide a solution for requirement #1. It seems you can only instantiate from the differences between two dates.
This library meets our first requirement, the ability to instantiate with time units. It also allows us to convert to another unit easily:
toTime('1 hour').seconds(); //3600
You can even add up various units:
toTime('1 Year 365 Days 4 Hours').hours(); //17524
While it can’t calculate the difference between dates, you could calculate the milliseconds between dates, and then use that to create a time frame instance:
const frame = toTime.fromMilliseconds(500005050505005);
And, of course, since you can convert any time frame to milliseconds, you can compare two.
Together, this technically meets our 3 core requirements.
This also has the ability to instantiate from both number of units and difference between dates:
const sevenWeeks = new Duration('7 Weeks');
const threeDays = Duration.fromDays(3);
const a = new Date(2019, 3, 14);
const b = new Date(2019, 3, 15);
const betweenDates = Duration.between(a, b);
Because you can convert a duration to milliseconds, you can effectively compare two durations. This meets all 3 requirements.
The creator put a warning on the NPM module page that leap years are ignored as all years are treated as 365 days.
This looks promising. But, the documentation is lacking. It says it mimics PHP’s DatePeriod class. If you are a PHP programmer, you might find it useful.
NOTE: I completed this blog post, used date-converter for Duration, then realized in the next class I converted I also needed LocalTime. Only then did I discover this class, making this an update to this post the next day.
According to a 2018 GitHub Issue, they changed it a little to be compatible with Typescript.
In the end we have three NPM modules that can meet our requirements. The to-time and duration-converter libraries do work, albeit with limitations and creativity. However, js-joda appears to be a complete solution if you are porting Java 8 code.