百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Java 阴历阳历转换 java农历

liebian365 2024-10-22 15:35 3 浏览 0 评论

代码如下 收藏备用


import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;

/**
* 工具类,实现阴阳历互转
*
* @author luohao
*/
public class LunarCalendar {
/**
* 支持转换的最小农历年份
*/
public static final int MIN_YEAR = 1900;

/**
* 支持转换的最大农历年份
*/
public static final int MAX_YEAR = 2099;

/**
* 公历每月前的天数
*/
private static final int[] DAYS_BEFORE_MONTH = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
/**
* 用来表示1900年到2099年间农历年份的相关信息,共24位bit的16进制表示,其中:
* 1. 前4位表示该年闰哪个月;
* 2. 5-17位表示农历年份13个月的大小月分布,0表示小,1表示大;
* 3. 最后7位表示农历年首(正月初一)对应的公历日期。
* 以2014年的数据0x955ABF为例说明:
* 1001 0101 0101 1010 1011 1111
* 闰九月 农历正月初一对应公历1月31号
*/
private static final int[] LUNAR_INFO = {
/*1900*/
0x84B6BF,
/*1901-1910*/
0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A,
/*1911-1920*/
0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754,
/*1921-1930*/
0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E,
/*1931-1940*/
0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48,
/*1941-1950*/
0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51,
/*1951-1960*/
0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C,
/*1961-1970*/
0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46,
/*1971-1980*/
0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50,
/*1981-1990*/
0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x095746, 0x5497BB,
/*1991-2000*/
0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645,
/*2001-2010*/
0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E,
/*2011-2020*/
0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9,
/*2021-2030*/
0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x6a573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43,
/*2031-2040*/
0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C,
/*2041-2050*/
0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37,
/*2051-2060*/
0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06AA44, 0x4AB638, 0x0AAE4C, 0x092E42,
/*2061-2070*/
0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B,
/*2071-2080*/
0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6,
/*2081-2090*/
0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E,
/*2091-2099*/
0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5
};

/**
* 将农历日期转换为公历日期
*
* @param year 农历年份
* @param month 农历月
* @param monthDay 农历日
* @param isLeapMonth 该月是否是闰月
* @return 返回农历日期对应的公历日期,year0, month1, day2.
*/
public static final int[] lunarToSolar(int year, int month, int monthDay, boolean isLeapMonth) {

int dayOffset;

int leapMonth;

int i;

if (year < MIN_YEAR || year > MAX_YEAR || month < 1 || month > 12
|| monthDay < 1 || monthDay > 30) {
throw new IllegalArgumentException(
"Illegal lunar date, must be like that:\n\t" +
"year : 1900~2099\n\t" +
"month : 1~12\n\t" +
"day : 1~30");
}
dayOffset = (LUNAR_INFO[year - MIN_YEAR] & 0x001F) - 1;
if (((LUNAR_INFO[year - MIN_YEAR] & 0x0060) >> 5) == 2) {
dayOffset += 31;
}
for (i = 1; i < month; i++) {
if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (i - 1))) == 0) {
dayOffset += 29;
} else {
dayOffset += 30;
}
}
dayOffset += monthDay;

leapMonth = (LUNAR_INFO[year - MIN_YEAR] & 0xf00000) >> 20;

// 这一年有闰月

if (leapMonth != 0) {
if (month > leapMonth || (month == leapMonth && isLeapMonth)) {

if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (month - 1))) == 0) {
dayOffset += 29;
} else {
dayOffset += 30;
}
}
}

if (dayOffset > 366 || (year % 4 != 0 && dayOffset > 365)) {
year += 1;

if (year % 4 == 1) {
dayOffset -= 366;
} else {
dayOffset -= 365;
}
}

int[] solarInfo = new int[3];
for (i = 1; i < 13; i++) {
int iPos = DAYS_BEFORE_MONTH[i];

if (year % 4 == 0 && i > 2) {

iPos += 1;
}

if (year % 4 == 0 && i == 2 && iPos + 1 == dayOffset) {

solarInfo[1] = i;

solarInfo[2] = dayOffset - 31;

break;

}
if (iPos >= dayOffset) {
solarInfo[1] = i;
iPos = DAYS_BEFORE_MONTH[i - 1];
if (year % 4 == 0 && i > 2) {
iPos += 1;
}
if (dayOffset > iPos) {
solarInfo[2] = dayOffset - iPos;
} else if (dayOffset == iPos) {
if (year % 4 == 0 && i == 2) {
solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1] + 1;
} else {
solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1];
}
} else {
solarInfo[2] = dayOffset;
}
break;
}
}
solarInfo[0] = year;
return solarInfo;
}

