You may not need Moment.js
github.com
github.com
I haven't had a chance to use it myself, but a friend dropped Moment.js for it (I think to keep the browser from adjusting the date to the local time).
New APIs (and hence, Temporal) are the type of things that if you don't know about, you can easily miss and go straight to a library for.
> NOTE: Although this proposal's API is not expected to change, implementers of this proposal MUST NOT ship unflagged Temporal implementations until IETF standardizes timezone/calendar string serialization formats. See #1450 for updates.
it's basically already accepted. Stage 3 means it's basically ready for a preview implementation and stage 4 means passed for "official" ecmascript inclusion
Other recent additions to stdlib have followed a fairly consistent pattern: design low level but with existing use cases and solutions in mind, explain the design in terms of migration path for library authors or in terms of usage comparisons to those libraries.
Temporal just has… a bunch of data types with very little in the way of explanation of what they are. And some of them are quite similar but have slightly different semantics and APIs to achieve the same thing.
It’s not entirely clear why most of the data types exist in the first place. Like, I don’t want a TimeZone class, and I don’t want multiple kinds of Instants. I want a Date, a Duration, and clear semantics about how they interact with each other and with time zones.
Anyway I ended up putting the work I was doing on hold because it became such a time sink, but when I come back to it I fully expect to look at my WIP stashes, and run screaming toward date-fns or whatever.
I mean no disrespect to the standards authors/contributors (in case any are reading), I’m sure standardizing anything to do with dates/times is even more challenging than anything else you deal with. I just… wonder if the low level design approach may have forced an unnecessary design in this case, and wish there was a somewhat more pragmatic approach for something end users and library authors alike routinely get wrong in subtle but important ways.
I think at this stage the only libraries I've seen to manage this clearly are the ones that cleanly seperate the concept of "LocalDate[Time]" from "ZonedDateTime" (which is different to OffsetDateTime, which is only useful when backwards looking because offsets are subject to change in future, and so you should probably just use a Zoned variant). While people might appreciate the simplicity of a single DateTime class, it just leads to unclear handling in application code of where the conversions happening and confusion as to what's actually going on with time zones.
The mix of zoned/not is a valid use case but almost certainly a specialized one that shouldn’t be the core API.
I'm curious, where is this ever a valid use case? The idea of an unzoned DateTime doesn't make sense to me. I guess if you're building software that lives in orbit or on other planets?
For the unzoned case I need my reminders to notify me at the same local time wherever I travel. For the mixed case I need to be able to apply local changes where the unzoned solution isn’t available.
These are ADHD meds, I have severe executive dysfunction and I depend on reminders for this. Traveling from Seattle to DC, this is literally the difference of whether I can function at all before lunchtime. Traveling further I might as well not go at all.
But a combined datetime (both date and time) in an unspecified non-UTC timezone is far less useful. As I mentioned in another comment, there are some rare use cases where it is genuinely appropriate, but far more often if you give people such a type they’ll use it to store data in a single specific time zone, without being explicit about what that time zone is-which is a bad practice.
That said, these kind of scenarios are rare. A non-UTC datetime in an unspecified timezone is much more likely to be in some particular yet unspecified timezone, or even to be an incoherent mix of data from different time zones, than to be the one of these rare cases where having a constant local date and time across multiple time zones is actually useful.
Arguably, library designers should not attempt to cater for these rare use cases. Doing so is adding complexity which is far more often going to be a cause of harm (people using an unzoned datetime type when they shouldn’t) than a benefit
Another is when you treat the timezone and datetime separately. Imagine an internal app for conference room bookings with a form that lets you input a DateTime + office building (which some Ruby or whatever backend then uses to compute the localized time). The JS DateTime input library would deal with a non-localized DateTime only.
That’s my point. Most recent standards try to optimize for this. I would be surprised if you could based on my experience with the APIs. Maybe I’m not well enough versed to see how it would be written. But its design feels much more likely to be something where the native types are passed around or substituted. They’re not designed to interoperate with each other as far as I can tell.
We have to keep using moment.js due to Highcharts, timezones and locales. It's quite easy to use if you're careful about mutating objects and the API is not brain damaged. We still use jQuery as well, it's a breath of fresh air compared to native Js APIs, except maybe fetch.
Go ahead and downvote, I couldn't care less. We can't keep changing our platform every time a new and hip way of doing things pops up.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- https://caniuse.com/mdn-javascript_builtins_intl_datetimefor...
Parsing, however, is an entirely different topic. I assume the Temporal proposal authors learned from the Date.parse fiasco. To this day, there are browser inconsistiencies that make it largely unusable for anything else than the full-length ISO date format. Hence, it might be better to use a userland library that works consistently regardless of the browser (version). There are also some notes about parsing in https://tc39.es/proposal-temporal/docs/parse-draft.html:
> Temporal's approach to most operations—including parsing—is to encourage strong typing, e.g. Temporal.Instant.from vs. Temporal.PlainDateTime.from. A type-spanning "parse anything" API goes against that strongly-typed model.
Does using a JS backend like Node or whatever help ease this pain?
I've yet to dabble in that realm much, but I've always hated working with dates in JS and C# because of how each language handles dates differently. It's not the most annoying thing by any means, but it does slow me down on the occasion.
There is tooling around immutability and a whole host of compiler optimizations. The resultant code is far less error prone.
Do you feel the same way about static typing?
There are times for immutability, and times for mutability. You have to be careful for different things.
Part of the problem is that moment would both mutate the underlying object and return the object.
const a = moment()
const b = a.add(1, 'second')
Both b and a are now the same object. I've lost a few hours to the design choice.If `a` is mutated by the `.add()` method, then it should probably return void rather than returning a copy of the object.
Is the immutable DX still better in this specific example? Probably. But the above at least would help developers avoid the major footgun with mutability.
Else: a.add(1, ‘second’).add(1, ‘day’).subtract(2, ‘minute’) would create 3 more objects that are not needed. Creating a new moment object is expensive, it happened to me to work with a lib that grew exponentially slow when using above N dates because they where constantly recreating moments instead of using them wisely so creating a new one on every operation would be quite bad.
That’s why the method .clone() exists, so you can declare that explicitly:
const a = moment()
const b = a.clone().add(1, ‘second’)
PS: don’t take RTFM as an offense, I just happen to like it a lot and we use it frequently at work, I don’t mean to be disrespectful towards you :)It's not always the best (or even an) option, but it does spare you some concerns.
Also I really don't recommend dayJS, its documentation is crap (for example this is the documentation of its timezone plugin: https://day.js.org/docs/en/plugin/timezone ) and is full of serious bugs that its developer does not respond to: https://github.com/iamkun/dayjs/issues
Also the code style is really concerning too: https://github.com/iamkun/dayjs/issues/1598
Curious, are there other languages where people feel this date/time mess does not exist?
This is missing in the OP explainer, so I created a PR[2].
1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
2: https://github.com/you-dont-need/You-Dont-Need-Momentjs/pull...
01/02 03:04:05PM '06 -0700
I actually think that's a really good idea. Sure, it may easier to remember "YYYY-MM-DD" than "2006-01-02" at first, but I think it helps a lot in many other cases, e.g. you don't need to remember what is exactly meant by MM and MMM and MMMM, you could just create your format string as "January 2, 2006" or "Jan 2, 2006".
I believe the standard library developers knew date/time was cursed, so punted on it. There is a minimal set of types and functions to allow the bare minimum of system calls etc:
https://doc.rust-lang.org/std/time/index.html
But you have to bring in one of a few crates to do anything else.
But note that before Chrono there were other time libraries; one of them was called time[2] - and IIRC it was created from code removed from Rust's stdlib std::time[3]. It eventually proved to be the best decision: designing a good API is a hard effort, and any design was prone to have mistakes and warts.
Chrono provides interoperability with both std::time and the time crate. It acknowledges other datetime crates that it was inspired, like datetime-rs[3] which itself was inspired by Joda time.
[0] https://rust-lang-nursery.github.io/rust-cookbook/datetime.h...
[1] https://crates.io/crates/chrono
Even devs with good defensive programming instincts make entirely wrong assumptions because the problem is so vast and complicated. For instance I remember repeatedly explaining to a previous team that we couldn’t treat all of Michigan’s locality outside of its 4 Central Time counties as America/New_York because America/Detroit is governed differently. This was hard to communicate even as I dug up the relatively recent history of TZ changed in MI.
Their eyes collectively glazed over as I tried to explain the complexity of DST in Arizona—the state doesn’t observe DST, most of the reservations do, but some don’t.
I have no idea how library authors are supposed to deal with this. Language authors are more likely to be able to defer to expertise, but even then it’s obviously not going to produce great results. And by and large library authors will depend on the quirks and bugs of the host language.
I agree this is a particular sore spot across the field. I think it’s something that would especially benefit from a cross-environment design.
As in: start with the existing ISO standards, which are good. Determine an appropriate level of abstraction that suits low level platforms, and coordinate higher level abstractions as warranted. I anticipate the XKCD comic, but this is a case where the problem is generally equal-bad for everyone involved and it wouldn’t hurt to try.
In data modeling I hide such things behind a foreign key to create a distinct domain. E.g. “PersonBirthDate”, “StartedAt”, “ValidAfter”, “AvailabilityInterval", “FiscalQuarter”, and “ExpiresBy” are all different representations, possibly also distinct by the source entity, and all treated as a distinct domain. Further I’ll often add UDTs and database functions/procedures to help assure integrity (and possibly quality, not always possible of course). Sum Types are unpleasant to model in RDBMS and descendants of such.
[0] a pun, HHOS. <https://en.wikipedia.org/wiki/Yoneda_lemma>
but by then, DateTime was used in a lot of places, for eg: and .NET Sql Server driver mapped datatime against DateTime (instead of DataTimeOffset)
yeah, .NET has these issues too. and I have not even gone into DateTime Culture!
Whoever can wrap this in WASM and expose a JS API will be a hero.
Also anyone trying to sell “Midnight GMT” as a date only format is in for a world of trouble down the line.
Another issue is the mental burden of knowing when a time stamp is supposed to be a date or a date time. You cannot write a reliable method to differentiate them because there will be valid date times that are exactly at GMT midnight.
Fundamentally dates and date times (instants) are different. Christmas is December 25th in Australia and the USA. But the instants that those time zones experience that date are different. People forget this and will try to treat the GMT midnight as a date time, when it should be a date.
I’ve routinely worked with date-fns and found it is usually 20KB or less
(Although it looks like `js-joda` doesn't contain the time zone database, for that you also need `@js-joda/timezone`, and the IANA TZ DB as generated by `moment-timezone`. Oh boy!)
You Don't Need MomentJS - https://news.ycombinator.com/item?id=20508166 - July 2019 (23 comments)
You Don't Need Moment.js - https://news.ycombinator.com/item?id=17990859 - Sept 2018 (85 comments)
So yeah, +1 on "be careful about using moment.js in performance sensitive/critical code".
The ultimate goal is, your <script>s are modules, and import their dependencies from a common CDN like unpkg. The browser will cache the import, so that large common imports are rarely actually fetched. Dependencies would have their own cached dependencies as well (although this would sharply decrease efficiency without extra coordination between client / server for bulk fetching).
This would significantly reduce MB-large JavaScript files because most of that code is shared general libraries. Even if you use a huge library like core.js with no tree shaking, it's no longer an issue, as long as many others are also using core.js.
I do know that module scripts can import from remote sites, and unpkg with the experimental '?module' resolves imports in unpkg modules to other unpkg modules. I also know that browsers are very good at caching modules. I doubt browsers are smart enough to bulk fetch multiple unpkg dependencies in one request.
Does anyone have more experience with, in general, trying to cache large JavaScript imports?
Cross site caching is dead. Safari hasn’t supported it in years and Chrome recently dropped it as well. It’s better to hold all assets on your domain to avoid TCP and TLS overhead.
Here’s a blog post with more details about Chrome’s change: https://www.stefanjudis.com/notes/say-goodbye-to-resource-ca...
https://developer.mozilla.org/en-US/docs/Web/Privacy/State_P...
I even wrote the solution on a scrap of paper I had in about 20 seconds.
It was everything I hated about the dev community; some insistence on using hip and popular stuff that's poorly suited to a problem and being snarky and elitest snobs whenever anyone claims they are being trend following fashionistas and not doing any actual engineering. Same thing is going to happen to reactjs unless it pivots hard to being something dramatically different (which it keeps doing).
When a tool makes easy things hard and hard things impossible its days are numbered regardless of how fancy and popular it looks
He worked at some really well funded place, the kinds that spend enormous money to create products people hate. Holding the position against the grain when it's appropriate is necessary for the progress of the craft but my word is it a lonely place sometimes
For those still stuck with Moment, it's worth exploring means to reduce the impact on bundle sizes. I wrote about that a while ago: https://dsebastien.net/blog/2020-07-12-removing-moment-js-lo...
Otherwise, definitely try native APIs first for straightforward date manipulation.
You may also want to consider a branded type, which can be useful but a little less strict.
declare class _MySpecialPrimitive {
private mySpecialPrimitive?: never;
}
type MySpecialPrimitive = number & _ MySpecialPrimitive;
Combined with type guards (which you can conditionally execute at runtime), you can narrow overly broad structural types safely, eg: const isMySpecialPrimitive(val: unknown): val is MySpecialPrimitive => /* anything that produces a boolean */
(And you can use assert guards in a similar way, but I find they make it easier to treat them as a noop) const MySpecialPrimitiveBrand = Symbol('mySpecialPrimitive')
const val = Object.assign(prevVal, { [MySpecialPrimitiveBrand]: doesntMatter })
Yeah, don’t do that unless you want to destroy every language facility that depends on reference equality checks. It boxes your primitive and breaks the world.The class/private approach has the advantage of hiding the extra property from everything except the type checker.
For complex types it also disallows spreading to prevent circumventing validation. However, errors are often not has human readable as one would like them to be.
Is there anything like this planned for "You don't need"?
I have never actually had to deal with XML from the backend but if I had to, I guess I would await on `response.text()` from `fetch()` and then with an instance of `DOMParser()` call `parseFromString(xml, "application/xml")` and then query the resulting XML tree with `querySelector` et.al.
https://youmightnotneedjquery.com/ Is this the kind of thing you were mentioning? Maybe it’s been a while, but if you Google “you don’t need jquery” you’ll find plenty like this and it seems to explain well enough.
Where is the "you don't need React" website/repo again?
If you know React well, it seems like there are things that everyone can learn from or think about. Would you use vanilla JS or other frameworks and why?
This is a real "where's my flying car" kind of argument.
Microsoft wants TypeScript and abandoned .Net dominance. Google failed with AMP. On the backend, Facebook's HHVM saw limited adoption, and node.js took over, even surpassing PHP in developer mindshare. So streamlining the front & backends was inevitable. Angular 2 was so bloated that it made React seem simple, and by the time Vue et al came around, React had so much inertia and community support that it was harder for them to gain traction. Apple checked out completely, Mozilla is still fighting the good fight but losing more ground every year, so now it's really just Facebook building on top of Google...
For what it's worth, the nightmarish toolchain is slowly getting better, with ES6 modules, dynamic imports, Web Components, service workers, and the such. NPM is also slowly improving, and semver has done wonders for maintaining library compatibility. Frameworks-on-top-of-libs like Next.js bring some much-needed boilerplate and tooling to React and generally make the whole experience both quicker and far more tolerable (you rarely have to edit tooling configs, and webpack/babel are invisibly handled for you). Not to say it's ideal -- far from it -- but people are definitely working on streamlining the developer experience. And from the UX side there is a lot of optimization and tree-shaking work happening too, to try to shrink down the ultimately delivered package sizes.
That's not to say React is right for every project. It's just the most popular, so easy to hire for and easy to collaborate on. Every vendor provides React demo code or readybuilt components and hooks, vs having to write your own for every trivial API use case. It's a real time-saver, and the closest thing to a de-facto standard the web dev world has had since jQuery was pronounced dead (RIP).
But hey, the JS ecosystem at its worst now is at least still better than having to choose between Flash, ActiveX, Java, and VRML. At least it all compiles down to JS. Or at least it did until WebAssembly (cry)...
In a way, JS is a victim of its own success. Reminds me a lot of the Linux ecosystem, where there are always 10,000 ways to do something depending on your particular distro and package manager and shell and window manager, yet never a single "best practices" way. There are a million ways to do anything in JS/TS/CoffeeScript/ECMAScript/React/Vue/Svelte and none of the come close to the relative orderliness of, say, PHP or the .Net stack. I'd say it's what happens when you do design-by-committee, except it's not, because JS is more like design-by-retrospective, and only after years or decades of suffering do best practices emerge from popular use and bubble up eventually into ECMA proposals, only to be largely ignored by Apple and so require polyfills (thanks, Safari).
Which is all to say, yes, it's still hard to work with and has room for a lot of improvement. The community at large is working on a lot of those problems, slowly but surely, while being constrained by the will and pacing of the behemoths. Maybe in 20 years' time things will be better... but who are we kidding.
JS frameworks aren’t cruft, or a mess, they are artifacts of the intended path to enable highly flexible extensibility.
An industry using the exact same framework (for a time, it never lasts) doesn't make that framework a "standard". jQuery was also "a standard" by the same logic.
edit: I'm talking about web standards here, which is the DOM is part of. After the inane amount of hate jQuery got with hit pieces, JS developers were quick running to an even more intrusive and bloated framework that certainly was not "vanilla JS" either, the irony is somehow lost somewhere...
However, isomorphic HTML generation/templating and state management are still unsolved from a browser native perspective.