Skip to content

获取公历日期的农历日期

Robert Yao edited this page Jul 1, 2019 · 1 revision
/**
 * 获取公历日期的农历日期
 * ========================================================================
 * @param time
 */
const getLunarDate = (time) => {
  const LUNAR_DATES = {
    PREFIX: [
      '初',
      '十',
      '廿'
    ],
    NUMBERS: [
      '一',
      '二',
      '三',
      '四',
      '五',
      '六',
      '七',
      '八',
      '九',
      '十'
    ]
  }
  const isLeapYear = (year) => {
    return ((year % 4 === 0) || (year % 400 === 0)) && (year % 100 !== 0)
  }
  /**
   * 获得年内日期序数
   * ========================================================================
   * @param {String} date - 表示日期的字符串
   * @returns {number}
   */
  const getDuringDays = (date) => {
    const DATES = [
      31,
      28,
      31,
      30,
      31,
      30,
      31,
      31,
      30,
      31,
      30,
      31
    ]
    let time = new Date(date)
    let year = time.getFullYear()
    let month = time.getMonth() + 1
    let total = time.getDate()

    DATES.forEach((days, i) => {
      if (i < month - 1) {
        if (isLeapYear(year) && i === 1) {
          days += 1
        }

        total += days
      }
    })

    return total
  }
  /**
   * 算法公式:
   * ========================================================================
   * 设:公元年数 - 1977(或1901)= 4Q + R
   * 则:阴历日期 = 14Q + 10.6(R+1) + 年内日期序数 - 29.5n
   * (注:式中Q、R、n均为自然数,R<4)
   * 例:1994年5月7日的阴历日期为:
   * 1994 - 1977 = 17 = 4×4+1
   * 故:Q = 4,R = 1 则:5月7日的阴历日期为:
   * 14 × 4 + 10.6(1 + 1) + (31 + 28 + 31 + 30 + 7) - 29.5n
   * = 204.2- 29.5n
   * 然后用 204.2 去除 29.5 得商数 6 余 27.2,6 即是 n 值,余数 27 即是阴历二十七日
   * ========================================================================
   * @param date
   * @returns {number}
   */
  const toLunarDate = (date) => {
    let time = new Date(date)
    let year = time.getFullYear()
    let Q = Math.floor((year - 1977) / 4)
    let R = (year - 1977) % 4
    let days = (14 * Q) + (10.6 * (R + 1)) + getDuringDays(date)

    return Math.floor(days % 29.5)
  }
  let date = toLunarDate(time)
  let text = ''

  switch (date) {
    case 10:
      text = text = '初十'

      break
    case 20:
      text = text = '二十'

      break
    case 30:
      text = text = '三十'

      break
    default:
      text = LUNAR_DATES.PREFIX[Math.floor(date / 10)] + LUNAR_DATES.NUMBERS[(date - 1) % 10] || date

      break
  }

  return text
}