diff.js 4.0 KB

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