fix(calendar): mark today and past days from the Europe/Paris date #312
No files matched your search
@@ -34,7 +34,7 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
[attr.data-date]="dateKey"
|
[attr.data-date]="dateKey"
|
||||||
[class.past]="day < getNow()"
|
[class.past]="dateKey < today"
|
||||||
[class.start]="selectedDates.isStart(day)"
|
[class.start]="selectedDates.isStart(day)"
|
||||||
[class.end]="selectedDates.isEnd(day)"
|
[class.end]="selectedDates.isEnd(day)"
|
||||||
[class.selected]="selectedDates.isSelected(day)"
|
[class.selected]="selectedDates.isSelected(day)"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { provideZonelessChangeDetection } from '@angular/core';
|
import { provideZonelessChangeDetection } from '@angular/core';
|
||||||
|
import { SelectedDates } from '../../services/calendar-service';
|
||||||
import { CalendarMonth } from './calendar-month';
|
import { CalendarMonth } from './calendar-month';
|
||||||
|
|
||||||
describe('CalendarMonth', () => {
|
describe('CalendarMonth', () => {
|
||||||
@@ -20,4 +21,20 @@ describe('CalendarMonth', () => {
|
|||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('styles only the dates before the given today as past', () => {
|
||||||
|
const monthFixture = TestBed.createComponent(CalendarMonth);
|
||||||
|
monthFixture.componentRef.setInput('monthIndex', 9);
|
||||||
|
monthFixture.componentRef.setInput('year', 2026);
|
||||||
|
monthFixture.componentRef.setInput('selectedDates', new SelectedDates());
|
||||||
|
monthFixture.componentRef.setInput('today', '2026-10-18');
|
||||||
|
monthFixture.detectChanges();
|
||||||
|
const button = (date: string) =>
|
||||||
|
(monthFixture.nativeElement as HTMLElement).querySelector(
|
||||||
|
`button[data-date="${date}"]`,
|
||||||
|
)!;
|
||||||
|
expect(button('2026-10-17').classList).toContain('past');
|
||||||
|
expect(button('2026-10-18').classList).not.toContain('past');
|
||||||
|
expect(button('2026-10-19').classList).not.toContain('past');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import { CalendarService, Month, SelectedDates } from '../../services/calendar-service';
|
import { CalendarService, Month, SelectedDates } from '../../services/calendar-service';
|
||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
import { CalendarSettingsService } from '../../services/calendar-settings-service';
|
import { CalendarSettingsService } from '../../services/calendar-settings-service';
|
||||||
import { DateCacheService } from '../../services/date-cache.service';
|
|
||||||
import { TranslationService } from '../../services/translation-service';
|
import { TranslationService } from '../../services/translation-service';
|
||||||
import { isWorkingPlanningDate } from '../../services/declared-non-working-days';
|
import { isWorkingPlanningDate } from '../../services/declared-non-working-days';
|
||||||
import type { LeaveType } from '../../services/leave-planner.service';
|
import type { LeaveType } from '../../services/leave-planner.service';
|
||||||
@@ -29,7 +28,6 @@ export interface DeclarationPreview {
|
|||||||
})
|
})
|
||||||
export class CalendarMonth implements OnInit {
|
export class CalendarMonth implements OnInit {
|
||||||
protected calendarSettingsService = inject(CalendarSettingsService);
|
protected calendarSettingsService = inject(CalendarSettingsService);
|
||||||
private dateCache = inject(DateCacheService);
|
|
||||||
protected translationService = inject(TranslationService);
|
protected translationService = inject(TranslationService);
|
||||||
|
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
@@ -42,11 +40,6 @@ export class CalendarMonth implements OnInit {
|
|||||||
return this.translationService.tr;
|
return this.translationService.tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use DateCacheService instead of creating Date objects
|
|
||||||
getNow(): Date {
|
|
||||||
return this.dateCache.getNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
currentMonth: Date = new Date();
|
currentMonth: Date = new Date();
|
||||||
|
|
||||||
weeksInAMonth: Month = [];
|
weeksInAMonth: Month = [];
|
||||||
@@ -56,6 +49,9 @@ export class CalendarMonth implements OnInit {
|
|||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
selectedDates!: SelectedDates;
|
selectedDates!: SelectedDates;
|
||||||
|
|
||||||
|
@Input({ required: true })
|
||||||
|
today!: string;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
horizonStart?: string;
|
horizonStart?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -608,6 +608,7 @@
|
|||||||
[monthIndex]="month.monthIndex"
|
[monthIndex]="month.monthIndex"
|
||||||
[year]="month.year"
|
[year]="month.year"
|
||||||
[selectedDates]="calendarSelectedDates()"
|
[selectedDates]="calendarSelectedDates()"
|
||||||
|
[today]="calendarProjection()?.today ?? ''"
|
||||||
[horizonStart]="calendarHorizon()?.start"
|
[horizonStart]="calendarHorizon()?.start"
|
||||||
[horizonEnd]="calendarHorizon()?.end"
|
[horizonEnd]="calendarHorizon()?.end"
|
||||||
[declarationEntry]="declarationEntry()"
|
[declarationEntry]="declarationEntry()"
|
||||||
|
|||||||
@@ -150,14 +150,14 @@ describe('CalendarService', () => {
|
|||||||
|
|
||||||
describe('getHolidays', () => {
|
describe('getHolidays', () => {
|
||||||
it('should return an array of holidays', () => {
|
it('should return an array of holidays', () => {
|
||||||
const holidays = service.getHolidays();
|
const holidays = service.getHolidays(2026);
|
||||||
expect(Array.isArray(holidays)).toBe(true);
|
expect(Array.isArray(holidays)).toBe(true);
|
||||||
expect(holidays.length).toBeGreaterThan(0);
|
expect(holidays.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should cache holidays for the same year', () => {
|
it('should cache holidays for the same year', () => {
|
||||||
const holidays1 = service.getHolidays();
|
const holidays1 = service.getHolidays(2026);
|
||||||
const holidays2 = service.getHolidays();
|
const holidays2 = service.getHolidays(2026);
|
||||||
expect(holidays1).toEqual(holidays2);
|
expect(holidays1).toEqual(holidays2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -179,11 +179,6 @@ describe('CalendarService', () => {
|
|||||||
expect(months.length).toBe(12);
|
expect(months.length).toBe(12);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should calculate months from now', () => {
|
|
||||||
const months = service.monthsInAYearFromNow();
|
|
||||||
expect(months.length).toBe(12);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return week number for a date', () => {
|
it('should return week number for a date', () => {
|
||||||
const date = new Date(2024, 0, 1);
|
const date = new Date(2024, 0, 1);
|
||||||
const weekNumber = CalendarService.getWeekNumber(date);
|
const weekNumber = CalendarService.getWeekNumber(date);
|
||||||
@@ -193,20 +188,44 @@ describe('CalendarService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('project', () => {
|
describe('project', () => {
|
||||||
const project = (horizon: { start: string; end: string }) =>
|
const project = (
|
||||||
service.project({ placements: [], horizon });
|
horizon: { start: string; end: string },
|
||||||
|
options?: Parameters<typeof service.project>[1],
|
||||||
|
) => service.project({ placements: [], horizon }, options);
|
||||||
const day = (key: string) => new Date(`${key}T00:00:00`);
|
const day = (key: string) => new Date(`${key}T00:00:00`);
|
||||||
|
|
||||||
it('projects weekends, holidays and today for the default planning horizon', () => {
|
it('projects weekends, holidays and today for the default planning horizon', () => {
|
||||||
const { selections } = project({ start: '2026-01-01', end: '2027-01-01' });
|
const { selections } = project({ start: '2026-01-01', end: '2027-01-01' });
|
||||||
expect(selections.dayTypes(day('2026-05-09'))).toContain(DayType.WEEKEND);
|
expect(selections.dayTypes(day('2026-05-09'))).toContain(DayType.WEEKEND);
|
||||||
expect(selections.dayTypes(day('2026-05-01'))).toContain(DayType.CLOSED_DAY);
|
expect(selections.dayTypes(day('2026-05-01'))).toContain(DayType.CLOSED_DAY);
|
||||||
const horizon = service.getDefaultPlanningHorizon();
|
const now = new Date();
|
||||||
expect(project(horizon).selections.getClasses(day(horizon.start))).toContain(
|
const horizon = service.getDefaultPlanningHorizon(now);
|
||||||
|
expect(project(horizon, { now }).selections.getClasses(day(horizon.start))).toContain(
|
||||||
DayType.TODAY,
|
DayType.TODAY,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('marks the Europe/Paris date as today when the device is in UTC', () => {
|
||||||
|
const previousTimeZone = process.env['TZ'];
|
||||||
|
process.env['TZ'] = 'UTC';
|
||||||
|
try {
|
||||||
|
const now = new Date('2026-10-17T22:16:00Z');
|
||||||
|
const horizon = service.getDefaultPlanningHorizon(now);
|
||||||
|
expect(horizon.start).toBe('2026-10-18');
|
||||||
|
const projection = project(horizon, { now });
|
||||||
|
expect(projection.today).toBe('2026-10-18');
|
||||||
|
expect(projection.selections.getClasses(day('2026-10-18'))).toContain(
|
||||||
|
DayType.TODAY,
|
||||||
|
);
|
||||||
|
expect(projection.selections.getClasses(day('2026-10-17'))).not.toContain(
|
||||||
|
DayType.TODAY,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
if (previousTimeZone === undefined) delete process.env['TZ'];
|
||||||
|
else process.env['TZ'] = previousTimeZone;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('lists the covered months, including partial boundary months and year changes', () => {
|
it('lists the covered months, including partial boundary months and year changes', () => {
|
||||||
expect(project({ start: '2024-11-20', end: '2025-02-02' }).months).toEqual([
|
expect(project({ start: '2024-11-20', end: '2025-02-02' }).months).toEqual([
|
||||||
{ monthIndex: 10, year: 2024 },
|
{ monthIndex: 10, year: 2024 },
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Injectable, inject } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { DateRange } from '@angular/material/datepicker';
|
import { DateRange } from '@angular/material/datepicker';
|
||||||
import { frenchPublicHolidaysForYear, isWorkingPlanningDate } from './declared-non-working-days';
|
import { frenchPublicHolidaysForYear, isWorkingPlanningDate } from './declared-non-working-days';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
||||||
import isoWeek from 'dayjs/plugin/isoWeek';
|
import isoWeek from 'dayjs/plugin/isoWeek';
|
||||||
import { DateCacheService } from './date-cache.service';
|
|
||||||
import {
|
import {
|
||||||
createPlanningCalculation as createPlanningCalculationOperation,
|
createPlanningCalculation as createPlanningCalculationOperation,
|
||||||
planLeave as planLeaveOperation,
|
planLeave as planLeaveOperation,
|
||||||
@@ -55,14 +54,13 @@ export function calendarProjectionHorizon(plan: CalendarPlan) {
|
|||||||
export interface CalendarProjection {
|
export interface CalendarProjection {
|
||||||
months: { monthIndex: number; year: number }[];
|
months: { monthIndex: number; year: number }[];
|
||||||
selections: SelectedDates;
|
selections: SelectedDates;
|
||||||
|
today: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class CalendarService {
|
export class CalendarService {
|
||||||
private dateCache = inject(DateCacheService);
|
|
||||||
|
|
||||||
readonly planLeave = planLeaveOperation;
|
readonly planLeave = planLeaveOperation;
|
||||||
readonly createPlanningCalculation = createPlanningCalculationOperation;
|
readonly createPlanningCalculation = createPlanningCalculationOperation;
|
||||||
|
|
||||||
@@ -74,7 +72,7 @@ export class CalendarService {
|
|||||||
/** `fixedMonths` lists only the plan horizon's months, so editing declarations never adds a month. */
|
/** `fixedMonths` lists only the plan horizon's months, so editing declarations never adds a month. */
|
||||||
project(
|
project(
|
||||||
plan: CalendarPlan & { horizon: PlanningStateSnapshot['horizon'] },
|
plan: CalendarPlan & { horizon: PlanningStateSnapshot['horizon'] },
|
||||||
{ fixedMonths = false } = {},
|
{ fixedMonths = false, now = new Date() } = {},
|
||||||
): CalendarProjection {
|
): CalendarProjection {
|
||||||
const horizon = calendarProjectionHorizon(plan)!;
|
const horizon = calendarProjectionHorizon(plan)!;
|
||||||
const firstMonth = plan.horizon.start.slice(0, 7);
|
const firstMonth = plan.horizon.start.slice(0, 7);
|
||||||
@@ -85,11 +83,8 @@ export class CalendarService {
|
|||||||
const holidays = new Set(
|
const holidays = new Set(
|
||||||
this.getHolidays(first.getFullYear(), last.getFullYear()).map((h) => h.getTime()),
|
this.getHolidays(first.getFullYear(), last.getFullYear()).map((h) => h.getTime()),
|
||||||
);
|
);
|
||||||
const {
|
const today = planningDateInParis(now);
|
||||||
date: todayDate,
|
const todayTime = new Date(`${today}T00:00:00`).getTime();
|
||||||
month: todayMonth,
|
|
||||||
year: todayYear,
|
|
||||||
} = this.dateCache.getTodayComponents();
|
|
||||||
const months: CalendarProjection['months'] = [];
|
const months: CalendarProjection['months'] = [];
|
||||||
const ranges: SelectedDate[] = [];
|
const ranges: SelectedDate[] = [];
|
||||||
const cursor = new Date(first);
|
const cursor = new Date(first);
|
||||||
@@ -122,11 +117,7 @@ export class CalendarService {
|
|||||||
ranges.push(
|
ranges.push(
|
||||||
new SelectedDate(DayType.CLOSED_DAY, new DateRange<Date>(day, day)),
|
new SelectedDate(DayType.CLOSED_DAY, new DateRange<Date>(day, day)),
|
||||||
);
|
);
|
||||||
if (
|
if (day.getTime() === todayTime)
|
||||||
day.getDate() === todayDate &&
|
|
||||||
day.getMonth() === todayMonth &&
|
|
||||||
day.getFullYear() === todayYear
|
|
||||||
)
|
|
||||||
ranges.push(new SelectedDate(DayType.TODAY, new DateRange<Date>(day, day)));
|
ranges.push(new SelectedDate(DayType.TODAY, new DateRange<Date>(day, day)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,10 +137,10 @@ export class CalendarService {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return { months, selections: new SelectedDates(ranges) };
|
return { months, selections: new SelectedDates(ranges), today };
|
||||||
}
|
}
|
||||||
|
|
||||||
getHolidays(startYear = this.dateCache.getCurrentYear(), lastYear = startYear + 1): Date[] {
|
getHolidays(startYear: number, lastYear = startYear + 1): Date[] {
|
||||||
const dates: Date[] = [];
|
const dates: Date[] = [];
|
||||||
for (let year = startYear; year <= lastYear; year++) {
|
for (let year = startYear; year <= lastYear; year++) {
|
||||||
for (const date of frenchPublicHolidaysForYear(year))
|
for (const date of frenchPublicHolidaysForYear(year))
|
||||||
@@ -204,18 +195,6 @@ export class CalendarService {
|
|||||||
return months;
|
return months;
|
||||||
}
|
}
|
||||||
|
|
||||||
monthsInAYearFromNow(): Year {
|
|
||||||
const months: Year = [];
|
|
||||||
const currentMonthIndex = this.dateCache.getCurrentMonth();
|
|
||||||
const currentYear = this.dateCache.getCurrentYear();
|
|
||||||
for (let i = 0; i < 12; i++) {
|
|
||||||
const monthIndex = (currentMonthIndex + i) % 12;
|
|
||||||
const year = currentYear + Math.floor((currentMonthIndex + i) / 12);
|
|
||||||
months.push(CalendarService.weeksInMonth(monthIndex, year));
|
|
||||||
}
|
|
||||||
return months;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getWeekNumber(date: Date): number {
|
static getWeekNumber(date: Date): number {
|
||||||
return dayjs(date).isoWeek();
|
return dayjs(date).isoWeek();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
import { provideZonelessChangeDetection } from '@angular/core';
|
|
||||||
import { DateCacheService } from './date-cache.service';
|
|
||||||
|
|
||||||
describe('DateCacheService', () => {
|
|
||||||
let service: DateCacheService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [provideZonelessChangeDetection()],
|
|
||||||
});
|
|
||||||
service = TestBed.inject(DateCacheService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should cache today date', () => {
|
|
||||||
const today1 = service.getToday();
|
|
||||||
const today2 = service.getToday();
|
|
||||||
expect(today1).toBe(today2); // Same reference
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should cache today components', () => {
|
|
||||||
const components1 = service.getTodayComponents();
|
|
||||||
const components2 = service.getTodayComponents();
|
|
||||||
expect(components1).toBe(components2); // Same reference
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should cache current month', () => {
|
|
||||||
const month1 = service.getCurrentMonth();
|
|
||||||
const month2 = service.getCurrentMonth();
|
|
||||||
expect(month1).toBe(month2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should cache current year', () => {
|
|
||||||
const year1 = service.getCurrentYear();
|
|
||||||
const year2 = service.getCurrentYear();
|
|
||||||
expect(year1).toBe(year2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should clear cache', () => {
|
|
||||||
const year1 = service.getCurrentYear();
|
|
||||||
service.clearCache();
|
|
||||||
const year2 = service.getCurrentYear();
|
|
||||||
expect(year1).toBe(year2); // Values should be the same even after clearing
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return today with time normalized to 00:00:00.000', () => {
|
|
||||||
const today = service.getToday();
|
|
||||||
expect(today.getHours()).toBe(0);
|
|
||||||
expect(today.getMinutes()).toBe(0);
|
|
||||||
expect(today.getSeconds()).toBe(0);
|
|
||||||
expect(today.getMilliseconds()).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return getNow() same as getToday()', () => {
|
|
||||||
const now = service.getNow();
|
|
||||||
const today = service.getToday();
|
|
||||||
expect(now).toBe(today);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service to cache and provide commonly used date values.
|
|
||||||
* This reduces redundant Date object creation across the application.
|
|
||||||
*/
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class DateCacheService {
|
|
||||||
private _today: Date | null = null;
|
|
||||||
private _todayComponents: { date: number; month: number; year: number } | null = null;
|
|
||||||
private _currentMonth: number | null = null;
|
|
||||||
private _currentYear: number | null = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get today's date (time set to 00:00:00.000)
|
|
||||||
*/
|
|
||||||
getToday(): Date {
|
|
||||||
if (!this._today || this.isNewDay(this._today)) {
|
|
||||||
this._today = new Date();
|
|
||||||
this._today.setHours(0, 0, 0, 0);
|
|
||||||
this._todayComponents = null; // Invalidate components cache
|
|
||||||
}
|
|
||||||
return this._today;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get today's date components (date, month, year) for efficient comparison
|
|
||||||
*/
|
|
||||||
getTodayComponents(): { date: number; month: number; year: number } {
|
|
||||||
if (!this._todayComponents || (this._today && this.isNewDay(this._today))) {
|
|
||||||
const today = this.getToday();
|
|
||||||
this._todayComponents = {
|
|
||||||
date: today.getDate(),
|
|
||||||
month: today.getMonth(),
|
|
||||||
year: today.getFullYear(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return this._todayComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current month (0-11)
|
|
||||||
*/
|
|
||||||
getCurrentMonth(): number {
|
|
||||||
if (this._currentMonth === null || this.isNewMonth()) {
|
|
||||||
this._currentMonth = new Date().getMonth();
|
|
||||||
}
|
|
||||||
return this._currentMonth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current year
|
|
||||||
*/
|
|
||||||
getCurrentYear(): number {
|
|
||||||
if (this._currentYear === null || this.isNewYear()) {
|
|
||||||
this._currentYear = new Date().getFullYear();
|
|
||||||
}
|
|
||||||
return this._currentYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current date with time set to 00:00:00.000 (alias for getToday)
|
|
||||||
*/
|
|
||||||
getNow(): Date {
|
|
||||||
return this.getToday();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a cached date is from a previous day
|
|
||||||
*/
|
|
||||||
private isNewDay(cachedDate: Date): boolean {
|
|
||||||
const now = new Date();
|
|
||||||
return (
|
|
||||||
cachedDate.getDate() !== now.getDate() ||
|
|
||||||
cachedDate.getMonth() !== now.getMonth() ||
|
|
||||||
cachedDate.getFullYear() !== now.getFullYear()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if we're in a new month
|
|
||||||
*/
|
|
||||||
private isNewMonth(): boolean {
|
|
||||||
return this._currentMonth !== null && this._currentMonth !== new Date().getMonth();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if we're in a new year
|
|
||||||
*/
|
|
||||||
private isNewYear(): boolean {
|
|
||||||
return this._currentYear !== null && this._currentYear !== new Date().getFullYear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all caches (useful for testing)
|
|
||||||
*/
|
|
||||||
clearCache(): void {
|
|
||||||
this._today = null;
|
|
||||||
this._todayComponents = null;
|
|
||||||
this._currentMonth = null;
|
|
||||||
this._currentYear = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user