-
Notifications
You must be signed in to change notification settings - Fork 64
chore: remove moment #1107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: remove moment #1107
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /** | ||
| * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
|
|
||
| import { getCanonicalLocale } from '@nextcloud/l10n' | ||
|
|
||
| const locale = getCanonicalLocale() | ||
|
|
||
| const relativeTimeFormat = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }) | ||
|
|
||
| /** | ||
| * Format duration in human-readable format. | ||
| * If the unit is not provided, the largest unit is used for rounded duration in milliseconds. | ||
| * @param duration - Duration in the unit | ||
| * @param unit - Unit to format to | ||
| */ | ||
| export function formatDuration(duration: number, unit?: Intl.RelativeTimeFormatUnit) { | ||
| if (!unit) { | ||
| const { value, unit: largestUnit } = convertMsToLargestTimeUnit(duration) | ||
| duration = value | ||
| unit = largestUnit | ||
| } | ||
|
|
||
| return new Intl.NumberFormat(locale, { style: 'unit', unit, unitDisplay: 'long' }).format(duration) | ||
| } | ||
|
|
||
| /** | ||
| * Format duration in human-readable format from now. | ||
| * If the unit is not provided, the largest unit is used for rounded duration in milliseconds. | ||
| * @param dateOrMs - Date or ms to format | ||
| * @param unit - Unit to format to | ||
| */ | ||
| export function formatDurationFromNow(dateOrMs: Date | number, unit?: Intl.RelativeTimeFormatUnit) { | ||
| return formatDuration(+new Date(dateOrMs) - Date.now(), unit) | ||
| } | ||
|
|
||
| /** | ||
| * Format relative time duration in human-readable format | ||
| * @param ms - Duration in milliseconds | ||
| */ | ||
| export function formatRelativeTime(ms: number) { | ||
| const { value, unit } = convertMsToLargestTimeUnit(ms) | ||
|
|
||
| return relativeTimeFormat.format(value, unit) | ||
| } | ||
|
|
||
| /** | ||
| * Format relative time duration in human-readable format from now | ||
| * @param dateOrMs - Date or ms to format | ||
| */ | ||
| export function formatRelativeTimeFromNow(dateOrMs: Date | number) { | ||
| return formatRelativeTime(+new Date(dateOrMs) - Date.now()) | ||
| } | ||
|
|
||
| /** | ||
| * Convert milliseconds to the largest unit rounded from 0.75 point. | ||
| * @example 123 -> { value: 0, unit: 'second' } | ||
| * @example 1000 -> { value: 1, unit: 'second' } | ||
| * @example 25 * 60 * 60 * 1000 -> { value: 25, unit: 'minute' } | ||
| * @example 35 * 60 * 60 * 1000 -> { value: 35, unit: 'minute' } | ||
| * @example 45 * 60 * 60 * 1000 -> { value: 1, unit: 'hour' } | ||
| * @example 3600000 -> { value: 1, unit: 'hour' } | ||
| * @example 86400000 -> { value: 1, unit: 'day' } | ||
| * @param ms - Duration in milliseconds | ||
| */ | ||
| export function convertMsToLargestTimeUnit(ms: number): { value: number; unit: Intl.RelativeTimeFormatUnit } { | ||
| const units = { | ||
| year: 0, | ||
| month: 0, | ||
| day: 0, | ||
| hour: 0, | ||
| minute: 0, | ||
| second: 0, | ||
| } | ||
|
|
||
| units.second = ms / 1000 | ||
| units.minute = units.second / 60 | ||
| units.hour = units.minute / 60 | ||
| units.day = units.hour / 24 | ||
| units.month = units.day / 30 | ||
| units.year = units.day / 365 | ||
|
|
||
| // | ||
| const round = (value: number) => Math.abs(value % 1) < 0.75 ? Math.trunc(value) : Math.round(value) | ||
|
|
||
| // Loop from the largest unit to the smallest | ||
| for (const key in units) { | ||
| const unit = key as keyof typeof units | ||
| // Round the value so 59 min 59 sec 999 ms is 1 hour and not 59 minutes | ||
| const rounded = round(units[unit]) | ||
| // Return the first non-zero unit | ||
| if (rounded !== 0) { | ||
| return { | ||
| value: rounded, | ||
| unit, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // now | ||
| return { | ||
| value: 0, | ||
| unit: 'second', | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,8 @@ | |
| */ | ||
|
|
||
| import type { ClearAtPredefinedConfig, PredefinedUserStatus, UserStatus, UserStatusStatusType } from './userStatus.types.ts' | ||
| import moment from '@nextcloud/moment' | ||
| import { translate as t } from '@nextcloud/l10n' | ||
| import { t, getFirstDay } from '@nextcloud/l10n' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Screenshot from also custom
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, this info is not available for clients, so, using locale data
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I cannot reproduce this state... Even for new accounts it's Anyway, Nextcloud defaults it to
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proposal: nextcloud-libraries/nextcloud-l10n#864 |
||
| import { formatDurationFromNow, formatDuration } from '../../../shared/datetime.utils.ts' | ||
|
|
||
| /** | ||
| * List of user status types that user can set | ||
|
|
@@ -58,11 +58,17 @@ export function getTimestampForPredefinedClearAt(clearAt: ClearAtPredefinedConfi | |
| } | ||
|
|
||
| if (clearAt.type === 'end-of') { | ||
| switch (clearAt.time) { | ||
| case 'day': | ||
| case 'week': | ||
| return Number(moment(new Date()).endOf(clearAt.time).format('X')) | ||
| const date = new Date() | ||
| // In any case, set the end of the day | ||
| date.setHours(23, 59, 59, 999) | ||
|
|
||
| if (clearAt.time === 'week') { | ||
| const firstDay = getFirstDay() | ||
| const lastDay = (firstDay + 6) % 7 | ||
| date.setDate(date.getDate() + (lastDay + 7 - date.getDay()) % 7) | ||
| } | ||
|
|
||
| return Math.floor(date.getTime() / 1000) | ||
| } | ||
|
|
||
| // Unknown type | ||
|
|
@@ -82,9 +88,7 @@ export function clearAtToLabel(clearAt: ClearAtPredefinedConfig | number | null) | |
|
|
||
| // Clear At has been already set | ||
| if (typeof clearAt === 'number') { | ||
| const momentNow = moment(new Date()) | ||
| const momentClearAt = moment(new Date(clearAt * 1000)) | ||
| return moment.duration(momentNow.diff(momentClearAt)).humanize() | ||
| return formatDurationFromNow(clearAt * 1000) | ||
| } | ||
|
|
||
| // ClearAt is an object description of predefined value | ||
|
|
@@ -98,7 +102,7 @@ export function clearAtToLabel(clearAt: ClearAtPredefinedConfig | number | null) | |
|
|
||
| // ClearAt is an object description of predefined value | ||
| if (clearAt.type === 'period') { | ||
| return moment.duration(clearAt.time * 1000).humanize() | ||
| return formatDuration(clearAt.time * 1000) | ||
| } | ||
|
|
||
| return '' | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Late-thought opinion:
getLanguageshould be used for relative time (not absolute, that required locale format):With 'en' language and 'de' locale we are geting human-readable represenation, but language of it won't match expected system:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and this is an old discussion about using locale for durations.
Here it works the same way it works on the server.