All files / calendrica-js/src gregorian.js

95.55% Statements 43/45
92.85% Branches 13/14
75% Functions 6/8
100% Lines 42/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 12724x     24x     24x     24x     24x     24x     24x     24x     24x     24x     24x     24x     24x     24x     24x 130419x       24x 260679x                   33x     24x     24x           24x 130287x 130287x 130287x 130287x 130287x 130287x 130287x 130287x 130287x 130287x       24x 33x 33x 33x     33x 33x 33x       24x       130254x     24x                                              
const { mod } = require( './general' )
 
// Fixed date of start of the (proleptic) Gregorian calendar.
const GREGORIAN_EPOCH = 1
 
// January on Julian/Gregorian calendar.
const JANUARY = 1
 
// February on Julian/Gregorian calendar.
const FEBRUARY = 2
 
// March on Julian/Gregorian calendar.
const MARCH = 3
 
// April on Julian/Gregorian calendar.
const APRIL = 4
 
// May on Julian/Gregorian calendar.
const MAY = 5
 
// June on Julian/Gregorian calendar.
const JUNE = 6
 
// July on Julian/Gregorian calendar.
const JULY = 7
 
// August on Julian/Gregorian calendar.
const AUGUST = 8
 
// September on Julian/Gregorian calendar.
const SEPTEMBER = 9
 
// October on Julian/Gregorian calendar.
const OCTOBER = 10
 
// November on Julian/Gregorian calendar.
const NOVEMBER = 11
 
// December on Julian/Gregorian calendar.
const DECEMBER = 12
 
// True if g-year is a leap year on the Gregorian calendar.
const isGregorianLeapYear = gYear => (
  ( mod( gYear, 4 ) === 0 ) && !( [ 100, 200, 300 ].includes( mod( gYear, 400 ) ) )
)
 
// Fixed date equivalent to the Gregorian date g-date.
const fixedFromGregorian = ( year, month, day ) => (
  GREGORIAN_EPOCH - 1 + 365 * ( year - 1 )
    + Math.floor( ( year - 1 ) / 4 )
    - Math.floor( ( year - 1 ) / 100 )
    + Math.floor( ( year - 1 ) / 400 )
    + Math.floor( ( 1 / 12 ) * ( 367 * month - 362 ) )
    + ( ( month <= 2 ) ? 0 : ( isGregorianLeapYear( year ) ? -1 : -2 ) )
    + day
)
 
// Fixed date of January 1 in g-year.
const gregorianNewYear = gYear => fixedFromGregorian( gYear, JANUARY, 1 )
 
// Fixed date of December 31 in g-year.
const gregorianYearEnd = gYear => fixedFromGregorian( gYear, DECEMBER, 31 )
 
// The range of moments in Gregorian year g-year.
const gregorianYearRange = gYear => [
  gregorianNewYear( gYear ),
  gregorianNewYear( gYear + 1 ),
]
 
// Gregorian year corresponding to the fixed date.
const gregorianYearFromFixed = date => {
  const d0 = date - GREGORIAN_EPOCH
  const n400 = Math.floor( d0 / 146097 )
  const d1 = mod( d0, 146097 )
  const n100 = Math.floor( d1 / 36524 )
  const d2 = mod( d1, 36524 )
  const n4 = Math.floor( d2 / 1461 )
  const d3 = mod( d2, 1461 )
  const n1 = Math.floor( d3 / 365 )
  const year = 400 * n400 + 100 * n100 + 4 * n4 + n1
  return ( n100 === 4 || n1 === 4 ) ? year : year + 1
}
 
// Gregorian (year month day) corresponding to fixed date.
const gregorianFromFixed = date => {
  const year = gregorianYearFromFixed( date )
  const priorDays = date - gregorianNewYear( year )
  const correction = date < fixedFromGregorian( year, MARCH, 1 )
    ? 0
    : ( isGregorianLeapYear( year ) ? 1 : 2 )
  const month = Math.floor( ( 1 / 367 ) * ( 12 * ( priorDays + correction ) + 373 ) )
  const day = date - fixedFromGregorian( year, month, 1 ) + 1
  return { year, month, day }
}
 
// Number of days from Gregorian date g-date1 until g-date2.
const gregorianDateDifference = (
  { year: year1, month: month1, day: day1 }, // g-date1
  { year: year2, month: month2, day: day2 }, // g-date2
) => (
  fixedFromGregorian( year2, month2, day2 ) - fixedFromGregorian( year1, month1, day1 )
)
 
module.exports = {
  GREGORIAN_EPOCH,
  JANUARY,
  FEBRUARY,
  MARCH,
  APRIL,
  MAY,
  JUNE,
  JULY,
  AUGUST,
  SEPTEMBER,
  OCTOBER,
  NOVEMBER,
  DECEMBER,
  isGregorianLeapYear,
  fixedFromGregorian,
  gregorianNewYear,
  gregorianYearEnd,
  gregorianYearRange,
  gregorianYearFromFixed,
  gregorianFromFixed,
  gregorianDateDifference,
}