2025-10-03 16:05:22 +02:00
|
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
|
|
|
import { TimeFormatter } from '../../src/utils/TimeFormatter';
|
|
|
|
|
|
|
|
|
|
describe('TimeFormatter', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
// Reset to default settings before each test
|
|
|
|
|
TimeFormatter.configure({
|
|
|
|
|
timezone: 'Europe/Copenhagen',
|
|
|
|
|
use24HourFormat: true,
|
|
|
|
|
locale: 'da-DK',
|
|
|
|
|
dateFormat: 'technical',
|
|
|
|
|
showSeconds: false
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Time Formatting', () => {
|
|
|
|
|
it('should format time in 24-hour format', () => {
|
|
|
|
|
let date = new Date('2025-01-15T10:30:00Z');
|
2025-10-30 23:47:30 +01:00
|
|
|
let formatted = TimeFormatter.formatTime(date);
|
|
|
|
|
|
2025-10-03 16:05:22 +02:00
|
|
|
// Should be 11:30 in Copenhagen (UTC+1 in winter)
|
|
|
|
|
expect(formatted).toBe('11:30');
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
it('should format time at midnight', () => {
|
|
|
|
|
let date = new Date('2025-01-15T23:00:00Z');
|
|
|
|
|
let formatted = TimeFormatter.formatTime(date);
|
2025-10-03 16:05:22 +02:00
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
// Should be 00:00 next day in Copenhagen
|
|
|
|
|
expect(formatted).toBe('00:00');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should format time range correctly', () => {
|
|
|
|
|
let startDate = new Date('2025-01-15T08:00:00Z');
|
|
|
|
|
let endDate = new Date('2025-01-15T10:00:00Z');
|
|
|
|
|
let formatted = TimeFormatter.formatTimeRange(startDate, endDate);
|
2025-10-30 23:47:30 +01:00
|
|
|
|
2025-10-03 16:05:22 +02:00
|
|
|
// 08:00 UTC = 09:00 CET, 10:00 UTC = 11:00 CET
|
|
|
|
|
expect(formatted).toBe('09:00 - 11:00');
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
it('should format time range across midnight', () => {
|
|
|
|
|
let startDate = new Date('2025-01-15T22:00:00Z');
|
|
|
|
|
let endDate = new Date('2025-01-16T01:00:00Z');
|
|
|
|
|
let formatted = TimeFormatter.formatTimeRange(startDate, endDate);
|
2025-10-03 16:05:22 +02:00
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
// 22:00 UTC = 23:00 CET, 01:00 UTC = 02:00 CET next day
|
|
|
|
|
expect(formatted).toBe('23:00 - 02:00');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Configuration', () => {
|
2025-10-30 23:47:30 +01:00
|
|
|
it('should respect timezone configuration', () => {
|
2025-10-03 16:05:22 +02:00
|
|
|
TimeFormatter.configure({ timezone: 'America/New_York' });
|
|
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
let date = new Date('2025-01-15T10:00:00Z');
|
2025-10-03 16:05:22 +02:00
|
|
|
let formatted = TimeFormatter.formatTime(date);
|
2025-10-30 23:47:30 +01:00
|
|
|
|
|
|
|
|
// 10:00 UTC = 05:00 EST (UTC-5 in winter)
|
|
|
|
|
expect(formatted).toBe('05:00');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
|
2025-10-30 23:47:30 +01:00
|
|
|
it('should respect showSeconds configuration', () => {
|
|
|
|
|
TimeFormatter.configure({ showSeconds: true });
|
|
|
|
|
|
|
|
|
|
let date = new Date('2025-01-15T10:30:45Z');
|
2025-10-03 16:05:22 +02:00
|
|
|
let formatted = TimeFormatter.formatTime(date);
|
2025-10-30 23:47:30 +01:00
|
|
|
|
|
|
|
|
// Should include seconds
|
|
|
|
|
expect(formatted).toBe('11:30:45');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Edge Cases', () => {
|
|
|
|
|
it('should handle DST transition correctly (spring forward)', () => {
|
|
|
|
|
// March 30, 2025 01:00:00 UTC is when Copenhagen springs forward
|
|
|
|
|
let beforeDST = new Date('2025-03-30T00:59:00Z');
|
|
|
|
|
let afterDST = new Date('2025-03-30T01:01:00Z');
|
2025-10-30 23:47:30 +01:00
|
|
|
|
|
|
|
|
let beforeFormatted = TimeFormatter.formatTime(beforeDST);
|
|
|
|
|
let afterFormatted = TimeFormatter.formatTime(afterDST);
|
|
|
|
|
|
2025-10-03 16:05:22 +02:00
|
|
|
// Before: 00:59 UTC = 01:59 CET
|
|
|
|
|
// After: 01:01 UTC = 03:01 CEST (jumped from 02:00 to 03:00)
|
2025-10-30 23:47:30 +01:00
|
|
|
expect(beforeFormatted).toBe('01:59');
|
|
|
|
|
expect(afterFormatted).toBe('03:01');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle DST transition correctly (fall back)', () => {
|
|
|
|
|
// October 26, 2025 01:00:00 UTC is when Copenhagen falls back
|
|
|
|
|
let beforeDST = new Date('2025-10-26T00:59:00Z');
|
|
|
|
|
let afterDST = new Date('2025-10-26T01:01:00Z');
|
2025-10-30 23:47:30 +01:00
|
|
|
|
|
|
|
|
let beforeFormatted = TimeFormatter.formatTime(beforeDST);
|
|
|
|
|
let afterFormatted = TimeFormatter.formatTime(afterDST);
|
|
|
|
|
|
2025-10-03 16:05:22 +02:00
|
|
|
// Before: 00:59 UTC = 02:59 CEST
|
|
|
|
|
// After: 01:01 UTC = 02:01 CET (fell back from 03:00 to 02:00)
|
2025-10-30 23:47:30 +01:00
|
|
|
expect(beforeFormatted).toBe('02:59');
|
|
|
|
|
expect(afterFormatted).toBe('02:01');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle year boundary correctly', () => {
|
|
|
|
|
// December 31, 2024 23:30:00 UTC = January 1, 2025 00:30:00 CET
|
2025-10-30 23:47:30 +01:00
|
|
|
let date = new Date('2024-12-31T23:30:00Z');
|
|
|
|
|
let formatted = TimeFormatter.formatTime(date);
|
|
|
|
|
|
|
|
|
|
expect(formatted).toBe('00:30');
|
2025-10-03 16:05:22 +02:00
|
|
|
});
|
|
|
|
|
});
|
2025-10-30 23:47:30 +01:00
|
|
|
});
|