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

integration with <input type="time"> and <input type="date"> #107

Open
kaizhu256 opened this issue Feb 20, 2019 · 27 comments
Open

integration with <input type="time"> and <input type="date"> #107

kaizhu256 opened this issue Feb 20, 2019 · 27 comments
Labels
behavior Relating to behavior defined in the proposal integration
Milestone

Comments

@kaizhu256
Copy link
Contributor

referenced from w3ctag-review

according to MDN, the input-values would be [1], [2]:

<!-- date -->
<input id="date" type="date" value="2017-06-01">
<!-- time -->
<input id="time" type="time" value="13:30">

what would UX-workflow integration look like? how would i use temporals to transform <input type="date">, <input type="time"> into JSONdatetime_utc, timezoneOffset?

var datetime_local;
var datetime_utc;
var timezoneOffset;

datetime_local = CivilDateTime.fromString(
    document.querySelector("#date").value
    + "T"
    + document.querySelector("#time").value
);
timezoneOffset = ???  // new Date().getTimezoneOffset()
datetime_utc = ??? // JSON.stringify(new Date(datetime_local))

ajax({
    "method": "POST",
    "url": "/api/schedule-appointment",
    "payload": JSON.stringify({
        datetime_utc: datetime_utc,
        timezoneOffset: timezoneOffset,
        ...
    })
});

[1] https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
[2] https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time

@pipobscure
Copy link
Collaborator

pipobscure commented Mar 22, 2019

let date = CivilDate.from(doument.getElementById('date').value);
let time = CivilTime.from(doument.getElementById('time').value);
let datetime = CivilDateTime.from(date, time);
let localdatetime = datetime.withZone('SYSTEM');
let timezoneOffsetSeconds = localdatetime.offsetSeconds;
let timezoneOffsetString = localdatetime.offsetString;
let timezoneName = localdatetime.timeZone;

ajax({
  "method": "POST",
  "url": "/api/schedule-appointment",
  "payload": localdatetime // serializes to "2019-03-21T09:32:24.012307238-04:00[America/New_York]" (as of this post)
});

// No need to pass the timezone separately. A ZonedDateTime has both the absolute time and zone

@kaizhu256
Copy link
Contributor Author

thx. but say i want to directly save ajax-result to sql-table that manages appointments across the u.s. i obviously want the dates normalized to utc so they're sortable (regardless of region).

can you fill in the ???:

var localdatetime;

localdatetime = CivilDateTime.from(
    CivilDate.from(document.getElementById("date").value),
    CivilTime.from(document.getElementById("time").value)
).withZone("SYSTEM");

ajax({
    "method": "POST",
    "url": "/api/schedule-appointment",
    "payload": JSON.stringify({
        // sortable utc-datetime saved to sql-table
        datetime_utc: ???,
        // metadata for future presentation-logic
        timezoneOffset: localdatetime.offsetSeconds / 60,
        ...
    })
});

@pipobscure
Copy link
Collaborator

pipobscure commented Mar 22, 2019

ajax({
    "method": "POST",
    "url": "/api/schedule-appointment",
    "payload": {
        utcdate: localdatetime.instant, // stringifies to 2019-03-21T14:47:01.012352312Z
        timezone: localdatetime.timeZone // either IANA-Name or the offsetString (-05:00),
        offset: localdatetime.offsetSeconds
    }
});

@kaizhu256
Copy link
Contributor Author

suggest this common use-case be added to README

@pipobscure
Copy link
Collaborator

To be honest, I was contemplating not putting it in this issue, because it's very likely to be a bad idea. The way you do this by keeping it as the localdatetime.toString() which includes both the time and the zone. Most databases worth their salt can accept this format into a datetime field. That makes it sortable in the db, yet still be filterable in the db by date.

Take the following example:

Your DB stores appointments. You want "all appointments on a specific date". With just the UTC date you can't do that selection even when storing timezone. So keeping the timezone and time in one value is fairly important. https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-2017 would be an example.

I'll be updating the FAQ soonish though

@kaizhu256
Copy link
Contributor Author

different perspective. my experience has made me distrustful of datetime-magic, and keep most "business-logic" utc-only.

for example in texas (+05:00 DST), i would want "all appointments on a specific [utc] datetime-range", e.g.:

