import { Injectable } from '@nestjs/common' ; import { format as fnsFormat , isWeekend as fnsIsWeekend , getDaysInMonth as fnsGetDaysInMonth , eachDayOfInterval , addDays , getYear } from 'date-fns' ; import { IDateUtils } from 'src/Application/IDateUtils' ; import { WorkingDayOfYearByMonth } from 'src/Domain/HumanResource/MealTicket/Strategy/WorkingDayOfYearByMonth' ; @ Injectable ( ) export class DateUtilsAdapter implements IDateUtils { public format ( date , format ) { return fnsFormat ( date , format ) ; } public getDaysInMonth ( date ) { return fnsGetDaysInMonth ( date ) ; } public isWeekend ( date ) { return fnsIsWeekend ( date ) ; } public getCurrentDate ( ) { return new Date ( ) ; } public getYear ( date ) { return getYear ( date ) ; } public getLastDayOfYear ( date ) { return new Date ( `${ getYear ( date ) }/12/31` ) ; } public getFirstDayOfYear ( date ) { return new Date ( `${ getYear ( date ) }/01/01` ) ; } public getCurrentDateToISOString ( ) { return this . getCurrentDate ( ) . toISOString ( ) ; } public addDaysToDate ( date , days ) { return addDays ( date , days ) ; } public getWorkedDaysDuringAPeriod ( start , end ) { const dates = [ ] ; const workedFreeDays = [ ] ; for ( let year = start . getFullYear ( ) ; year <= end . getFullYear ( ) ; year ++ ) { workedFreeDays . push ( ... this . getWorkedFreeDays ( year ) ) ; } for ( const day of eachDayOfInterval ( { start , end } ) ) { if ( this . isWeekend ( day ) || workedFreeDays . filter ( d => d . toISOString ( ) === day . toISOString ( ) ) . length > 0 ) { continue ; } dates . push ( day ) ; } return dates ; } public getAllWorkingDayOfYearByMonth ( date ) { const lastDayOfYear = this . getLastDayOfYear ( date ) ; const firstDayOfYear = this . getFirstDayOfYear ( date ) ; const workedDaysOfYear = this . getWorkedDaysDuringAPeriod ( firstDayOfYear , lastDayOfYear ) ; const defaultValues = [ ] ; return workedDaysOfYear . reduce ( ( prev , next ) => { const currentMonth = next . getMonth ( ) + 1 ; const itemWithMonth = prev . find ( item => item . month === currentMonth ) ; if ( itemWithMonth ) { itemWithMonth . addOneWorkingDay ( ) ; return prev ; } const working = new WorkingDayOfYearByMonth ( currentMonth ) ; working . addOneWorkingDay ( ) ; return [ ... prev , working ] ; } , defaultValues ) ; } public getWorkedFreeDays ( year ) { const fixedDays = [ new Date ( `${ year }-01-01` ) , new Date ( `${ year }-05-01` ) , new Date ( `${ year }-05-08` ) , new Date ( `${ year }-07-14` ) , new Date ( `${ year }-08-15` ) , new Date ( `${ year }-11-01` ) , new Date ( `${ year }-11-11` ) , new Date ( `${ year }-12-25` ) ] ; const easterDate = this . getEasterDate ( year ) ; const easterDays = [ addDays ( easterDate , 1 ) , addDays ( easterDate , 39 ) ] ; return [ ... fixedDays , ... easterDays ] ; } public getEasterDate ( year ) { const a = year % 19 ; const b = Math . floor ( year / 100 ) ; const c = year % 100 ; const d = Math . floor ( b / 4 ) ; const e = b % 4 ; const f = Math . floor ( ( b + 8 ) / 25 ) ; const g = Math . floor ( ( b - f + 1 ) / 3 ) ; const h = ( 19 * a + b - d - g + 15 ) % 30 ; const i = Math . floor ( c / 4 ) ; const k = c % 4 ; const l = ( 32 + 2 * e + 2 * i - h - k ) % 7 ; const m = Math . floor ( ( a + 11 * h + 22 * l ) / 451 ) ; const n0 = h + l + 7 * m + 114 ; const n = Math . floor ( n0 / 31 ) - 1 ; const p = ( n0 % 31 ) + 1 ; return new Date ( year , n , p ) ; } public getLeaveDuration ( startDate , isStartsAllDay , endDate , isEndsAllDay ) { let duration = this . getWorkedDaysDuringAPeriod ( new Date ( startDate ) , new Date ( endDate ) ) . length ; if ( false === isStartsAllDay ) { duration -= 0.5 ; } if ( false === isEndsAllDay && duration > 0.5 ) { duration -= 0.5 ; } return duration ; } }