For Moment users
Luxon borrows lots of ideas from Moment.js, but there are a lot of differences too. This document clarifies what they are.
Immutability
Luxon's objects are immutable, whereas Moment's are mutable. For example, in Moment:
var m1 = moment();
var m2 = m1.add(1, 'hours');
m1.valueOf() === m2.valueOf(); //=> true
This happens because m1
and m2
are really the same object; add()
mutated the object to be an hour later. Compare that to Luxon:
var d1 = DateTime.local();
var d2 = d1.plus({ hours: 1 });
d1.valueOf() === d2.valueOf(); //=> false
This happens because the plus
method returns a new instance, leaving d1
unmodified. It also means that Luxon doesn't require copy constructors or clone methods.
Other API style differences
- Luxon methods often take option objects as their last parameter
- Luxon has different static methods for object creation (e.g.
fromISO
), as opposed to Moment's one function that dispatches based on the input - Luxon parsers are very strict, whereas Moment's are more lenient.
- Luxon uses getters instead of accessor methods, so
dateTime.year
instead ofdateTime.year()
- Luxon centralizes its "setters", like
dateTime.set({year: 2016, month: 4})
instead ofdateTime.year(2016).month(4)
like in Moment. - Luxon's Durations are a separate top-level class.
- Arguments to Luxon's methods are not automatically coerced into Luxon instances. E.g.
m.diff('2017-04-01')
would bedt.diff(DateTime.fromISO('2017-04-01'))
.
Major functional differences
- Months in Luxon are 1-indexed instead of 0-indexed like in Moment and the native Date type.
- Localizations and time zones are implemented by the native Intl API (or a polyfill of it), instead of by the library itself.
- Luxon has both a Duration type and an Interval type
DateTime method equivalence
Here's a rough mapping of DateTime methods in Moment to ones in Luxon. I haven't comprehensively documented stuff that's in Luxon but not in Moment, just a few odds and ends that seemed obvious for inclusion; there are more. I've probably missed a few things too.
Creation
Operation | Moment | Luxon | Notes |
---|---|---|---|
Now | moment() |
DateTime.local() |
|
From ISO | moment(String) |
DateTime.fromISO(String) |
|
From RFC 2822 | moment(String) |
DateTime.fromRFC2822(String) |
|
From custom format | moment(String, String) |
DateTime.fromString(String, String) |
|
From object | moment(Object) |
DateTime.fromObject(Object) |
|
From timestamp | moment(Number) |
DateTime.fromMillis(Number) |
|
From JS Date | moment(Date) |
DateTime.fromJSDate(Date) |
|
From civil time | moment(Array) |
DateTime.local(Number...) |
Like DateTime.local(2016, 12, 25, 10, 30) |
From UTC civil time | moment.utc(Array) |
DateTime.utc(Number...) |
Luxon also uses moment.utc() to take other arguments. In Luxon, use the appropriate method and pass in the { zone: 'utc'} option |
Clone | moment(Moment) |
N/A | Immutability makes this pointless; just reuse the object |
Use the string's offset | parseZone |
See note | Methods taking strings that can specify offset or zone take a keepZone argument |
Getters and setters
Basic information getters
Property | Moment | Luxon | Notes |
---|---|---|---|
Validity | isValid() |
isValid |
See also invalidReason |
Locale | locale() |
locale |
|
Zone | tz() |
zone |
Moment requires a plugin for this, but not Luxon |
Unit getters
Property | Moment | Luxon | Notes |
---|---|---|---|
Year | year() |
year |
|
Month | month() |
month |
|
Day of month | date() |
day |
|
Day of week | day() , weekday() , isoWeekday() |
weekday |
1-7, Monday is 1, Sunday is 7, per ISO |
Day of year | dayOfYear() |
ordinal |
|
Hour of day | hour() |
hour |
|
Minute of hour | minute() |
minute |
|
Second of minute | second() |
second |
|
Millisecond of seconds | millisecond() |
millisecond |
|
Week of ISO week year | weekYear , isoWeekYear |
weekYear |
|
Quarter | quarter |
None | Just divide the months by 4 |
Programmatic get and set
For programmatic getting and setting, Luxon and Moment are very similar here:
Operation | Moment | Luxon | Notes |
---|---|---|---|
get value | get(String) |
get(String) |
|
set value | set(String, Number) |
None | |
set values | set(Object) |
set(Object) |
Like dt.set({ year: 2016, month: 3 }) |
Transformation
Operation | Moment | Luxon | Notes |
---|---|---|---|
Addition | add(Number, String) |
plus(Object) |
Like dt.plus({ months: 3, days: 2 }) |
Subtraction | subtract(Number, String) |
minus(Object) |
Like dt.minus({ months: 3, days: 2 }) |
Start of unit | startOf(String) |
startOf(String) |
|
End of unit | endOf(String) |
endOf(String) |
|
Change unit values | set(Object) |
set(Object) |
Like dt.set({ year: 2016, month: 3 }) |
Change time zone | tz(String) |
zone(string) |
Luxon doesn't require a plugin |
Change zone to utc | utc() |
toUTC() |
|
Change local zone | local() |
toLocal() |
|
Change offset | utcOffset(Number) |
None | Set the zone instead |
Change locale | locale(String) |
setLocale(String) |
Query
Question | Moment | Luxon | Notes |
---|---|---|---|
Is this time before that time? | m1.isBefore(m2) |
dt1 < dt2 |
The Moment versions of these take a unit. To do that in Luxon, use startOf on both instances. |
Is this time after that time? | m1.isAfter(m2) |
dt1 > dt2 |
|
Is this time the same or before that time? | m1.isSameOrBefore(m2) |
dt1 <= dt2 |
|
Is this time the same or after that time? | m1.isSameOrAfter(m2) |
dt1 >= dt2 |
|
Do these two times have the same [unit]? | m1.isSame(m2, unit) |
dt1.hasSame(dt2, unit) |
|
Is this time between these two times? | m1.isBetween(m2, m3) |
Interval.fromDateTimes(dt2, dt3).contains(dt1) |
|
Is this time inside a DST | isDST() |
isInDST |
|
Is this time's year a leap year? | isInLeapYear() |
isInLeapYear |
|
How many days are in this time's month? | daysInMonth() |
daysInMonth |
|
How many days are in this time's year? | None | daysInYear |
|
-------------------------------------------- | ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
Output
Basics
See the formatting guide for more about the string-outputting methods.
Output | Moment | Luxon | Notes |
---|---|---|---|
simple string | toString() |
toString() |
Luxon just uses ISO 8601 for this. See Luxon's toLocaleString() |
full ISO 8601 | iso() |
toISO() |
|
ISO date only | None | toISODate() |
|
ISO time only | None | toISOTime() |
|
custom format | format(...) |
toFormat(...) |
|
RFC 2822 | toRFC2822() |
||
HTTP date string | toHTTP() |
||
JS Date | toDate() |
toJSDate() |
|
Epoch time | valueOf() |
valueOf() |
|
Object | toObject() |
toObject() |
|
Duration | diff(Moment) |
diff(DateTime) |
Moment's diff returns a count of milliseconds, but Luxon's returns a Duration. To replicate the Moment behavior, use dt1.diff(d2).milliseconds . |
Humanization
Luxon doesn't support these, and won't until the Relative Time Format proposal lands in browsers.
Operation | Moment | Luxon |
---|---|---|
Time from now | fromNow() |
None |
Time from other time | from(Moment) |
None |
Time to now | toNow() |
None |
Time to other time | `to(Moment) | None |
"Calendar time" | calendar() |
None |
Durations
Moment Durations and Luxon Durations are broadly similar in purpose and capabilities. The main differences are:
- Luxon durations have more sophisticated conversion capabilities. They can convert from one set of units to another using
shiftTo
. They can also be configured to use different unit conversions. See Duration Math for more. - Luxon does not (yet) have an equivalent of Moment's
humanize
method - Like DateTimes, Luxon Durations have separate methods for creating objects from different sources.
See the Duration API docs for more.
Intervals
Moment doesn't have direct support intervals, which must be provided by plugins like Twix or moment-range. Luxon's Intervals have similar capabilities to theirs, with the exception of the humanization features. See the Interval API docs for more.