-- find all appointments on date 2019-03-22 in texas
SELECT * FROM appointment
    -- filter by [timzoneoffset'd] utc-datetime-range
    WHERE
        '2019-03-22T05:00:00' <= appointment.utcdatetime
        AND appointment.utcdatetime < '2019-03-23T05:00:00'

@littledan
Copy link
Member

@kaizhu256 That sounds like a good use case for the Instant class, rather than ZonedDateTime with a UTC timezone.

@kaizhu256
Copy link
Contributor Author

@littledan, yes Instant's ISOString and timezoneOffset are of most value to me when baton-passing datetime between no-magic/zero-config systems.

ZonedDateTime in my scenario is primarily for UI-logic with humans.

@pipobscure
Copy link
Collaborator

@kaizhu256 your use-case actually screams for OffsetDateTime, which is something we talked about last week. It’s bascially an Instant with a timezone offset that stringifies to an ISO-string with the offset (rather than IANA zone). No magic involved.
I’ll @-mention you in the PR when I get the state of that discussion written up so you can go over it.

@kaizhu256
Copy link
Contributor Author

@pipobscure, are OffsetDateTime utc-based when serialized? if not, they are not sortable across timezones :`(

javascript commonly interfaces (via JSON) with "dumb" systems/shell-scripts,
that cannot easily sort non-utc-based ISO-strings like these:

2017‑12‑30T19:00:00-05:00        // [US/CDT]
2017-12-31T00:00:00.000000+00:00 // [UTC]
2017‑12‑31T09:00:00.000+09:00    // [Asia/Tokyo]

@pipobscure
Copy link
Collaborator

The creation of Duration, CivilYearMonth and CivilMonthDay address the original issue.

@littledan
Copy link
Member

littledan commented Jun 25, 2019

Creating types is half of this; the other half would be making a proposal in HTML for the new input methods. Let's continue tracking this.

@domenic
Copy link
Member

domenic commented Jul 12, 2019

Here is a strawperson proposal:

  • Add a valueAsTemporal getter/setter to HTMLInputElement
    • <input type=date> accepts/returns CivilDates
    • <input type=time> accepts/returns CivilTimes
    • <input type=datetime-local> accepts/returns CivilDateTimes
    • <input type=month> accepts/returns CivilYearMonths
    • (Unlike valueAsDate) The same object must always be returned until the value changes, and setting to a specific Temporal object means the getter must return that object. (This works, because temporal objects are immutable.)
    • If type="" is in a different state, the getter returns null and the setter throws an "InvalidStateError" DOMException.
  • <input type=week> does not have a mapping
  • Instant, OffsetDateTime, ZonedDateTime do not have a mapping

Other ideas:

  • Use separate accessors for each type. HTMLInputElement.prototype is full of stuff that only works for one type="" anyway; 4 new accessors vs. 1 new accessor isn't a big deal.
  • Use functions instead of accessors. (I don't think this is necessary; the valueAsDate sucks as an accessor because Date is mutable, but we don't have that problem here.)

@ryzokuken ryzokuken added behavior Relating to behavior defined in the proposal integration labels Jul 12, 2019
@ryzokuken ryzokuken added this to the Stage 3 milestone Jul 12, 2019
@kaizhu256
Copy link
Contributor Author

Here is a strawperson proposal:

-1 for overengineering and unecessary coupling with temporal-proposal.

here's a simpler strawperson-proposal using ISOStrings thats more cost-effective/library-agnostic:

<!--
  -- strawperson-proposal with simpler spec and UX
  -- by introducing 2 extra isostrings
  -- `valueZoned` and `valueUTC` for <input type="datetime-local">
  -->

<input id="input1" type="datetime-local"
    value      = "2019-07-21T00:00:00"
    valueZoned = "2019-07-21T00:00:00-05:00[America/Houston]"
    valueUTC   = "2019-07-21T05:00:00Z"
>

<script>
document.querySelector(
    "#input1"
).addEventListener("change", function (evt) {
/*
 * this function will handle change <evt> to get
 * 1. value
 * 2. valueZoned
 * 3. valueUTC
 */
    var civilZonedInstant;
    var civilInstant;
    var civilDatetime;

    // get civil-object from #input1
    civilDatetime     = CivilDateTime.fromString( evt.target.value      );
    civilZonedInstant = ZonedInstant.fromString(  evt.target.valueZoned );
    civilInstant      = Instant.fromString(       evt.target.valueUTC   );

    // output civil-object to #input1
    evt.target.value      = JSON.stringify(civilDatetime);
    evt.target.valueZoned = JSON.stringify(civilZonedInstant);
    evt.target.valueUTC   = JSON.stringify(civilInstant);
    ...
});
</script>

this is perfect for the common-scenario where you're just baton-passing isostrings between user <-> dom <-> backend (and bypass civil-classes entirely).

@kaizhu256
Copy link
Contributor Author

that came off harsh. i don't want heavy-handed coupling between and temporal-proposal that locks them into future-interoperability commitments that can be avoided. i do appreciate @domenic's original strawman for getting the ball-rolling and understanding the UX.

@ljharb
Copy link
Member

ljharb commented Jul 22, 2019

Anything that requires passing around strings, instead of instances, isn’t going to be viable.

@domenic
Copy link
Member

domenic commented Jul 22, 2019

Yes. We have no intention of adding more stringly-typed APIs to HTML or ES.

@kaizhu256
Copy link
Contributor Author

why is it not viable?

@ljharb
Copy link
Member

ljharb commented Jul 22, 2019

Strings are brittle. They are hard to validate, hard to identify, there’s no way of attaching methods/behavior to them; programmer intention is hard to make clear, as there is often overlap for a given string between more than one potential domain out of infinite domains.

@littledan
Copy link
Member

littledan commented May 14, 2020

@domenic presented a good proposal in #107 (comment) . Thanks for the help! I think this is all we need for now; after Stage 3, we can raise this as an HTML proposal. We should also cross-reference @domenic 's proposal when we file again for a TAG review (#102 ). Other than that, I don't think any more action is needed for now. So, I'm removing this from the Stage 3 milestone and Finalize spec text project.

@littledan littledan removed this from the Stage 3 milestone May 14, 2020
@littledan littledan reopened this May 14, 2020
@ptomato ptomato added this to the Stage 4 milestone Feb 18, 2021
@kbrilla
Copy link

kbrilla commented Nov 4, 2021

Anything that requires passing around strings, instead of instances, isn’t going to be viable.

strings are easy to serialize, You can easily serialize forms that have value types but as soon as You go with any objects You are done for, and need some kind of adapter in place.

@ljharb
Copy link
Member

ljharb commented Nov 4, 2021

@criskrzysiu a string is already serialized, and yes, you do need to define your serialization algorithm. I'm not sure how that changes anything.

@justingrant
Copy link
Collaborator

I'd suggest using different accessors for each Temporal type (e.g. valueAsTemporalPlainDate, valueAsTemporalPlainTime) instead of a single valueAsTemporal accessor. Here's a few reasons which led me to this opinion:

  • Using different accessors seems closer to the spirit of Temporal's strongly-typed philosophy, where callers deliberately opt into a specific data type.
  • Aligns with type-specific API being added to Date: Date.prototype.toTemporalInstant().
  • Autocomplete in browser devtools or IDEs makes it really obvious what the type of the returned object will be.
  • Allows overloading, e.g. if an app uses a type="date" and expects a PlainDate in JS code, then and someone changes the UI to type="datetime-local", then existing code that call to valueAsTemporalPlainDate will continue to work as-is. Similarly, if the caller wants to extract only the date or only the time of a type="datetime-local", they can do so ergonomically.
  • If we later choose to re-add a modern version of type="datetime" to leverage new timezone enumeration proposals that the 402 folks are working on, then we could have both a valueAsTemporalZonedDateTime and valueAsTemporalInstant.
  • Makes it easier to detect incompatibilities at runtime, because the wrong accessor for the type can fail-fast (return null or throw exception?) instead of waiting for deeper JS code to fail when given the wrong Temporal type. There might be a way in the future to leverage ESLint and/or TS to detect these incompatibilities at development time, although honestly I don't know if the ability to infer type-specific TS types is something that TS and/or ESLint can do.

@pipobscure
Copy link
Collaborator

pipobscure commented Apr 3, 2022

Please no! Individual accessors are not a good idea. Also these already export an ISO string, so just use the temporal from methods and leave these alone. (I'm very much with @domenic 's proposal)

@rene-stesl
Copy link

Sorry for this really dumb question, I know that this isn't part of this proposal, but since this proposal may require some HTML proposals I wanted to ask if there are any plans of creating an integration with and Temporal.PlainMonthDay?

HTML support for date, date-time and so on has always been a little bit lackluster IMHO. This proposal could be the spark to change this. For yearly recurring events a "MonthDay" picker would be great! A type="month" picker does already exist, so why not a "month-day"/"yearless-date" picker? Sure this could be achived with two comboboxes, but it isn't the same UX as with type="date" or type="month".

I just would love to see a full integration of temporal (maybe even with all possible permutations or even timezone selection) with an input component.

@ptomato
Copy link
Collaborator

ptomato commented May 23, 2024

@rene-stesl Adding new input types sounds like an exciting initiative, but is not part of this proposal. I don't know of any existing plans, but maybe it's something you'd be interested in raising?

@rajmondx
Copy link

rajmondx commented Dec 6, 2024

A type="month" picker does already exist, so why not a "month-day"/"yearless-date" picker? Sure this could be achived with two comboboxes, but it isn't the same UX as with type="date" or type="month".

This is out of scope. The implementation of Temporal is managed by EcmaScript, not the W3C. For more information, visit EcmaScript proposal stages.

Your question would be more appropriate for W3C Submission Guidelines.

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 integration
Projects
None yet
Development

No branches or pull requests