diff.js
4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
var totalDaysInMonth = require('./totalDaysInMonth');
var totalDaysInYear = require('./totalDaysInYear');
var convert = require('../time/convert');
/**
* calculate the difference between dates (range)
*/
function diff(start, end, unitName){
// sort the dates to make it easier to process (specially year/month)
if (start > end) {
var swap = start;
start = end;
end = swap;
}
var output;
if (unitName === 'month') {
output = getMonthsDiff(start, end);
} else if (unitName === 'year'){
output = getYearsDiff(start, end);
} else if (unitName != null) {
if (unitName === 'day') {
// ignore timezone difference because of daylight savings time
start = toUtc(start);
end = toUtc(end);
}
output = convert(end - start, 'ms', unitName);
} else {
output = end - start;
}
return output;
}
function toUtc(d){
// we ignore timezone differences on purpose because of daylight
// savings time, otherwise it would return fractional days/weeks even
// if a full day elapsed. eg:
// Wed Feb 12 2014 00:00:00 GMT-0200 (BRST)
// Sun Feb 16 2014 00:00:00 GMT-0300 (BRT)
// diff should be 4 days and not 4.041666666666667
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(),
d.getHours(), d.getMinutes(), d.getSeconds(),
d.getMilliseconds());
}
function getMonthsDiff(start, end){
return getElapsedMonths(start, end) +
getElapsedYears(start, end) * 12 +
getFractionalMonth(start, end);
}
function getYearsDiff(start, end){
var elapsedYears = getElapsedYears(start, end);
return elapsedYears + getFractionalYear(start, end, elapsedYears);
}
function getElapsedMonths(start, end){
var monthDiff = end.getMonth() - start.getMonth();
if (monthDiff < 0) {
monthDiff += 12;
}
// less than a full month
if (start.getDate() > end.getDate()) {
monthDiff -= 1;
}
return monthDiff;
}
function getElapsedYears(start, end){
var yearDiff = end.getFullYear() - start.getFullYear();
// less than a full year
if (start.getMonth() > end.getMonth()) {
yearDiff -= 1;
}
return yearDiff;
}
function getFractionalMonth(start, end){
var fractionalDiff = 0;
var startDay = start.getDate();
var endDay = end.getDate();
if (startDay !== endDay) {
var startTotalDays = totalDaysInMonth(start);
var endTotalDays = totalDaysInMonth(end);
var totalDays;
var daysElapsed;
if (startDay > endDay) {
// eg: Jan 29 - Feb 27 (29 days elapsed but not a full month)
var baseDay = startTotalDays - startDay;
daysElapsed = endDay + baseDay;
// total days should be relative to 1st day of next month if
// startDay > endTotalDays
totalDays = (startDay > endTotalDays)?
endTotalDays + baseDay + 1 : startDay + baseDay;
} else {
// fractional is only based on endMonth eg: Jan 12 - Feb 18
// (6 fractional days, 28 days until next full month)
daysElapsed = endDay - startDay;
totalDays = endTotalDays;
}
fractionalDiff = daysElapsed / totalDays;
}
return fractionalDiff;
}
function getFractionalYear(start, end, elapsedYears){
var base = elapsedYears?
new Date(end.getFullYear(), start.getMonth(), start.getDate()) :
start;
var elapsedDays = diff(base, end, 'day');
return elapsedDays / totalDaysInYear(end);
}
module.exports = diff;