diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx
index c5290d641522e1..5f5628180c02f2 100644
--- a/app/javascript/mastodon/components/status.jsx
+++ b/app/javascript/mastodon/components/status.jsx
@@ -24,7 +24,7 @@ import Card from '../features/status/components/card';
import Bundle from '../features/ui/components/bundle';
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_context';
-import { cropAttachmentThumbnailsOnTimeline, displayMedia } from '../initial_state';
+import { cropAttachmentThumbnailsOnTimeline, displayMedia, useAbsoluteTime } from '../initial_state';
import { injectIntl } from './intl';
import { StatusHeader } from './status/header'
@@ -33,6 +33,7 @@ import { getHashtagBarForStatus } from './hashtag_bar';
import StatusActionBar from './status_action_bar';
import StatusContent from './status_content';
import { StatusThreadLabel } from './status_thread_label';
+import { FormattedDateWrapper } from './formatted_date';
const domParser = new DOMParser();
@@ -617,6 +618,27 @@ class Status extends ImmutablePureComponent {
>
)}
+ {useAbsoluteTime && (
+
+ )}
+
{(showActions && !isQuotedPost) &&
}
diff --git a/app/javascript/mastodon/components/status/header.tsx b/app/javascript/mastodon/components/status/header.tsx
index 9b1445e9c1cb3d..62e32138932bda 100644
--- a/app/javascript/mastodon/components/status/header.tsx
+++ b/app/javascript/mastodon/components/status/header.tsx
@@ -15,6 +15,7 @@ import type { DisplayNameProps } from '../display_name';
import { LinkedDisplayName } from '../display_name';
import { RelativeTimestamp } from '../relative_timestamp';
import { VisibilityIcon } from '../visibility_icon';
+import { useAbsoluteTime } from '@/mastodon/initial_state';
export interface StatusHeaderProps {
status: Status;
@@ -56,10 +57,11 @@ export const StatusHeader: FC = ({
className='status__relative-time'
>
+ {!useAbsoluteTime && (
+ />)}
{editedAt && }
diff --git a/app/javascript/mastodon/features/account_timeline/v2/status_header.tsx b/app/javascript/mastodon/features/account_timeline/v2/status_header.tsx
index 9958a47d965425..39e20f4191a6a8 100644
--- a/app/javascript/mastodon/features/account_timeline/v2/status_header.tsx
+++ b/app/javascript/mastodon/features/account_timeline/v2/status_header.tsx
@@ -10,6 +10,7 @@ import {
StatusVisibility,
} from '@/mastodon/components/status/header';
import type { Account } from '@/mastodon/models/account';
+import { useAbsoluteTime } from '@/mastodon/initial_state';
export const AccountStatusHeader: FC = ({
status,
@@ -36,10 +37,11 @@ export const AccountStatusHeader: FC = ({
className='status__relative-time'
>
+ {!useAbsoluteTime && (
+ />)}
{editedAt && }
diff --git a/app/javascript/mastodon/initial_state.ts b/app/javascript/mastodon/initial_state.ts
index e394996fc5feef..aefa313cf7b7f2 100644
--- a/app/javascript/mastodon/initial_state.ts
+++ b/app/javascript/mastodon/initial_state.ts
@@ -51,6 +51,7 @@ interface InitialStateMeta {
wider_column: boolean;
status_page_url: string;
terms_of_service_enabled: boolean;
+ use_absolute_time: boolean;
emoji_style?: string;
wrapstodon?: InitialWrapstodonState | null;
}
@@ -144,6 +145,7 @@ export const criticalUpdatesPending = initialState?.critical_updates_pending;
export const statusPageUrl = getMeta('status_page_url');
export const sso_redirect = getMeta('sso_redirect');
export const termsOfServiceEnabled = getMeta('terms_of_service_enabled');
+export const useAbsoluteTime = getMeta('use_absolute_time');
export const wrapstodon = getMeta('wrapstodon');
const displayNames =
diff --git a/app/javascript/styles/mods/_index.scss b/app/javascript/styles/mods/_index.scss
index 17ac6088a9750e..47189b9969a98f 100644
--- a/app/javascript/styles/mods/_index.scss
+++ b/app/javascript/styles/mods/_index.scss
@@ -1,3 +1,4 @@
+@use 'absolute_status_datetime';
@use 'announcements';
@use 'bigger-publish';
@use 'compact-padding';
diff --git a/app/javascript/styles/mods/absolute_status_datetime.scss b/app/javascript/styles/mods/absolute_status_datetime.scss
new file mode 100644
index 00000000000000..b3e278997008c4
--- /dev/null
+++ b/app/javascript/styles/mods/absolute_status_datetime.scss
@@ -0,0 +1,42 @@
+.mods_status__meta {
+ margin-top: 12px;
+ color: var(--color-text-tertiary);
+ font-size: 14px;
+ line-height: 18px;
+
+ &__line {
+ border-bottom: 1px solid var(--color-border-primary);
+ padding: 8px 0;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ &:first-child {
+ padding-top: 0;
+ }
+
+ &:last-child {
+ padding-bottom: 0;
+ border-bottom: 0;
+ }
+ }
+
+ .icon {
+ width: 18px;
+ height: 18px;
+ }
+
+ .animated-number {
+ color: var(--color-text-primary);
+ font-weight: 500;
+ }
+}
+
+.mods_status__datetime {
+ text-decoration: none;
+ color: inherit;
+
+ &:is(a):hover {
+ text-decoration: underline;
+ }
+}
\ No newline at end of file
diff --git a/app/models/concerns/user/has_settings.rb b/app/models/concerns/user/has_settings.rb
index 33df1955ea4474..af4d1c15d7a865 100644
--- a/app/models/concerns/user/has_settings.rb
+++ b/app/models/concerns/user/has_settings.rb
@@ -182,4 +182,8 @@ def setting_hide_translate_button
def setting_crop_attachment_thumbnails_on_timeline
settings['web.crop_attachment_thumbnails_on_timeline']
end
+
+ def setting_use_absolute_time
+ settings['web.use_absolute_time']
+ end
end
diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb
index 7e09cdca5d1008..2550151e54353b 100644
--- a/app/models/user_settings.rb
+++ b/app/models/user_settings.rb
@@ -43,6 +43,7 @@ class KeyError < Error; end
setting :mod_reverse_nav, default: false
setting :hide_translate_button, default: false
setting :crop_attachment_thumbnails_on_timeline, default: false
+ setting :use_absolute_time, default: false
setting :emoji_style, default: 'auto', in: %w(auto native twemoji)
setting :color_scheme, default: 'auto', in: %w(auto light dark)
setting :contrast, default: 'auto', in: %w(auto high)
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index 6f3875a12c9d6e..44db00927d8aa5 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -140,6 +140,7 @@ def current_account_settings
wider_column: object_account_user.setting_wider_column,
hide_translate_button: object_account_user.setting_hide_translate_button,
crop_attachment_thumbnails_on_timeline: object_account_user.setting_crop_attachment_thumbnails_on_timeline,
+ use_absolute_time: object_account_user.setting_use_absolute_time,
reverse_nav: object_account_user.setting_reverse_nav,
emoji_style: object_account_user.settings['web.emoji_style'],
wrapstodon: wrapstodon,
diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml
index 4170284ab98eab..3f7c875af9734d 100644
--- a/app/views/settings/preferences/appearance/show.html.haml
+++ b/app/views/settings/preferences/appearance/show.html.haml
@@ -89,6 +89,9 @@
.fields-group
= ff.input :'web.hide_translate_button', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_hide_translate_button')
+ .fields-group
+ = ff.input :'web.use_absolute_time', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_absolute_time')
+
%h2= t 'appearance.animations_and_accessibility'
.fields-group
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 0921c84ac338fb..4410b44adbf0cd 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -276,6 +276,7 @@ en:
setting_theme: Site theme
setting_trends: Show today's trends
setting_unfollow_modal: Show confirmation dialog before unfollowing someone
+ setting_use_absolute_time: Use absolute time format
setting_use_blurhash: Show colorful gradients for hidden media
setting_use_pending_items: Slow mode
setting_bigger_publish: Use bigger publish button
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index 3bba04bb4bcdee..962df8343dc464 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -260,6 +260,7 @@ ja:
setting_theme: サイトテーマ
setting_trends: 本日のトレンドタグを表示する
setting_unfollow_modal: フォローを解除する前に確認ダイアログを表示する
+ setting_use_absolute_time: 投稿日時を絶対時刻で表示する
setting_use_blurhash: 非表示のメディアを色付きのぼかしで表示する
setting_use_pending_items: 手動更新モード
setting_bigger_publish: より大きな投稿ボタンを使用する