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

Advice on JS passing points-in-time or offsets-from-now #425

Open
jyasskin opened this issue Mar 14, 2023 · 8 comments
Open

Advice on JS passing points-in-time or offsets-from-now #425

jyasskin opened this issue Mar 14, 2023 · 8 comments
Labels
tc39-tracker Issues where TC39 input would be useful Topic: JS

Comments

@jyasskin
Copy link
Contributor

jyasskin commented Mar 14, 2023

This came up in WICG/storage-buckets#79, which is asking whether to have a setExpires(Date.now() + offset) or a setMaxAge(offset) method. It seems like it'd be useful to write some general advice about whether to prefer interfaces that expect a point in time, or interfaces that expect an offset relative to now.

In favor of offsets:

In favor of points in time:

  • If developers ever need to pass the same time to multiple API calls, it's much easier and more reliable to compute a single instant in one place, and pass it around. Doing the same with an offset-based API implies a lot of doIn(goalTime - Date.now()), and each of those gets skewed by the amount of time between the call and when the method internally converts back to a point in time.
  • Implementations have to convert offsets to points in time internally in most cases anyway.

I've probably missed several considerations on both sides.

@annevk
Copy link
Member

annevk commented Mar 15, 2023

https://www.mnot.net/blog/2007/05/15/expires_max-age lists some other considerations, such as that point-in-time has more potential for invalid inputs. (If we did cookies today and ignored all their other problems they'd use max-age, for sure.)

@jyasskin
Copy link
Contributor Author

I think JS APIs avoid most of the issues in mnot's blog post by accepting a number of milliseconds past the Epoch, rather than HTTP's complicated date format. Unless I've missed something, the paragraph that's relevant to us is

Furthermore, if you forget to update your Expires time, or get the time zone conversions wrong (source of many an error), you’ll end up with unpredictable results as well.

@annevk
Copy link
Member

annevk commented Mar 16, 2023

It also seems true that with an offset you at least cannot give times in the past (or at least that's more easily enforceable).

@LeaVerou LeaVerou added Topic: JS tc39-tracker Issues where TC39 input would be useful labels Apr 21, 2023
@bakkot
Copy link
Contributor

bakkot commented Apr 22, 2023

I would guess that setTimeout is overwhelmingly the most common API in this class, probably followed by AbortSignal.timeout, and deviating from the pattern used in those APIs is likely to be confusing.

Also, almost all of the time I want something like "in X units of time" rather than "at time X", and making the input be "at time X" requires me to do more math. Seems simpler to not make the developer do math.

For longer durations I like the idea of accepting Durations, which are completely unambiguous and avoid the need for readers to figure out the math: expiresAfter(Temporal.Duration.from({ days: 5 })) is much easier to read than expiresAfter(5 * 24 * 60 * 60 * 1000). To simplify things there could even be a general pattern of accepting options bags or strings coercible to a Duration or Instant (as appropriate).

@LeaVerou
Copy link
Member

What about both? Then a) UAs are not blocked by Temporal, and APIs can improve once Temporal is shipped and b) accepting numbers is consistent with existing API surface

@jyasskin
Copy link
Contributor Author

@LeaVerou, your "both" seems to be about accepting both a number and a Temporal object, once Temporal is ready? That's fine, but the question for this thread is whether to accept points-in-time or offsets-from-now. Before Temporal is shipped, both of those are simple numbers, so "both" would require us to define two names for each time-accepting API.

@LeaVerou
Copy link
Member

@LeaVerou, your "both" seems to be about accepting both a number and a Temporal object, once Temporal is ready? That's fine, but the question for this thread is whether to accept points-in-time or offsets-from-now. Before Temporal is shipped, both of those are simple numbers, so "both" would require us to define two names for each time-accepting API.

It was somewhat orthogonal: regardless of what guidance we go with wrt points-in-time vs offsets-from-now (which I suspect somewhat depends on the use case, but I agree offsets-from-now is more commonly needed), these APIs should accept both Temporal objects and numbers whenever possible (perhaps even after Temporal ships, for consistency).

@ayuishii
Copy link

I think another point in favor of "points in time" not mentioned here yet is the favorability for how its read after being set, and its format consistency with read/write. This is relevant to Storage Buckets and Cookie Store API that isn't quite relevant to say setTimeout.

I'd assume reading expiration as "points in time" (ex. bucket.expires()) is desirable regardless of if we choose "points in time" or "offsets" for setting expiration (feel free to correct me if this assumption is wrong). But if so, having consistency in formatting of how its written and read seems like a plus, as it can easily be validated, and wouldn't have to convert between the 2 formats when deciding to update expiration based off the previous value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tc39-tracker Issues where TC39 input would be useful Topic: JS
Projects
None yet
Development

No branches or pull requests

5 participants