ローカル時刻表示
stimeo--local-time
UTC のタイムスタンプを閲覧者のロケール/TZ の絶対時刻に Intl で整形する。
stimeo--local-time コントローラは HTML の <time> セマンティクスに従います。UTC の datetime 属性を読み、Intl.DateTimeFormat(ブラウザ標準・追加依存なし)で閲覧者のロケールとタイムゾーンの表示へ整形します。サーバは素の UTC を出力でき(閲覧者の TZ を知る必要がなく、マークアップはキャッシュ可能)、現地化はクライアントが担います。Relative Time の「3 分前」とは別の、絶対時刻のローカライズ軸です。機械可読な datetime は不変のまま保持され、支援技術やクローラは正準値を保てます。datetime/TZ が不正な場合は元のテキストを残します。整形は datetime の純粋な関数なので、Turbo のキャッシュ復元や Morphing 後も再実行されて整合します。ライブラリは挙動のみを提供し、見た目はこの Playground が持ちます。
- 公開 UTC 2026-06-08 12:30
- リリース UTC 2026-01-01 09:00
- 開始 UTC 2026-12-24 21:00
- 現在 UTC 2026-06-21 22:10
各時刻は datetime 属性に UTC で保持され、ブラウザ上であなたのロケール/タイムゾーンに現地化されます。同じ瞬間でも、異なるタイムゾーンの閲覧者には異なる時計表示になります。機械可読な datetime は不変で、各時刻にカーソルを合わせると title でより詳細な形が表示されます。
<%# Markup for the local-time demo.
Each <time> carries a machine-readable UTC datetime; the controller reformats the
visible text into the viewer's locale and timezone via Intl.DateTimeFormat, leaving
the datetime attribute (the screen-reader / SEO value) intact. The locale follows the
page language and the timezone follows the browser, so the server can emit plain UTC
and stay cacheable. The last row clears the time style to show a date-only format. %>
<% rows = [
{ at: Time.utc(2026, 6, 8, 12, 30), key: "published", date: "medium", time: "short" },
{ at: Time.utc(2026, 1, 1, 9, 0), key: "released", date: "full", time: "short" },
{ at: Time.utc(2026, 12, 24, 21, 0), key: "starts", date: "long", time: "" },
{ at: Time.now.utc, key: "now", date: "medium", time: "medium" }
] %>
<ul class="local-time-demo">
<% rows.each do |row| %>
<li class="local-time-demo__row">
<span class="local-time-demo__label">
<%= t("components.local_time.demo.#{row[:key]}") %>
</span>
<span class="local-time-demo__convert">
<span class="local-time-demo__source">UTC <%= row[:at].strftime("%Y-%m-%d %H:%M") %></span>
<span class="local-time-demo__arrow" aria-hidden="true">→</span>
<time
class="local-time"
data-controller="stimeo--local-time"
datetime="<%= row[:at].iso8601 %>"
data-stimeo--local-time-locale-value="<%= I18n.locale %>"
data-stimeo--local-time-date-style-value="<%= row[:date] %>"
data-stimeo--local-time-time-style-value="<%= row[:time] %>"
data-stimeo--local-time-title-format-value="long">
<%= row[:at].strftime("%Y-%m-%d %H:%M UTC") %>
</time>
</span>
</li>
<% end %>
</ul>
<p class="local-time-demo__hint"><%= t("components.local_time.demo.hint") %></p>
/*
* Presentation-only styles for the local-time demo.
* The library only replaces the element's text with the localized absolute time
* (and adds a detailed title); the machine-readable datetime attribute is kept.
*/
.local-time-demo {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 0.5rem;
max-width: 46rem;
}
.local-time-demo__row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 1rem;
/* Keep the label and value on one line when there's room; on a genuinely narrow
stage the value group drops to a second line as a whole — never mid-value
(see the nowrap rules below), which is what made English look cluttered. */
flex-wrap: wrap;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
border-radius: 0.375rem;
}
.local-time-demo__label {
color: var(--muted);
font-size: 0.9rem;
}
.local-time-demo__convert {
display: flex;
align-items: baseline;
gap: 0.5rem;
white-space: nowrap;
}
/* The source UTC, shown next to the localized time so the conversion is verifiable. */
.local-time-demo__source {
color: var(--muted);
font-size: 0.8rem;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.local-time-demo__arrow {
color: var(--muted);
}
/* The localized absolute time. An English full date is long, so keep it on one
line and let the row (not the time) wrap when space is tight. */
.local-time {
font-variant-numeric: tabular-nums;
color: var(--fg);
white-space: nowrap;
}
/* Explanatory caption: the time is localized on the client from the UTC datetime. */
.local-time-demo__hint {
margin: 0.75rem 0 0;
max-width: 46rem;
font-size: 0.85rem;
line-height: 1.5;
color: var(--muted);
}
このデモに固有の消費側 JS はありません(挙動はコントローラが担います)。
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--local-time"
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
locale
|
Intl.DateTimeFormat のロケール。空なら要素の lang、次に文書の lang。既定は空。 |
data-stimeo--local-time-locale-value |
timeZone
|
IANA タイムゾーン。空ならブラウザ既定。 | data-stimeo--local-time-time-zone-value |
dateStyle
|
Intl の dateStyle(full/long/medium/short)。空で日付を省略(既定 medium)。 |
data-stimeo--local-time-date-style-value |
timeStyle
|
Intl の timeStyle(full/long/medium/short)。空で時刻を省略(既定 short)。 |
data-stimeo--local-time-time-style-value |
titleFormat
|
title 用に日付と時刻の両方へ適用する Intl スタイル。空なら title を付けない(既定空)。 | data-stimeo--local-time-title-format-value |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
format
|
整形後に発火。detail.formatted を伴う。 |
stimeo--local-time:format |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
テキスト |
ルート要素 | ローカライズされた絶対時刻。 |
title |
ルート要素 | 任意の詳細形(titleFormat を設定したとき)。 |
datetime |
ルート要素 | 機械可読な UTC 値(不変)。 |