本文介绍了如何使用 JavaScript 处理中国农历日历,并提供了一组实用的功能,用于将农历日期转换为数字、获取每月的天数、确定每月的第一天和最后一天的星期几等任务。这些功能有助于创建一个具有农历和阳历详细信息的日历应用。
先看效果图
引入依赖 首先,我们需要引入所需的依赖项,包括 dateFormater 和 lunar-javascript
dateFormater是对日期进行格式化的函数
lunar-javascript 使用npm install lunar-javascript
选择月份的用的是iviewUI库
import { dateFormater } from "@/common.js"
import { Solar, Lunar } from 'lunar-javascript'
hineseDateToNumber个函数用于将中文农历日期转换为数字值,包括年、月和日。它接受一个中文日期字符串作为输入,并返回一个包含数字值的对象。
// 中文日期转数字
export const chineseDateToNumber = function (chineseDate) {
const yearMap = {
'0': 0, 'O': 0, '〇': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '十一': 11, '十二': 12,
}
const monthMap = {
'正': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '十一': 11, '腊': 12, '冬': 11,
'闰正': 1, '闰二': 2, '闰三': 3, '闰四': 4, '闰五': 5, '闰六': 6, '闰七': 7, '闰八': 8, '闰九': 9, '闰十': 10, '闰十一': 11, '闰冬': 11, '闰腊': 12,
}
const dayMap = {
'一': 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,
}
let [year, res1] = chineseDate.split('年')
let [month, day] = res1.split('月')
year = year.split('').map(v => yearMap[v]).join('')
month = monthMap[month.replace('闰', '')]
day = day.replace('初', '')
day = dayMap[day]
return { year: Number(year), month, day }
}
etDaysByMonth函数用于获取指定年份和月份的天数。它返回该月的总天数。
// 判断当前月有多少天
export const getDaysByMonth = function (year, month) {
return new Date(year, month + 1, 0).getDate()
}
etFirstDayByMonths个函数用于确定指定月份的第一天是星期几。返回值是一个数字,其中 0 表示星期日,1 表示星期一,依此类推。
// 当前月的第一天是星期几
export const getFirstDayByMonths = function (year, month) {
return new Date(year, month, 1).getDay()
}
etLastDayByMonth函数用于确定指定月份的最后一天是星期几。返回值与getFirstDayByMonths类似。
// 当前月的最后一天是星期几
export const getLastDayByMonth = function (year, month) {
const lastDay = new Date(year, month + 1, 0).getDate();
return new Date(year, month, lastDay).getDay();
}
5.etCurrentYearMonth函数用于设置当前的年份、月份和日期。它接受一个日期对象作为可选参数。
// 获取年月日
export const setCurrentYearMonth = function (d = this.shareDate) {
let year = d.getFullYear()
let month = d.getMonth()
let date = d.getDate()
this.showYearMonth = {
year,
month,
date,
}
}
6.reateCalendar函数用于创建一个包含农历和阳历详细信息的当前月份的日历。它填充了一个包含日期对象和相关信息的数组。
export const createCalendar = async function () {
// 一天有多少毫秒
const oneDayMS = 24 * 60 * 60 * 1000
let list = []
let { year, month } = this.showYearMonth
// 当前月份第一天是星期几
let firstDay = this.getFirstDayByMonths(year, month)
// 填充多少天,因为我将星期日放到最后了,所以需要另外调整下
let prefixDaysLen = firstDay === 0 ? 6 : firstDay - 1
// 向前移动之后的毫秒数
let begin = new Date(year, month, 1).getTime() - oneDayMS * prefixDaysLen
// 当前月份最后一天是星期几
let lastDay = this.getLastDayByMonth(year, month)
// 填充多少天,因为我将星期日放到最后了,所以需要另外调整下
let suffixDaysLen = lastDay === 0 ? 0 : 7 - lastDay
// 向后移动之后的毫秒数
let end = new Date(year, month + 1, 0).getTime() + oneDayMS * suffixDaysLen
// 填充天
while (begin <= end) {
let currentDate = new Date(begin)
let curYear = currentDate.getFullYear()
let curMonth = currentDate.getMonth()
let date = currentDate.getDate()
list.push({
year: curYear,
month: curMonth + 1, // 月是从0开始的
date: date,
value: dateFormater('YYYY-MM-DD', currentDate),
disable: curMonth !== month,
})
begin += oneDayMS
}
list = list.map(v => {
var solar = Solar.fromDate(new Date(v.value))
// 获取阴历
v.lunar = solar.getLunar().toString()
v._lunar = v.lunar.substring(v.lunar.length - 2)
// 获取阳历节日
v.festivals = solar.getFestivals().toString()
// 获取节气
const timeObj = this.chineseDateToNumber(v.lunar)
const res = Lunar.fromYmd(timeObj.year, timeObj.month, timeObj.day)
v.jieQi = res.getJieQi() || ''
// 获取阴历节日
v._festivals = res.getFestivals().join(' ') || ''
return v
})
this.calendarList = list
}
7.hangeDate数用于更改选定的日期并更新日历。它接受一个日期作为参数,并将其设置为选定日期,然后重新生成日历。
// 切换日期
export const changeDate = function (date) {
this.shareDate = new Date(date)
this.setCurrentYearMonth()
this.createCalendar() // 创建当前月对应日历的日期数据
}
8.nitDataFun函数用于初始化日历的数据。它设置了一个默认的当前日期,然后调用 etCurrentYearMonth和 reateCalendar以生成初始的日历数据。
// 初始化数据
export const initDataFun = function () {
this.shareDate = new Date()
this.setCurrentYearMonth()
this.createCalendar()
this.getNow()
}
9.getNow 函数用于获取当前日期的农历、阳历节日和节气信息。它使用 lunar-javascript 库来获取相关信息。
// 获取当前日期的农历,节气,节日
export const getNow = function () {
var solar = Solar.fromDate(new Date())
let nowLunar = solar.getLunar().toString()
// 农历日期
this.lunar = nowLunar.substring(nowLunar.length - 4)
// 阳历节日
this.gregorianFestival = solar.getFestivals().toString()
// 中文日期转数字
const timeObj = this.chineseDateToNumber(nowLunar)
const res = Lunar.fromYmd(timeObj.year, timeObj.month, timeObj.day)
// 农历节日
this.lunarFestival = res.getFestivals().join(' ') || ''
// 节气
this.jieQi = res.getJieQi() || ''
}
10.nowTime 函数用于返回当前月份的日历。它将选定日期设置为当前日期,然后调用 setCurrentYearMonth 和 createCalendar 以生成当前月份的日历数据。
// 回到当前月份
export const nowTime = function(){
this.shareDate=new Date()
this.setCurrentYearMonth()
this.createCalendar() // 创建当前月对应日历的日期数据
}
下面给出完整的代码,为了便于维护将一个vue文件拆分成4个模块,分别引入
HTML代码
<template>
<div style="background-color: skyblue;" class="pl20 pr20">
<h1 class="tc">带阴历-阳历-节日-节气的日历组件</h1>
<div class="f xb ac mt10 mb10">
<div class="b">
当前时间:{{ currentTime }}
农历{{ lunar }}
<!-- 节气 -->
{{ jieQi }}
<!-- 阳历节日 -->
{{ gregorianFestival }}
<!-- 阴历节日 -->
{{ lunarFestival }}
</div>
<div>
<Button type="success" class="mr10" @click="nowTime">回到当前月份</Button>
<DatePicker type="month" placeholder="选择年月" style="width: 200px" v-model="shareDate" @on-change="changeDate" :clearable="false" :editable="false"></DatePicker>
</div>
</div>
<!-- 第一排的星期几 -->
<div class="f b" style="border: 1px #000 solid;border-right: 0;">
<div
class="f1 tc pt20 pb20"
style="background-color: pink;border-right: 1px #000 solid;"
v-for="(item, index) in weekList" :key="index"
>
{{ item }}
</div>
</div>
<div class="f" style="flex-wrap: wrap; border: 1px solid #000;border-left: 0;border-top: 0;border-bottom: 0;">
<div
v-for="item, index in calendarList" :key="index"
style="width: calc( 100% / 7);height: 150px;border-left: 1px solid #000;border-bottom: 1px solid #000;"
:class="['pl10 pt10',item.value==$Z.dateFormater('YYYY-MM-DD',new Date())?'today':'',item.disable ? 'allowed' : 'chooseDay']"
>
<div :class="['f',item.disable?'g9':'gred']">
<div class="mr10 b">{{ item.date }}</div>
<!-- 如果有节日或节气就显示节日或节气,否则显示阴历 -->
<div>{{ item.festivals ? item.festivals : item._festivals ? item._festivals : item.jieQi ? item.jieQi : item._lunar }}</div>
</div>
</div>
</div>
</div>
</template>
<script src='./index.js'></script>
<style src='./index.css' scoped></style>
index.css代码
.today{
background-color: rgba(255, 165, 0,.4);
}
.chooseDay:hover{
background-color: rgba(255, 165, 0,.8);
}
.allowed{
cursor: not-allowed;
}
index.js代码
import * as func from "./func.js"
import { dateFormater } from "@/common.js"
export default {
name: '',
components: {},
data() {
return {
showYearMonth: {}, // 显示的年月
calendarList: [], // 用于遍历显示
shareDate: '', //
weekList: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"], // 周
now: new Date(),
lunar:'', //农历
lunarFestival:'', //农历节日
jieQi:'', //节气
gregorianFestival:'' //阳历节日
}
},
methods: {
...func,
},
created() {
this.initDataFun()
},
mounted() {
setInterval(() => {
this.now = new Date()
}, 1000);
},
computed: {
currentTime() {
return dateFormater('YYYY-MM-DD hh:mm:ss', this.now)
},
},
}
func.js代码
import { dateFormater } from "@/common.js"
import { Solar, Lunar } from 'lunar-javascript'
// 中文日期转数字
export const chineseDateToNumber = function (chineseDate) {
const yearMap = {
'0': 0, 'O': 0, '〇': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '十一': 11, '十二': 12,
}
const monthMap = {
'正': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '十一': 11, '腊': 12, '冬': 11,
'闰正': 1, '闰二': 2, '闰三': 3, '闰四': 4, '闰五': 5, '闰六': 6, '闰七': 7, '闰八': 8, '闰九': 9, '闰十': 10, '闰十一': 11, '闰冬': 11, '闰腊': 12,
}
const dayMap = {
'一': 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,
}
let [year, res1] = chineseDate.split('年')
let [month, day] = res1.split('月')
year = year.split('').map(v => yearMap[v]).join('')
month = monthMap[month.replace('闰', '')]
day = day.replace('初', '')
day = dayMap[day]
return { year: Number(year), month, day }
}
// 判断当前月有多少天
export const getDaysByMonth = function (year, month) {
return new Date(year, month + 1, 0).getDate()
}
// 当前月的第一天是星期几
export const getFirstDayByMonths = function (year, month) {
return new Date(year, month, 1).getDay()
}
// 当前月的最后一天是星期几
export const getLastDayByMonth = function (year, month) {
const lastDay = new Date(year, month + 1, 0).getDate();
return new Date(year, month, lastDay).getDay();
}
// 获取年月日
export const setCurrentYearMonth = function (d = this.shareDate) {
let year = d.getFullYear()
let month = d.getMonth()
let date = d.getDate()
this.showYearMonth = {
year,
month,
date,
}
}
export const createCalendar = async function () {
// 一天有多少毫秒
const oneDayMS = 24 * 60 * 60 * 1000
let list = []
let { year, month } = this.showYearMonth
// 当前月份第一天是星期几
let firstDay = this.getFirstDayByMonths(year, month)
// 填充多少天,因为我将星期日放到最后了,所以需要另外调整下
let prefixDaysLen = firstDay === 0 ? 6 : firstDay - 1
// 向前移动之后的毫秒数
let begin = new Date(year, month, 1).getTime() - oneDayMS * prefixDaysLen
// 当前月份最后一天是星期几
let lastDay = this.getLastDayByMonth(year, month)
// 填充多少天,因为我将星期日放到最后了,所以需要另外调整下
let suffixDaysLen = lastDay === 0 ? 0 : 7 - lastDay
// 向后移动之后的毫秒数
let end = new Date(year, month + 1, 0).getTime() + oneDayMS * suffixDaysLen
// 填充天
while (begin <= end) {
let currentDate = new Date(begin)
let curYear = currentDate.getFullYear()
let curMonth = currentDate.getMonth()
let date = currentDate.getDate()
list.push({
year: curYear,
month: curMonth + 1, // 月是从0开始的
date: date,
value: dateFormater('YYYY-MM-DD', currentDate),
disable: curMonth !== month,
})
begin += oneDayMS
}
list = list.map(v => {
var solar = Solar.fromDate(new Date(v.value))
// 获取阴历
v.lunar = solar.getLunar().toString()
v._lunar = v.lunar.substring(v.lunar.length - 2)
// 获取阳历节日
v.festivals = solar.getFestivals().toString()
// 获取节气
const timeObj = this.chineseDateToNumber(v.lunar)
const res = Lunar.fromYmd(timeObj.year, timeObj.month, timeObj.day)
v.jieQi = res.getJieQi() || ''
// 获取阴历节日
v._festivals = res.getFestivals().join(' ') || ''
return v
})
this.calendarList = list
console.log(list);
}
// 切换日期
export const changeDate = function (date) {
this.shareDate = new Date(date)
this.setCurrentYearMonth()
this.createCalendar() // 创建当前月对应日历的日期数据
}
// 初始化数据
export const initDataFun = function () {
this.shareDate = new Date()
this.setCurrentYearMonth()
this.createCalendar()
this.getNow()
}
// 获取当前日期的农历,节气,节日
export const getNow = function () {
var solar = Solar.fromDate(new Date())
let nowLunar = solar.getLunar().toString()
// 农历日期
this.lunar = nowLunar.substring(nowLunar.length - 4)
// 阳历节日
this.gregorianFestival = solar.getFestivals().toString()
// 中文日期转数字
const timeObj = this.chineseDateToNumber(nowLunar)
const res = Lunar.fromYmd(timeObj.year, timeObj.month, timeObj.day)
// 农历节日
this.lunarFestival = res.getFestivals().join(' ') || ''
// 节气
this.jieQi = res.getJieQi() || ''
}
// 回到当前月份
export const nowTime = function(){
this.shareDate=new Date()
this.setCurrentYearMonth()
this.createCalendar() // 创建当前月对应日历的日期数据
}