vue实现农历日期选择器

2021-08-08 968点热度 0人点赞 0条评论

原文链接

https://blog.csdn.net/qq_40665861/article/details/102953571

实现公农历转换的算法

/**
  * 数组LunarDaysOfMonth存入农历1901年到2050年每年中的月天数信息
  * 农历每月只能是29或30天,一年用12(或13)个二进制位表示,从高到低,对应位为1表示30天,否则29天
  */
 var LunarDaysOfMonth = new Array
 (
     0x4ae0, 0xa570, 0x5268, 0xd260, 0xd950, 0x6aa8, 0x56a0, 0x9ad0, 0x4ae8, 0x4ae0,   // 1901-1910   
     0xa4d8, 0xa4d0, 0xd250, 0xd548, 0xb550, 0x56a0, 0x96d0, 0x95b0, 0x49b8, 0x49b0,   // 1920   
     0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada8, 0x2b60, 0x9570, 0x4978, 0x4970, 0x64b0,   // 1930   
     0xd4a0, 0xea50, 0x6d48, 0x5ad0, 0x2b60, 0x9370, 0x92e0, 0xc968, 0xc950, 0xd4a0,   // 1940   
     0xda50, 0xb550, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, 0xb4a8, 0x6ca0,   // 1950   
     0xb550, 0x55a8, 0x4da0, 0xa5b0, 0x52b8, 0x52b0, 0xa950, 0xe950, 0x6aa0, 0xad50,   // 1960   
     0xab50, 0x4b60, 0xa570, 0xa570, 0x5260, 0xe930, 0xd950, 0x5aa8, 0x56a0, 0x96d0,   // 1970   
     0x4ae8, 0x4ad0, 0xa4d0, 0xd268, 0xd250, 0xd528, 0xb540, 0xb6a0, 0x96d0, 0x95b0,   // 1980   
     0x49b0, 0xa4b8, 0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada0, 0xab60, 0x9370, 0x4978,   // 1990   
     0x4970, 0x64b0, 0x6a50, 0xea50, 0x6b28, 0x5ac0, 0xab60, 0x9368, 0x92e0, 0xc960,   // 2000 
     0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950,      // 2001-2010 
     0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8,   // 2011-2020 
     0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0,      // 2021-2030 
     0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0,      // 2031-2040 
     0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0   // 2041-2050 
 );
/**
*   数组LunarLeapYear存放农历1901年到2050年闰月的月份,如没有则为0,从高到低,每字节存两年
*/
var LunarLeapYear = new Array
 (
     0x00, 0x50, 0x04, 0x00, 0x20,   // 1901-1910   
     0x60, 0x05, 0x00, 0x20, 0x70,   // 1920   
     0x05, 0x00, 0x40, 0x02, 0x06,   // 1930   
     0x00, 0x50, 0x03, 0x07, 0x00,   // 1940   
     0x60, 0x04, 0x00, 0x20, 0x70,   // 1950   
     0x05, 0x00, 0x30, 0x80, 0x06,   // 1960   
     0x00, 0x40, 0x03, 0x07, 0x00,   // 1970   
     0x50, 0x04, 0x08, 0x00, 0x60,   // 1980   
     0x04, 0x0a, 0x00, 0x60, 0x05,   // 1990   
     0x00, 0x30, 0x80, 0x05, 0x00,   // 2000
     0x40, 0x02, 0x07, 0x00, 0x50,  // 2001-2010 
     0x04, 0x09, 0x00, 0x60, 0x04,  // 2011-2020 
     0x00, 0x20, 0x60, 0x05, 0x00,  // 2021-2030 
     0x30, 0xb0, 0x06, 0x00, 0x50,  // 2031-2040 
     0x02, 0x07, 0x00, 0x50, 0x03   // 2041-2050 
 );

/**
* 日期转换
* 使用方法
* var dc = new dateChange();
* var a=dc.getSolarDate([2005,1,10]);   //农历转公历
* var b=dc.getLunarDate([2005,1,10]); //公历转农历
*/
// function dateChange() {
 /**
   * 返回农历iLunarYear年的闰月月份,如没有则返回0 
   */
 function GetLeapMonth(iLunarYear) {
     var Leap = LunarLeapYear[(iLunarYear - 1901) >> 1];
     return (((iLunarYear - 1901) & 1) == 0) ? (Leap >> 4) : (Leap & 0x0f);
 }
 /**
   * 返回农历iLunarYer年iLunarMonth月的天数,结果是一个长整数
   * 如果iLunarMonth不是闰月, 高字为0,低字为该月的天数
   * 如果iLunarMonth是闰月, 高字为后一个月的天数,低字为前一个月的天数
   */
 function LunarMonthDays(iLunarYear, iLunarMonth) {
     var High;
     var Low;
     var Bit;

     High = 0;
     Low = 29;
     Bit = 16 - iLunarMonth;
     if ((iLunarMonth > GetLeapMonth(iLunarYear)) && (GetLeapMonth(iLunarYear) > 0)) Bit--;
     if ((LunarDaysOfMonth[iLunarYear - 1901] & (1 << Bit)) > 0) Low++;
     if (iLunarMonth == GetLeapMonth(iLunarYear)) {
         High = ((LunarDaysOfMonth[iLunarYear - 1901] & (1 << (Bit - 1))) > 0) ? 30 : 29;
     }
     return Low + (High << 16);
 }
 /**
   * 返回公历iSolarYear年iSolarMonth月的天数,结果是一个长整数
   */
 function SolarMonthDays(iSolarYear, iSolarMonth) {
     var MonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
     var isl = isLeapYear(iSolarYear);
     if (isl) MonthDays[1] = 29;
     return MonthDays[iSolarMonth - 1];
 }
 /**
   * 返回农历iLunarYear年的总天数
   */
 function LunarYearDays(iLunarYear) {
     var Days;
     var tmp;

     Days = 0;
     for (var i = 1; i <= 12; i++) {
         tmp = LunarMonthDays(iLunarYear, i);
         Days = Days + ((tmp >> 16) & 0xffff); //取高位 
         Days = Days + (tmp & 0xffff); //取低位 
     }
     return Days;
 }
 /**
   * 返回公历iSolarYear年的总天数
   */
 function SolarYearDays(iSolarYear) {
     var isl = isLeapYear(iSolarYear);
     return isl ? 366 : 365;
 }
 /**
   * 判断公历年是否是润年
   */
 function isLeapYear(iSolarYear) {
     var y = parseInt(iSolarYear);
     return ((y % 100 == 0 && y % 400 == 0) || (y % 4 == 0 & y % 100 != 0));
 }
 /**
   * 将农历iLunarYear年格式化成天干地支记年法表示的字符串 
   */
 function FormatLunarYear(iLunarYear) {
     var szText1 = new String("甲乙丙丁戊己庚辛壬癸");
     var szText2 = new String("子丑寅卯辰巳午未申酉戌亥");
     var strYear;
     strYear = szText1.substr((iLunarYear - 4) % 10, 1);
     strYear = strYear + szText2.substr((iLunarYear - 4) % 12, 1);
     return strYear + "年";
 }
 /**
   * 将农历iLunarMonth月格式化成农历表示的字符串
   */
 function FormatLunarMonth(iLunarMonth) {
     var szText = new String("正二三四五六七八九十");
     var strMonth;

     if (iLunarMonth <= 10) {
         strMonth = szText.substr(iLunarMonth - 1, 1);
     }
     else if (iLunarMonth == 11) strMonth = "冬";
     else strMonth = "腊";

     return strMonth + "月";
 }
 /**
   * 将农历iLunarDay日格式化成农历表示的字符串
   */
 function FormatLunarDay(iLunarDay) {
     var szText1 = new String("初十廿三");
     var szText2 = new String("一二三四五六七八九十");
     var strDay;
     if ((iLunarDay != 20) && (iLunarDay != 30)) {
         strDay = szText1.substr((iLunarDay - 1) / 10, 1) + szText2.substr((iLunarDay - 1) % 10, 1);
     }
     else if (iLunarDay != 20) {
         strDay = szText1.substr(iLunarDay / 10, 1) + "十";
     }
     else {
         strDay = "二十";
     }

     return strDay;
 }
 /**
   * 计算两个公历日期相差的天数
   */
 function CaculateSolarSpanDays(start, end) {
     var starty = start[0];
     var startm = start[1];
     var startd = start[2];
     var endy = end[0];
     var endm = end[1];
     var endd = end[2];
     var daynum = 0;

     //年份的天数
     for (var i = starty; i < endy; i++) {
         daynum += SolarYearDays(i);
     }
     //月份的天数
     for (var i = 1; i < endm; i++) {
         daynum += SolarMonthDays(endy, i);
     }
     daynum += endd - startd;
     return daynum;
 }
 /**
   * 计算两个农历日期相差的天数
   * isleap--> end的月份是闰月还是非闰月
   */
 function CaculateLunarSpanDays(start, end, isleap) {
     var starty = start[0];
     var startm = start[1];
     var startd = start[2];
     var endy = end[0];
     var endm = end[1];
     var endd = end[2];
     var daynum = 0;

     //年份的天数
     for (var i = starty; i < endy; i++) {
         daynum += LunarYearDays(i);
     }
     //月份的天数
     for (var i = 1; i < endm; i++) {
         var mdays = 0;
         var tmp = LunarMonthDays(endy, i);
         mdays += ((tmp >> 16) & 0xffff); //取高位 
         mdays += (tmp & 0xffff); //取低位 
         daynum += mdays;
         //w('lunar'+endy+'年'+i+'月的天数为'+ LunarMonthDays(endy,i));
     }
     //如果当前月是闰月,加上当前月的非闰月天数
     if (isleap) {
         var Low;
         var Bit;
         Low = 29;
         Bit = 16 - endm;
         if ((endm > GetLeapMonth(endy)) && (GetLeapMonth(endy) > 0)) Bit--;
         if ((LunarDaysOfMonth[endy - 1901] & (1 << Bit)) > 0) Low++;
         daynum += Low;
     }
     daynum += endd - startd;
     return daynum;
 }
 /**
   * 将公历日期转换为农历日期,返回农历表示的字符串
   */
 function GetLunarDateString(SolarDate) {
     var tmp;
     var iLunarYear;
     var iLunarMonth;
     var iLunarDay;
     var Leap = false;
     var MinMilli = 1000 * 60;
     var HrMilli = MinMilli * 60;
     var DyMilli = HrMilli * 24;

     /* 从1901年1月1日算起,给定的公历日期已经过去的天数
        Date是从1970年1月1日作为起点的    */
     var StartDate = [1901, 1, 1];
     var iSpanDays = CaculateSolarSpanDays(StartDate, SolarDate);
     //w('公历'+StartDate+'至'+SolarDate+'的总天数:'+iSpanDays);

     // 公历1901年2月19日为农历1901年正月初一,差49天
     if (iSpanDays <= 18) {
         iLunarYear = 1900;
         iLunarMonth = 11;
         iLunarDay = 11 + iSpanDays;
     }
     else if (iSpanDays > 18 && iSpanDays < 49) {
         iLunarYear = 1900;
         iLunarMonth = 12;
         iLunarDay = iSpanDays - 18;
     }
     else {
         // 从农历1901年正月初一算起 
         iSpanDays = iSpanDays - 49;
         iLunarYear = 1901;
         iLunarMonth = 1;
         iLunarDay = 1;

         // 计算农历年 
         tmp = LunarYearDays(iLunarYear);
         while (iSpanDays >= tmp) {
             iSpanDays -= tmp;
             iLunarYear++;
             tmp = LunarYearDays(iLunarYear);
             //w(iLunarYear + '总天数' + tmp + '  减后剩余天数:' +iSpanDays);
         }
         //w('年--'+iLunarYear);

         // 计算农历月 
         tmp = LunarMonthDays(iLunarYear, iLunarMonth) & 0xffff; //取低字
         while (iSpanDays >= tmp) {
             iSpanDays -= tmp;
             if (iLunarMonth == GetLeapMonth(iLunarYear))  // 该年该月闰月
             {
                 tmp = LunarMonthDays(iLunarYear, iLunarMonth) >> 16; //取高字
                 if (iSpanDays < tmp) {
                     Leap = (tmp > 0) ? true : false;  // 闰月的后个月?
                     break;
                 }
                 iSpanDays = iSpanDays - tmp;
             }

             iLunarMonth++;
             tmp = LunarMonthDays(iLunarYear, iLunarMonth) & 0xffff; //取低字
         }

         // 计算农历日 
         iLunarDay += iSpanDays;
     }
     return [iLunarYear, (Leap ? iLunarMonth * 10 : iLunarMonth), iLunarDay, FormatLunarYear(iLunarYear) + '(' + iLunarYear + ')', (Leap ? "闰" : "") + FormatLunarMonth(iLunarMonth), FormatLunarDay(iLunarDay), 'fromSolarDay' + SolarDate];
     //return FormatLunarYear(iLunarYear) + (Leap ? "闰" : "") + FormatLunarMonth(iLunarMonth) + FormatLunarDay(iLunarDay);
 }
 /**
   * 将农历日期转换为公历日期
   */
 function GetSolarDateString(LunarDate) {
     var tmp;
     var iSolarYear;
     var iSolarMonth;
     var iSolarDay;
     var Leap = false;
     var MinMilli = 1000 * 60;
     var HrMilli = MinMilli * 60;
     var DyMilli = HrMilli * 24;

     //判断LunarDate的月份是否属于闰月, 例 4为非闰月 40为闰月.
     var monthIsLeap = false;
     if (LunarDate[1] > 12) {
         monthIsLeap = true;
         LunarDate[1] = LunarDate[1] / 10;
     }
     if (LunarDate[0] < 1900) {
         alert('超出计算范围0');
         return false;
     }

     // 从1900年冬月十一(公历1901年1月1日)算起,给定的农历日期已经过去的天数    
     // 公历1901年2月19日为农历1901年正月初一,差49天
     // 公历1901年1月1日为农历1900年11月11,差49天
     var StartDate = [1901, 1, 1];
     if (LunarDate[0] == 1900) {
         if (LunarDate[1] == 11) {
             var iSpanDays = LunarDate[2] - 11;
         } else if (LunarDate[1] == 12) {
             var iSpanDays = LunarDate[2] + 18;
         } else {
             alert('超出计算范围');
             return false;
         }
     } else {
         var iSpanDays = CaculateLunarSpanDays(StartDate, LunarDate, monthIsLeap) + 49;
     }
     //w('1900年冬月十一 至 '+LunarDate+'的总天数:'+iSpanDays);   

     // 从公历1901年1月1日算起  
     iSolarYear = 1901;
     iSolarMonth = 1;
     iSolarDay = 1;

     // 计算公历年 
     tmp = SolarYearDays(iSolarYear);
     //w(iSolarYear+'年'+'的总天数:'+tmp);
     while (iSpanDays >= tmp) {
         iSpanDays -= tmp;
         iSolarYear++;
         tmp = SolarYearDays(iSolarYear);
         //w(iSolarYear+'年'+'的总天数:'+tmp);
     }
     //w('计算公历年后剩余天数:'+iSpanDays);

     // 计算公历月 
     tmp = SolarMonthDays(iSolarYear, iSolarMonth);
     //w(iSolarYear+'年'+iSolarMonth+'月'+'的天数:'+tmp);
     while (iSpanDays >= tmp) {
         iSpanDays -= tmp;
         iSolarMonth++;
         tmp = SolarMonthDays(iSolarYear, iSolarMonth);
         //w(iSolarYear+'年'+iSolarMonth+'月'+'的天数:'+tmp + ' 减后:'+iSpanDays);
     }
     //w('计算月后剩余天数:'+iSpanDays);

     // 计算公历日 
     iSolarDay += iSpanDays;
     return [iSolarYear, iSolarMonth, iSolarDay, iSolarYear + '年', iSolarMonth + '月', iSolarDay + '日', 'fromLunarDays' + LunarDate];
 }
