Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/common/date.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { localize } from '../../nls.js';
7
import { Lazy } from './lazy.js';
8
import { LANGUAGE_DEFAULT } from './platform.js';
9
10
const minute = 60;
11
const hour = minute * 60;
12
const day = hour * 24;
13
const week = day * 7;
14
const month = day * 30;
15
const year = day * 365;
16
17
/**
18
* Create a localized difference of the time between now and the specified date.
19
* @param date The date to generate the difference from.
20
* @param appendAgoLabel Whether to append the " ago" to the end.
21
* @param useFullTimeWords Whether to use full words (eg. seconds) instead of
22
* shortened (eg. secs).
23
* @param disallowNow Whether to disallow the string "now" when the difference
24
* is less than 30 seconds.
25
*/
26
export function fromNow(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean, disallowNow?: boolean): string {
27
if (typeof date === 'undefined') {
28
return localize('date.fromNow.unknown', 'unknown');
29
}
30
31
if (typeof date !== 'number') {
32
date = date.getTime();
33
}
34
35
const seconds = Math.round((new Date().getTime() - date) / 1000);
36
if (seconds < -30) {
37
return localize('date.fromNow.in', 'in {0}', fromNow(new Date().getTime() + seconds * 1000, false));
38
}
39
40
if (!disallowNow && seconds < 30) {
41
return localize('date.fromNow.now', 'now');
42
}
43
44
let value: number;
45
if (seconds < minute) {
46
value = seconds;
47
48
if (appendAgoLabel) {
49
if (value === 1) {
50
return useFullTimeWords
51
? localize('date.fromNow.seconds.singular.ago.fullWord', '{0} second ago', value)
52
: localize('date.fromNow.seconds.singular.ago', '{0} sec ago', value);
53
} else {
54
return useFullTimeWords
55
? localize('date.fromNow.seconds.plural.ago.fullWord', '{0} seconds ago', value)
56
: localize('date.fromNow.seconds.plural.ago', '{0} secs ago', value);
57
}
58
} else {
59
if (value === 1) {
60
return useFullTimeWords
61
? localize('date.fromNow.seconds.singular.fullWord', '{0} second', value)
62
: localize('date.fromNow.seconds.singular', '{0} sec', value);
63
} else {
64
return useFullTimeWords
65
? localize('date.fromNow.seconds.plural.fullWord', '{0} seconds', value)
66
: localize('date.fromNow.seconds.plural', '{0} secs', value);
67
}
68
}
69
}
70
71
if (seconds < hour) {
72
value = Math.round(seconds / minute);
73
if (appendAgoLabel) {
74
if (value === 1) {
75
return useFullTimeWords
76
? localize('date.fromNow.minutes.singular.ago.fullWord', '{0} minute ago', value)
77
: localize('date.fromNow.minutes.singular.ago', '{0} min ago', value);
78
} else {
79
return useFullTimeWords
80
? localize('date.fromNow.minutes.plural.ago.fullWord', '{0} minutes ago', value)
81
: localize('date.fromNow.minutes.plural.ago', '{0} mins ago', value);
82
}
83
} else {
84
if (value === 1) {
85
return useFullTimeWords
86
? localize('date.fromNow.minutes.singular.fullWord', '{0} minute', value)
87
: localize('date.fromNow.minutes.singular', '{0} min', value);
88
} else {
89
return useFullTimeWords
90
? localize('date.fromNow.minutes.plural.fullWord', '{0} minutes', value)
91
: localize('date.fromNow.minutes.plural', '{0} mins', value);
92
}
93
}
94
}
95
96
if (seconds < day) {
97
value = Math.round(seconds / hour);
98
if (appendAgoLabel) {
99
if (value === 1) {
100
return useFullTimeWords
101
? localize('date.fromNow.hours.singular.ago.fullWord', '{0} hour ago', value)
102
: localize('date.fromNow.hours.singular.ago', '{0} hr ago', value);
103
} else {
104
return useFullTimeWords
105
? localize('date.fromNow.hours.plural.ago.fullWord', '{0} hours ago', value)
106
: localize('date.fromNow.hours.plural.ago', '{0} hrs ago', value);
107
}
108
} else {
109
if (value === 1) {
110
return useFullTimeWords
111
? localize('date.fromNow.hours.singular.fullWord', '{0} hour', value)
112
: localize('date.fromNow.hours.singular', '{0} hr', value);
113
} else {
114
return useFullTimeWords
115
? localize('date.fromNow.hours.plural.fullWord', '{0} hours', value)
116
: localize('date.fromNow.hours.plural', '{0} hrs', value);
117
}
118
}
119
}
120
121
if (seconds < week) {
122
value = Math.round(seconds / day);
123
if (appendAgoLabel) {
124
return value === 1
125
? localize('date.fromNow.days.singular.ago', '{0} day ago', value)
126
: localize('date.fromNow.days.plural.ago', '{0} days ago', value);
127
} else {
128
return value === 1
129
? localize('date.fromNow.days.singular', '{0} day', value)
130
: localize('date.fromNow.days.plural', '{0} days', value);
131
}
132
}
133
134
if (seconds < month) {
135
value = Math.round(seconds / week);
136
if (appendAgoLabel) {
137
if (value === 1) {
138
return useFullTimeWords
139
? localize('date.fromNow.weeks.singular.ago.fullWord', '{0} week ago', value)
140
: localize('date.fromNow.weeks.singular.ago', '{0} wk ago', value);
141
} else {
142
return useFullTimeWords
143
? localize('date.fromNow.weeks.plural.ago.fullWord', '{0} weeks ago', value)
144
: localize('date.fromNow.weeks.plural.ago', '{0} wks ago', value);
145
}
146
} else {
147
if (value === 1) {
148
return useFullTimeWords
149
? localize('date.fromNow.weeks.singular.fullWord', '{0} week', value)
150
: localize('date.fromNow.weeks.singular', '{0} wk', value);
151
} else {
152
return useFullTimeWords
153
? localize('date.fromNow.weeks.plural.fullWord', '{0} weeks', value)
154
: localize('date.fromNow.weeks.plural', '{0} wks', value);
155
}
156
}
157
}
158
159
if (seconds < year) {
160
value = Math.round(seconds / month);
161
if (appendAgoLabel) {
162
if (value === 1) {
163
return useFullTimeWords
164
? localize('date.fromNow.months.singular.ago.fullWord', '{0} month ago', value)
165
: localize('date.fromNow.months.singular.ago', '{0} mo ago', value);
166
} else {
167
return useFullTimeWords
168
? localize('date.fromNow.months.plural.ago.fullWord', '{0} months ago', value)
169
: localize('date.fromNow.months.plural.ago', '{0} mos ago', value);
170
}
171
} else {
172
if (value === 1) {
173
return useFullTimeWords
174
? localize('date.fromNow.months.singular.fullWord', '{0} month', value)
175
: localize('date.fromNow.months.singular', '{0} mo', value);
176
} else {
177
return useFullTimeWords
178
? localize('date.fromNow.months.plural.fullWord', '{0} months', value)
179
: localize('date.fromNow.months.plural', '{0} mos', value);
180
}
181
}
182
}
183
184
value = Math.round(seconds / year);
185
if (appendAgoLabel) {
186
if (value === 1) {
187
return useFullTimeWords
188
? localize('date.fromNow.years.singular.ago.fullWord', '{0} year ago', value)
189
: localize('date.fromNow.years.singular.ago', '{0} yr ago', value);
190
} else {
191
return useFullTimeWords
192
? localize('date.fromNow.years.plural.ago.fullWord', '{0} years ago', value)
193
: localize('date.fromNow.years.plural.ago', '{0} yrs ago', value);
194
}
195
} else {
196
if (value === 1) {
197
return useFullTimeWords
198
? localize('date.fromNow.years.singular.fullWord', '{0} year', value)
199
: localize('date.fromNow.years.singular', '{0} yr', value);
200
} else {
201
return useFullTimeWords
202
? localize('date.fromNow.years.plural.fullWord', '{0} years', value)
203
: localize('date.fromNow.years.plural', '{0} yrs', value);
204
}
205
}
206
}
207
208
export function fromNowByDay(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean): string {
209
if (typeof date !== 'number') {
210
date = date.getTime();
211
}
212
213
const todayMidnightTime = new Date();
214
todayMidnightTime.setHours(0, 0, 0, 0);
215
const yesterdayMidnightTime = new Date(todayMidnightTime.getTime());
216
yesterdayMidnightTime.setDate(yesterdayMidnightTime.getDate() - 1);
217
218
if (date > todayMidnightTime.getTime()) {
219
return localize('today', 'Today');
220
}
221
222
if (date > yesterdayMidnightTime.getTime()) {
223
return localize('yesterday', 'Yesterday');
224
}
225
226
return fromNow(date, appendAgoLabel, useFullTimeWords);
227
}
228
229
/**
230
* Gets a readable duration with intelligent/lossy precision. For example "40ms" or "3.040s")
231
* @param ms The duration to get in milliseconds.
232
* @param useFullTimeWords Whether to use full words (eg. seconds) instead of
233
* shortened (eg. secs).
234
*/
235
export function getDurationString(ms: number, useFullTimeWords?: boolean) {
236
const seconds = Math.abs(ms / 1000);
237
if (seconds < 1) {
238
return useFullTimeWords
239
? localize('duration.ms.full', '{0} milliseconds', ms)
240
: localize('duration.ms', '{0}ms', ms);
241
}
242
if (seconds < minute) {
243
return useFullTimeWords
244
? localize('duration.s.full', '{0} seconds', Math.round(ms) / 1000)
245
: localize('duration.s', '{0}s', Math.round(ms) / 1000);
246
}
247
if (seconds < hour) {
248
return useFullTimeWords
249
? localize('duration.m.full', '{0} minutes', Math.round(ms / (1000 * minute)))
250
: localize('duration.m', '{0} mins', Math.round(ms / (1000 * minute)));
251
}
252
if (seconds < day) {
253
return useFullTimeWords
254
? localize('duration.h.full', '{0} hours', Math.round(ms / (1000 * hour)))
255
: localize('duration.h', '{0} hrs', Math.round(ms / (1000 * hour)));
256
}
257
return localize('duration.d', '{0} days', Math.round(ms / (1000 * day)));
258
}
259
260
export function toLocalISOString(date: Date): string {
261
return date.getFullYear() +
262
'-' + String(date.getMonth() + 1).padStart(2, '0') +
263
'-' + String(date.getDate()).padStart(2, '0') +
264
'T' + String(date.getHours()).padStart(2, '0') +
265
':' + String(date.getMinutes()).padStart(2, '0') +
266
':' + String(date.getSeconds()).padStart(2, '0') +
267
'.' + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +
268
'Z';
269
}
270
271
export const safeIntl = {
272
DateTimeFormat(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): Lazy<Intl.DateTimeFormat> {
273
return new Lazy(() => {
274
try {
275
return new Intl.DateTimeFormat(locales, options);
276
} catch {
277
return new Intl.DateTimeFormat(undefined, options);
278
}
279
});
280
},
281
Collator(locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): Lazy<Intl.Collator> {
282
return new Lazy(() => {
283
try {
284
return new Intl.Collator(locales, options);
285
} catch {
286
return new Intl.Collator(undefined, options);
287
}
288
});
289
},
290
Segmenter(locales?: Intl.LocalesArgument, options?: Intl.SegmenterOptions): Lazy<Intl.Segmenter> {
291
return new Lazy(() => {
292
try {
293
return new Intl.Segmenter(locales, options);
294
} catch {
295
return new Intl.Segmenter(undefined, options);
296
}
297
});
298
},
299
Locale(tag: Intl.Locale | string, options?: Intl.LocaleOptions): Lazy<Intl.Locale> {
300
return new Lazy(() => {
301
try {
302
return new Intl.Locale(tag, options);
303
} catch {
304
return new Intl.Locale(LANGUAGE_DEFAULT, options);
305
}
306
});
307
},
308
NumberFormat(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions): Lazy<Intl.NumberFormat> {
309
return new Lazy(() => {
310
try {
311
return new Intl.NumberFormat(locales, options);
312
} catch {
313
return new Intl.NumberFormat(undefined, options);
314
}
315
});
316
}
317
};
318
319