Adds DateService using date-fns-tz for robust time zone conversions and date manipulations. Refactors DateCalculator and TimeFormatter to utilize the DateService, centralizing date logic and ensuring consistent time zone handling throughout the application. Improves event dragging by updating time displays and data attributes, handling cross-midnight events correctly.
259 lines
No EOL
8.6 KiB
TypeScript
259 lines
No EOL
8.6 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { DateService } from '../../src/utils/DateService';
|
|
|
|
describe('DateService', () => {
|
|
let dateService: DateService;
|
|
|
|
beforeEach(() => {
|
|
dateService = new DateService('Europe/Copenhagen');
|
|
});
|
|
|
|
describe('Core Conversions', () => {
|
|
it('should convert local date to UTC', () => {
|
|
// 2024-01-15 10:00:00 Copenhagen (UTC+1 in winter)
|
|
const localDate = new Date(2024, 0, 15, 10, 0, 0);
|
|
const utcString = dateService.toUTC(localDate);
|
|
|
|
// Should be 09:00:00 UTC
|
|
expect(utcString).toContain('2024-01-15T09:00:00');
|
|
expect(utcString).toContain('Z');
|
|
});
|
|
|
|
it('should convert UTC to local date', () => {
|
|
const utcString = '2024-01-15T09:00:00.000Z';
|
|
const localDate = dateService.fromUTC(utcString);
|
|
|
|
// Should be 10:00 in Copenhagen (UTC+1)
|
|
expect(localDate.getHours()).toBe(10);
|
|
expect(localDate.getMinutes()).toBe(0);
|
|
});
|
|
|
|
it('should handle summer time (DST)', () => {
|
|
// 2024-07-15 10:00:00 Copenhagen (UTC+2 in summer)
|
|
const localDate = new Date(2024, 6, 15, 10, 0, 0);
|
|
const utcString = dateService.toUTC(localDate);
|
|
|
|
// Should be 08:00:00 UTC
|
|
expect(utcString).toContain('2024-07-15T08:00:00');
|
|
});
|
|
});
|
|
|
|
describe('Time Formatting', () => {
|
|
it('should format time without seconds', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 45);
|
|
const formatted = dateService.formatTime(date);
|
|
|
|
expect(formatted).toBe('14:30');
|
|
});
|
|
|
|
it('should format time with seconds', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 45);
|
|
const formatted = dateService.formatTime(date, true);
|
|
|
|
expect(formatted).toBe('14:30:45');
|
|
});
|
|
|
|
it('should format time range', () => {
|
|
const start = new Date(2024, 0, 15, 9, 0, 0);
|
|
const end = new Date(2024, 0, 15, 10, 30, 0);
|
|
const formatted = dateService.formatTimeRange(start, end);
|
|
|
|
expect(formatted).toBe('09:00 - 10:30');
|
|
});
|
|
|
|
it('should format technical datetime', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 45);
|
|
const formatted = dateService.formatTechnicalDateTime(date);
|
|
|
|
expect(formatted).toBe('2024-01-15 14:30:45');
|
|
});
|
|
|
|
it('should format date as ISO', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 0);
|
|
const formatted = dateService.formatDate(date);
|
|
|
|
expect(formatted).toBe('2024-01-15');
|
|
});
|
|
});
|
|
|
|
describe('Time Calculations', () => {
|
|
it('should convert time string to minutes', () => {
|
|
expect(dateService.timeToMinutes('09:00')).toBe(540);
|
|
expect(dateService.timeToMinutes('14:30')).toBe(870);
|
|
expect(dateService.timeToMinutes('00:00')).toBe(0);
|
|
expect(dateService.timeToMinutes('23:59')).toBe(1439);
|
|
});
|
|
|
|
it('should convert minutes to time string', () => {
|
|
expect(dateService.minutesToTime(540)).toBe('09:00');
|
|
expect(dateService.minutesToTime(870)).toBe('14:30');
|
|
expect(dateService.minutesToTime(0)).toBe('00:00');
|
|
expect(dateService.minutesToTime(1439)).toBe('23:59');
|
|
});
|
|
|
|
it('should get minutes since midnight', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 0);
|
|
const minutes = dateService.getMinutesSinceMidnight(date);
|
|
|
|
expect(minutes).toBe(870); // 14*60 + 30
|
|
});
|
|
|
|
it('should calculate duration in minutes', () => {
|
|
const start = new Date(2024, 0, 15, 9, 0, 0);
|
|
const end = new Date(2024, 0, 15, 10, 30, 0);
|
|
const duration = dateService.getDurationMinutes(start, end);
|
|
|
|
expect(duration).toBe(90);
|
|
});
|
|
|
|
it('should calculate duration from ISO strings', () => {
|
|
const start = '2024-01-15T09:00:00.000Z';
|
|
const end = '2024-01-15T10:30:00.000Z';
|
|
const duration = dateService.getDurationMinutes(start, end);
|
|
|
|
expect(duration).toBe(90);
|
|
});
|
|
});
|
|
|
|
describe('Week Operations', () => {
|
|
it('should get week bounds (Monday to Sunday)', () => {
|
|
// Wednesday, January 17, 2024
|
|
const date = new Date(2024, 0, 17);
|
|
const bounds = dateService.getWeekBounds(date);
|
|
|
|
// Should start on Monday, January 15
|
|
expect(bounds.start.getDate()).toBe(15);
|
|
expect(bounds.start.getDay()).toBe(1); // Monday
|
|
|
|
// Should end on Sunday, January 21
|
|
expect(bounds.end.getDate()).toBe(21);
|
|
expect(bounds.end.getDay()).toBe(0); // Sunday
|
|
});
|
|
|
|
it('should add weeks', () => {
|
|
const date = new Date(2024, 0, 15);
|
|
const newDate = dateService.addWeeks(date, 2);
|
|
|
|
expect(newDate.getDate()).toBe(29);
|
|
});
|
|
|
|
it('should subtract weeks', () => {
|
|
const date = new Date(2024, 0, 15);
|
|
const newDate = dateService.addWeeks(date, -1);
|
|
|
|
expect(newDate.getDate()).toBe(8);
|
|
});
|
|
});
|
|
|
|
describe('Grid Helpers', () => {
|
|
it('should create date at specific time', () => {
|
|
const baseDate = new Date(2024, 0, 15);
|
|
const date = dateService.createDateAtTime(baseDate, 870); // 14:30
|
|
|
|
expect(date.getHours()).toBe(14);
|
|
expect(date.getMinutes()).toBe(30);
|
|
expect(date.getDate()).toBe(15);
|
|
});
|
|
|
|
it('should snap to 15-minute interval', () => {
|
|
const date = new Date(2024, 0, 15, 14, 37, 0); // 14:37
|
|
const snapped = dateService.snapToInterval(date, 15);
|
|
|
|
// 14:37 is closer to 14:30 than 14:45, so should snap to 14:30
|
|
expect(snapped.getHours()).toBe(14);
|
|
expect(snapped.getMinutes()).toBe(30);
|
|
});
|
|
|
|
it('should snap to 30-minute interval', () => {
|
|
const date = new Date(2024, 0, 15, 14, 20, 0); // 14:20
|
|
const snapped = dateService.snapToInterval(date, 30);
|
|
|
|
// Should snap to 14:30
|
|
expect(snapped.getHours()).toBe(14);
|
|
expect(snapped.getMinutes()).toBe(30);
|
|
});
|
|
});
|
|
|
|
describe('Utility Methods', () => {
|
|
it('should check if same day', () => {
|
|
const date1 = new Date(2024, 0, 15, 10, 0, 0);
|
|
const date2 = new Date(2024, 0, 15, 14, 30, 0);
|
|
const date3 = new Date(2024, 0, 16, 10, 0, 0);
|
|
|
|
expect(dateService.isSameDay(date1, date2)).toBe(true);
|
|
expect(dateService.isSameDay(date1, date3)).toBe(false);
|
|
});
|
|
|
|
it('should get start of day', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 45);
|
|
const start = dateService.startOfDay(date);
|
|
|
|
expect(start.getHours()).toBe(0);
|
|
expect(start.getMinutes()).toBe(0);
|
|
expect(start.getSeconds()).toBe(0);
|
|
});
|
|
|
|
it('should get end of day', () => {
|
|
const date = new Date(2024, 0, 15, 14, 30, 45);
|
|
const end = dateService.endOfDay(date);
|
|
|
|
expect(end.getHours()).toBe(23);
|
|
expect(end.getMinutes()).toBe(59);
|
|
expect(end.getSeconds()).toBe(59);
|
|
});
|
|
|
|
it('should add days', () => {
|
|
const date = new Date(2024, 0, 15);
|
|
const newDate = dateService.addDays(date, 5);
|
|
|
|
expect(newDate.getDate()).toBe(20);
|
|
});
|
|
|
|
it('should add minutes', () => {
|
|
const date = new Date(2024, 0, 15, 10, 0, 0);
|
|
const newDate = dateService.addMinutes(date, 90);
|
|
|
|
expect(newDate.getHours()).toBe(11);
|
|
expect(newDate.getMinutes()).toBe(30);
|
|
});
|
|
|
|
it('should parse ISO string', () => {
|
|
const isoString = '2024-01-15T10:30:00.000Z';
|
|
const date = dateService.parseISO(isoString);
|
|
|
|
expect(date.toISOString()).toBe(isoString);
|
|
});
|
|
|
|
it('should validate dates', () => {
|
|
const validDate = new Date(2024, 0, 15);
|
|
const invalidDate = new Date('invalid');
|
|
|
|
expect(dateService.isValid(validDate)).toBe(true);
|
|
expect(dateService.isValid(invalidDate)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle midnight', () => {
|
|
const date = new Date(2024, 0, 15, 0, 0, 0);
|
|
const minutes = dateService.getMinutesSinceMidnight(date);
|
|
|
|
expect(minutes).toBe(0);
|
|
});
|
|
|
|
it('should handle end of day', () => {
|
|
const date = new Date(2024, 0, 15, 23, 59, 0);
|
|
const minutes = dateService.getMinutesSinceMidnight(date);
|
|
|
|
expect(minutes).toBe(1439);
|
|
});
|
|
|
|
it('should handle cross-midnight duration', () => {
|
|
const start = new Date(2024, 0, 15, 23, 0, 0);
|
|
const end = new Date(2024, 0, 16, 1, 0, 0);
|
|
const duration = dateService.getDurationMinutes(start, end);
|
|
|
|
expect(duration).toBe(120); // 2 hours
|
|
});
|
|
});
|
|
}); |