export  {GetLunarDateString,GetSolarDateString,SolarYearDays,SolarMonthDays,LunarYearDays,LunarMonthDays,GetLeapMonth,FormatLunarMonth,FormatLunarDay,FormatLunarYear}

组件封装

<template>
  <div>
    <div class="btn">
      <div class="btn_left" @click="err">取消</div>
      <div class="btn_right" @click="send">确定</div>
    </div>
    <div class="select">
      <div>
        <select name id @change="lunary" ref="lunary" class="select_y" size="5">
          <option v-for="(item,index) in ylist" :key="index" selected>{{item}}</option>
        </select>
      </div>
      <div>
        <select name id @change="lunarm" ref="lunarm" class="select_m" size="5">
          <option v-for="(item,index) in mlist" :key="index">{{item}}</option>
        </select>
      </div>
      <div>
        <select name id @change="lunard" ref="lunard" class="select_d" size="5">
          <option v-for="(item,index) in dlist" :key="index">{{item}}</option>
        </select>
      </div>
    </div>
  </div>
</template>
<script>
import {
  GetLunarDateString,
  GetSolarDateString,
  SolarYearDays,
  SolarMonthDays,
  LunarYearDays,
  LunarMonthDays,
  GetLeapMonth,
  FormatLunarMonth,
  FormatLunarDay,
  FormatLunarYear
} from "./lucnDate.js";
import { stringify } from "querystring";
import { nextTick } from "q";
export default {
  data() {
    return {
      ylist: null,
      mlist: null,
      dlist: null,
      data: {}
    };
  },
  methods: {
    // 取消
    err() {
      // 向父组件传值
      this.$emit("func", this.data);
    },
    // 确认
    send() {
      if (
        this.$refs.lunary.value &&
        this.$refs.lunarm.value &&
        this.$refs.lunard.value
      ) {
        console.log(this.$refs.lunard.selectedIndex);
        this.data = {
          lunary: this.$refs.lunary.value,
          lunarm: this.$refs.lunarm.value,
          lunard: this.$refs.lunard.value,
          dindex: this.$refs.lunard.selectedIndex + 1
        };
        this.$emit("func", this.data);
      } else {
        this.$toast({
          message: "请选择生日",
          duration: 1000
        });
      }
    },
    // 年
    lunary() {
      this.mlist = this.lunarMonthOptions(this.$refs.lunary.value);
      console.log(this.lunarMonthOptions(this.$refs.lunary.value));
      // 从新选择年再次计算
      this.lunarm();
    },
    // 月
    lunarm() {
      console.log(this.$refs.lunarm.value);
      // 将农历月转化为公历月
      var disLength = this.$refs.lunarm.value.length;
        var shortName = this.$refs.lunarm.value.substring(disLength - 2, disLength);
        console.log(shortName);
        switch (shortName) {
          case "正月":
            this.m = 1;
            break;
          case "二月":
            this.m = 2;
            break;
          case "三月":
            this.m = 3;
            break;
          case "四月":
            this.m = 4;
            break;
          case "五月":
            this.m = 5;
            break;
          case "六月":
            this.m = 6;
            break;
          case "七月":
            this.m = 7;
            break;
          case "八月":
            this.m = 8;
            break;
          case "九月":
            this.m = 9;
            break;
          case "十月":
            this.m = 10;
            break;
          case "冬月":
            this.m = 11;
            break;
          case "腊月":
            this.m = 12;
            break;
          default:
        }
      // 输入当年当月的天数
      this.dlist =  this.lunarDayOptions(this.$refs.lunary.value, this.m);
    },
    // 天
    lunard() {
      //$("select").on("blur", function() {
      //  window.scroll(0, 0); //失焦后强制让页面归位
      //});
    },
    // 循环年
    lunarYearOptions(from, to, curyear) {
      var str = [];
      for (var i = from; i <= to; i++) {
        str.push(i);
        // str.push(FormatLunarYear(i) + "(" + i + ")");
      }
      return str;
    },
    // 循环月
    lunarMonthOptions(year, month) {
      var leapMonth = GetLeapMonth(year);
      var str = [];
      var from = 1;
      var to = 12;

      var leap = false;
      if (month > 12) {
        leap = true;
        month = month / 10;
      }
      for (var i = from; i <= to; i++) {
        str.push(FormatLunarMonth(i));
        if (leapMonth > 0 && i == leapMonth) {
          str.push("闰" + FormatLunarMonth(i));
        }
      }
      return str;
    },
    // 循环天
    lunarDayOptions(year, month, day) {
      console.log(year, month, day)
      var from = 1;
      var to = 0;
      var leap = false;
      if (month > 12) {
        month = month / 10;
        leap = true;
        var monthdaynum = (LunarMonthDays(year, month) >> 16) & 0xffff;
      } else {
        var monthdaynum = LunarMonthDays(year, month) & 0xffff;
      }
      to = monthdaynum;
      console.log(to)
      var str = [];
      for (var i = from; i <= to; i++) {
        str.push(FormatLunarDay(i));
      }
      return str;
    }
  },
  mounted() {
    // //设定当前农历公历日期
    var curSolarDate = [2019, 11, 4];
    // 年,月,日
    var curLunarDate = GetSolarDateString(curSolarDate);
    this.ylist = this.lunarYearOptions(1902, 2019, curLunarDate[0]);
    this.mlist = this.lunarMonthOptions(
      curLunarDate[0],
      curLunarDate[1],
      curLunarDate[2]
    );
  }
};
</script>
<style scoped>
.btn {
  height: 0.3rem;
  line-height: 1rem;
  font-size: 0.29rem;
}
.btn_left {
  float: left;
  padding-left: 0.1rem;
  color: #1989fa;
}
.btn_right {
  float: right;
  padding-right: 0.1rem;
  color: #1989fa;
}
.select {
  margin-top: 1rem;
  width: 100%;
  /* text-align: center; */
  display: flex;
  justify-content: space-around;
  overflow-y: hidden;
}
.select_y option {
  /* width: 33%; */
  /*去掉默认的下拉三角*/
  /* appearance: none; */
  height: 0.7rem;
  padding: 0.2rem 0;
}
.select_m option {
  /* width: 33%; */
  height: 0.7rem;
  padding: 0.2rem 0;
}
.select_d option {
  /* width: 33%; */
  height: 0.7rem;
  padding: 0.2rem 0;
}
</style>>

