gnome-shell/js/misc/dateUtils.js

233 lines
7.6 KiB
JavaScript
Raw Normal View History

import * as System from 'system';
import * as Gettext from 'gettext';
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import Shell from 'gi://Shell';
import * as Params from './params.js';
let _desktopSettings = null;
let _localTimeZone = null;
/**
* @private
*
* @param {Date} date a Date object
* @returns {GLib.DateTime | null}
*/
function _convertJSDateToGLibDateTime(date) {
if (_localTimeZone === null)
_localTimeZone = GLib.TimeZone.new_local();
const dt = GLib.DateTime.new(_localTimeZone,
date.getFullYear(),
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds());
return dt;
}
/**
* Formats a Date object according to a C sprintf-style string using
* the cached local timezone.
*
* @param {Date} date a Date object
* @param {string} format a format String for the date
* @returns {string}
*/
export function formatDateWithCFormatString(date, format) {
const dt = _convertJSDateToGLibDateTime(date);
return dt?.format(format) ?? '';
}
/**
* Formats a time span string representing the
* date passed in to the current time.
*
* @param {Date} date the start of the time span
* @returns {string}
*/
export function formatTimeSpan(date) {
if (_localTimeZone === null)
_localTimeZone = GLib.TimeZone.new_local();
const now = GLib.DateTime.new_now(_localTimeZone);
const timespan = now.difference(date);
const minutesAgo = timespan / GLib.TIME_SPAN_MINUTE;
const hoursAgo = timespan / GLib.TIME_SPAN_HOUR;
const daysAgo = timespan / GLib.TIME_SPAN_DAY;
const weeksAgo = daysAgo / 7;
const monthsAgo = daysAgo / 30;
const yearsAgo = weeksAgo / 52;
if (minutesAgo < 5)
return _('Just now');
if (hoursAgo < 1) {
return Gettext.ngettext(
'%d minute ago',
'%d minutes ago',
minutesAgo
).format(minutesAgo);
}
if (daysAgo < 1) {
return Gettext.ngettext(
'%d hour ago',
'%d hours ago',
hoursAgo
).format(hoursAgo);
}
if (daysAgo < 2)
return _('Yesterday');
if (daysAgo < 15) {
return Gettext.ngettext(
'%d day ago',
'%d days ago',
daysAgo
).format(daysAgo);
}
if (weeksAgo < 8) {
return Gettext.ngettext(
'%d week ago',
'%d weeks ago',
weeksAgo
).format(weeksAgo);
}
if (yearsAgo < 1) {
return Gettext.ngettext(
'%d month ago',
'%d months ago',
monthsAgo
).format(monthsAgo);
}
return Gettext.ngettext(
'%d year ago',
'%d years ago',
yearsAgo
).format(yearsAgo);
}
/**
* Formats a date time string based on style parameters
*
* @param {GLib.DateTime | Date} time a Date object
* @param {object} [params] style parameters for the output string
* @param {boolean=} params.timeOnly whether the string should only contain the time (no date)
* @param {boolean=} params.ampm whether to include the "am" or "pm" in the string
* @returns {string}
*/
export function formatTime(time, params) {
let date;
// HACK: The built-in Date type sucks at timezones, which we need for the
// world clock; it's often more convenient though, so allow either
// Date or GLib.DateTime as parameter
if (time instanceof Date)
date = _convertJSDateToGLibDateTime(time);
else
date = time;
if (!date)
return '';
// _localTimeZone is defined in _convertJSDateToGLibDateTime
const now = GLib.DateTime.new_now(_localTimeZone);
const daysAgo = now.difference(date) / (24 * 60 * 60 * 1000 * 1000);
let format;
if (_desktopSettings == null)
_desktopSettings = new Gio.Settings({schema_id: 'org.gnome.desktop.interface'});
const clockFormat = _desktopSettings.get_string('clock-format');
params = Params.parse(params, {
timeOnly: false,
ampm: true,
});
if (clockFormat === '24h') {
// Show only the time if date is on today
if (daysAgo < 1 || params.timeOnly)
/* Translators: Time in 24h format */
format = N_('%H\u2236%M');
// Show the word "Yesterday" and time if date is on yesterday
else if (daysAgo < 2)
/* Translators: this is the word "Yesterday" followed by a
time string in 24h format. i.e. "Yesterday, 14:30" */
// xgettext:no-c-format
format = N_('Yesterday, %H\u2236%M');
// Show a week day and time if date is in the last week
else if (daysAgo < 7)
/* Translators: this is the week day name followed by a time
string in 24h format. i.e. "Monday, 14:30" */
// xgettext:no-c-format
format = N_('%A, %H\u2236%M');
else if (date.get_year() === now.get_year())
/* Translators: this is the month name and day number
followed by a time string in 24h format.
i.e. "May 25, 14:30" */
// xgettext:no-c-format
format = N_('%B %-d, %H\u2236%M');
else
/* Translators: this is the month name, day number, year
number followed by a time string in 24h format.
i.e. "May 25 2012, 14:30" */
// xgettext:no-c-format
format = N_('%B %-d %Y, %H\u2236%M');
} else {
// Show only the time if date is on today
if (daysAgo < 1 || params.timeOnly) // eslint-disable-line no-lonely-if
/* Translators: Time in 12h format */
format = N_('%l\u2236%M %p');
// Show the word "Yesterday" and time if date is on yesterday
else if (daysAgo < 2)
/* Translators: this is the word "Yesterday" followed by a
time string in 12h format. i.e. "Yesterday, 2:30 pm" */
// xgettext:no-c-format
format = N_('Yesterday, %l\u2236%M %p');
// Show a week day and time if date is in the last week
else if (daysAgo < 7)
/* Translators: this is the week day name followed by a time
string in 12h format. i.e. "Monday, 2:30 pm" */
// xgettext:no-c-format
format = N_('%A, %l\u2236%M %p');
else if (date.get_year() === now.get_year())
/* Translators: this is the month name and day number
followed by a time string in 12h format.
i.e. "May 25, 2:30 pm" */
// xgettext:no-c-format
format = N_('%B %-d, %l\u2236%M %p');
else
/* Translators: this is the month name, day number, year
number followed by a time string in 12h format.
i.e. "May 25 2012, 2:30 pm"*/
// xgettext:no-c-format
format = N_('%B %-d %Y, %l\u2236%M %p');
}
// Time in short 12h format, without the equivalent of "AM" or "PM"; used
// when it is clear from the context
if (!params.ampm)
format = format.replace(/\s*%p/g, '');
let formattedTime = date.format(Shell.util_translate_time_string(format));
// prepend LTR-mark to colon/ratio to force a text direction on times
return formattedTime.replace(/([:\u2236])/g, '\u200e$1');
}
/**
* Update the timezone used by JavaScript Date objects and other
* date utilities
*/
export function clearCachedLocalTimeZone() {
// SpiderMonkey caches the time zone so we must explicitly clear it
// before we can update the calendar, see
// https://bugzilla.gnome.org/show_bug.cgi?id=678507
System.clearDateCaches();
_localTimeZone = GLib.TimeZone.new_local();
}