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

server/src/Infrastructure/Adapter/DateUtilsAdapter.ts   A

Complexity

Total Complexity 24
Complexity/F 1.6

Size

Lines of Code 182
Function Count 15

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 24
eloc 150
mnd 9
bc 9
fnc 15
dl 0
loc 182
bpm 0.6
cpm 1.6
noi 0
c 0
b 0
f 0
rs 10

15 Functions

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