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

Should Absolute and DateTime have different names for inTimeZone ? #574

Closed
justingrant opened this issue May 16, 2020 · 15 comments · Fixed by #705
Closed

Should Absolute and DateTime have different names for inTimeZone ? #574

justingrant opened this issue May 16, 2020 · 15 comments · Fixed by #705
Assignees
Labels
behavior Relating to behavior defined in the proposal feedback non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved

Comments

@justingrant
Copy link
Collaborator

As a Temporal noob, I wanted to share a challenge I've had when reading code that uses Temporal: it's often hard to know which Temporal type an object is. Is it Absolute? DateTime? Date? This comes up a lot because most non-trivial Temporal patterns involve one or more type conversions. This especially happens when there's a long chain of calls where there's no local variable names to provide context.

After running into this problem a few times, I realized what was confusing me most: the inTimeZone() method was named the same in both Absolute and DateTime. This means that if you see code like event.inTimeZone(tz) you know that one of them is a DateTime and the other is an Absolute. But you don't know which is which, so you have to scan forward or backward in the code until you find a clue about one of the types. Or if you're in an IDE, intellisense might help you. But I still found it distracting to have to think about this every time.

Also, it felt weird for the same method name to perform the opposite operation in two different classes. Like if .foo() meant "plus" in one type and "minus" in another.

I think it'd be clearer if those two methods had unique names that clarified what the destination type will be. toAbsolute/toDateTime? asAbsolute/asDateTime? getAbsolute/getDateTime?

This is a fairly minor issue, but I did want to record it in case other people testing the API have had a similar experience.

@ryzokuken
Copy link
Member

I guess this is something that could be considered in the champions meeting before freezing the API, thanks.

@ryzokuken ryzokuken added behavior Relating to behavior defined in the proposal non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved labels May 18, 2020
@ryzokuken ryzokuken added this to the Stable API milestone May 18, 2020
@gilmoreorless
Copy link
Contributor

gilmoreorless commented May 19, 2020

When I was looking through the cookbook examples there was something that felt slightly off but I couldn't quite place it. I think you've nailed what it was — in hindsight it should have been obvious to me.

On reflection, it's a bit weird to have two concepts of "a fixed point in time, without a time zone" and "an abstract local wall clock time, without a time zone", then convert between the two of them via a method called .inTimeZone(). (I totally understand why it's called that, and the underlying model, but it still feels like unintuitive naming.)

