FP in date-fns v2

Published by Sasha Koss's avatar Sasha Koss

In this post, I tell about one of the most exciting features in v2: functional programming submodule. It provides alternative to code chains and enables currying. FP fans will love this!

date-fns v2 introduces many new features and breaking changes and this post is a part of a series where we describe in detail most notable ones.

Currying by default

FP submodule introduces copies of regular functions which accept arguments in inverse order and curryied by default. They could be imported from date-fns/fp and used along with regular functions.

const { differenceInDays: regularDifferenceInDays } = require("date-fns");
const { differenceInDays: fpDifferenceInDays } = require("date-fns/fp");

regularDifferenceInDays(Date.now(), 0);
//=> 17815

fpDifferenceInDays(0, Date.now());
//=> 17815

fpDifferenceInDays(0)(Date.now());
//=> 17815

const daysSinceUnixEpoch = fpDifferenceInDays(0);
daysSinceUnixEpoch(Date.now());
//=> 17815

We also refined the order of arguments in the regular functions so they would work well with currying.

Usage with options

Each FP function comes in two variations:

  1. One that accepts options as the first argument. Such functions has WithOptions added to the end of its name.

  2. Another that doesn’t have the options argument.

const { format, formatWithOptions } = require("date-fns/fp");
const { eo, ru } = require("date-fns/locale");

const dateFormat = "LLLL yyyy";

const english = format(dateFormat);
const russian = formatWithOptions({ locale: ru }, dateFormat);
const esperanto = formatWithOptions({ locale: eo }, dateFormat);

english(Date.now());
//=> 'October 2018'

russian(Date.now());
//=> 'октябрь 2018'

esperanto(Date.now());
//=> 'oktobro 2018'

Lodash compatibility

FP submodule was inspired by Lodash and fully compatible with it. You can use its helpers to compose date-fns functions:

const { flow } = require("lodash/fp");
const { setDate, addDays, addMonths, format } = require("date-fns/fp");

const idealDate = format("yyyy-MM-dd");
const firstDayNextMonth = flow(addMonths(1), setDate(1));
const nearestSunday = (date) =>
  date.getDay() && addDays(7 - date.getDay(), date);
const nextMonthSunday = flow(firstDayNextMonth, nearestSunday, idealDate);

nextMonthSunday(Date.now());
//=> '2018-11-04'

Price of pureness

While we were working on the FP submodule we realized that functions which create an internal state (e.g. `isToday`) couldn’t be safely curried and might cause bugs as in the given example:

import { distanceInWordsToNowWithOptions } from "date-fns/fp";
const distanceInWordsToNow = distanceInWordsToNowWithOptions({
  addSuffix: true,
});

// Days later you'll get an expected behavior:
const result = distanceInWordsToNow(Date.now());

So we’ve removed all functions that involve creating a date, and it made date-fns 100% pure library.


Happy coding time! Please support us at Open Collective.