返回

Android开发之春节节气以及各类历法日期转换工具

Android

一、前言

农历、阴历、阳历都是时间系统的两种表达方式,而春节和节气是基于时间系统而产生的节日和时间节点。
本工具能实现将阳历日期转换成农历日期和阴历日期,也能将农历日期、阴历日期转换成阳历日期。

二、工具原理

阳历日期转换农历日期或阴历日期,实质上是将阳历日期转换成农历或阴历的年、月、日。
首先将阳历日期转换为距1900年1月1日经过的天数,然后利用【中国农历工具网站】提供的【农历查询】获取这一天是农历或阴历的哪一年、哪一月、哪一日。

三、工具类

public class LunarCalendar {

    private int year;
    private int month;
    private int day;
    private boolean leap;

    /**
     * 将阳历日期转换成农历日期
     *
     * @param solarYear  阳历年
     * @param solarMonth 阳历月
     * @param solarDay   阳历日
     */
    public LunarCalendar(int solarYear, int solarMonth, int solarDay) {
        // 将阳历日期转换为距1900年1月1日经过的天数
        int daysSince1900 = solarToDays(solarYear, solarMonth, solarDay);

        // 获取农历年份
        year = 1900 + daysSince1900 / 365;

        // 获取农历月份
        int daysInLunarYear = 365 * (year - 1900) + daysSince1900 % 365;
        month = 1;
        while (daysInLunarYear > getDaysInLunarMonth(year, month)) {
            daysInLunarYear -= getDaysInLunarMonth(year, month);
            month++;
        }

        // 获取农历日子
        day = daysInLunarYear;

        // 判断农历年份是否为闰年
        leap = isLunarLeapYear(year);
    }

    /**
     * 将阳历日期转换成农历日期
     *
     * @param date 阳历日期,格式为"yyyy-MM-dd"
     */
    public LunarCalendar(String date) {
        String[] parts = date.split("-");
        int year = Integer.parseInt(parts[0]);
        int month = Integer.parseInt(parts[1]);
        int day = Integer.parseInt(parts[2]);

        this(year, month, day);
    }

    /**
     * 将阳历日期转换成距1900年1月1日经过的天数
     *
     * @param year  阳历年
     * @param month 阳历月
     * @param day   阳历日
     * @return 距1900年1月1日经过的天数
     */
    private int solarToDays(int year, int month, int day) {
        int days = 0;

        // 计算从1900年1月1日到year年1月1日经过的天数
        for (int i = 1900; i < year; i++) {
            days += 365 + isSolarLeapYear(i);
        }

        // 计算从year年1月1日到year年month月day日经过的天数
        for (int i = 1; i < month; i++) {
            days += getDaysInSolarMonth(year, i);
        }

        // 计算year年month月day日当天经过的天数
        days += day;

        return days;
    }

    /**
     * 判断阳历年是否为闰年
     *
     * @param year 阳历年
     * @return true if year is a leap year, false otherwise
     */
    private boolean isSolarLeapYear(int year) {
        return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
    }

    /**
     * 获取阳历年中某个月的天数
     *
     * @param year  阳历年
     * @param month 阳历月
     * @return 阳历年中某个月的天数
     */
    private int getDaysInSolarMonth(int year, int month) {
        int[] daysInMonths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        if (month == 2 && isSolarLeapYear(year)) {
            return 29;
        } else {
            return daysInMonths[month - 1];
        }
    }

    /**
     * 获取农历年中某个月的天数
     *
     * @param year  农历年
     * @param month 农历月
     * @return 农历年中某个月的天数
     */
    private int getDaysInLunarMonth(int year, int month) {
        int[] daysInLunarMonths = {29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30};

        if (isLunarLeapYear(year) && month == 13) {
            return 29;
        } else {
            return daysInLunarMonths[month - 1];
        }
    }

    /**
     * 判断农历年是否为闰年
     *
     * @param year 农历年
     * @return true if year is a leap year, false otherwise
     */
    private boolean isLunarLeapYear(int year) {
        return ((year - 4) % 19) == 0;
    }

    /**
     * 获取农历年份
     *
     * @return 农历年份
     */
    public int getYear() {
        return year;
    }

    /**
     * 获取农历月份
     *
     * @return 农历月份
     */
    public int getMonth() {
        return month;
    }

    /**
     * 获取农历日子
     *
     * @return 农历日子
     */
    public int getDay() {
        return day;
    }

    /**
     * 判断农历年份是否为闰年
     *
     * @return true if year is a leap year, false otherwise
     */
    public boolean isLeap() {
        return leap;
    }

    /**
     * 将农历日期转换成阳历日期
     *
     * @return 阳历日期,格式为"yyyy-MM-dd"
     */
    public String toSolarString() {
        int daysSince1900 = lunarToDays(year, month, day);

        int solarYear = 1900 + daysSince1900 / 365;
        int solarMonth = 1;
        while (daysSince1900 > getDaysInSolarMonth(solarYear, solarMonth)) {
            daysSince1900 -= getDaysInSolarMonth(solarYear, solarMonth);
            solarMonth++;
        }
        int solarDay = daysSince1900;

        return String.format("%04d-%02d-%02d", solarYear, solarMonth, solarDay);
    }

    /**
     * 将农历日期转换成距1900年1月1日经过的天数
     *
     * @param year  农历年
     * @param month 农历月
     * @param day   农历日
     * @return 距1900年1月1日经过的天数
     */
    private int lunarToDays(int year, int month, int day) {
        int days = 0;

        // 计算从1900年1月1日到year年1月1日经过的天数
        for (int i = 1900; i < year; i++) {
            days += 365 + isLunarLeapYear(i);
        }

        // 计算从year年1月1日到year年month月day日经过的天数
        for (int i = 1; i < month; i