tc39/proposal-intl-relative-time

add support for a custom value of `now` when calling format()

caridy opened this issue · 8 comments

add support for a custom value of `now` when calling format()

What's the use case please @caridy?

@ericf might have more information here, but if I remember correctly, there are to main use-cases here:

  • as a developer, I can reproduce a formatting process by holding a snapshot of the timeline (this is especially useful for testing)
  • as a developer, I can format a relative time on the server side, and rehydrate it on the client side without invalidating the initial markup (this one is especially useful for react isomorphic apps, which will attempt to rehydrate the initial HTML, and potentially producing something different, if we use seconds as unit, and as a result, react will fail to rehydrate it, forcing the engine to produce a brand new html of the app).

I will say that this is not a primary use-case, and we have learned to mitigate them using other tricks, but this is the first formatting process that takes into consideration a variable environment value (now).

Thanks. Interestingly, #6 has the same root cause. Can we use a generic solution that works for both?

Both are caused due to the lack of control over the relative time calculation performed by the implementation, e.g., {value: Date.now() - 10 * msInSecond, unit: 'second'} => {value: -10, unit: 'second'} => 10 seconds ago. While it's really handy to pass the date instance and having the formatter to perform the calculation for us, we have these cases where it would be good if it could have the formatter doing only the i18n, i.e., formatting (no calculation). One approach would be to allow passing the calculated value and the unit ("{value: -10, unit: 'second'}").

Any ideas?

ericf commented

There's something I like about format() taking a ms delta. But I think there's value in the units being determined for you and not having to specify them. Ideally I think the way the units should resolve should be configure through the constructor, just like the other formatters.

let rf = Intl.RelativeTimeFormat('en');
let now = Date.now();
console.log(rf.format(date - now)); // "10 seconds ago"

The main issue I see with this is people getting the values switched around when subtracting.

Can the formatter be configured (by an option) to either accept the date instance or delta?

let rf = Intl.RelativeTimeFormat('en'); // defaults to {inputType: 'date'}
console.log(rf.format(date)); // "10 seconds ago"

let rf = Intl.RelativeTimeFormat('en', {inputType: 'millisecond'});
let now = Date.now();
console.log(rf.format(date - now)); // "10 seconds ago"

let rf = Intl.RelativeTimeFormat('en', {inputType: 'second'});
console.log(rf.format(-10); // "10 seconds ago"
let rf = Intl.RelativeTimeFormat('en');
let now = Date.now();
console.log(rf.format(date - now)); // "10 seconds ago"

@ericf, your example looks nice, although I'm afraid we can't use it considering the formatter also assumes a number is an epoch number, in which case it applies 7. Let ms be x - now., right? In other words, it wouldn't be able to tell the difference between an absolute number like date.getTime() from the relative difference of your example date - now (in which case step 7 should be skipped).

Approach 1, consider numbers as Epoch numbers. (I understand this is the existing proposal)

let rf = Intl.RelativeTimeFormat('en');
let now = Date.now();
console.log(rf.format(date)); // "10 seconds ago"
console.log(rf.format(date.getTime())); // "10 seconds ago"
console.log(rf.format(now)); // "now"
console.log(rf.format(new Date(now))); // "now"
console.log(rf.format(date - now)); // "<bazillion> seconds ago" !!

Approach 2, consider numbers as relative distances in ms.

let rf = Intl.RelativeTimeFormat('en');
let now = Date.now();
console.log(rf.format(date)); // "10 seconds ago"
console.log(rf.format(date.getTime())); // "in <bazillion> seconds" !!
console.log(rf.format(now)); // "in <bazillion> seconds" !!
console.log(rf.format(new Date(now))); // "now"
console.log(rf.format(date - now)); // "10 seconds ago"

Approach 3, formatter function to accept options as a second parameter.

let rf = Intl.RelativeTimeFormat('en');
console.log(rf.format(date, {now:  Date.now()})); // "10 seconds ago"

There are a couple of things to consider:

  • accepting both options (a timestand and a relative distance in ms) is problematic and confusing at least, better to provide one way of doing it.
  • the anchoring of the now is useful, but a very edge case that can be solve with user-land abstractions IMO.
  • if we receive the relative distance value in ms, how are we doing to handle the "discrete distance" explained in #14? Is it still possible @rxaviers?

I'm leaning toward the relative distance in ms as the most simple case, but I will like to spend more time on this because we make a decision.