在父组件中的使用

      <van-popup v-else v-model="show" position="bottom" :style="{ height: '40%' }">
        <nongli @func="getMsgFormSon"></nongli>
      </van-popup>
//这里在对农历进行了转换方便后台的存储
getMsgFormSon(data) {
      if (Object.keys(data).length !== 0) {
        var disLength = data.lunarm.length;
        var shortName = data.lunarm.substring(disLength - 2, disLength);
        console.log(shortName);
        switch (shortName) {
          case "正月":
            this.m = 1;
            break;
          case "二月":
            this.m = 2;
            break;
          case "三月":
            this.m = 3;
            break;
          case "四月":
            this.m = 4;
            break;
          case "五月":
            this.m = 5;
            break;
          case "六月":
            this.m = 6;
            break;
          case "七月":
            this.m = 7;
            break;
          case "八月":
            this.m = 8;
            break;
          case "九月":
            this.m = 9;
            break;
          case "十月":
            this.m = 10;
            break;
          case "冬月":
            this.m = 11;
            break;
          case "腊月":
            this.m = 12;
            break;
          default:
        }
        this.y = data.lunary;
        this.dindex = data.dindex + 1;
        var time = this.y + "-" + this.m + "-" + this.dindex;
        this.BirthdaySR = dayjs(time).format("YYYY-MM-DD");
        this.userInfo.BirthdaySR = this.BirthdaySR + " " + "23:59:00";
        this.show = false;
        console.log(this.y + "-" + this.m + "-" + this.d);
      } else {
        this.show = false;
      }
    },

王显锋

激情工作,快乐生活!

文章评论