FP in date-fns v2

Oct 11, 2018
3 mins read
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 #date_fns_v2 where we describe in detail most notable ones.

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.

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'

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

import { flow } from 'lodash/fp'
import { setDate, addDays, addMonths, format } from 'date-fns/fp'

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'

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: opencollective.com/date-fns
Join date-fns newsletter 👉
Subscribe to the date-fns newsletter to receive community updates, news and tips about the library and JavaScript dates in general.