/**
* 将公历日期转换为农历日期,且标识是否是闰月
*
* @param year
* @param month
* @param monthDay
* @return 返回公历日期对应的农历日期,year0,month1,day2,leap3
*/
public static final int[] solarToLunar(int year, int month, int monthDay) {
int[] lunarDate = new int[4];
Date baseDate = new GregorianCalendar(1900, 0, 31).getTime();
Date objDate = new GregorianCalendar(year, month - 1, monthDay).getTime();
int offset = (int) ((objDate.getTime() - baseDate.getTime()) / 86400000L);
// 用offset减去每农历年的天数计算当天是农历第几天
// iYear最终结果是农历的年份, offset是当年的第几天
int iYear, daysOfYear = 0;
for (iYear = MIN_YEAR; iYear <= MAX_YEAR && offset > 0; iYear++) {
daysOfYear = daysInLunarYear(iYear);
offset -= daysOfYear;
}
if (offset < 0) {
offset += daysOfYear;
iYear--;
}
// 农历年份
lunarDate[0] = iYear;
int leapMonth = leapMonth(iYear);
// 闰哪个月,1-12
boolean isLeap = false;
// 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth <= 13 && offset > 0; iMonth++) {
daysOfMonth = daysInLunarMonth(iYear, iMonth);
offset -= daysOfMonth;
}
// 当前月超过闰月,要校正
if (leapMonth != 0 && iMonth > leapMonth) {
--iMonth;
if (iMonth == leapMonth) {
isLeap = true;
}
}
// offset小于0时,也要校正
if (offset < 0) {
offset += daysOfMonth;
--iMonth;
}
lunarDate[1] = iMonth;
lunarDate[2] = offset + 1;
lunarDate[3] = isLeap ? 1 : 0;
return lunarDate;
}

/**
* 传回农历year年month月的总天数
*
* @param year 要计算的年份
* @param month 要计算的月
* @return 传回天数
*/
final public static int daysInMonth(int year, int month) {
return daysInMonth(year, month, false);
}

/**
* 传回农历year年month月的总天数
*
* @param year 要计算的年份
* @param month 要计算的月
* @param leap 当月是否是闰月
* @return 传回天数,如果闰月是错误的,返回0.
*/
public static final int daysInMonth(int year, int month, boolean leap) {
int leapMonth = leapMonth(year);
int offset = 0;
// 如果本年有闰月且month大于闰月时,需要校正
if (leapMonth != 0 && month > leapMonth) {
offset = 1;
}
// 不考虑闰月
if (!leap) {
return daysInLunarMonth(year, month + offset);
} else {
// 传入的闰月是正确的月份
if (leapMonth != 0 && leapMonth == month) {
return daysInLunarMonth(year, month + 1);
}
}
return 0;
}

/**
* 传回农历 year年的总天数
*
* @param year 将要计算的年份
* @return 返回传入年份的总天数
*/
private static int daysInLunarYear(int year) {
int i, sum = 348;
if (leapMonth(year) != 0) {
sum = 377;
}
int monthInfo = LUNAR_INFO[year - MIN_YEAR] & 0x0FFF80;
for (i = 0x80000; i > 0x7; i >>= 1) {
if ((monthInfo & i) != 0) {
sum += 1;
}
}
return sum;
}

/**
* 传回农历 year年month月的总天数,总共有13个月包括闰月
*
* @param year 将要计算的年份
* @param month 将要计算的月份
* @return 传回农历 year年month月的总天数
*/
private static int daysInLunarMonth(int year, int month) {
if ((LUNAR_INFO[year - MIN_YEAR] & (0x100000 >> month)) == 0) {
return 29;
} else {
return 30;
}
}

/**
* 传回农历 year年闰哪个月 1-12 , 没闰传回 0
*
* @param year 将要计算的年份
* @return 传回农历 year年闰哪个月1-12, 没闰传回 0
*/
private static int leapMonth(int year) {
return ((LUNAR_INFO[year - MIN_YEAR] & 0xF00000)) >> 20;
}

public static void main(String[] args) {
System.out.println(Arrays.toString(solarToLunar(2019, 4, 4)));
}
}

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: