1
0
Fork 0

Fix time formatting

This commit is contained in:
Pabloader 2026-04-10 14:50:00 +00:00
parent 87f582590b
commit 7148254b35
4 changed files with 121 additions and 14 deletions

View File

@ -59,6 +59,7 @@ Bun.serve<ClientData>({
clients.delete(ws); clients.delete(ws);
if (clients.size === 0) wsClients.delete(game); if (clients.size === 0) wsClients.delete(game);
} }
console.log(`[css-hot] ${game} disconnected (${wsClients.get(game)!.size} clients)`);
}, },
message() { }, message() { },
}, },

View File

@ -4,7 +4,7 @@
"version": "1.0.0", "version": "1.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "bun --hot build/server.ts", "start": "bun build/server.ts",
"bake": "bun build/build.ts", "bake": "bun build/build.ts",
"test": "bun test" "test": "bun test"
}, },

View File

@ -120,13 +120,25 @@ export const formatNumber = (n: number): string => {
}; };
export const formatTime = (seconds: number): string => { export const formatTime = (seconds: number): string => {
const y = Math.floor(seconds / 31536000); const secInMinute = 60;
const mo = Math.floor((seconds % 31536000) / 2592000); const secInHour = 60 * secInMinute;
const w = Math.floor((seconds % 2592000) / 604800); const secInDay = 24 * secInHour;
const d = Math.floor((seconds % 604800) / 86400); const secInWeek = 7 * secInDay;
const h = Math.floor((seconds % 86400) / 3600); const secInMonth = 30 * secInDay;
const mi = Math.floor((seconds % 3600) / 60); const secInYear = 365 * secInDay;
const s = Math.floor(seconds % 60);
const y = Math.floor(seconds / secInYear);
let rem = seconds % secInYear;
const mo = Math.floor(rem / secInMonth);
rem %= secInMonth;
const w = Math.floor(rem / secInWeek);
rem %= secInWeek;
const d = Math.floor(rem / secInDay);
rem %= secInDay;
const h = Math.floor(rem / secInHour);
rem %= secInHour;
const mi = Math.floor(rem / secInMinute);
const s = Math.floor(rem % secInMinute);
const parts: string[] = []; const parts: string[] = [];
if (y > 0) parts.push(`${y}y`); if (y > 0) parts.push(`${y}y`);
@ -135,9 +147,10 @@ export const formatTime = (seconds: number): string => {
if (d > 0) parts.push(`${d}d`); if (d > 0) parts.push(`${d}d`);
const hasBigParts = parts.length > 0; const hasBigParts = parts.length > 0;
const hasTime = h > 0 || mi > 0 || s > 0; const timeStr = hasBigParts || h > 0
if (hasBigParts || hasTime) { ? `${h}:${String(mi).padStart(2, '0')}:${String(s).padStart(2, '0')}`
parts.push(`${h}:${String(mi).padStart(2, '0')}:${String(s).padStart(2, '0')}`); : `${mi}:${String(s).padStart(2, '0')}`;
}
return parts.join(' ') || '0:00:00'; parts.push(timeStr);
return parts.join(' ');
}; };

View File

@ -16,6 +16,8 @@ import {
sinHash, sinHash,
throttle, throttle,
callUpdater, callUpdater,
formatTime,
formatNumber,
} from '@common/utils'; } from '@common/utils';
describe('utils', () => { describe('utils', () => {
@ -268,7 +270,13 @@ describe('utils', () => {
it('should be deterministic', () => { it('should be deterministic', () => {
const hash1 = sinHash(1, 2, 3); const hash1 = sinHash(1, 2, 3);
const hash2 = sinHash(1, 2, 3); const hash2 = sinHash(1, 2, 3);
expect(hash1).toBe(hash2); expect(hash1).toBeCloseTo(hash2);
});
it('should produce different hashes for different inputs', () => {
const hash1 = sinHash(1, 2, 3);
const hash2 = sinHash(4, 5, 6);
expect(hash1).not.toBeCloseTo(hash2);
}); });
}); });
@ -300,4 +308,89 @@ describe('utils', () => {
expect(callUpdater(10, 5)).toBe(10); expect(callUpdater(10, 5)).toBe(10);
}); });
}); });
describe('formatNumber', () => {
it('should return small numbers as-is', () => {
expect(formatNumber(0)).toBe('0');
expect(formatNumber(42)).toBe('42');
expect(formatNumber(999)).toBe('999');
});
it('should format thousands with k suffix', () => {
expect(formatNumber(1_000)).toBe('1.00k');
expect(formatNumber(5_500)).toBe('5.50k');
expect(formatNumber(999_999)).toBe('1000.00k');
});
it('should format millions with M suffix', () => {
expect(formatNumber(1_000_000)).toBe('1.00M');
expect(formatNumber(2_500_000)).toBe('2.50M');
expect(formatNumber(999_999_999)).toBe('1000.00M');
});
it('should format billions with B suffix', () => {
expect(formatNumber(1_000_000_000)).toBe('1.00B');
expect(formatNumber(3_750_000_000)).toBe('3.75B');
expect(formatNumber(999_999_999_999)).toBe('1000.00B');
});
it('should format trillions with T suffix', () => {
expect(formatNumber(1_000_000_000_000)).toBe('1.00T');
expect(formatNumber(5_250_000_000_000)).toBe('5.25T');
});
});
describe('formatTime', () => {
it('should return 0:00 for zero seconds', () => {
expect(formatTime(0)).toBe('0:00');
});
it('should format seconds correctly', () => {
expect(formatTime(1)).toBe('0:01');
expect(formatTime(30)).toBe('0:30');
expect(formatTime(59)).toBe('0:59');
});
it('should format minutes correctly', () => {
expect(formatTime(60)).toBe('1:00');
expect(formatTime(2 * 60 + 5)).toBe('2:05');
expect(formatTime(59 * 60 + 59)).toBe('59:59');
});
it('should format hours correctly', () => {
expect(formatTime(60 * 60)).toBe('1:00:00');
expect(formatTime(2 * 60 * 60 + 60 + 5)).toBe('2:01:05');
});
it('should format days correctly', () => {
expect(formatTime(24 * 60 * 60)).toBe('1d 0:00:00');
expect(formatTime(2 * 24 * 60 * 60)).toBe('2d 0:00:00');
});
it('should format weeks correctly', () => {
expect(formatTime(7 * 24 * 60 * 60)).toBe('1w 0:00:00');
});
it('should format months correctly', () => {
const month = 30 * 24 * 60 * 60;
expect(formatTime(month)).toBe('1m 0:00:00');
});
it('should format years correctly', () => {
const year = 365 * 24 * 60 * 60;
expect(formatTime(year)).toBe('1y 0:00:00');
});
it('should format complex durations', () => {
const total =
365 * 24 * 60 * 60 + // 1y
30 * 24 * 60 * 60 + // 1m
7 * 24 * 60 * 60 + // 1w
24 * 60 * 60 + // 1d
60 * 60 + // 1h
60 + // 1m
1; // 1s
expect(formatTime(total)).toBe('1y 1m 1w 1d 1:01:01');
});
});
}); });