Day.js – Fast 2kB alternative to Moment.js with the same modern API
day.js.org
day.js.org
- https://github.com/tc39/proposal-temporal
- https://github.com/tc39/proposal-temporal#polyfills
- https://tc39.es/proposal-temporal/
- https://tc39.es/proposal-temporal/docs/index.html
- https://github.com/tc39/proposal-temporal/issues/1450
- https://tc39.es/proposal-temporal/docs/parse-draft.html
As far as I know, issue #1450 is the last remaining blocker for the standardization. I'd assume that this will be resolved in the next months. So Temporal will likely be officially released with ECMAScript 2023, but browser vendors and other implementors will start shipping it before the offical release.
Also, once the spec is finalized, there may also be a compliant polyfill available. If so, you'll get the functionality early and still have good compatibility down the line.
Or as it is coming RealSoonNow(tm) perhaps start looking into polyfills as you are going to need one anyway for a story time at least to support LTS browser versions.
The fact that it only took me a few hours to find these suggests there are plenty more bugs like these to find. The fact that these bugs have been open since the start of March with no movement on them suggests they aren’t too interested in correct behaviour (or perhaps they’re just your typical under-staffed open source project).
Maybe I just got super unlucky and ran into the only two bugs here… but it’s not likely.
Luxon and moment.js both handled these cases perfectly. If you’re looking to move from whatever you’re using now, and you can’t wait for the new standard, I’d pick one of those.
const firstInMonth = Temporal.Now.with({ day: 1 }); Temporal.Now.plainDateISO().with({ day: 1 })
Today (2022-10-10 on my computer), that’ll get you a PlainDate representing 2022-10-01.The “ISO” in there identifies the calendar. Want to know what the first of the current month in the Hebrew calendar is?
Temporal.Now.plainDate("hebrew").with({ day: 1 })
And that gives you 2022-09-26[u-ca=hebrew].you don't need to hold off - you just wrap the library in an api of your own, specific for your usage. Then, when/if the ecmascript standard library adds a good one in, you just need to re-implement the wrapper, which would be presumably pretty easy as the api surface area is fairly small.
Right from the beginning, I told anyone who would listen that the underlying data was in UTC. So far, so good.
They get to T-24h for the client's Big Demo Day...
...and someone in London, UK notices the front end UI times are all an hour out (that would be because the UK is still on summer time, UTC+1). I happened to be in Germany and after finally being given a login for the UI found that, wonder of wonders, the timings were two hours out!
<groan>
So we had to bodge the API to fiddle the times forward to UTC+1 for the purposes of the damned demo.
Someone is presumably going to find this in the repo waaaay in the future and ask themselves "wtf were they thinking?". I wish I knew the answer.
By then you can assume that the other library will be a lightweight wrapper around Temporal.
I just think it was needlessly assertive to say nobody should migrate their datetime library until it's ready
Moment.js objects are mutable [0], and this library's objects are ... immutable.
But yeah, very important difference.
https://day.js.org/docs/en/plugin/bad-mutable
However it is discouraged as mutable dates often lead to less maintainable, harder to debug, code.
Interesting, Luxon seems to be the only library in that article using Intl [1] for locales
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Dayjs has the familiar momentjs API.
Both libraries have the greatest differentiating feature from moment: immutable objects. Being able to compose dayjs objects together without fear of modifying them afterwards makes everything a breeze.
The other reason I like DayJS over Luxon is the sheer number of plugins you can pull in to do various things. Like for example I was building an application where I had to build a weekly calendar form for a timesheet, the requirement was weeks start on Saturday and end of Friday.
In DayJS I was able to do this pretty easily by doing: dayjs().startOf('week').subtract(1, 'day') to get the start and then took the result and did res.add(6, 'days') to get the end. I'm not sure if Luxon has this type of functionality.
Lastly I like the plugin architecture rather than giving you everything up front. By default DayJS does not include any of those cool transformations like I talked about above, you have to pull them in as plugins from DayJS, this results in a bit more setup but smaller bundle sizes at the end of the day.
"M" is used for months in Luxon, and is usually what you should use. "L" is only for standalone months, i.e. not within a date string, usually not what you want. In English these are the same thing, but in some languages they are different.
https://github.com/moment/luxon/blob/master/docs/formatting....
https://day.js.org/docs/en/manipulate/start-of
I can’t trust a date/time library that’s blasé about time zones at the API level. Undefined behavior around time zones causes a steady stream of off-by-one bugs in your codebase if you’re not vigilant.
As a dev who’s used all three, is there a massive difference? Not really. Stick with what you like (though moment is no longer maintained so maybe not that)
I just use what the native Date() object offers.
Other devs always say "Just wait, one day it will fall on your feet".
But this has been going on for many years, in which my software has served millions of users and nothing ever fell on my feet. I think the complexity of a library like this (423 files, 1433 commits, 53004 lines of code) would have created more problems during this time. So not using one is a net positive.
Any minimal code example of what is prone to break without a date library and how this date library is supposed to prevent it?
- https://infiniteundo.com/post/25326999628/falsehoods-program...
- https://infiniteundo.com/post/25509354022/more-falsehoods-pr...
In my experience engineers will often brush these sorts of things off as “edge cases”, but really all of these complexities are just how dates and time work in the real life (I’d argue that they’re just “normal cases” to test for)… So any anomaly in software will cause real problems of varying importance for users.
User: set an alarm in eight hours.
It's 10PM right now. At what time should the alarm be set? 6AM? Woops, tomorrow is the switch to DST! What now? User: remind me to brush my teeth on November 21st at 8AM.
Okay, will do! Wait, you took a plane on November 2nd and are now on the other side of the world? Should I remind you at 8AM or 5PM? User: please note my doctor's appointment in two weeks at 10AM.
Sure thing bub! Wait, but you live in Morocco in 2019? And the government just announced that reverse DST will be in effect for the month of Ramadan, which begins next week?! WTF do I do now?---
tl;dr It's not just an issue of storage. Managing time is hard. There are requirements that we, as humans, will intuitively find the right interpretation for, that computers will absolutely break their teeth on.
I mean, there is no way to write code to “handle” this that isn’t just guessing on the part of the programmer. The correct thing to do is to prompt the user for verification or further information.
> There are requirements that we, as humans, will intuitively find the right interpretation for…
Interpretation is subject to error. (Yes humans have immensely more context to work with than computer programs, but just because we we’re better guessers doesn’t mean we’re not still guessing.)
I'm not interested in long theoretical articles. But I would look at a few lines of code.
Here is an example of some code I recently wrote:
logEvent {
'date': new Date().toISOString(),
'event': 'image_updated',
'value': image['id'],
}
This logs that an image with a given id was updated.Why would I trade in my single date line for 423 files with 53004 lines of code?
I'd agree that it feels like that quiet often as a web developer, but that's only because most of our APIs are actually quiet easy to use.
The illusion usually falls away if you look at the code of that API, however.
Those articles are more empirical in nature than theoretical.
> This logs that an image with a given id was updated
As a thought exercise, imagine that your log trail needed to be created in a distributed system, spanning multiple machine time zones, or that you needed to build a report that is read from browsers in multiple time zones that differ from multiple differing written time zones, and you need to account for human readable things like knowing what day of the week it is and what some given locale calls that day.
If you are doing the equivalent of printf debugging with your times, maybe you likely don’t need a time library.
If you are using time as a central part of a distributed algorithm, web content, or a business workflow, then you may likely need a time library.
I heard it very often. I don't buy it. Any system, no matter how complex, can be composed of small, simple systems.
I never ran against a "complexity wall" when writing software in a lean way and suddenly thought "Damn, those tens of thousands of lines of library code now would be the better approach".
Sound software construction techniques are one thing, but convincing someone to pay you to reinvent the wheel is another.
Especially when you consider that budgets for new, bespoke brand websites can start as low as about a couple of days pay for a senior developer.
Libraries come in handy when doing things that aren’t one liners.
A colleague thought it was super easy to change that exact ISO string to use the local timezone instead of UTC, against my advice. Guess what. The minus sign broke it and he would have never known because most customers are in the US, then they travel to Singapore and your product is worthless. By the time you hear about it, you lost the customer’s money and time therefore you lost the customer.
Moment and Luxon are too heavy, I agree, but date-fns isn’t.
You could make an argument that there are more important things to fix, but then you’d be deciding consciously that it was okay to ship software known to be incorrect.
The js date is a bit primitive and moment looks easier but in practice it's actually a convoluted clunky type system that hides important nuance behind impressively bad defaults.
I approach all of these "better than what the language offers" solutions the same way: it would be truly remarkable if some kid had a more nuanced and correct take then people with years of experience and PhDs in language design who made the language but more likely, I think the kid who wrote the library is just better at drawing cartoon characters, hype posting on social media and making something popular.
I used to get immediate hostility and belittling insults when I stated this about 10 years ago. I think people have finally come around. Let's see how the replies go.
It's been like this for decades. Emotional salience sells software better than hard practicality to just about everyone. Then people rationalize their irrational choices then the timeline slips and the product sucks.
You can just sit and watch it play out like someone studying monkeys. It's remarkably predicable.
This wasn't anything about the posted software. It was a reply to a comment.
Formal peer-review does trump download count, nonetheless.
And I’m all for professional licensure, continuing education programs, and formal, public reviews of the software engineering behind the open source libraries that comprise global infrastructure.
Your main point wasn’t missed.
Tell me if you've ever had this experience.
You see something that looks like it's pretty popular. You try it. You find it has nothing but problems. After much research you then find out that other people don't have the level of sophisticated asks for the product and they are doing less complicated and less critical things.
It's the disconnect between the hype and the reality that really rubs me the wrong way. I've personally lost so much time on inappropriate tools.
Again I'm not here to insult anybody specifically or to speak poorly upon any specific product. I know how many people read these comments and I don't want to cast shade on anybody's hard work. I just wish there was more authenticity to the fit and purpose of things.
I know a lot of this depends on the users. I speak as somebody who has very popular projects and very not so popular projects. The popular ones are hyped (but sarcastically) and the ones that I worked very hard on to be extremely technical about do quite poorly.
To make things super current I haven't working for about a month on an article and I have been making sure it is extremely accurate and I know that that will probably hurt me because the liberties which inherently contain inaccuracy are simply more entertaining
This is a shared experience except for a select few. This carries is over to other things. Inaccurate pop science is read much more widely then the direct research material. There's something more emotionally approachable through this tactic. It just hurts productivity and it's a shame
Quoting your writing that is probably rubbing others the wrong way, as it certainly reads easily as being specific to “these” solutions, as you put it.
You might avoid triggering people’s negative emotions by sticking to your main point and avoiding the marginalizing.
This is so vague. Can you say how you're relating this to dayjs? How is its purpose inauthentic?
That was a reply to a comment, not to the code posted. You're being sloppy imprecise and presumptive and expressing it as haughty snide arrogance.
Cool attitude
You described your comment being an attack on modern development culture, as your use of euphemism, you chose the insultingly denotative word “kid” to attack the project.
Cool attitude, too?
You're being sloppy imprecise and presumptive once again. I'm noticing a pattern here. Let's see if it comes in threes.
And in case you're wondering, you're the one who set the rules of this engagement, I'm only playing by them.
We can be adults any time you want.
Nothing about that comment was belittling or hostile. It was a bit snarky, but with very good reason, and did not name its target.
What is one month ago when you are March, 31st?
We have to deal with monthly subscriptions and it's not fun.
No library can help you with that. You have to define what you actually want to calculate.
Time libraries can help you with that.
This discussion reminds me of this bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=1715455
"one month ago" is between "a few weeks ago" and "a few months ago".
>We have to deal with monthly subscriptions and it's not fun.
it is a lot less unfun if you define a month as N calendar days in your terms of service, like virtually everyone does
This is why we don’t let engineers write contracts. Many seem to think that law is a programming language in which they can redefine reality. It ain’t.
And... it's a multi tenant system, where some organizations use Sunday as the start of a week, and some use Monday. And they all want to be able to switch.
In addition, should the legal authority in timezone B change their DST rules in the meantime, the local time of the event as observed in timezone B should still be what the user initially selected, which is not the same in UTC as it was at creation time
Checked some of the popular sites (caching enabled)-
Amazon.com - 4.8MB
Google.com - 2.5MB
Hosting is cheaper.
And the average American is heavier than they should be. Doesn't make it ideal. Always endeavour to trim the fat.
This is HN, and despite the likely predominance of US big-city devs here, I'd wager that most of them like money from rural dwellers just as well as they do the money of their fellow city-slickers.
if your shitty startup or ecommerce site takes >1s to load... not so much.
It’s just 140kb extra, don’t worry about it. Repeat 5 times.
This is the mindset that got us into this mess…
See https://medium.com/rise-engineering/how-we-managed-to-shed-3... for an example. Takes Moment.js from 364KB to 59KB. Still much larger than 2KB, but perhaps small enough.
That's the only real issue for me with Moment and I'm not sure this lib would change that... especially if I need to extend it for various uses every time it's called, which for me would be a rather large drawback that would end up polluting lots of modules with extra lines of code for specific date comparison purposes.
This attitude is why large parts of the Internet suck these days.
I recently visited a friend in Kallithea, Athens, Greece. With his Internet connection, that would add about half a second. It‘s a typical speed for residential connections in Athens.
That said, I tend to err on writing a custom function / importing only a custom function over importing an entire library just to run a 2 lines function.
It’s literally final pending commitments from/to another standards body. If they hadn’t made that commitment there’d be people chastising them for something else. I swear to fuck, we can’t have nice things because no one will ever accept having nice things.
Here’s what I wrote on this (along with a small library to handle this problem): https://lisper.in/javascript-date
Edit: looks like I need a date object specifically, so I will go with the timezone conversion method and convert back to timestamp
It’s functional and tree shakable!
I’ll have to check out Day.js next time though.
Where are the benchmarks?