Time-related utilities and performance helpers providing timestamp generation and timing operations for applications.
Utilities for generating and working with timestamps.
/**
* Get current timestamp in milliseconds
* @returns Current timestamp as number (equivalent to +Date.now())
*/
function timestamp(): number;Usage Examples:
import { timestamp } from "@antfu/utils";
// Basic timestamp usage
const now = timestamp(); // e.g., 1703123456789
console.log('Current time:', now);
// Performance measurement
const startTime = timestamp();
await someAsyncOperation();
const endTime = timestamp();
const duration = endTime - startTime;
console.log(`Operation took ${duration}ms`);
// Event logging
function logEvent(eventType: string, data: any): void {
const entry = {
type: eventType,
data,
timestamp: timestamp(),
id: generateId()
};
eventLog.push(entry);
}
// Cache expiration
class TimestampCache<T> {
private cache = new Map<string, { value: T; timestamp: number }>();
private ttl = 5 * 60 * 1000; // 5 minutes
set(key: string, value: T): void {
this.cache.set(key, {
value,
timestamp: timestamp()
});
}
get(key: string): T | null {
const entry = this.cache.get(key);
if (!entry) return null;
const now = timestamp();
if (now - entry.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return entry.value;
}
cleanup(): void {
const now = timestamp();
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > this.ttl) {
this.cache.delete(key);
}
}
}
}
// Rate limiting
class RateLimiter {
private requests = new Map<string, number[]>();
private windowMs = 60 * 1000; // 1 minute
private maxRequests = 100;
isAllowed(clientId: string): boolean {
const now = timestamp();
const clientRequests = this.requests.get(clientId) || [];
// Remove old requests outside the time window
const validRequests = clientRequests.filter(
requestTime => now - requestTime < this.windowMs
);
if (validRequests.length >= this.maxRequests) {
return false;
}
validRequests.push(now);
this.requests.set(clientId, validRequests);
return true;
}
}
// Session management
class SessionManager {
private sessions = new Map<string, {
userId: string;
createdAt: number;
lastActivity: number;
}>();
createSession(userId: string): string {
const sessionId = generateSessionId();
const now = timestamp();
this.sessions.set(sessionId, {
userId,
createdAt: now,
lastActivity: now
});
return sessionId;
}
updateActivity(sessionId: string): boolean {
const session = this.sessions.get(sessionId);
if (!session) return false;
session.lastActivity = timestamp();
return true;
}
isSessionValid(sessionId: string, maxAgeMs: number = 24 * 60 * 60 * 1000): boolean {
const session = this.sessions.get(sessionId);
if (!session) return false;
const now = timestamp();
return (now - session.lastActivity) < maxAgeMs;
}
getSessionAge(sessionId: string): number | null {
const session = this.sessions.get(sessionId);
if (!session) return null;
return timestamp() - session.createdAt;
}
}
// Metrics collection
class MetricsCollector {
private metrics: Array<{
name: string;
value: number;
timestamp: number;
tags?: Record<string, string>;
}> = [];
record(name: string, value: number, tags?: Record<string, string>): void {
this.metrics.push({
name,
value,
timestamp: timestamp(),
tags
});
}
timer(name: string, tags?: Record<string, string>) {
const startTime = timestamp();
return {
end: () => {
const duration = timestamp() - startTime;
this.record(name, duration, { ...tags, unit: 'ms' });
}
};
}
getMetricsInRange(startTime: number, endTime: number) {
return this.metrics.filter(
metric => metric.timestamp >= startTime && metric.timestamp <= endTime
);
}
}
// Usage examples
const metrics = new MetricsCollector();
// Time a function
const timer = metrics.timer('api.user.fetch');
await fetchUser('123');
timer.end();
// Record custom metrics
metrics.record('active.users', 1543, { region: 'us-east' });
metrics.record('response.size', 2048, { endpoint: '/api/data' });
// Scheduled tasks
class TaskScheduler {
private tasks: Array<{
id: string;
fn: () => void | Promise<void>;
interval: number;
lastRun: number;
}> = [];
addTask(id: string, fn: () => void | Promise<void>, intervalMs: number): void {
this.tasks.push({
id,
fn,
interval: intervalMs,
lastRun: 0
});
}
async runDueTasks(): Promise<void> {
const now = timestamp();
for (const task of this.tasks) {
if (now - task.lastRun >= task.interval) {
try {
await task.fn();
task.lastRun = now;
} catch (error) {
console.error(`Task ${task.id} failed:`, error);
}
}
}
}
removeTask(id: string): void {
const index = this.tasks.findIndex(task => task.id === id);
if (index !== -1) {
this.tasks.splice(index, 1);
}
}
}
// File modification tracking
class FileWatcher {
private lastModified = new Map<string, number>();
hasChanged(filePath: string, currentModTime: number): boolean {
const lastMod = this.lastModified.get(filePath);
this.lastModified.set(filePath, currentModTime);
return lastMod !== undefined && lastMod !== currentModTime;
}
recordAccess(filePath: string): void {
this.lastModified.set(filePath, timestamp());
}
}
// Profiling utility
class Profiler {
private profiles = new Map<string, {
count: number;
totalTime: number;
minTime: number;
maxTime: number;
lastRun: number;
}>();
profile<T>(name: string, fn: () => T): T {
const startTime = timestamp();
try {
const result = fn();
const endTime = timestamp();
this.recordExecution(name, endTime - startTime);
return result;
} catch (error) {
const endTime = timestamp();
this.recordExecution(name, endTime - startTime);
throw error;
}
}
async profileAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
const startTime = timestamp();
try {
const result = await fn();
const endTime = timestamp();
this.recordExecution(name, endTime - startTime);
return result;
} catch (error) {
const endTime = timestamp();
this.recordExecution(name, endTime - startTime);
throw error;
}
}
private recordExecution(name: string, duration: number): void {
const existing = this.profiles.get(name);
if (existing) {
existing.count++;
existing.totalTime += duration;
existing.minTime = Math.min(existing.minTime, duration);
existing.maxTime = Math.max(existing.maxTime, duration);
existing.lastRun = timestamp();
} else {
this.profiles.set(name, {
count: 1,
totalTime: duration,
minTime: duration,
maxTime: duration,
lastRun: timestamp()
});
}
}
getStats(name: string) {
const profile = this.profiles.get(name);
if (!profile) return null;
return {
count: profile.count,
avgTime: profile.totalTime / profile.count,
minTime: profile.minTime,
maxTime: profile.maxTime,
totalTime: profile.totalTime,
lastRun: profile.lastRun
};
}
getAllStats() {
const stats: Record<string, any> = {};
for (const [name, profile] of this.profiles) {
stats[name] = this.getStats(name);
}
return stats;
}
}
// Usage
const profiler = new Profiler();
// Profile synchronous functions
const result = profiler.profile('expensive-calculation', () => {
return performExpensiveCalculation();
});
// Profile async functions
const data = await profiler.profileAsync('api-call', async () => {
return await fetch('/api/data').then(r => r.json());
});
// View performance statistics
console.log(profiler.getStats('api-call'));
console.log(profiler.getAllStats());