Luxon - a new library for working with dates from the team Moment.js
It would seem, why do we need another library to work with dates and times when there is a well-known Moment library ?! The more interesting is that the alternative is offered by the Moment team itself.
Luxon library is declared as a powerful, modern and convenient tool for working with dates and times in JavaScript. The library was created by Isaac Cambron, a member of the Moment development team since 2013.
The author had a lot of ideas on the development of Moment, which he could not do in the framework of the existing code. Here are the main points that I wanted to realize:
- try out some ideas on how to make the API more logical (but these ideas were not compatible with the approach adopted in Moment),
- implement “out of the box” work with time zones without additional extensions,
- completely rethink the work with internationalization with the introduction of Intl API,
- go to a modern set of tools and approaches in the formation of the JS code.
Therefore, he decided to write everything from scratch, which took about two years.
The result was a modernized version of Moment.
The resulting option seemed interesting to the entire Moment development team, so it was decided to promote the new library under the auspices of the team.
Luxon principles
- Call chains as in Moment.
- All types are immutable.
- Clearer and more obvious API: for different objects - different methods with clearly defined parameters.
- Intl API to ensure internationalization (rollback to the English version, if the browser does not support the Intl API).
- Intl API for working with time zones.
- More complete support for calculating duration.
- Built-in support for working with intervals.
- Inline code documentation.
These principles led to the following improvements:
- Luxon code is much easier to understand and debug.
- Using the browser’s built-in capabilities for internationalization improves the library’s behavior and, again, makes debugging easier.
- Time zone support is implemented better than in any other JS library.
- Luxon provides both a simple and very powerful tool for working with duration.
- The library has good documentation.
But Luxon has its drawbacks:
- The emphasis on using the built-in capabilities of the browser leads to difficulties in supporting older browsers.
- Some internationalization features that are not yet supported by browsers are not implemented in the library either (it is necessary to wait for such support to appear in browsers).
- The implementation of the Intl API in different browsers may vary, and Luxon’s behavior will vary accordingly.
Installation
Luxon provides modules for all modern JavaScript platforms.
The documentation has a complete list of supported browsers with restrictions on use. For browsers that have no or limited Intl support, it is recommended to use a polyfill (in particular, this concerns IE 10 or 11).
When working with Node.js (6+), if you need to work with locales, then you will need to additionally install the full-icu package and set the environment variable to enable the use of this package.
The standard installation method from npm is:
npm install - save luxon
Luxon has support for both TypeScript and Flow, as well as a module in ES6 format.
Quick review
The Luxon library consists of five main classes:
DateTime - the date and time with the time zone and display settings, as well as related methods.
Duration - a period of time (duration), for example, “2 months” or “1 day, 3 hours”.
Info - static methods for getting general data about time and date.
Interval - time interval and methods for working with it.
Settings are static methods that define Luxon's overall behavior.
import {DateTime, Duration, Info, Interval, Settings} from'luxon';
Your first datetime
Luxon's most important class is DateTime. DateTime represents a date + time along with a time zone and locale. This is how you can set it on May 15, 2017 at 08:30 in the local time zone:
var dt = DateTime.local(2017, 5, 15, 8, 30);
Here is a call to determine the current time:
var now = DateTime.local();
Creation from object
DateTime.fromObject({
month:12,
day: 22,
hour: 12,
minutes: 20,
zone: 'Europe/Kaliningrad'
}); //=> 2018-12-22T12:20:00.000+02:00
Creating from a string in ISO 8601 format
DateTime.fromISO("2017-05-15"); //=> May 15, 2017 at 0:00
DateTime.fromISO("2017-05-15T08:30:00"); //=> May 15, 2017 at 8:30
When converted to a string, Luxon also returns a string in ISO 8601 format:
DateTime.local().toString(); //=> "2018-12-18T20:58:29.995+03:00"
Getting the individual components:
var dt = DateTime.local();
dt.year; //=> 2018
dt.month; //=> 12
dt.day; //=> 18
dt.second; //=> 27
dt.weekday; //=> 2
dt.zoneName; //=> "Europe/Moscow"
dt.offset; //=> 180
dt.daysInMonth; //=> 31
Formatted output
Luxon has many methods for converting DateTime to a string, two of them are most important toLocaleString and toISO, the first converts to the format according to the browser's color, and the second prepares the text for software processing (for example, for transmission to the server):
dt.toLocaleString(); //=> "18.12.2018"
dt.toLocaleString(DateTime.DATETIME_MED); //=> "18 дек. 2018 г., 21:46"
dt.toISO(); //=> "2018-12-18T21:46:55.013+03:00"
For formatted output in Luxon there are two dozen ready-made “presets” (such as DATETIME_MED and TIME_WITH_LONG_OFFSET).
You can also create your own format based on tokens:
dt.setLocale('ru').toFormat('d MMMM tt - ZZZZZ');
//=> "18 декабря 21:46:55 - Москва, стандартное время"
DateTime Transformations
Important note: Luxon objects are immutable, i.e. any modifying methods applied to them return the modified copy without changing the original object. Therefore, all terms in this article (as in Luxon documentation) such as “change”, “install”, “override” should be understood as “create a new instance with different properties”.
Math Transformations
var dt = DateTime.local(2018, 12, 18, 20, 30); //=> "18.12.2018, 20:30"
dt.plus({hours: 3, minutes: 2}); //=> "18.12.2018, 23:32"
dt.minus({days: 7}); //=> "11.12.2018, 20:30"
dt.startOf('day'); //=> "18.12.2018, 0:00"
dt.endOf('hour'); //=> "18.12.2018, 20:00"
Redefinition of individual parameters
var dt = DateTime.local();
dt.set({hour: 3}).hour //=> 3
Intl Conversions
Luxon supports several different Intl transformations, one of the most important is formatting for various locales:
var dt = DateTime.local();
var f = {month: 'long', day: 'numeric'};
dt.setLocale('fr').toLocaleString(f); //=> "18 décembre"
dt.setLocale('en-GB').toLocaleString(f); //=> "18 December"
dt.setLocale('en-US').toLocaleString(f); //=> "December 18"
The Info class can return lists of months and days of the week in a given locale:
Info.months('long', {locale: 'it'}); //=> ["gennaio", "febbraio", "marzo", ...]
Info.weekdays ('short', {locale: 'de'}); //=> ["Mo", "Di", "Mi", ...]
Time Zones
Luxon supports time zones. If you create a DateTime without explicitly specifying the time zone, the local zone will be selected by default. If the existing DateTime changes the zone, the time and date will be recalculated taking into account the difference between time zones.
var dt = DateTime.local(2018, 12, 18, 20, 00); //=> 2018-12-18T20:00:00.000+03:00
dt.zone.name; //=> "Europe/Moscow"
dt.setZone('Asia/Vladivostok'); //=> 2018-12-19T03:00:00.000+10:00
Luxon also supports working with date and time in UTC:
DateTime.utc(2018, 5, 15); //=> 2018-05-15T00:00:00.000Z
DateTime.utc(); //=> 2018-12-18T17:58:29.995Z
DateTime.local().toUTC(); //=> 2018-12-18T17:58:29.995Z
DateTime.utc().toLocal(); //=> 2018-12-18T20:58:29.995+03:00
Duration
The Duration class provides the ability to work with a duration, for example, “2 hours and 7 minutes”. You can create a duration like this:
var dur = Duration.fromObject({hours: 2, minutes: 7});
Durations can add and subtract. Duration may be negative.
dur.minus(dur).minus(dur); //=> {hours: -2, minutes: -7}
Similarly, the duration can be added or subtracted from the DateTime.
DateTime.local().plus(dur);
Duration has getters (similar to DateTime getters):
dur.hours; //=> 2
dur.minutes; //=> 7
dur.seconds; //=> 0
dur.zone; //=> undefined
Duration also has other useful methods:
dur.as('seconds'); //=> 7620
dur.toObject(); //=> { hours: 2, minutes: 7 }
dur.toISO(); //=> 'PT2H7M'
Intervals
Intervals are defined as the period between two time points, the Interval class is used to work with them. The start time is included in the interval, and the end time is not: respectively, the beginning when converted to a string is indicated by a square bracket, and the end is indicated by a round bracket.
var today = DateTime.local(2018, 12, 18);
var later = DateTime.local(2020, 10, 12);
var interval = Interval.fromDateTimes(today, later);
interval.toString();
//=> "[2018-12-18T00:00:00.000+03:00 – 2020-10-12T00:00:00.000+03:00)"
interval.toISO();
//=> "2018-12-18T00:00:00.000+03:00/2020-10-12T00:00:00.000+03:00"
interval.length(); //=> 57369600000
interval.length('years', true); //=> 1.8169398907103824
interval.contains(DateTime.local(2019)); //=> true
Intervals can be compared with each other and combined with each other:
var nextYear = Interval.after(DateTime.local(), {year: 1});
var prevYear = Interval.before(DateTime.local(), {year: 1});
prevYear.overlaps(nextYear); //false
prevYear.abutsStart(nextYear); //true
nextYear.union(prevYear).length('years'); //=> 2
Luxon and Moment
The Luxon library “lives” in the Moment project, but is not a complete replacement for the Moment library. Luxon does not provide full Moment functionality, for example, relative date formatting was only recently implemented in the Chrome browser version 71, in other browsers does not work yet, and Luxon has not yet implemented support for it (although it is expected). But even if browsers support the required functionality, then it should be understood that it will be available only in these new environments. In obsolete browsers, Luxon will work with problems, while Moment works always and everywhere.
In addition, the Luxon API has been completely redesigned and it does not completely coincide with the Moment API.
Note the main differences between Moment and Luxon.
Immunity
Luxon objects are immutable, while Moment is not.
In the example below, m1 and m2 are the same object that was modified by the add method.
var m1 = moment();
var m2 = m1.add(1, 'hours');
m1 === m2; //=> true
In the case of Luxon, the plus method returns a new d2 object without changing the original d1.
var d1 = DateTime.local();
var d2 = d1.plus({ hours: 1 });
d1 === d2; //=> false
d1.valueOf() === d2.valueOf(); //=> false
For this reason, Luxon does not require special copy constructors and cloning methods that Moment uses to make copies without changing the original value.
Main functional differences
- The countdown of months in Luxon starts from 1, and not from scratch as in Moment (and the native js Date object).
- Localization and time zones are implemented using the native Intl API (or polyphile), rather than being built into the library.
- Luxon has built-in types Duration and Interval.
- Luxon does not yet support relative date formatting.
- In Luxon, there is also no humanize method for representing duration in a “humanized” style (for example, “a few seconds”).
API style differences
- In API Luxon methods, the optional parameters are usually located last.
- Luxon has many separate methods for creating objects (for example, fromISO), unlike Moment, which has one function for this, and the type of an object is given by parameters.
- Luxon has very strict parsers, while Moment has more liberal parsers, i.e. if the input line format is different from the standard one, Luxon will immediately generate an error, and Moment will try to correct some format errors.
- Luxon uses getters (dt.year, dt.isValid) rather than methods like Moment (m.year (), m.isValid ()) to get the internal field values.
- Luxon allows one method to immediately set all the necessary parameters of dt.set ({year: 2016, month: 4}), in Moment they are set only one by one - by the chain of calls m.year (2016) .month (4).
- Duration in Luxon is a separate class of the top level Duration.
For the rest, Luxon borrowed a lot of ideas from Moment, the documentation even lists the equivalence tables of the Moment and Luxon methods.
Library file sizes
Luxon (v. 1.8.2)
luxon.min.js - 61 KB
Moment (v. 2.23.0)
moment.min.js - 51 KB
moment.min.js + locale / ru.js - 59 KB
moment-with- locales.min.js - 323 KB
As you can see, without Moment locales, the size is 10 KB smaller than Luxon, but with the addition of several locales, the size becomes approximately equal.
If the support of all locales is required at once, then there is a significant gain for Luxon.
Summary
The library is fully ready for use and the author promises its support. The library already has 7k + stars on the githaba and its popularity is only growing. In its code commits not only the author himself, but not less than 6 developers.
I suppose that the Luxon library is a response to the appearance of Intl API support in browsers. Moment developers understand that working with dates on the web can change significantly and try to prepare for these changes. But they cannot accurately predict the development of the web, and with it the new project (which they themselves call Moment labs project). Will Luxon ideas be moved to Moment 3? Will most users switch from Moment to Luxon at some point? Maybe Luxon will be renamed to Moment? The developers themselves admit that they can not now answer these questions.