I like the idea of dateTime.toAbsolute(timeZone) and absolute.toDateTime(timeZone). But if we went with that naming scheme, it would hinder a possible renaming of Absolute to Timestamp (#569 (comment)). If I saw dateTime.toTimestamp(timeZone) I would assume I'd get a numeric value back, not a Temporal.Timestamp object (because a lot of programming languages already define "timestamp" as "an integer value of time since an epoch").

@sffc
Copy link
Collaborator

sffc commented May 19, 2020

In the ZonedAbsolute data model I suggested in #569 (comment), the methods would be called withCalendar (ZonedAbsolute to DateTime) and inTimeZone (DateTime to ZonedAbsolute).

@justingrant
Copy link
Collaborator Author

Here's a specific use-case I ran across today. In my app, I put all date-related logic into a single module of utility functions. Here's how one of these functions could be written using Temporal. Note that there's no context or surrounding code that I can use to infer types.

export function addHours(t, hours, tz) {
  return t.inTimeZone(tz).plus({hours}).inTimeZone(tz)
}

A few problems here:

  • Impossible to know whether plus is incrementing clock time or real-world time
  • Impossible to understand the expected behavior of this function around DST transitions
  • Easy to call with the "wrong" type because neither will throw and both will return usually identical results (except around DST transitions). A "called with wrong type" bug would be really hard to find without TypeScript or DST-specific unit tests.
  • A goal of Temporal's type separation is to compel developers to clearly decide whether they are working with clock time or real-world time, but this code is even more domain-ambiguous than equivalent code with legacy Date.

Of course a real reusable library would have better variable/function names, JSDoc, etc. But I think it's reasonable for method names to help provide context for code in isolation.

Out of curiosity, what are the advantages of the current naming scheme? What use-cases are made easier by making the names identical for both operations?

@ryzokuken ryzokuken removed this from the Stable API milestone May 20, 2020
@littledan
Copy link
Member

Personally, I've also found the use of the same name surprising when writing Temporal code samples. I'd be in favor of using different method names (no particular opinion on what the method name is).

@ptomato ptomato added this to the Stable API milestone Jun 4, 2020
@ryzokuken
Copy link
Member

I haven't had a lot of trouble using inTimeZone myself, but just to float a proposal, what about toAbsolute and toDateTime as the method names?

@justingrant
Copy link
Collaborator Author

@ryzokuken what about toAbsolute and toDateTime as the method names?

That's exactly what I expected these methods to be named.

@sffc
Copy link
Collaborator

sffc commented Jun 10, 2020

I'd also have a slight preference for using the to* convention on the other conversion methods which add information:

  • Temporal.MonthDay.prototype.withDay --> toDate
  • Temporal.YearMonth.prototype.withYear --> toDate
  • Temporal.Time.prototype.withDate --> toDateTime
  • Temporal.Date.prototype.withTime --> toDateTime

We also have a few methods that remove information, which are named get*. We could rename these or keep them the same:

  • Temporal.Date.prototype.getYearMonth
  • Temporal.Date.prototype.getMonthDay
  • Temporal.DateTime.prototype.getDate
  • Temporal.DateTime.prototype.getTime

@ryzokuken
Copy link
Member

I would be happy with renaming every type conversion method to toFoo for consistency.

@justingrant
Copy link
Collaborator Author

justingrant commented Jun 11, 2020

Common prefixes like @ryzokuken recommends are also usually good for IDE experience. With autocomplete, the developer could just type "to" (or "as" or "get" or whatever is decided) and then start typing the name of the desired type. Also, seeing the full list of conversion options in autocomplete will probably also help developers discover the presence of more obscure types like MonthDay.

@ptomato
Copy link
Collaborator

ptomato commented Jun 12, 2020

I'm fairly attached to the withFoo methods, I find them very visually intuitive. In yearMonth.withDay(1), I can literally imagine the day being tacked on to the YearMonth to form a Date. 😄

@justingrant
Copy link
Collaborator Author

@ptomato, I originally agreed with you but after using Temporal for a while I came around to @ryzokuken's POV. After a few days of using Temporal whenever I needed to do a type conversion I always thought first about the type I wanted and only secondarily about the parameter types I needed to use to get it. I found it more natural to focus on ends over means. It's also why I find "inTimeZone" so frustrating-- because I'm not trying to get a TimeZone, I'm trying to get a DateTime or Absolute!

I also like the IDE experience where you just type "to" and the name of the desired type. No thinking required. Also I like the idea of using IDE autocomplete for "marketing" of less common Temporal types by putting them next to more popular neighbors like DateTime.

One exception might be withCalendar because it doesn't result in a new type. Although inCalendar might be shorter if all the other with* and in* methods are renamed.

@ptomato
Copy link
Collaborator

ptomato commented Jun 18, 2020

Meeting, June 18: We'll rename everything to toTheTypeThatItConvertsTo. (inTimeZonetoAbsolute or toDateTime; withYeartoDate; getMonthDaytoMonthDay), and do this fairly quickly while still in the early stages of gathering feedback.

@justingrant
Copy link
Collaborator Author

What about withCalendar? Unlike all other with*/in*/get* methods, withCalendar doesn't change the resulting type. Should it stay withCalendar? Switch to inCalendar?

@ptomato
Copy link
Collaborator

ptomato commented Jun 18, 2020

Personally, I think withCalendar should stay, both because it doesn't change the resulting type, and it is similar to with({ calendar }).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
behavior Relating to behavior defined in the proposal feedback non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants