Esri / calcite-design-system

A monorepo containing the packages for Esri's Calcite Design System
https://developers.arcgis.com/calcite-design-system/
Other
289 stars 76 forks source link

calcite-input-time-zone-offset-picker #6590

Closed richiecarmichael closed 1 year ago

richiecarmichael commented 1 year ago

Description

Background

Esri is adding support for three new field types, one of which is esriFieldTypeTimestampOffset. The values in this field are encoded as ISO8601 date strings with a time zone offset, for example: 2023-03-13T20:49:00-08:00 2023-03-13T20:49:00Z (same as 2023-03-13T20:49:00+00:00)

We have calcite components to edit the date component, time component but not the time-zone-offset component.

Proposal

If a feature has a field value of 2023-03-02T02:53:31-08:00, then the JSAPI's editor would present the following UI.

image

Where the UI is comprised of the following components:

  1. <calcite-input-date-picker>
  2. <calcite-input-time-picker>
  3. <calcite-input-time-zone-offset-picker>

When the user clicks the calcite-input-time-zone-offset-picker the following dropdown menu appears. image

// @jcfranco

User Stories

Possible scenarios involve editing of the new esriFieldTypeTimestampOffset date field values. These date fields can be edited in either the JSAPI's Editor or FeatureTable.

Scenario.

  1. Richie lives in New York and manages a team of inspectors around the US.
  2. Richie schedules an inspector to install a gizmo in Redlands for 8am the following day.
  3. Richie uses Editor to add a point on the map with tomorrow's date and time in Pacific time zone.

Acceptance Criteria

  1. Must support LTR and RTL
  2. Must support locales
  3. Component's value is numeric ranging for -720 to 720. This represents the offset from UTC in minutes.
  4. The default value is the user's current UTC offset.

Relevant Info

No response

Helpful Details

The JSAPI's Daylight widget has a Timezone Picker.

image

How time zone offsets are picked in Google Calendar.

image

image

image

Esri team

ArcGIS Maps SDK for JavaScript

Reference

  1. JSAPI - Enhancement - Editor- Support New Date Fields (see #50595)
  2. JSAPI - Enhancement - FeatureTable - Support New Date Fields (see #50596)
github-actions[bot] commented 1 year ago

cc @ashetland, @yelenakreyndel, @SkyeSeitz

geospatialem commented 1 year ago

This request is a requirement of the Maps SDK for JavaScript to support new date fields throughout the ArcGIS ecosystem - should be paired with the enhancement request from #6591.

geospatialem commented 1 year ago

@jcfranco Routing this and 6591 to the April milestone, (the slider issue priority has been re-accessed to later milestones and moderate priorities).

We should prioritize work on this issue prior to work on #6591.

Both should land in April for sufficient testing for the JS Maps SDK team.

richiecarmichael commented 1 year ago

@jcfranco

The JSAPI currently has a simple timezone picker component that is used internally on the Daylight and ShadowCast widgets. This component might be a useful reference and source of I18N strings. This picker whilst currently adequate does have a few limitations, for instance, it is not daylight savings aware and may not follow the calcite design pattern.

I would suggest that core of the your picker is a collection of prominent IANA time zones paired with an internationalized name. For previously internationalized location names you may be able to utilize this.

const timeZonePairing = Map<string, string>([
  { timeZone: "America/Argentina/Buenos_Aires", name: "Buenos Aires" },
  { timeZone: "Asia/Tbilisi", name: "Tbilisi" },
  { timeZone: "America/Los_Angeles", name: "Los Angeles" }
]),

Ultimately we want to produce a visual that looks like this:

GMT-9 Buenos Aires
GMT-8 Tbilisi
GMT-7 Los Angeles (PST)

The GMT component can be obtained via Intl.DateTimeFormat. It is important to note that these offsets differ throughout the year due to daylight savings so it needs a date context.

function getTimeZoneShortOffset(prototype: Date, locale: string = "en-US"): string {
  const dateTimeFormat = new Intl.DateTimeFormat(locale, { timeZoneName: "shortOffset" });
  const parts = dateTimeFormat.formatToParts(date);
  const { value } = parts.find(({ type }) => type === "timeZoneName");
  return value; // return "GMT-8" etc
}

Some locales may have a localized name of a time zone offsets. For example, people living the US will refer to US offsets as "PDT", "PST', "EDT', "EST" etc. To find the localized offset name use this snippet. When this value is different from the GMT offset then we should display it next to the location name, for example, Los Angeles (PST).

function getTimeZoneShort(prototype: Date, locale: string = "en-US"): string {
  const dateTimeFormat = new Intl.DateTimeFormat(locale, { timeZoneName: "short" });
  const parts = dateTimeFormat.formatToParts(date);
  const { value } = parts.find(({ type }) => type === "timeZoneName");
  return value; // return "UTC", "GMT-8", "PDT" etc
}

Once we have GMT offsets (and possible named offsets) for each city then need to be grouped and sorted. Specifically, grouped by GMT offset and locations groups alphabetically, for example:

GMT+10 Guam, Melbourne, Sydney
GMT+11 New Caledonia, Victoria
GMT+12 Auckland (NZST), Wellington (NZST)

Hope this helps!

hccampos commented 1 year ago

This is the latest look on the ArcGIS Maps SDK. It is using a calcite-dropdown and a <calcite-button> as the trigger. We initially were using an element similar to a <calcite-select> but in the context of the ShadowCast and Daylight widgets it was deemed to be too prominent.

image

Ideally we'd have a few different options for the trigger which would open the select/dropdown. In cases like the one brought up by @richiecarmichael in the original issue, a sull "select" makes sense, but I think we should also have a smaller and less prominent alternative for when you want to display the timezone picker next to a time value, for example.

hccampos commented 1 year ago

I think this can also be an invaluable resource: https://www.nngroup.com/articles/time-zone-selectors/ The findings are really interesting and, when thinking about it, they make a lot of sense. For example, one thing we didn't consider here but which I think is almost a 'must have' is a search (could be done with <calcite-combobox> potentially, although we lack the ability of displaying a shortened value when the dropdown is closed (dropdown itself should include more info, whereas the trigger input can display only an abbreviation of the selected timezone).

I also think we need to consider the use case where a date is not only set before selecting a timezone but also set afterwards. In the Maps SDK we sometimes want to update the lighting when the date is changed such that the displayed clock time stays the same. While that could be possible by trying to compute the change in offset for the previous and new date, I think ideally we should have the ability of storing an actual timezone ID/name which we could eventually pass to Temporal.Timezone.from or to Luxon's DateTime.setZone.

richiecarmichael commented 1 year ago

The following will give a list of all named IANA time zones.

console.log(Intl.supportedValuesOf('timeZone'));
// Array ["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", ...

Unfortunately Safari is holding us back.

JSAPI 4.27 Supported browsers (see here)

Browser Support of supportedValuesOf (see here).

image

Localized location names of IANA time zones.

The closest I could get to localized names is Intl's "long" timeZoneName output.

en

Africa/Addis_Ababa

long: East Africa Time shortGeneric: Ethiopia Time longGeneric: East Africa Time

Pacific/Auckland

long: New Zealand Standard Time shortGeneric: New Zealand Time longGeneric: New Zealand Time

Europe/Zurich

long: Central European Summer Time shortGeneric: Switzerland Time longGeneric: Central European Time

Asia/Shanghai

long: China Standard Time shortGeneric: China Time longGeneric: China Standard Time

de

Africa/Addis_Ababa

long: Ostafrikanische Zeit shortGeneric: Äthiopien (Ortszeit) longGeneric: Ostafrikanische Zeit

Pacific/Auckland

long: Neuseeland-Normalzeit shortGeneric: Neuseeland (Ortszeit) longGeneric: Neuseeland-Zeit

Europe/Zurich

long: Mitteleuropäische Sommerzeit shortGeneric: MEZ longGeneric: Mitteleuropäische Zeit

Asia/Shanghai

long: Chinesische Normalzeit shortGeneric: China (Ortszeit) longGeneric: Chinesische Normalzeit

zh

Africa/Addis_Ababa

long: 东部非洲时间 shortGeneric: 埃塞俄比亚时间 longGeneric: 东部非洲时间

Pacific/Auckland

long: 新西兰标准时间 shortGeneric: 新西兰时间 longGeneric: 新西兰时间

Europe/Zurich

long: 中欧夏令时间 shortGeneric: 瑞士时间 longGeneric: 中欧时间

Asia/Shanghai

long: 中国标准时间 shortGeneric: 中国时间 longGeneric: 中国标准时间

ar

Africa/Addis_Ababa

long: توقيت شرق أفريقيا shortGeneric: توقيت إثيوبيا longGeneric: توقيت شرق أفريقيا

Pacific/Auckland

long: توقيت نيوزيلندا الرسمي shortGeneric: توقيت نيوزيلندا longGeneric: توقيت نيوزيلندا

Europe/Zurich

long: توقيت وسط أوروبا الصيفي shortGeneric: توقيت سويسرا longGeneric: توقيت وسط أوروبا

Asia/Shanghai

long: توقيت الصين الرسمي shortGeneric: توقيت الصين longGeneric: توقيت الصين الرسمي

const names = [
  "Africa/Addis_Ababa",
  "Pacific/Auckland",
  "Europe/Zurich",
  "Asia/Shanghai"
];
const locales = ["en", "de", "zh", "ar"];

function getTimeZoneName(timeZone, locale, timeZoneName) {
  return new Intl.DateTimeFormat(locale, {
    timeZone,
    timeZoneName
  }).formatToParts().find(({ type }) => type === 'timeZoneName').value;
}

for (const locale of locales) {
  console.log(
`## ${locale}`);
  for (const name of names) {
    console.log(
`### ${name}
long: ${getTimeZoneName(name, locale, "long")}
shortGeneric: ${getTimeZoneName(name, locale, "shortGeneric")}
longGeneric: ${getTimeZoneName(name, locale, "longGeneric")}
`);
  }
}
geospatialem commented 1 year ago

Reallocating to the May milestone, where it is expected to land soon for additional texting in next.

geospatialem commented 1 year ago

Reallocating to the November milestone per Teams discussion to provide support to Safari versions.

geospatialem commented 1 year ago

Re-re-allocated to May.

macandcheese commented 1 year ago

IMO this still seems a bit too compositional to be a “lego piece” component. Choosing a single component to display this data can be limiting.

Will a single component satisfy the design needs of displaying this data in combobox, list, drop-down, select, all of which could be valid depending on use case?

If we decide this will be data rendered into a combobox, does that help the team that wants to invoke a drop-down of this data from a button, like the examples above?

jcfranco commented 1 year ago

IMO this still seems a bit too compositional to be a “lego piece” component. Choosing a single component to display this data can be limiting.

I disagree. In the end we are providing a consistent way for users to select a time zone offset and, IMO, this is akin to displaying days on a calendar. We don't provide the data behind the calendar for alternate ways of displaying that data.

Will a single component satisfy the design needs of displaying this data in combobox, list, drop-down, select, all of which could be valid depending on use case?

Not sure about this one, but there wasn't an option before and hence why we have fragmentation at the moment.

If we decide this will be data rendered into a combobox, does that help the team that wants to invoke a drop-down of this data from a button, like the examples above?

Depending on the use cases, we could enhance the component to cover the gaps that necessitate using other components for the same experience.

ubatsukh commented 1 year ago

@jcfranco we will not using this component at 4.27 as we decided to only support read-only versions of the new date/time fields at 4.27. However, we will pick up this component as soon as the 4.27 is released.

You can find the general updates on adding support for new date/time fields from this planning doc issue: https://devtopia.esri.com/WebGIS/arcgis-js-api-planning-docs/issues/287#issue-1369706

geospatialem commented 1 year ago

Reallocated to the upcoming July milestone per the discussion above.

jcfranco commented 1 year ago

Quick update, the initial version of this component will display a list of time zone offsets:

simple input-time-zone

I've got a PR in the works that will add a mode to display more info per time zone and also allow users to search for a time zone regardless of being listed or not:

advanced input-time-zone

This should allow the simple version to ship in the upcoming version and the advanced version being available in the following one.

richiecarmichael commented 1 year ago

@jcfranco

In the first screenshot, what does the time refer to? image

With respect to the second screenshot, can the place names be sorted alphabetically?

jcfranco commented 1 year ago

@richiecarmichael

When opened, each time zone offset will display a preview of local time.

Good catch. I'll make sure cities are sorted alphabetically.

richiecarmichael commented 1 year ago

When opened, each time zone offset will display a preview of local time.

I don't think this is needed.

jcfranco commented 1 year ago

Per our convo, we'll hold off on the preview for the initial version and revisit once @ashetland comes back next week.

Reasoning:

github-actions[bot] commented 1 year ago

Installed and assigned for verification.

geospatialem commented 1 year ago

Verified on main, including:

cc @ashetland @SkyeSeitz for Figma updates