Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a brief comparison with Moment.js? #275

Open
rauschma opened this Issue Dec 5, 2016 · 30 comments

Comments

Projects
None yet
@rauschma
Copy link

rauschma commented Dec 5, 2016

Given how much of a de-facto standard Moment.js has become, it may make sense to briefly explain how date-fns differs.

@s-a

This comment has been minimized.

Copy link

s-a commented Dec 5, 2016

This was my first thought when I found date-fns. https://date-fns.org/ tells some details. I personly often call moment.js to use http://momentjs.com/docs/#/displaying/ the display methods. However pretty interesting solution here 👍

@kossnocorp

This comment has been minimized.

Copy link
Member

kossnocorp commented Dec 5, 2016

@rauschma Moment.js has a few problems that motivated me to start the project:

Also date-fns works with the native date type: no extra dependencies for propTypes in React, Sinon.js works out of the box (and other mocking tools), and so on.

date-fns cons is:

Functionality-wise date-fns equals to Moment.js.

@c-dante

This comment has been minimized.

Copy link

c-dante commented Dec 5, 2016

Some more to add from my reply to a recent r/javascript post

  • Similar bundle size (64 KB min v1,12,1 vs moment's 59.9 KB minified v2.17.1)
    • Although if you only include what you use, you'll get significantly smaller
  • Does not force wrapping dates
    • In order to do anything in moment, you have to wrap everything in a moment object
    • While moment doesn't extend the Date object, it does expect certain functionality through its code
    • Better for tree shaking if you're using a modern bundler
  • All of date-fns's code are pure functions (and simple to grok)
    • Easy to read code for debugging
    • Immutable is nice
    • No global settings
    • No plugins
    • No chaining (composition is better anyway though)
  • Timezone coming soon
  • Locale and internationalization as configs to display functions
  • No duration support (could be coming if an api is suggested)

Source: my reddit comment

Edit: Updated to reflect bundle sizes. Minified bundles are a bad comparison though since ES6 imports and tree shaking, especially since this is a pure function approach.

@bfred-it

This comment has been minimized.

Copy link

bfred-it commented Dec 6, 2016

I see 64KB here: https://github.com/date-fns/date-fns/blob/master/dist/date_fns.min.js

Which is still not that small and if you keep adding features the difference might end up not being much. Moment.js started out as as micro library and look where it ended up 😄

@thisconnect

This comment has been minimized.

Copy link

thisconnect commented Dec 6, 2016

Good look trying to tree shake Moment.js

@s-a

This comment has been minimized.

Copy link

s-a commented Dec 6, 2016

@bfred-it in fact no one need s the full API. It is interesting to bundle functions I need.

@kossnocorp

This comment has been minimized.

Copy link
Member

kossnocorp commented Dec 6, 2016

@bfred-it the dist version of date-fns (https://github.com/date-fns/date-fns/blob/master/dist/date_fns.min.js) coming as a single file while with webpack, Browserify (and other module bundler tools) you'll get the only code you use. It's possible to optimize the dist by splitting the functions into "packs", but our focus is npm version. Contributions are welcome tho!

@bfred-it

This comment has been minimized.

Copy link

bfred-it commented Dec 6, 2016

Perfect! I didn't even realize. 😅 I was only responding to c-dante's comment

@luislobo

This comment has been minimized.

Copy link

luislobo commented Dec 6, 2016

It would be good to add this to the README.md

@kossnocorp

This comment has been minimized.

Copy link
Member

kossnocorp commented Dec 7, 2016

Will convert the comments into FAQ. Please tell me if you have more questions.

@kossnocorp

This comment has been minimized.

@benjamingr

This comment has been minimized.

Copy link

benjamingr commented Dec 9, 2016

A way to do chaining would be absolutely great. Personally I wouldn't mind even altering the built in Date object with immutable helpers. The part I want is mostly just infix.

@c-dante

This comment has been minimized.

Copy link

c-dante commented Dec 9, 2016

@benjamingr chaining is not good -- mutation of objects defeats the purpose of this library being small, pure functions. Also, manipulating the built-in prototypes is also a bad practice. At that point, just use moment which embrasess that approach.

If you want chaining in the sense of not having to do nested functions, check out the FP issue #253 which would let the library support pure function composition nicely.

That all being said, a small function (chain) that would basically do what Lodash's wrapper does would support this in a possibly not awful way.

@benjamingr

This comment has been minimized.

Copy link

benjamingr commented Dec 9, 2016

@c-dante I didn't suggest mutation at all - you can chain functions without mutating the objects.

Two example that come to mind are how functional languages like Haskell deal with this through infix notation or how languages like C# deal with it with the DateTime class instances being mutable.

To be clear. Something like:

imaginaryApi(date).addDays(3).addMinutes(30)

Would return a new Date instance. If we want to avoid intermediate dates we can do:

imaginaryApi(date).addDays(3).addMinutes(30).get()
@c-dante

This comment has been minimized.

Copy link

c-dante commented Dec 9, 2016

Yeah, I don't know if you saw what I added, but I'm not opposed to either the FP changes happening, and implementing the chain as just a "flow wrapper", or creating a light chain operator such as you pointed out.

All this being said -- make a different issue with the request? This doesn't pertain to this issue.
I'm not a fan of mutating the Date prototype, as that is a bad practice.

@benjamingr

This comment has been minimized.

Copy link

benjamingr commented Dec 9, 2016

@c-dante you could just return a Proxy for a date and that could give you chaining without .value() needed.

@blyndcide

This comment has been minimized.

Copy link

blyndcide commented Dec 10, 2016

The bind operator :: would be great for chaining in a functional library like date-fns. Maybe look into it after ecma stage 1 approval.

@milankinen

This comment has been minimized.

Copy link

milankinen commented Dec 13, 2016

@benjamingr I've also thought a lot about chaining but IMHO OO is not the right approach for this library because we're talking about date-fns. I'm also worried about tree shaking issues with OO implementation.

How about currying and re-ordering of function arguments to support partial application (like Ramda does)? That would enable quite elegant composition of date functions and also supports chaining.

// fromMillis :: millis -> date
// format :: format -> date -> formatted-string
// add :: unit -> value -> date -> date
// sub :: unit -> value -> date -> date
// set :: unit -> value -> date -> date
// startOf :: unit -> date -> date

// functions can be used like any other function
fromMillis(0) // => 1.1.1970
startOf("day", new Date())  // today at 00:00

// see http://ramdajs.com/docs/#pipe
const doPipe = (x, ...fns) => R.pipe(...fns)(x)

// supports inline "chaining"
doPipe(fromMillis(0),
  set("year", 2016),
  add("days", 1),
  add("minutes", 50),
  sub("seconds", 10),
  format("YYYY-MM-DDTHH:mm:ss"))
// => "2016-01-02T00:49:50"

// and point-free composition!
const addDays = add("days")
const startOfHour = startOf("hour")

const tomorrowAt15 = R.pipe(
  addDays(1),
  set("hour", 15),
  startOfHour)

// reusability!
tomorrowAt15(new Date())
const apiObjects = ...
const apiObjsWithModifiedDate =
  R.map(R.evolve({start_time: R.pipe(parse, tomorrowAt15)}), apiObjects)

However, I see some at least the following caveat in this approach:

  • What is the correct place for locale?
@kossnocorp

This comment has been minimized.

Copy link
Member

kossnocorp commented Dec 21, 2016

Hey, there! We're looking for testimonials for the new date-fns.org home page. If you want to share your thoughts with the world, see: date-fns/date-fns.org#93. 😇

@pke

This comment has been minimized.

Copy link

pke commented Mar 11, 2017

Similar bundle size (64 KB min v1,12,1 vs moment's 59.9 KB minified v2.17.1)

I am seeing momentjs at 141kb when used with webpack. That is because their package.json main file points to the non-minified version. Momentjs together with opening_hours are both each bigger than my main app code. That's insane.
It all comes down to i18n. Lib authors always forget, that no-one actually needs all languages and that languages should be optional in the first place. At least in the npm packages. In the CDN distros they can build one with all languages included.

I'll switch to date-fns. Thanks for the library!

And I am surprised to see momentjs started as 3.7kb lib! WOW, this thing has exploded.

@larssn

This comment has been minimized.

Copy link

larssn commented Sep 27, 2017

@pke package.json's have started pointing to non-minified versions of code because of webpack. Webpack does better analysis of non-minified code.

@d3viant0ne

This comment has been minimized.

Copy link

d3viant0ne commented Oct 25, 2017

@pke - I say this as I am in the middle of converting from Moment to Date-fns.

If you, or anyone else is stuck with moment while you convert & the bundle bloat is grinding your OCD like it did mine ... you can use a bit of Webpack magic to lean it out.

Given a great deal of the bloat comes from not being able to tree shake all the locales ( no, you still can't do that effectively ) you can filter them out if you don't need them.

Note: You can further refine the regex to filter out a subset of the locales as well

https://twitter.com/d3viant0ne/status/919839837657628677

@larssn has a point about not targeting minified version of libraries, though in the case of Moment and how it's designed, it's going to be a long time before that is front end friendly. It comes from a pre dead code removal / tree shaking time and refactoring from it's OOP implementation to something you can tree shake effectively is not an enviable task.

@pke

This comment has been minimized.

Copy link

pke commented Oct 25, 2017

Thanks @d3viant0ne I was already filtering out all locales, but momenjs is still way bigger than date-fns.
My refactoring is almost done, thanks for your input.
Personally I do not see a future for momentjs. Good bye and thank you for the fish.

@d3viant0ne

This comment has been minimized.

Copy link

d3viant0ne commented Oct 25, 2017

Yeah, I agree it's kind of putting a bandaid on a bullet hole ¯_(ツ)_/¯ but I figured it was worth mentioning.

It comes in quite a lot in webpack / webpack-contrib issues & S.O more frequently than I would have ever expected.

I'm personally still stuck with Moment ( need timezone support unfortunately ) though I am looking forward to an initial release of the date-fns timezone plugin.

@machour

This comment has been minimized.

Copy link

machour commented Dec 14, 2017

Another important thing to note is the differences when it comes to compute a "time ago".
distanceInWordsStrict() from date-fns is really different from moment.js fromNow()

date-fns seems to always report a moment lesser or equal to what moment.js would have outputted (3 days instead of 4, 1 minute instead of 2, etc).

Working on a Github client, moment.js was giving the same approximation as github web, while date-fns reports a smaller distance.

Having the ability to fine tune this behavior would be really great!

@helmbold

This comment has been minimized.

Copy link

helmbold commented Jan 25, 2018

A comparison with Luxon would be helpful, too.

Why not add the "need help" status to this issue, since the comparison page still doesn't exist since this issue was created in 2016?

@Jogai

This comment has been minimized.

@RehanSaeed

This comment has been minimized.

Copy link

RehanSaeed commented Aug 22, 2018

A comparison with dayjs would also be helpful (a 2kb bundle size and moment drop-in replacement). Although date-fns is 30kb, it's more like lodash in that it's just a collection of functions so you pay for what you use. However, what else would I be missing if I picked dayjs?

cbcruk referenced this issue in justinaus/dbr2 Aug 22, 2018

@skjnldsv skjnldsv referenced this issue Sep 5, 2018

Open

Moment #13

@stevemao

This comment has been minimized.

Copy link

stevemao commented Sep 12, 2018

For those who'd like to transition from momentjs to date-fns, please check out https://github.com/you-dont-need/You-Dont-Need-Momentjs

@LunaPg

This comment has been minimized.

Copy link

LunaPg commented Oct 5, 2018

How did you extract your metring between your repo and Moment ?
Do you covert the full range of moment methods ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.