Remove moment.js

Moment.js has a large bundle size and it causes a performance overhead.

Change-Id: Ida5c2642006d5018300527cb2b5eaab3c61772d2
This commit is contained in:
Milutin Kristofic
2020-05-05 16:21:05 +02:00
parent da63e01daa
commit 6ce37aa397
19 changed files with 335 additions and 98 deletions

View File

@@ -26,7 +26,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-messages-list-experimental_html.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {MessageTag} from '../../../constants/constants.js';
import {appContext} from '../../../services/app-context.js';
@@ -219,8 +219,8 @@ class GrMessagesListExperimental extends mixinBehaviors( [
combinedMessages = combinedMessages.concat(messages.slice(mi));
break;
}
mDate = mDate || util.parseDate(messages[mi].date);
rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
mDate = mDate || parseDate(messages[mi].date);
rDate = rDate || parseDate(reviewerUpdates[ri].date);
if (rDate < mDate) {
combinedMessages.push(reviewerUpdates[ri++]);
rDate = null;

View File

@@ -25,7 +25,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-messages-list_html.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {appContext} from '../../../services/app-context.js';
const MAX_INITIAL_SHOWN_MESSAGES = 20;
@@ -191,8 +191,8 @@ class GrMessagesList extends mixinBehaviors( [
result = result.concat(messages.slice(mi));
break;
}
mDate = mDate || util.parseDate(messages[mi].date);
rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
mDate = mDate || parseDate(messages[mi].date);
rDate = rDate || parseDate(reviewerUpdates[ri].date);
if (rDate < mDate) {
result.push(reviewerUpdates[ri++]);
rDate = null;
@@ -303,14 +303,14 @@ class GrMessagesList extends mixinBehaviors( [
const messages = this.messages || [];
const index = message._index;
const authorId = message.author && message.author._account_id;
const mDate = util.parseDate(message.date).getTime();
const mDate = parseDate(message.date).getTime();
// NB: Messages array has oldest messages first.
let nextMDate;
if (index > 0) {
for (let i = index - 1; i >= 0; i--) {
if (messages[i] && messages[i].author &&
messages[i].author._account_id === authorId) {
nextMDate = util.parseDate(messages[i].date).getTime();
nextMDate = parseDate(messages[i].date).getTime();
break;
}
}
@@ -324,7 +324,7 @@ class GrMessagesList extends mixinBehaviors( [
fileComments[i].author._account_id !== authorId) {
continue;
}
const cDate = util.parseDate(fileComments[i].updated).getTime();
const cDate = parseDate(fileComments[i].updated).getTime();
if (cDate <= mDate) {
if (nextMDate && cDate <= nextMDate) {
continue;

View File

@@ -22,7 +22,7 @@ import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-l
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-thread-list_html.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {NO_THREADS_MSG} from '../../../constants/messages.js';
@@ -163,8 +163,8 @@ class GrThreadList extends GestureEventListeners(
return c1.thread.line - c2.thread.line;
}
const c1Date = c1.__date || util.parseDate(c1.updated);
const c2Date = c2.__date || util.parseDate(c2.updated);
const c1Date = c1.__date || parseDate(c1.updated);
const c2Date = c2.__date || parseDate(c2.updated);
const dateCompare = c2Date - c1Date;
if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) {
return 0;

View File

@@ -21,7 +21,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-comment-api_html.js';
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
const PARENT = 'PARENT';
@@ -470,7 +470,7 @@ class ChangeComments {
.sort(
(c1, c2) => {
const dateDiff =
util.parseDate(c1.updated) - util.parseDate(c2.updated);
parseDate(c1.updated) - parseDate(c2.updated);
if (dateDiff) {
return dateDiff;
}

View File

@@ -27,7 +27,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-diff-host_html.js';
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
import {GrDiffBuilder} from '../gr-diff-builder/gr-diff-builder.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {DiffSide, rangesEqual} from '../gr-diff/gr-diff-utils.js';
import {appContext} from '../../../services/app-context.js';
@@ -667,7 +667,7 @@ class GrDiffHost extends mixinBehaviors( [
return comments.slice(0).sort((a, b) => {
if (b.__draft && !a.__draft ) { return -1; }
if (a.__draft && !b.__draft ) { return 1; }
return util.parseDate(a.updated) - util.parseDate(b.updated);
return parseDate(a.updated) - parseDate(b.updated);
});
}

View File

@@ -48,7 +48,6 @@ import {GrRangeNormalizer} from './diff/gr-diff-highlight/gr-range-normalizer.js
import {GrCountStringFormatter} from './shared/gr-count-string-formatter/gr-count-string-formatter.js';
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
import {util} from '../scripts/util.js';
import moment from 'moment/src/moment.js';
import page from 'page/page.mjs';
import {Auth} from './shared/gr-rest-api-interface/gr-auth.js';
import {EventEmitter} from './shared/gr-event-interface/gr-event-interface.js';
@@ -103,7 +102,6 @@ export function initGlobalVariables() {
window.GrCountStringFormatter = GrCountStringFormatter;
window.GrReviewerSuggestionsProvider = GrReviewerSuggestionsProvider;
window.util = util;
window.moment = moment;
window.page = page;
window.Auth = Auth;
window.EventEmitter = EventEmitter;

View File

@@ -26,7 +26,7 @@ import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-comment-thread_html.js';
import {PathListBehavior} from '../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {appContext} from '../../../services/app-context.js';
@@ -307,8 +307,8 @@ class GrCommentThread extends mixinBehaviors( [
_sortedComments(comments) {
return comments.slice().sort((c1, c2) => {
const c1Date = c1.__date || util.parseDate(c1.updated);
const c2Date = c2.__date || util.parseDate(c2.updated);
const c1Date = c1.__date || parseDate(c1.updated);
const c2Date = c2.__date || parseDate(c2.updated);
const dateCompare = c1Date - c2Date;
// Ensure drafts are at the end. There should only be one but in edge
// cases could be more. In the unlikely event two drafts are being

View File

@@ -22,13 +22,7 @@ import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mix
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-date-formatter_html.js';
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
import {util} from '../../../scripts/util.js';
import moment from 'moment/src/moment.js';
const Duration = {
HOUR: 1000 * 60 * 60,
DAY: 1000 * 60 * 60 * 24,
};
import {parseDate, fromNow, isValidDate, isWithinDay, isWithinHalfYear, formatDate, utcOffsetString} from '../../../utils/date-util.js';
const TimeFormats = {
TIME_12: 'h:mm A', // 2:14 PM
@@ -106,6 +100,10 @@ class GrDateFormatter extends mixinBehaviors( [
};
}
constructor() {
super();
}
/** @override */
attached() {
super.attached();
@@ -113,7 +111,7 @@ class GrDateFormatter extends mixinBehaviors( [
}
_getUtcOffsetString() {
return ' UTC' + moment().format('Z');
return utcOffsetString();
}
_loadPreferences() {
@@ -190,50 +188,28 @@ class GrDateFormatter extends mixinBehaviors( [
return this.$.restAPI.getPreferences();
}
/**
* Return true if date is within 24 hours and on the same day.
*/
_isWithinDay(now, date) {
const diff = -date.diff(now);
return diff < Duration.DAY && date.day() === now.getDay();
}
/**
* Returns true if date is from one to six months.
*/
_isWithinHalfYear(now, date) {
const diff = -date.diff(now);
return (date.day() !== now.getDay() || diff >= Duration.DAY) &&
diff < 180 * Duration.DAY;
}
_computeDateStr(
dateStr, timeFormat, dateFormat, relative, showDateAndTime
) {
if (!dateStr || !timeFormat || !dateFormat) { return ''; }
const date = moment(util.parseDate(dateStr));
if (!date.isValid()) { return ''; }
const date = parseDate(dateStr);
if (!isValidDate(date)) { return ''; }
if (relative) {
const dateFromNow = date.fromNow();
if (dateFromNow === 'a few seconds ago') {
return 'just now';
} else {
return dateFromNow;
}
return fromNow(date);
}
const now = new Date();
let format = dateFormat.full;
if (this._isWithinDay(now, date)) {
if (isWithinDay(now, date)) {
format = timeFormat;
} else {
if (this._isWithinHalfYear(now, date)) {
if (isWithinHalfYear(now, date)) {
format = dateFormat.short;
}
if (this.showDateAndTime) {
format = `${format} ${timeFormat}`;
}
}
return date.format(format);
return formatDate(date, format);
}
_timeToSecondsFormat(timeFormat) {
@@ -253,11 +229,11 @@ class GrDateFormatter extends mixinBehaviors( [
}
if (!dateStr) { return ''; }
const date = moment(util.parseDate(dateStr));
if (!date.isValid()) { return ''; }
const date = parseDate(dateStr);
if (!isValidDate(date)) { return ''; }
let format = dateFormat.full + ', ';
format += this._timeToSecondsFormat(timeFormat);
return date.format(format) + this._getUtcOffsetString();
return formatDate(date, format) + this._getUtcOffsetString();
}
}

View File

@@ -34,7 +34,7 @@ limitations under the License.
<script type="module">
import '../../../test/common-test-setup.js';
import './gr-date-formatter.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
suite('gr-date-formatter tests', () => {
let element;
let sandbox;
@@ -51,7 +51,7 @@ suite('gr-date-formatter tests', () => {
* Parse server-formatter date and normalize into current timezone.
*/
function normalizedDate(dateStr) {
const d = util.parseDate(dateStr);
const d = parseDate(dateStr);
d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
return d;
}

View File

@@ -29,7 +29,7 @@ import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-c
import {GrEtagDecorator} from './gr-etag-decorator.js';
import {SiteBasedCache, FetchPromisesCache, GrRestApiHelper} from './gr-rest-apis/gr-rest-api-helper.js';
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {authService} from './gr-auth.js';
const DiffViewMode = {
@@ -2075,7 +2075,7 @@ class GrRestApiInterface extends mixinBehaviors( [
_setRanges(comments) {
comments = comments || [];
comments.sort(
(a, b) => util.parseDate(a.updated) - util.parseDate(b.updated)
(a, b) => parseDate(a.updated) - parseDate(b.updated)
);
for (const comment of comments) {
this._setRange(comments, comment);

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
import {MessageTag} from '../../../constants/constants.js';
/** @constructor */
@@ -106,8 +106,8 @@ GrReviewerUpdatesParser.prototype._groupUpdates = function() {
if (!this._batch) {
this._batch = this._startBatch(update);
}
const updateDate = util.parseDate(update.updated).getTime();
const batchUpdateDate = util.parseDate(this._batch.date).getTime();
const updateDate = parseDate(update.updated).getTime();
const batchUpdateDate = parseDate(this._batch.date).getTime();
const reviewerId = update.reviewer._account_id.toString();
if (updateDate - batchUpdateDate >
GrReviewerUpdatesParser.REVIEWER_UPDATE_THRESHOLD_MILLIS ||
@@ -206,14 +206,14 @@ GrReviewerUpdatesParser.prototype._advanceUpdates = function() {
const updates = this.result.reviewer_updates;
const messages = this.result.messages;
messages.forEach((message, index) => {
const messageDate = util.parseDate(message.date).getTime();
const messageDate = parseDate(message.date).getTime();
const nextMessageDate = index === messages.length - 1 ? null :
util.parseDate(messages[index + 1].date).getTime();
parseDate(messages[index + 1].date).getTime();
for (const update of updates) {
const date = util.parseDate(update.date).getTime();
const date = parseDate(update.date).getTime();
if (date >= messageDate &&
(!nextMessageDate || date < nextMessageDate)) {
const timestamp = util.parseDate(update.date).getTime() -
const timestamp = parseDate(update.date).getTime() -
GrReviewerUpdatesParser.MESSAGE_REVIEWERS_THRESHOLD_MILLIS;
update.date = new Date(timestamp)
.toISOString()

View File

@@ -27,7 +27,7 @@ limitations under the License.
<script type="module">
import '../../../test/common-test-setup.js';
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
import {util} from '../../../scripts/util.js';
import {parseDate} from '../../../utils/date-util.js';
suite('gr-reviewer-updates-parser tests', () => {
let sandbox;
@@ -253,7 +253,7 @@ suite('gr-reviewer-updates-parser tests', () => {
});
test('_advanceUpdates', () => {
const T0 = util.parseDate('2017-02-17 19:04:18.000000000').getTime();
const T0 = parseDate('2017-02-17 19:04:18.000000000').getTime();
const tplus = delta => new Date(T0 + delta)
.toISOString()
.replace('T', ' ')
@@ -297,8 +297,8 @@ suite('gr-reviewer-updates-parser tests', () => {
instance = new GrReviewerUpdatesParser(change);
instance._advanceUpdates();
const updates = instance.result.reviewer_updates;
assert.isBelow(util.parseDate(updates[0].date).getTime(), T0);
assert.isBelow(util.parseDate(updates[1].date).getTime(), T0);
assert.isBelow(parseDate(updates[0].date).getTime(), T0);
assert.isBelow(parseDate(updates[1].date).getTime(), T0);
assert.equal(updates[2].date, tplus(100));
assert.equal(updates[3].date, tplus(500));
});

View File

@@ -272,14 +272,6 @@ const packages: PackageInfo[] = [
name: "isarray",
license: SharedLicenses.IsArray
},
{
name: "moment",
license: {
name: "moment",
type: LicenseTypes.Mit,
packageLicenseFile: "LICENSE"
}
},
{
name: "page",
license: SharedLicenses.Page

View File

@@ -26,7 +26,6 @@
"@webcomponents/shadycss": "^1.9.2",
"@webcomponents/webcomponentsjs": "^1.3.3",
"es6-promise": "^3.3.1",
"moment": "^2.24.0",
"page": "^1.11.5",
"polymer-bridges": "file:../../polymer-bridges/",
"ba-linkify": "file:../../lib/ba-linkify/src/",

View File

@@ -29,14 +29,6 @@ function getPathFromNode(el) {
// TODO (dmfilippov): Each function must be exported separately. According to
// the code style guide, a namespacing is not allowed.
export const util = {
parseDate(dateStr) {
// Timestamps are given in UTC and have the format
// "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
// nanoseconds.
// Munge the date into an ISO 8061 format and parse that.
return new Date(dateStr.replace(' ', 'T') + 'Z');
},
getCookie(name) {
const key = name + '=';
const cookies = document.cookie.split(';');

View File

@@ -58,6 +58,5 @@ var FetchPromisesCache;
var GrRestApiHelper;
var GrDisplayNameUtils;
var GrReviewerSuggestionsProvider;
var moment;
var page;
var util;

View File

@@ -0,0 +1,172 @@
/**
* @license
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const Duration = {
HOUR: 1000 * 60 * 60,
DAY: 1000 * 60 * 60 * 24,
};
export function parseDate(dateStr) {
// Timestamps are given in UTC and have the format
// "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
// nanoseconds.
// Munge the date into an ISO 8061 format and parse that.
return new Date(dateStr.replace(' ', 'T') + 'Z');
}
export function isValidDate(date) {
return date instanceof Date && !isNaN(date);
}
// similar to fromNow from moment.js
export function fromNow(date) {
const now = new Date();
const secondsAgo = Math.round((now - date) / 1000);
if (secondsAgo <= 44) return 'just now';
if (secondsAgo <= 89) return 'a minute ago';
const minutesAgo = Math.round(secondsAgo / 60);
if (minutesAgo <= 44) return `${minutesAgo} minutes ago`;
if (minutesAgo <= 89) return 'an hour ago';
const hoursAgo = Math.round(minutesAgo / 60);
if (hoursAgo <= 21) return `${hoursAgo} hours ago`;
if (hoursAgo <= 35) return 'a day ago';
const daysAgo = Math.round(hoursAgo / 24);
if (daysAgo <= 25) return `${daysAgo} days ago`;
if (daysAgo <= 45) return `a month ago`;
const monthsAgo = Math.round(daysAgo / 30);
if (daysAgo <= 319) return `${monthsAgo} months ago`;
if (daysAgo <= 547) return `a year ago`;
const yearsAgo = Math.round(daysAgo / 365);
return `${yearsAgo} years ago`;
}
/**
* Return true if date is within 24 hours and on the same day.
*/
export function isWithinDay(now, date) {
const diff = now - date;
return diff < Duration.DAY && date.getDay() == now.getDay();
}
/**
* Returns true if date is from one to six months.
*/
export function isWithinHalfYear(now, date) {
const diff = now - date;
return diff < 180 * Duration.DAY;
}
export function formatDate(date, format) {
const options = {};
if (format.includes('MM')) {
if (format.includes('MMM')) {
options.month = 'short';
} else {
options.month = '2-digit';
}
}
if (format.includes('YY')) {
if (format.includes('YYYY')) {
options.year = 'numeric';
} else {
options.year = '2-digit';
}
}
if (format.includes('DD')) {
options.day = '2-digit';
}
if (format.includes('HH')) {
options.hour = '2-digit';
options.hour12 = false;
}
if (format.includes('h')) {
options.hour = 'numeric';
options.hour12 = true;
}
if (format.includes('mm')) {
options.minute = '2-digit';
}
if (format.includes('ss')) {
options.second = '2-digit';
}
// en-GB is using h23 on Chrome 80, en-US is using h24 (midnight is 24:00)
const dtf = new Intl.DateTimeFormat('en-GB', options);
const parts = dtf.formatToParts(date).filter(o => o.type != 'literal')
.reduce((acc, o) => {
acc[o.type] = o.value;
return acc;
}, {});
if (format.includes('YY')) {
if (format.includes('YYYY')) {
format = format.replace('YYYY', parts.year);
} else {
format = format.replace('YY', parts.year);
}
}
if (format.includes('DD')) {
format = format.replace('DD', parts.day);
}
if (format.includes('HH')) {
format = format.replace('HH', parts.hour);
}
if (format.includes('h')) {
format = format.replace('h', parts.hour);
}
if (format.includes('mm')) {
format = format.replace('mm', parts.minute);
}
if (format.includes('ss')) {
format = format.replace('ss', parts.second);
}
if (format.includes('A')) {
if (parts.dayperiod) {
// Workaround for chrome 70 and below
format = format.replace('A', parts.dayperiod.toUpperCase());
} else {
format = format.replace('A', parts.dayPeriod.toUpperCase());
}
}
if (format.includes('MM')) {
if (format.includes('MMM')) {
format = format.replace('MMM', parts.month);
} else {
format = format.replace('MM', parts.month);
}
}
return format;
}
export function utcOffsetString() {
const now = new Date();
const tzo = -now.getTimezoneOffset();
const pad = num => {
const norm = Math.floor(Math.abs(num));
return (norm < 10 ? '0' : '') + norm;
};
return ` UTC${tzo >= 0 ? '+' : '-'}${pad(tzo / 60)}:${pad(tzo%60)}`;
}

View File

@@ -0,0 +1,114 @@
/**
* @license
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '../test/common-test-setup-karma.js';
import {isValidDate, parseDate, fromNow, isWithinDay, isWithinHalfYear, formatDate} from './date-util.js';
suite('date-util tests', () => {
suite('parseDate', () => {
test('parseDate server date', () => {
const parsed = parseDate('2015-09-15 20:34:00.000000000');
assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
});
});
suite('isValidDate', () => {
test('date is valid', () => {
assert.isTrue(isValidDate(new Date()));
});
test('broken date is invalid', () => {
assert.isFalse(isValidDate(new Date('xxx')));
});
});
suite('fromNow', () => {
test('test all variants', () => {
const fakeNow = new Date('May 08 2020 12:00:00');
sinon.useFakeTimers(fakeNow.getTime());
assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
assert.equal('a minute ago', fromNow(new Date('May 08 2020 11:59:00')));
assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
assert.equal('an hour ago', fromNow(new Date('May 08 2020 11:00:00')));
assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
assert.equal('a day ago', fromNow(new Date('May 07 2020 12:00:00')));
assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
assert.equal('a month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
assert.equal('a year ago', fromNow(new Date('May 05 2019 12:00:00')));
assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
});
});
suite('isWithinDay', () => {
test('basics works', () => {
assert.isTrue(isWithinDay(new Date('May 08 2020 12:00:00'),
new Date('May 08 2020 02:00:00')));
assert.isFalse(isWithinDay(new Date('May 08 2020 12:00:00'),
new Date('May 07 2020 12:00:00')));
});
});
suite('isWithinHalfYear', () => {
test('basics works', () => {
assert.isTrue(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
new Date('Feb 08 2020 12:00:00')));
assert.isFalse(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
new Date('Nov 07 2019 12:00:00')));
});
});
suite('formatDate', () => {
test('works for standard format', () => {
const stdFormat = 'MMM DD, YYYY';
assert.equal('May 08, 2020',
formatDate(new Date('May 08 2020 12:00:00'), stdFormat));
assert.equal('Feb 28, 2020',
formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat));
const time24Format = 'HH:mm:ss';
assert.equal('Feb 28, 2020 12:01:12',
formatDate(new Date('Feb 28 2020 12:01:12'), stdFormat + ' '
+ time24Format));
});
test('works for euro format', () => {
const euroFormat = 'DD.MM.YYYY';
assert.equal('01.12.2019',
formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat));
assert.equal('20.01.2002',
formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat));
const time24Format = 'HH:mm:ss';
assert.equal('28.02.2020 00:01:12',
formatDate(new Date('Feb 28 2020 00:01:12'), euroFormat + ' '
+ time24Format));
});
test('works for iso format', () => {
const isoFormat = 'YYYY-MM-DD';
assert.equal('2015-01-01',
formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat));
assert.equal('2013-07-03',
formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat));
const timeFormat = 'h:mm:ss A';
assert.equal('2013-07-03 5:00:00 AM',
formatDate(new Date('Jul 03 2013 05:00:00'), isoFormat + ' '
+ timeFormat));
assert.equal('2013-07-03 5:00:00 PM',
formatDate(new Date('Jul 03 2013 17:00:00'), isoFormat + ' '
+ timeFormat));
});
});
});

View File

@@ -338,11 +338,6 @@ isarray@0.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
moment@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
page@^1.11.5:
version "1.11.5"
resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"