Passed
Pull Request — master (#235)
by Mathieu
01:44
created

DateUtilsAdapter.isAWorkingDay   A

Complexity

Conditions 4

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 15
c 0
b 0
f 0
rs 9.8
cc 4
1
import { Injectable } from '@nestjs/common';
2
import {
3
  format as fnsFormat,
4
  isWeekend as fnsIsWeekend,
5
  getDaysInMonth as fnsGetDaysInMonth,
6
  eachDayOfInterval,
7
  addDays,
8
  getYear
9
} from 'date-fns';
10
import { IDateUtils } from 'src/Application/IDateUtils';
11
import { WorkingDayOfYearByMonth } from 'src/Domain/HumanResource/MealTicket/Strategy/WorkingDayOfYearByMonth';
12
13
@Injectable()
14
export class DateUtilsAdapter implements IDateUtils {
15
  public format(date: Date, format: string): string {
16
    return fnsFormat(date, format);
17
  }
18
19
  public getDaysInMonth(date: Date): number {
20
    return fnsGetDaysInMonth(date);
21
  }
22
23
  public isWeekend(date: Date): boolean {
24
    return fnsIsWeekend(date);
25
  }
26
27
  public isAWorkingDay(date: Date): boolean {
28
    if (this.isWeekend(date)) {
29
      return false;
30
    }
31
32
    const workedFreeDays = this.getWorkedFreeDays(date.getFullYear());
33
34
    for (const day of workedFreeDays) {
35
      if (day.getTime() === date.getTime()) {
36
        return false;
37
      }
38
    }
39
40
    return true;
41
  }
42
43
  public getCurrentDate(): Date {
44
    return new Date();
45
  }
46
47
  public getYear(date: Date): number {
48
    return getYear(date);
49
  }
50
51
  public getLastDayOfYear(date: Date): Date {
52
    return new Date(`${getYear(date)}/12/31`);
53
  }
54
55
  public getFirstDayOfYear(date: Date): Date {
56
    return new Date(`${getYear(date)}/01/01`);
57
  }
58
59
  public getCurrentDateToISOString(): string {
60
    return this.getCurrentDate().toISOString();
61
  }
62
63
  public addDaysToDate(date: Date, days: number): Date {
64
    return addDays(date, days);
65
  }
66
67
  public getWorkedDaysDuringAPeriod(start: Date, end: Date): Date[] {
68
    const dates: Date[] = [];
69
    const workedFreeDays: Date[] = [];
70
71
    for (let year = start.getFullYear(); year <= end.getFullYear(); year++) {
72
      workedFreeDays.push(...this.getWorkedFreeDays(year));
73
    }
74
75
    for (const day of eachDayOfInterval({ start, end })) {
76
      if (
77
        this.isWeekend(day) ||
78
        workedFreeDays.filter(d => d.toISOString() === day.toISOString())
79
          .length > 0
80
      ) {
81
        continue;
82
      }
83
84
      dates.push(day);
85
    }
86
87
    return dates;
88
  }
89
90
  public getAllWorkingDayOfYearByMonth(date: Date): WorkingDayOfYearByMonth[] {
91
    const lastDayOfYear = this.getLastDayOfYear(date);
92
    const firstDayOfYear = this.getFirstDayOfYear(date);
93
94
    const workedDaysOfYear = this.getWorkedDaysDuringAPeriod(
95
      firstDayOfYear,
96
      lastDayOfYear
97
    );
98
99
    const defaultValues: WorkingDayOfYearByMonth[] = [];
100
101
    return workedDaysOfYear.reduce((prev, next) => {
102
      const currentMonth = next.getMonth() + 1;
103
      const itemWithMonth = prev.find(item => item.month === currentMonth);
104
105
      if (itemWithMonth) {
106
        itemWithMonth.addOneWorkingDay();
107
        return prev;
108
      }
109
      const working = new WorkingDayOfYearByMonth(currentMonth);
110
      working.addOneWorkingDay();
111
112
      return [...prev, working];
113
    }, defaultValues);
114
  }
115
116
  public getWorkedFreeDays(year: number): Date[] {
117
    const fixedDays: Date[] = [
118
      new Date(`${year}-01-01`), // New Year's Day
119
      new Date(`${year}-05-01`), // Labour Day
120
      new Date(`${year}-05-08`), // Victory in 1945
121
      new Date(`${year}-07-14`), // National Day
122
      new Date(`${year}-08-15`), // Assumption
123
      new Date(`${year}-11-01`), // All Saints' Day
124
      new Date(`${year}-11-11`), // The Armistice
125
      new Date(`${year}-12-25`) // Christmas
126
    ];
127
128
    const easterDate = this.getEasterDate(year);
129
    const easterDays: Date[] = [
130
      addDays(easterDate, 1), // Easter Monday
131
      addDays(easterDate, 39) // Ascension
132
    ];
133
134
    return [...fixedDays, ...easterDays];
135
  }
136
137
  public getEasterDate(year: number): Date {
138
    const a = year % 19;
139
    const b = Math.floor(year / 100);
140
    const c = year % 100;
141
    const d = Math.floor(b / 4);
142
    const e = b % 4;
143
    const f = Math.floor((b + 8) / 25);
144
    const g = Math.floor((b - f + 1) / 3);
145
    const h = (19 * a + b - d - g + 15) % 30;
146
    const i = Math.floor(c / 4);
147
    const k = c % 4;
148
    const l = (32 + 2 * e + 2 * i - h - k) % 7;
149
    const m = Math.floor((a + 11 * h + 22 * l) / 451);
150
    const n0 = h + l + 7 * m + 114;
151
    const n = Math.floor(n0 / 31) - 1;
152
    const p = (n0 % 31) + 1;
153
154
    return new Date(year, n, p);
155
  }
156
157
  public getLeaveDuration(
158
    startDate: string,
159
    isStartsAllDay: boolean,
160
    endDate: string,
161
    isEndsAllDay: boolean
162
  ): number {
163
    let duration = this.getWorkedDaysDuringAPeriod(
164
      new Date(startDate),
165
      new Date(endDate)
166
    ).length;
167
168
    if (false === isStartsAllDay) {
169
      duration -= 0.5;
170
    }
171
172
    if (false === isEndsAllDay && duration > 0.5) {
173
      duration -= 0.5;
174
    }
175
176
    return duration;
177
  }
178
}
179