Replace moment with date-fns

This commit is contained in:
2026-05-11 21:38:11 +02:00
parent 0140f2af3c
commit 405184b1f8
13 changed files with 73 additions and 77 deletions
+11 -37
View File
@@ -77,6 +77,7 @@
"connect-mongo": "6.0.0",
"cookie-parser": "1.4.4",
"core-js": "3.2.1",
"date-fns": "^4.1.0",
"del": "8.0.1",
"delta-e": "0.0.8",
"errorhandler": "1.5.1",
@@ -116,7 +117,6 @@
"markdown-tree": "0.0.0",
"merge2": "1.2.4",
"mocha": "6.2.0",
"moment": "2.24.0",
"mongoose": "9.3.2",
"morgan": "1.9.1",
"ngx-bootstrap": "18.0.1",
@@ -5495,9 +5495,6 @@
"cpu": [
"arm"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5511,9 +5508,6 @@
"cpu": [
"arm"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5527,9 +5521,6 @@
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5543,9 +5534,6 @@
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5559,9 +5547,6 @@
"cpu": [
"ppc64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5575,9 +5560,6 @@
"cpu": [
"riscv64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5591,9 +5573,6 @@
"cpu": [
"s390x"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5607,9 +5586,6 @@
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -5623,9 +5599,6 @@
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -10685,6 +10658,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@@ -20800,15 +20783,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/mongodb": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.1.tgz",
+1 -1
View File
@@ -118,6 +118,7 @@
"connect-mongo": "6.0.0",
"cookie-parser": "1.4.4",
"core-js": "3.2.1",
"date-fns": "^4.1.0",
"del": "8.0.1",
"delta-e": "0.0.8",
"errorhandler": "1.5.1",
@@ -157,7 +158,6 @@
"markdown-tree": "0.0.0",
"merge2": "1.2.4",
"mocha": "6.2.0",
"moment": "2.24.0",
"mongoose": "9.3.2",
"morgan": "1.9.1",
"ngx-bootstrap": "18.0.1",
+18 -13
View File
@@ -1,5 +1,5 @@
import * as moment from 'moment';
import { escapeRegExp, startsWith, range, uniq, compact } from 'lodash';
import { differenceInYears, format, formatDistanceToNow, subDays } from 'date-fns';
import { escapeRegExp, startsWith, uniq, compact } from 'lodash';
import { fromNow, toInt, hasFlag, compareDates, removeItem, includes } from './utils';
import { DAY } from './constants';
import {
@@ -45,7 +45,7 @@ export function highlightWords(text?: string) {
}
export function getAge(birthdate: Date) {
return moment().diff(birthdate, 'years');
return differenceInYears(new Date(), birthdate);
}
// chat & events
@@ -55,17 +55,19 @@ export interface ChatDate {
label: string;
}
export function createChatDate(date: moment.Moment): ChatDate {
export function createChatDate(date: Date): ChatDate {
return {
value: date.toISOString(),
label: date.format('MMMM Do YYYY'),
label: format(date, 'MMMM do yyyy')
};
}
export function createDateRange(startDate: string | Date, days: number): ChatDate[] {
return range(days, 0)
.map(d => moment(startDate).subtract(d, 'days'))
.map(createChatDate);
const start = new Date(startDate);
return Array.from({ length: days }, (_, i) =>
createChatDate(subDays(start, days - i - 1))
);
}
// filtering
@@ -324,19 +326,22 @@ const fieldToAction: { [key: string]: string | undefined; } = {
ban: 'Banned',
};
export function banMessage(field: string, value: number) {
const action = fieldToAction[field] || 'Did';
if (value === 0) {
return `Un${action.toLowerCase()}`;
} else if (value === -1) {
return action;
} else {
return `${action} for (${moment.duration(value - Date.now()).humanize()})`;
}
if (value === -1) {
return action;
}
return `${action} for (${formatDistanceToNow(new Date(value), { addSuffix: false })})`;
}
export function isActive(value: number | undefined): boolean {
export function isActive(value: number | undefined): value is number {
return !!value && (value === -1 || value > Date.now());
}
@@ -1,5 +1,4 @@
import { Component, Input, OnDestroy, ElementRef } from '@angular/core';
import * as moment from 'moment';
import { AdminModel } from '../../../services/adminModel';
import { Account } from '../../../../common/adminInterfaces';
import { ChatDate, createChatDate, createDateRange } from '../../../../common/adminUtils';
@@ -7,6 +6,7 @@ import { faSearch, faSpinner, faSync, faFileAlt, faTimes, faChevronLeft, faChevr
import { removeAllNodes, appendAllNodes, showTextInNewTab } from '../../../../client/htmlUtils';
import { includes } from '../../../../common/utils';
import { replaceSwears } from '../../../../client/adminHtmlUtils';
import { addDays } from 'date-fns';
@Component({
selector: 'admin-chat-log',
@@ -25,7 +25,7 @@ export class AdminChatLog implements OnDestroy {
accounts: Account[] = [];
search?: string;
open = false;
today: ChatDate = createChatDate(moment());
today: ChatDate = createChatDate(new Date());
dates: ChatDate[] = [/*{ value: 'all', label: 'All' },*/ ...createDateRange(new Date(), 14)];
date?: ChatDate;
chatRaw?: string;
@@ -133,7 +133,9 @@ export class AdminChatLog implements OnDestroy {
}
private switchDate(days: number) {
const validDate = this.date && this.date.value !== 'all';
this.date = validDate ? createChatDate(moment(this.date!.value).add(days, 'days')) : this.today;
this.date = validDate
? createChatDate(addDays(new Date(this.date!.value), days))
: this.today;
this.refresh();
}
private stopInterval() {
+6 -4
View File
@@ -1,6 +1,6 @@
import { Component, Input, OnInit, OnDestroy, OnChanges, ElementRef, ChangeDetectionStrategy } from '@angular/core';
import * as moment from 'moment';
import { IntervalUpdateService } from '../../services/intervalUpdateService';
import { formatDistanceToNow } from 'date-fns';
@Component({
selector: 'from-now',
@@ -9,13 +9,13 @@ import { IntervalUpdateService } from '../../services/intervalUpdateService';
})
export class FromNow implements OnInit, OnDestroy, OnChanges {
@Input() time?: any;
private moment?: moment.Moment;
private date?: Date;
private text?: string;
private unsubscribe?: () => void;
constructor(private element: ElementRef, private updateService: IntervalUpdateService) {
}
ngOnChanges() {
this.moment = this.time ? moment(this.time) : undefined;
this.date = this.time ? new Date(this.time) : undefined;
this.update();
}
ngOnInit() {
@@ -26,7 +26,9 @@ export class FromNow implements OnInit, OnDestroy, OnChanges {
this.unsubscribe && this.unsubscribe();
}
private update() {
const text = this.moment ? this.moment.fromNow(true).replace('seconds', 'secs') : '';
const text = this.date
? formatDistanceToNow(this.date, { addSuffix: false }).replace('seconds', 'secs')
: '';
if (this.text !== text) {
this.text = text;
+10 -5
View File
@@ -13,8 +13,8 @@ import { faCaretUp, faArrowDown, faSearch } from '../../../client/icons';
import { sampleMessages } from '../../../common/debugData';
import { findEntityById } from '../../../client/worldMap';
import { colorToRGBA, rgb2hsl, HSL, hsl2CSS } from '../../../common/color';
import * as moment from 'moment';
import { isMobile } from '../../../client/data';
import { format } from 'date-fns';
interface IndexEntryUser {
id: number;
@@ -143,13 +143,18 @@ export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage, h
replaceNodes(line.message, message);
}
function updateTime(line: ChatLogLineDOM, hourMode?: '12' | '24') {
line.time.style.display = 'inline';
if (!hourMode) return;
if (hourMode === '24')
replaceNodes(line.timeContent, `[${moment().format('HH:mm:ss')}] `);
if (hourMode === '12')
replaceNodes(line.timeContent, `[${moment().format('LTS')}] `);
if (hourMode === '24') {
replaceNodes(line.timeContent, `[${format(new Date(), 'HH:mm:ss')}] `);
}
if (hourMode === '12') {
replaceNodes(line.timeContent, `[${format(new Date(), 'hh:mm:ss a')}] `);
}
}
function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[]) {
+2 -2
View File
@@ -1,4 +1,4 @@
import * as moment from 'moment';
import { formatDistanceToNow } from 'date-fns';
import { Types } from 'mongoose';
import { uniq, truncate } from 'lodash';
import { AccountState, AccountFlags, AuthBase } from '../common/adminInterfaces';
@@ -38,7 +38,7 @@ export interface CreateAccountOptions extends SuspiciousCheckers {
}
function getBanInfo(value: number | undefined): string | undefined {
return isActive(value) ? (value === -1 ? 'perma' : moment(value).fromNow(true)) : undefined;
return isActive(value) ? (value === -1 ? 'perma' : formatDistanceToNow(new Date(value))) : undefined;
}
export function getModInfo({ accountId, account, country }: IClient): ModInfo {
+8 -2
View File
@@ -1,7 +1,7 @@
import * as moment from 'moment';
import { Socket, SocketServer, Method, ClientExtensions } from 'ag-sockets';
import { AccountCounters, Subscription } from '../common/interfaces';
import { HOUR } from '../common/constants';
import { formatDuration as formatDurationDateFn } from 'date-fns';
import { fromNow, removeItem, formatDuration } from '../common/utils';
import { hasRole } from '../common/accountUtils';
import {
@@ -38,6 +38,7 @@ import { splitAccounts } from './api/merge';
import { removeAuth, assignAuth } from './api/admin-auths';
import { removeFriend, addFriend } from './accountUtils';
import { ClientAdminActionsTemplate, ClientUpdate } from '../common/clientAdminActionsTemplate';
import { intervalToDuration } from 'date-fns';
@Socket({
id: 'admin',
@@ -413,7 +414,12 @@ export class AdminServerActions implements IAdminServerActions, SocketServer {
}
@Method({ promise: true })
async timeoutAccount(accountId: string, timeout: number) {
const message = timeout ? `Timed out ${moment.duration(timeout).humanize()}` : 'Unmuted';
const message = timeout
? `Timed out ${formatDurationDateFn(
intervalToDuration({ start: 0, end: timeout }),
{ format: ['days', 'hours', 'minutes', 'seconds'] }
)}`
: 'Unmuted';
system(accountId, `${message} ${this.by()}`);
await timeoutAccount(accountId, fromNow(timeout | 0));
}
+2 -2
View File
@@ -1,4 +1,4 @@
import * as moment from 'moment';
import { formatDistanceToNow } from 'date-fns';
import { ACCOUNT_NAME_MAX_LENGTH, ACCOUNT_NAME_MIN_LENGTH, MIN_CHATLOG_RANGE, MAX_CHATLOG_RANGE, HIDES_PER_PAGE } from '../../common/constants';
import {
UpdateAccountData, AccountSettings, AccountData, ModAction, EntitiesEditorInfo, EntityNameTypes
@@ -179,7 +179,7 @@ export async function getHides(account: IAccount, page: number) {
return hideRequests.map((f: any) => ({
id: f._id.toString(),
name: f.name,
date: moment(f.date).fromNow(),
date: formatDistanceToNow(new Date(f.date), { addSuffix: true }),
}));
}
+2 -2
View File
@@ -1,5 +1,5 @@
import * as fs from 'fs';
import * as moment from 'moment';
import { format } from 'date-fns';
import {
AdminState, eventFields, BaseValues, UpdateOrigin, UserCountStats, AccountDetails, SupporterInvite,
InternalGameServerState, InternalLoginServerState, OtherStats, Settings, GameServerSettings
@@ -116,7 +116,7 @@ export async function getChat(search: string, date: string, caseInsensitive: boo
const options = { maxBuffer: 1 * 1024 * 1024 }; // 1MB
async function fetchChatlog(lines: number) {
const logFile = paths.pathTo('logs', `info.${moment(date).format('YYYYMMDD')}.log`);
const logFile = paths.pathTo('logs', `info.${format(date, 'yyyyMMdd')}.log`)
const { stdout } = await execAsync(`grep ${flags}"${query}" "${logFile}" | tail -n ${lines}`, options);
return stdout;
}
+2 -2
View File
@@ -1,4 +1,4 @@
import * as moment from 'moment';
import { format } from 'date-fns';
import chalk from 'chalk';
import { IClient } from './serverInterfaces';
import { decodeMovement, dirToVector, flagsToSpeed, isMovingRight } from '../common/movementUtils';
@@ -172,7 +172,7 @@ function checkTeleporting(
const colY = outY ? chalk.red : chalk.reset;
logger.log(
`[${chalk.gray(moment().format('MMM DD HH:mm:ss'))}] [${chalk.yellow('teleport')}] ` +
`[${chalk.gray(format(new Date(), 'MMM dd HH:mm:ss'))}] [${chalk.yellow('teleport')}] ` +
`[${chalk.gray(client.accountId)}] (${client.account.name})\n` +
`\tdx: ${client.lastX.toFixed(5)} -> ${colX(x.toFixed(5))} [${minX.toFixed(5)}-${maxX.toFixed(5)}]\n` +
`\tdy: ${client.lastY.toFixed(5)} -> ${colY(y.toFixed(5))} [${minY.toFixed(5)}-${maxY.toFixed(5)}]\n` +
+4 -2
View File
@@ -1,7 +1,7 @@
import { Request, Response, RequestHandler } from 'express';
import * as fs from 'fs';
import * as path from 'path';
import * as moment from 'moment';
import { formatDistanceToNow } from 'date-fns';
import rateLimit from 'express-rate-limit';
import { noop } from 'lodash';
import { HASH } from '../generated/hash';
@@ -102,7 +102,9 @@ export function limit(freeRetries: number, lifetime: number) {
max: freeRetries,
handler(req, res) {
logger.warn(`rate limit ${req.url} ${req.ip}`);
const retryAfter = moment(Date.now() + lifetime * 1000).fromNow();
const retryAfter = formatDistanceToNow(new Date(Date.now() + lifetime * 1000), {
addSuffix: true
});
res.status(429).send(`Too many requests, please try again ${retryAfter}`);
}
});
+2 -2
View File
@@ -1,11 +1,11 @@
import * as fs from 'fs';
import * as path from 'path';
import * as moment from 'moment';
import { compact } from 'lodash';
import { Request } from 'express';
import { RequestStats, ServerStats } from '../common/adminInterfaces';
import { HOUR } from '../common/constants';
import { ByteSize } from './utils/byteSize';
import { format } from 'date-fns';
interface Stats {
count: number;
@@ -175,7 +175,7 @@ export class StatsTracker {
}
private submitDailyStats(statsPath: string) {
const statsEntry = [
moment().format('MMM DD'), // DD-MM-YY HH:mm:ss
format(new Date(), 'MMM dd'), // DD-MM-YY HH:mm:ss
this.dailyRequestCount.toString(),
this.dailyRequestSize.toString(),
this.dailySwearing.toString(),