From cfc60b2142af18f843325b94313a8aafbbfe6908 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 16 Feb 2026 11:58:04 +0100 Subject: [PATCH] Use `relative-time` to render absolute dates (#36238) `` can render absolute dates when passed [`threshold="P0Y"`](https://github.com/github/relative-time-element#threshold-string-default-p30d) and `prefix=""`, so remove the previously used `` element in its favor. Devtest before: Screenshot 2025-12-23 at 20 22 44 Devtest after: Screenshot 2025-12-23 at 20 22 49 Repo activity (rendering unchanged): image --------- Signed-off-by: silverwind Co-authored-by: Claude Opus 4.6 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- modules/templates/util_date.go | 6 +-- modules/templates/util_date_test.go | 4 +- templates/devtest/gitea-ui.tmpl | 13 +++--- .../js/webcomponents/absolute-date.test.ts | 26 ------------ web_src/js/webcomponents/absolute-date.ts | 41 ------------------- web_src/js/webcomponents/index.ts | 1 - webpack.config.ts | 1 - 7 files changed, 11 insertions(+), 81 deletions(-) delete mode 100644 web_src/js/webcomponents/absolute-date.test.ts delete mode 100644 web_src/js/webcomponents/absolute-date.ts diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index fc3f3f2339a..1b36722c43d 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -93,14 +93,14 @@ func dateTimeFormat(format string, datetime any) template.HTML { attrs := []string{`weekday=""`, `year="numeric"`} switch format { case "short", "long": // date only - attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + attrs = append(attrs, `threshold="P0Y"`, `month="`+format+`"`, `day="numeric"`, `prefix=""`) case "full": // full date including time attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) default: panic("Unsupported format " + format) } + + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) } func timeSinceTo(then any, now time.Time) template.HTML { diff --git a/modules/templates/util_date_test.go b/modules/templates/util_date_test.go index 2c1f2d242ea..b74bbb0ceed 100644 --- a/modules/templates/util_date_test.go +++ b/modules/templates/util_date_test.go @@ -32,10 +32,10 @@ func TestDateTime(t *testing.T) { assert.EqualValues(t, "-", du.AbsoluteShort(timeutil.TimeStamp(0))) actual := du.AbsoluteShort(refTime) - assert.EqualValues(t, `2018-01-01`, actual) + assert.EqualValues(t, `2018-01-01`, actual) actual = du.AbsoluteShort(refTimeStamp) - assert.EqualValues(t, `2017-12-31`, actual) + assert.EqualValues(t, `2017-12-31`, actual) actual = du.FullTime(refTimeStamp) assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index cb5aad7b0c1..c1e6590a43e 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -118,13 +118,12 @@
-

GiteaAbsoluteDate

-
-
-
-
-
-
relative-time:
+

Absolute Dates

+
+
+
+
+
diff --git a/web_src/js/webcomponents/absolute-date.test.ts b/web_src/js/webcomponents/absolute-date.test.ts deleted file mode 100644 index 4eee80048dd..00000000000 --- a/web_src/js/webcomponents/absolute-date.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {toAbsoluteLocaleDate} from './absolute-date.ts'; - -test('toAbsoluteLocaleDate', () => { - expect(toAbsoluteLocaleDate('2024-03-15', 'en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - })).toEqual('March 15, 2024'); - - expect(toAbsoluteLocaleDate('2024-03-15T01:02:03', 'de-DE', { - year: 'numeric', - month: 'long', - day: 'numeric', - })).toEqual('15. März 2024'); - - // these cases shouldn't happen - expect(toAbsoluteLocaleDate('2024-03-15 01:02:03', '', {})).toEqual('Invalid Date'); - expect(toAbsoluteLocaleDate('10000-01-01', '', {})).toEqual('Invalid Date'); - - // test different timezone - const oldTZ = import.meta.env.TZ; - import.meta.env.TZ = 'America/New_York'; - expect(new Date('2024-03-15').toLocaleString('en-US')).toEqual('3/14/2024, 8:00:00 PM'); - expect(toAbsoluteLocaleDate('2024-03-15', 'en-US')).toEqual('3/15/2024, 12:00:00 AM'); - import.meta.env.TZ = oldTZ; -}); diff --git a/web_src/js/webcomponents/absolute-date.ts b/web_src/js/webcomponents/absolute-date.ts deleted file mode 100644 index 5ab4deaa14b..00000000000 --- a/web_src/js/webcomponents/absolute-date.ts +++ /dev/null @@ -1,41 +0,0 @@ -export function toAbsoluteLocaleDate(date: string, lang?: string, opts?: Intl.DateTimeFormatOptions) { - // only use the date part, it is guaranteed to be in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ) or (YYYY-MM-DD) - // if there is an "Invalid Date" error, there must be something wrong in code and should be fixed. - // TODO: there is a root problem in backend code: the date "YYYY-MM-DD" is passed to backend without timezone (eg: deadline), - // then backend parses it in server's timezone and stores the parsed timestamp into database. - // If the user's timezone is different from the server's, the date might be displayed in the wrong day. - const dateSep = date.indexOf('T'); - date = dateSep === -1 ? date : date.substring(0, dateSep); - return new Date(`${date}T00:00:00`).toLocaleString(lang || [], opts); -} - -window.customElements.define('absolute-date', class extends HTMLElement { - static observedAttributes = ['date', 'year', 'month', 'weekday', 'day']; - - initialized = false; - - update = () => { - const opts: Record = {}; - for (const attr of ['year', 'month', 'weekday', 'day']) { - if (this.getAttribute(attr)) { - opts[attr] = this.getAttribute(attr)!; - } - } - const lang = this.closest('[lang]')?.getAttribute('lang') || - this.ownerDocument.documentElement.getAttribute('lang') || ''; - - if (!this.shadowRoot) this.attachShadow({mode: 'open'}); - this.shadowRoot!.textContent = toAbsoluteLocaleDate(this.getAttribute('date')!, lang, opts); - }; - - attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null) { - if (!this.initialized || oldValue === newValue) return; - this.update(); - } - - connectedCallback() { - this.initialized = false; - this.update(); - this.initialized = true; - } -}); diff --git a/web_src/js/webcomponents/index.ts b/web_src/js/webcomponents/index.ts index 6c0f5558648..8251f6ddae4 100644 --- a/web_src/js/webcomponents/index.ts +++ b/web_src/js/webcomponents/index.ts @@ -2,4 +2,3 @@ import './polyfills.ts'; import '@github/relative-time-element'; import './origin-url.ts'; import './overflow-menu.ts'; -import './absolute-date.ts'; diff --git a/webpack.config.ts b/webpack.config.ts index 6902d182d75..ef082393540 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -39,7 +39,6 @@ const webComponents = new Set([ // our own, in web_src/js/webcomponents 'overflow-menu', 'origin-url', - 'absolute-date', // from dependencies 'markdown-toolbar', 'relative-time',