According to their docs, Luxon's DateTime
class implements #valueof
, which returns the primitive value of an object– in this case it's the epoch milliseconds. That means you can directly use <
or >
to compare Luxon DateTime objects when sorting.
Here's a one-liner compareFn
I use to sort Luxon DateTime arrays sometimes.
The quick answer
sortDateTimes = (a, b) => a < b ? -1 : a > b ? 1 : 0;
This approach works because equality is the catch-all condition (the 0
at the end). Although you can use <
and >
freely with DateTime
objects, you can't just use ===
to check for equality. Luxon provides a .equals(...)
function for that. Alternative, because they implement #valueOf
, you can make the DateTime
objects convert to their primitive values using +
.
const { DateTime } = require('luxon');
a = DateTime.fromISO('2020-01-15');
b = DateTime.fromISO('2020-01-15');
a === b; // false
+a === +b; // true
The little compareFn
one-liner above works fine on an array of DateTime
objects, but since we often want to sort an array of objects that the DateTime
embedded in a property (like created
), we have to take a slightly different approach.
sortByCreated = (a, b) =>
a.created < b.created ? -1 : a.created > b.created ? 1 : 0;
The robust answer
For bonus points, make this a little more reusable with a function generator.
createPropertySorter = (propertyName) => (a, b) =>
a[propertyName] < b[propertyName] ? -1 : a[propertyName] > b[propertyName] ? 1 : 0;
The generator would then be used when you need to sort instead of the sort function itself directly. From OP's example:
const results = objectGroupedByYearMonth[year][month].results.sort(
createPropertySorter('created')
);
// results is now sorted, e.g. results.map(JSON.stringify) is
// [
// '{"name":"some Object","created":"2020-01-25T00:00:00.000-07:00"}',
// '{"name":"some Object","created":"2020-01-31T00:00:00.000-07:00"}',
// '{"name":"some Object","created":"2020-02-01T00:00:00.000-07:00"}',
// '{"name":"some Object","created":"2020-02-01T00:00:00.000-07:00"}',
// '{"name":"some Object","created":"2020-02-07T00:00:00.000-07:00"}'
// ]
Watch out for mutability
A quick aside on mutability: in the example above, objectGroupedByYearMonth[year][month]
has a property called results
. Because sort()
sorts arrays in-place, objectGroupedByYearMonth[year][month].results
is also sorted (not just the returned value). This may have been the OP's intention, or it may be inconsequential, but I think it's worth minding. A revised version that preserves the original sorting would sort a copy of the original array using the spread operator.
const results = [...objectGroupedByYearMonth[year][month].results].sort(
createPropertySorter('created')
);
// results is sorted, while objectGroupedByYearMonth[year][month].results
// is still in its original order
Reverse sorting
If you want to reverse the sort order (latest dates first), switch a
and b
in the sort function.
createPropertyReverseSorter = (propertyName) => (a, b) =>
b[propertyName] < a[propertyName] ? -1 : b[propertyName] > a[propertyName] ? 1 : 0;
const sortByProperty = <TItem, TProperty>(propertySelector: PropertySelector<TItem, TProperty>) => (a: TItem, b: TItem): number => propertySelector(a) < propertySelector(b) ? -1 : propertySelector(a) > propertySelector(b) ? 1 : 0;
Usage[...results].sort((a, b) => sortByProperty<Item, DateTime>(c => c.created)(a, b))
– Prostatitis