Skip to content

Commit a04c9c3

Browse files
authored
Merge pull request #7067 from nextcloud-libraries/feat/relative-time
feat: add `useFormatRelativeTime` composable
2 parents 0d41248 + 046344e commit a04c9c3

File tree

10 files changed

+435
-190
lines changed

10 files changed

+435
-190
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
This composable allows to format a timestamp or `Date` object either as human readable, localized, string or as relative time.
7+
8+
## Definition
9+
10+
```ts static
11+
/**
12+
* Format a timestamp or date object as relative time.
13+
*
14+
* This is a composable wrapper around `formatRelativeTime` from `@nextcloud/l10n`.
15+
*
16+
* @param timestamp - The timestamp to format
17+
* @param opts - Formatting options
18+
*/
19+
declare function useFormatRelativeTime(timestamp: MaybeRefOrGetter<Date | number> = Date.now(), opts: MaybeRefOrGetter<FormatRelativeTimeOptions> = {}): Readonly<Ref<string>>
20+
21+
/**
22+
* Format a given timestamp or date object as a human readable string.
23+
*
24+
* @param timestamp - Timestamp or date object to format
25+
* @param opts - Formatting options
26+
*/
27+
declare function useFormatTime(timestamp: MaybeRefOrGetter<number | Date>, opts: MaybeRefOrGetter<FormatTimeOptions>): Readonly<Ref<string>>
28+
29+
interface FormatRelativeTimeOptions {
30+
/**
31+
* If set and the time is only a couple of seconds then instead of the number of seconds "a few seconds ago" will be shown
32+
*
33+
* @default false
34+
*/
35+
ignoreSeconds?: boolean
36+
37+
/**
38+
* Language to use for formatting.
39+
*
40+
* @default The current users language
41+
*/
42+
language?: string
43+
44+
/**
45+
* The relative time formatting option to use.
46+
*
47+
* @default 'long
48+
*/
49+
relativeTime?: 'long' | 'short' | 'narrow'
50+
51+
/**
52+
* If set to false the relative time will not be updated anymore.
53+
*
54+
* @default true - Meaning the relative time will be updated if needed
55+
*/
56+
update?: boolean
57+
}
58+
59+
interface FormatTimeOptions {
60+
/**
61+
* Locale to use for formatting.
62+
*
63+
* @default The current users locale
64+
*/
65+
locale?: string
66+
67+
/**
68+
* The format used for displaying.
69+
*
70+
* @default { timeStyle: 'medium', dateStyle: 'short' }
71+
*/
72+
format?: Intl.DateTimeFormatOptions
73+
}
74+
```
75+
76+
77+
## Usage
78+
```js static
79+
import {
80+
useFormatRelativeTime,
81+
useFormatTime,
82+
} from '@nextcloud/vue/composables/useFormatDateTime'
83+
84+
const timestamp = Date.now()
85+
const date = new Date('2025-07-03T19:00:00Z')
86+
87+
const relativeTime = useFormatRelativeTime(timestamp, relativeTimeOptions)
88+
const formattedTime = useFormatTime(date, timeOptions)
89+
```
90+
91+
### Example
92+
93+
```vue
94+
<template>
95+
<div class="container">
96+
<p class="description">Pick a time to show it formatted</p>
97+
<NcDateTimePicker v-model="date" confirm type="datetime" />
98+
<br />
99+
<p>Relative time: {{ relativeTime }}</p>
100+
<p>Formatted time: {{ formattedTime }}</p>
101+
</div>
102+
</template>
103+
104+
<script>
105+
import { ref } from 'vue'
106+
import {
107+
useFormatRelativeTime,
108+
useFormatTime,
109+
} from '../../src/composables/useFormatDateTime/index.js'
110+
111+
export default {
112+
setup() {
113+
const date = ref(new Date())
114+
115+
const relativeTime = useFormatRelativeTime(date)
116+
const formattedTime = useFormatTime(date)
117+
118+
return {
119+
date,
120+
formattedTime,
121+
relativeTime,
122+
}
123+
},
124+
}
125+
</script>
126+
127+
<style scoped>
128+
.description {
129+
margin-block: 10px;
130+
}
131+
</style>
132+
```

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
"@nextcloud/capabilities": "^1.2.0",
7676
"@nextcloud/event-bus": "^3.3.2",
7777
"@nextcloud/initial-state": "^2.2.0",
78-
"@nextcloud/l10n": "^3.2.0",
78+
"@nextcloud/l10n": "^3.3.0",
7979
"@nextcloud/logger": "^3.0.2",
8080
"@nextcloud/router": "^3.0.1",
8181
"@nextcloud/sharing": "^0.2.4",

src/components/NcDateTime/NcDateTime.vue

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ h4 {
9292
<template>
9393
<span class="nc-datetime"
9494
:data-timestamp="timestamp"
95-
:title="formattedFullTime"
95+
:title
9696
v-text="formattedTime" />
9797
</template>
9898

9999
<script setup lang="ts">
100-
import { toRef } from 'vue'
101-
import { useFormatDateTime } from '../../composables/useFormatDateTime.ts'
100+
import { computed, toRef } from 'vue'
101+
import { useFormatRelativeTime, useFormatTime } from '../../composables/useFormatDateTime/index.ts'
102102
103103
const props = withDefaults(defineProps<{
104104
/**
@@ -130,8 +130,15 @@ const props = withDefaults(defineProps<{
130130
relativeTime: 'long',
131131
})
132132
133-
const {
134-
formattedTime,
135-
formattedFullTime,
136-
} = useFormatDateTime(toRef(() => props.timestamp), props)
133+
const timeOptions = computed(() => ({ format: props.format }))
134+
const relativeTimeOptions = computed(() => ({
135+
ignoreSeconds: props.ignoreSeconds,
136+
relativeTime: props.relativeTime || 'long',
137+
update: props.relativeTime !== false,
138+
}))
139+
140+
const title = useFormatTime(toRef(() => props.timestamp), timeOptions)
141+
const relativeTime = useFormatRelativeTime(toRef(() => props.timestamp), relativeTimeOptions)
142+
143+
const formattedTime = computed(() => props.relativeTime ? relativeTime.value : title.value)
137144
</script>

src/composables/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
export * from './useFormatDateTime.ts'
6+
export {
7+
useFormatDateTime,
8+
useFormatRelativeTime,
9+
useFormatTime,
10+
} from './useFormatDateTime/index.ts'
11+
712
export * from './useHotKey/index.ts'
813
export * from './useIsDarkTheme/index.ts'
914
export * from './useIsFullscreen/index.ts'

src/composables/useFormatDateTime.ts

Lines changed: 0 additions & 127 deletions
This file was deleted.

0 commit comments

Comments
 (0)