-
Notifications
You must be signed in to change notification settings - Fork 1
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
Format a Temporal object into a user-supplied string format #5
Comments
All I want is something like https://date-fns.org/v2.23.0/docs/format eg. I have read the doc of DateTimeFormat and I don't think it can match my requirement. |
I think strongly that Temporal should stick to the standards here. Format-transforms are a useful use-case for third-party modules. |
It IS the standard: https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table 3rd-party libraries like moment, luxon, dayjs, date-fns are already very easy to use and their APIs are familiar. People choose to a new standard object that is not very stable, has learning costs and browser compatibility concerns mainly because it can reduce 3rd party library dependencies and publication code sizes. If people still have to use 3rd-party libs for such a common use case formatting string, why do they have to learn something completely different? |
@CarterLi I disagree. First of all, LDML is not a timestamp format standard, it is meant for localized formatting for i18n. We already allow localized formatting for Temporal objects via Anything that's not "canonical timestamp format for interchange" and "localized format for display" should be done using third-party modules. |
I have a requirement to format some dates as either ‘8 Sep’ or ‘8 Sep 2020‘ (depending on whether the year is the current year or not).
Is there a way to achieve those formats with the current APIs available? If not, current APIs seem too rigid, and I would like to see custom formatting using tokens. It has been an issue in the past that there have only been de-facto standards for such tokens, and it would be problematic to adopt any of these on a presumably arbitrary basis. However, the Unicode Consortium is a standards body, and as part of the Locale Data Markup Language (LDML) have defined a standard set of pattern fields for date formatting (https://unicode-org.github.io/cldr/ldml/tr35-dates.html#Date_Format_Patterns). As LDML is intended explicitly for locale-specific applications, and includes references to non-Gregorian calendars (such as the Chinese lunar calendar), it looks as if it would make a good fit for the Temporal proposal. I hope I don‘t migrate to Temporal, and then still have to load the whole of a third-party module such as moment just to be able to generate custom formats. Surely Unicode TR35 Part 4 (Dates) Section 8 (Date Format Patterns) would make a good basis for Temporal custom formatting? |
The discussion thread starting from tc39/ecma402#554 (comment) might prove illuminating as to why there is caution about a formatter API. I'm not sure whether your requirement
means that you want to format dates with the day before the month and no comma, even in the In any case
It's more likely that a third-party module specifically for custom formatting would spring up, rather than loading Moment. |
I can't believe this is even a debate. Formatting strings based on user-supplied specifiers is a standard across a wide range of languages and libraries. Sticking to only the "standards" is the kind of decision that gets made in ivory tower rooms of computer theory and completely ignores the needs of programmers dealing with the real, messy world that we have to code for. |
I mean... this is a repo for incubating a proposal for the standard, and there are other programmers in this messy world that have needs that would conflict with just copying the API from date-fns ... so I guess I don't understand why it's so unbelievable that there is a discussion about this? In any case, it would be helpful if you could provide some details about your use case. The more we know about how people would use this API, the better. |
Today, I wanted to get the following date/time format: French: (20:22 isn't technically the format for use in sentences in French, but it's widely accepted as a more compact, more practical format to use for displaying times, compared to 20 h 22. Our design team isn't 100 % sure which format they want at this point.) English: I couldn't find a way to do that with the current Maybe there's an obscure locale that allows it, but the lack of a full documentation of all supported locales and the formats they provide anywhere that I could find isn't making the search easy. Anyway, with this, I was able to get pretty close: myDate.toLocaleString('fr-CA', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: 'numeric',
minute: '2-digit',
})
// This is the same
myDate.toLocaleString('fr-CA', {
dateStyle: 'short',
timeStyle: 'short',
})
// Output: 2022-08-05 13 h 06 But the only way to get a separator in there that I found was: const date = new Date()
const formattedDate = new Date().toLocaleString('fr-CA', {
dateStyle: 'short',
})
const formattedTime = new Date().toLocaleString('fr-CA', {
timeStyle: 'short',
})
const formattedDateTime = `${ formattedDate } à ${ formattedTime }` I do have a string translation library with variable insertion that allows me to do the English version of this, adding "at" instead of "à", pretty well, but isn't it unfortunate that I had to do that? Basically, we have locales that define the "visuals" of the format. The order of the numbers. The separators between the numbers. The separators between hours and minutes. The separators between the date and time. All of these factors can't be overridden. It's basically just magic that happens behind the scenes that we have no power over. I really, really wish I could pick Additionally, I'm lucky; I'm from Canada, and the ISO-8601 representation of a date (just the 2022-12-30 part; not the whole machine-friendly string) is what JS understands as a short date for me. But what if someone wants that, but they're not aware of locale One more point: What do I do if I'm writing a French date but I want the colon representation of the time (20:22 instead of 20 h 22)? Should I just... pretend the locale is English? And lastly: what if people want to put the date in bold? Should Temporal help with wrapping stuff in HTML tags/markdown markers or not? Because even if you offer separator handling, if people want to format the date differently, they kinda have to do string concatenation anyway, unless there's some way to wrap things in offer. |
Thanks for the detailed use cases! I agree, these would be good use cases for a string format minilanguage. The point about starting from localized defaults and tweaking a few things is, I fear, difficult to write code for in a general case, so it's probably best to consider it for one or a few locales, like You can pick function formatCustom(plainDateTime) {
const formatter = new Intl.DateTimeFormat('fr-CA', {
dateStyle: 'short',
timeStyle: 'short'
});
const { year, month, day, hour, minute } = formatter
.formatToParts(plainDateTime)
.reduce((result, { type, value }) => {
if (type !== 'literal') {
result[type] = value;
}
return result;
}, {});
return `${year}-${month}-${day} à <strong>${hour}:${minute}</strong>`;
} It would be easier to do things like this if I do think that HTML and Markdown are out of scope for a facility that's part of the core JS language. Early JS included special HTML facilities like |
What if we could do something like this? const localeDateFormatParams = Intl.getDateFormatParamsForLocale('fr-CA');
console.log(localeDateFormatParams);
// Would output something like:
const localeDateFormatParams = {
separators: {
afterDay: '-',
afterMonth: '-',
afterDate: ' à ',
},
// And much much more info about the minute details of how this locale works
} And then use it like: // An object for a locale would mean "I'm about to define to you the slightest details of a locale that may or may not exist"
const formatter = new Intl.DateTimeFormat(localeDateFormatParams, {
dateStyle: 'short',
timeStyle: 'short'
}) As for your code example, the existence of |
It would be fewer lines to use ECMA-402 have previously indicated that they are skeptical about such changes to Intl.DateTimeFormat: tc39/ecma402#554 (comment) There is a data-driven API being discussed at tc39/ecma402#210 that I think would address this. |
Oh, I see! Thanks. :) My sneaky way out of the colon issue was to use |
It seems to me there is a confusion between localization (for human beings) and formatting (for other computing uses). The Intl API might be suitable for localization; but is definitely not appropriate for formatting. Most of my time is actually spent interacting with non-standard systems and providing strings like 202211210000, 00H12H, 301022. It's a breeze with standard "format" APIs provided with all major date and time libraries. But it's a really sore point pain with Temporal and Intl :( |
I think the problem with string formatting is the concept and idioms themselves are very English-centric. For example, most implementation assumes
However, this does not even translate to other Latin alphabet languages, for example in French, the equivalent of 3-letter month is 4 letters -- Also how does the string format apply to languages where people do not use space separators? (e.g. Asian languages) Does |
We just need to find the language with the most different ways to express, say, a month, and prepare a scale of complexity based on that. After that, it's probably relatively trivial to just simplify for the simpler languages. The concept of a short month doesn't exist in your language at all? Great! When you ask for a short month, you get the only month that exists. |
OK, in that case, let's say the hypothetical "most different" language is some French dialect locale and their 4-letter word abbreviation for Month is represented by Since as you say just "simplify for the simpler languages" and English is simpler, English would get:
Would you be happy with that? I am pretty sure not, since that is obviously illogical for English speakers. |
I'd be satisfied with that. It may not be the ideal solution, but it'd be a workable solution. A workable solution is much better than "let's not have a solution because there is no absolutely perfect one". Though "MMMM" and such isn't the only model in existence. We could, for example, do templates with keywords that would be a bit more explicit than repeated letters. This is just me improvising, but keywords like There are lots of possibilities. We should strive to choose the one(s) that will apply best to the most use cases. But even if there isn't a solution that will perfectly match every use case, I think it'll still be a significant win if we can cover most of them. |
English is however the de-facto standard in programming / developer-facing strings, and that's not going to be changed by one datetime library. Introducing location-dependent variation in machine-readable dates would be surprising even to non-English speaking devs, lets follow the principle of least surprise here! The primary use-case for As wonderful as they are, ISO-8601 and RFC 3339 do not suit all use-cases, there are reasons to need things like these:
Of course you can technically achieve these with some library-free hand-written string slicing and assembling code right now: tc39/proposal-temporal#2501 (comment) but the whole point of There's a reason
It doesn't need to be the recommended or primary way of producing date strings, but because it's such an industry standard it would remove the need for external packages just to access this feature. As it stands now, |
Similar to #2, but for string formatting instead of string parsing.
If #2 is adopted, an API using the same microformat could be proposed.
Advantages:
Sometimes it's necessary to obtain a string that fits a particular format that is neither ISO 8601 nor locale-sensitive. For these cases, third-party date libraries usually provide a formatting API.
Concerns:
In general, for human-readable strings, developers should not customize the format themselves, and use only the locale-specific formats provided by Intl.DateTimeFormat. While this functionality might be useful for formatting strings that must fit a certain format for machine-readability, providing such an API might result in worse user experiences because developers are tempted to use it for human-readable strings instead of Intl.DateTimeFormat.
Unlike parsing, this kind of functionality is easy to build in business logic.
Prior art:
TBD
Constraints / corner cases:
TBD