最近遇到处理阴历日期的问题(生日),就查资料了解了一下关于阴历阳历的知识。参照百度文库

下面简略介绍一下阴历阳历转换的算法原理:

阳历,有很强的规律性。每年12个月,1、3、5、7、8、10、12月都为31天;2月份平年28天,能被4除尽的年份里为29天,但1900年为28天;其余月份为31天。阴历却没有什么特定的规律,是根据天文观测得到的某月是29天还是30天。下面是经过整理的150年内的阴历数据:

     0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0,0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6,0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0

然后解释一下表中的数据,拿第一个0x04bd8来说吧,他是5个16进制数,共20bit。最后四位,即8,代表该年闰月的月份,为0则没有闰月。前四位,即0,在该年有闰月才有意义,为0表示闰月29天,为1表示闰月30天。中间12位,即4bd代表该年12个月每个月的天数,0表示29天,1表示30天。

然后就是根据阳历的1900年1月31日是阴历的1900年的正月初一,然后查表得出阴历和阳历的关系。

下面上代码:

package com.wekri.calendar;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;/*** <b>描述</b>: 日历转换工具类:阴历和阳历日期互换(阴历日期范围19000101~20491229)<br>* @author liu 2015-1-5*/
public class CalendarUtil {//   private static final Logger logger = LoggerFactory.getLogger(CalendarUtil.class);// 计算阴历日期参照1900年到2049年private final static int[] LUNAR_INFO = {0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0,0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6,0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0};// 允许输入的最小年份private final static int MIN_YEAR = 1900;// 允许输入的最大年份private final static int MAX_YEAR = 2049;// 当年是否有闰月private static boolean isLeapYear;// 阳历日期计算起点private final static String START_DATE = "19000130";/*** 计算阴历 {@code year}年闰哪个月 1-12 , 没闰传回 0* @param year 阴历年* @return (int)月份* @author liu 2015-1-5*/private static int getLeapMonth(int year) {return (int) (LUNAR_INFO[year - 1900] & 0xf);}/*** 计算阴历{@code year}年闰月多少天* @param year 阴历年* @return (int)天数* @author liu 2015-1-5*/private static int getLeapMonthDays(int year) {if(getLeapMonth(year)!=0){if((LUNAR_INFO[year - 1900] & 0xf0000)==0){return 29;}else {return 30;}}else{return 0;}}/*** 计算阴历{@code lunarYeay}年{@code month}月的天数* @param lunarYeay 阴历年* @param month 阴历月* @return (int)该月天数* @throws Exception* @author liu 2015-1-5*/private static int getMonthDays(int lunarYeay, int month) throws Exception {if ((month > 31) || (month < 0)) {throw(new Exception("月份有错!"));}// 0X0FFFF[0000 {1111 1111 1111} 1111]中间12位代表12个月,1为大月,0为小月int bit = 1 << (16-month);if(((LUNAR_INFO[lunarYeay - 1900] & 0x0FFFF)&bit)==0){return 29;}else {return 30;}}/*** 计算阴历{@code year}年的总天数* @param year 阴历年* @return (int)总天数* @author liu 2015-1-5*/private static int getYearDays(int year) {int sum = 29*12;for(int i=0x8000;i>=0x8;i>>=1){if((LUNAR_INFO[year-1900]&0xfff0&i)!=0){sum++;}}return sum+getLeapMonthDays(year);}/*** 计算两个阳历日期相差的天数。计算不准确,已经废弃* @param startDate 开始时间* @param endDate 截至时间* @return (int)天数* @author liu 2015-1-5*/@Deprecatedprivate static int daysBetween2(Date startDate, Date endDate) {long between_days=(endDate.getTime()-startDate.getTime())/(1000*3600*24);return Integer.parseInt(String.valueOf(between_days));}/*** 计算两个阳历日期相差的天数。* @param startDate 开始时间* @param endDate 截至时间* @return (int)天数* @author liu 2017-3-2*/private static int daysBetween(Date startDate, Date endDate) {int days = 0;//将转换的两个时间对象转换成Calendar对象Calendar can1 = Calendar.getInstance();can1.setTime(startDate);Calendar can2 = Calendar.getInstance();can2.setTime(endDate);//拿出两个年份int year1 = can1.get(Calendar.YEAR);int year2 = can2.get(Calendar.YEAR);//天数Calendar can = null;//如果can1 < can2//减去小的时间在这一年已经过了的天数//加上大的时间已过的天数if(can1.before(can2)){days -= can1.get(Calendar.DAY_OF_YEAR);days += can2.get(Calendar.DAY_OF_YEAR);can = can1;}else{days -= can2.get(Calendar.DAY_OF_YEAR);days += can1.get(Calendar.DAY_OF_YEAR);can = can2;}for (int i = 0; i < Math.abs(year2-year1); i++) {//获取小的时间当前年的总天数days += can.getActualMaximum(Calendar.DAY_OF_YEAR);//再计算下一年。can.add(Calendar.YEAR, 1);}return days;}/*** 检查阴历日期是否合法* @param lunarYear 阴历年* @param lunarMonth 阴历月* @param lunarDay 阴历日* @param leapMonthFlag 闰月标志* @throws Exception*/private static void checkLunarDate(int lunarYear, int lunarMonth, int lunarDay, boolean leapMonthFlag) throws Exception {if ((lunarYear < MIN_YEAR) || (lunarYear > MAX_YEAR)) {throw(new Exception("非法农历年份!"));}if ((lunarMonth < 1) || (lunarMonth > 12)) {throw(new Exception("非法农历月份!"));}if ((lunarDay < 1) || (lunarDay > 30)) { // 中国的月最多30天throw(new Exception("非法农历天数!"));}int leap = getLeapMonth(lunarYear);// 计算该年应该闰哪个月if ((leapMonthFlag == true) && (lunarMonth != leap)) {throw(new Exception("非法闰月!"));}}/*** 阴历转换为阳历* @param lunarDate 阴历日期,格式YYYYMMDD* @param leapMonthFlag 是否为闰月* @return 阳历日期,格式:YYYYMMDD* @throws Exception* @author liu 2015-1-5*/public static String lunarToSolar(String lunarDate, boolean leapMonthFlag) throws Exception{int lunarYear = Integer.parseInt(lunarDate.substring(0, 4));int lunarMonth = Integer.parseInt(lunarDate.substring(4, 6));int lunarDay = Integer.parseInt(lunarDate.substring(6, 8));checkLunarDate(lunarYear, lunarMonth, lunarDay, leapMonthFlag);int offset = 0;for (int i = MIN_YEAR; i < lunarYear; i++) {int yearDaysCount = getYearDays(i); // 求阴历某年天数offset += yearDaysCount;}//计算该年闰几月int leapMonth = getLeapMonth(lunarYear);if(leapMonthFlag & leapMonth != lunarMonth){throw(new Exception("您输入的闰月标志有误!"));}//当年没有闰月或月份早于闰月或和闰月同名的月份if(leapMonth==0|| (lunarMonth < leapMonth) || (lunarMonth==leapMonth && !leapMonthFlag)){for (int i = 1; i < lunarMonth; i++) {int tempMonthDaysCount = getMonthDays(lunarYear, i);offset += tempMonthDaysCount;}// 检查日期是否大于最大天if (lunarDay > getMonthDays(lunarYear, lunarMonth)) {throw(new Exception("不合法的农历日期!"));}offset += lunarDay; // 加上当月的天数}else{//当年有闰月,且月份晚于或等于闰月for (int i = 1; i < lunarMonth; i++) {int tempMonthDaysCount = getMonthDays(lunarYear, i);offset += tempMonthDaysCount;}if (lunarMonth>leapMonth) {int temp = getLeapMonthDays(lunarYear); // 计算闰月天数offset += temp; // 加上闰月天数if (lunarDay > getMonthDays(lunarYear, lunarMonth)) {throw(new Exception("不合法的农历日期!"));}offset += lunarDay;}else {  // 如果需要计算的是闰月,则应首先加上与闰月对应的普通月的天数// 计算月为闰月int temp = getMonthDays(lunarYear, lunarMonth); // 计算非闰月天数offset += temp;if (lunarDay > getLeapMonthDays(lunarYear)) {throw(new Exception("不合法的农历日期!"));}offset += lunarDay;}}SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");Date myDate = null;myDate = formatter.parse(START_DATE);Calendar c = Calendar.getInstance();c.setTime(myDate);c.add(Calendar.DATE, offset);myDate = c.getTime();return formatter.format(myDate);}/*** 阳历日期转换为阴历日期* @param solarDate 阳历日期,格式YYYYMMDD* @return 阴历日期* @throws Exception* @author liu 2015-1-5*/public static String solarToLunar(String solarDate) throws Exception{int i;int temp = 0;int lunarYear;int lunarMonth; //农历月份int lunarDay; //农历当月第几天boolean leapMonthFlag =false;SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");Date myDate = null;Date startDate = null;try {myDate = formatter.parse(solarDate);startDate = formatter.parse(START_DATE);} catch (ParseException e) {e.printStackTrace();}int offset = daysBetween(startDate,myDate);for (i = MIN_YEAR; i <= MAX_YEAR; i++){temp = getYearDays(i);  //求当年农历年天数if (offset - temp < 1){break;}else{offset -= temp;}}lunarYear = i;int leapMonth = getLeapMonth(lunarYear);//计算该年闰哪个月//设定当年是否有闰月if (leapMonth > 0){isLeapYear = true;}else{isLeapYear = false;}for (i = 1;  i<=12; i++) {if(i==leapMonth+1 && isLeapYear){temp = getLeapMonthDays(lunarYear);isLeapYear = false;leapMonthFlag = true;i--;}else{temp = getMonthDays(lunarYear, i);}offset -= temp;if(offset<=0){break;}}offset += temp;lunarMonth = i;lunarDay = offset;return "阴历:"+lunarYear+"年"+(leapMonthFlag&(lunarMonth==leapMonth)?"闰":"")+lunarMonth+"月"+lunarDay+"日";}}

下面测试一下

package calendar;public class Test {public static void main(String[] args) throws Exception {System.out.println(CalendarUtil.lunarToSolar("19901204", false));System.out.println(CalendarUtil.lunarToSolar("19841021", true));System.out.println("************");System.out.println(CalendarUtil.solarToLunar("19000923"));System.out.println(CalendarUtil.solarToLunar("19000924"));System.out.println(CalendarUtil.solarToLunar("19001022"));System.out.println(CalendarUtil.solarToLunar("19001023"));System.out.println(CalendarUtil.solarToLunar("19900630"));System.out.println(CalendarUtil.solarToLunar("19841213"));System.out.println(CalendarUtil.solarToLunar("19910119"));}
}

结果:

19910119
19841213
************
阴历:1900年8月30日
阴历:1900年闰8月1日
阴历:1900年闰8月29日
阴历:1900年9月1日
阴历:1990年闰5月7日
阴历:1984年闰10月21日
阴历:1990年12月4日

希望对大家有帮助,欢迎大家吐槽。

java-阴历日期和阳历日期互相转换相关推荐

  1. java 获取阴历日期公历日期转农历日期或者阳历日期转阴历日期

    背景 项目中需要获取农历日期,展示在页面,不使用第三方工具类的情况下,直接使用原生的java api工具类开发 代码如下 package com.hidata.devops.paas;import j ...

  2. java 公历 农历_java已知阳历日期求对应阴历日期源代码

    import java.text.*; import java.util.*; class ChineseCalendarGB { private int gregorianYear; private ...

  3. solarlunar库, 阴历,阳历日期及转换库

    阴历日期,阳历日期,阴历阳历转换库. 没时间写中文了,直接复制库文件里面的,见量.... 1. solar calendar interface:    date range: any date... ...

  4. java中M格式_Java中Date日期字符串格式的各种转换

    编程语言 Java中Date日期字符串格式的各种转换 字号+ 作者:小虾米 2017-04-21 08:51 以下程序源码都是从网络上整理之后,才发到本网站的,新手请收藏啊! public class ...

  5. Java利用正则表达式实现中英文日期转换函数封装

    前言:  Java利用正则表达式实现中英文日期互相转换函数封装,一共实现了6个方法(封装的原因是因为在Android中使用SimpleDateFormat 太麻烦了,各种try catch excep ...

  6. python实现农历和阳历日期转换

    需安装sxtwl包,命令如下 pip install sxtwl 农历(Lunar calendar)<->阳历(solar calendar)转换 代码如下(基于python3): im ...

  7. java 农历节日 转公历日期_公历农历互相转换的Java日历工具类

    /** * 工具类,实现公农历互转 */ public class LunarCalendar { /** * 支持转换的最小农历年份 */ public static final int MIN_Y ...

  8. java utc 转换pst_关于c#:如何将UTC + 0日期转换为PST日期?

    我有这个UTC+0日期: 2011-11-28T07:21:41.000Z 我想在C上把它转换成一个PST日期.我该怎么做?尝试: object.Data.ToLocalTime() 但是我不能得到正 ...

  9. java 时间处理_JAVA处理日期时间常用方法

    Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR.MONTH.DAY_OF_MONTH.HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了 ...

  10. java阳历农历互相转换

    package fhj.help; import java.text.ParseException; import java.text.SimpleDateFormat; import java.ut ...

最新文章

  1. 解决KeyError: ‘acc‘ 和KeyError: ‘val_acc‘错误
  2. NR 5G 安全架构概述
  3. 软件本地化,软件本地化公司
  4. boost::range模块heap算法相关的测试程序
  5. SalesArea F4 help implementation
  6. ubuntu下集群设置静态ip
  7. buildroot自带程序(库)编译并安装
  8. 显示recv调用次数_腾讯云“云开发”日调用超7亿次,只为和开发者“交个朋友”...
  9. 如何在设计项目中使用冷调酷色
  10. php ajax 长轮询 表单,Thinkphp结合AJAX长轮询实现PC与APP推送详解
  11. 趣学 C 语言(四)—— 字符串与字符数组
  12. mysql中like,limit,union及union all查询
  13. oracle regexp
  14. 哈理工OJ 1151 追求(斐波那契变形【思维题目】)
  15. cognex扫码枪识别内容直接_S7-1200与 扫 描 枪 Cognex DM60S 通信问题。
  16. Word2016更改不同的级别标题序号:如2.2 ,2.2.1类标题序号
  17. hive 关于用户留存率的计算
  18. APP UI结构-首页功能点大集锦,很干很详细
  19. 安全的微信群管理工具
  20. 海康威视网络摄像头配置本地存储服务器(远程连接查看回放)

热门文章

  1. Linux学习3 :用户及文件权限管理
  2. 美团点评运营数据产品化应用与实践
  3. python程度员要学很多英语吗_为什么程序员应该学好英语?
  4. powerdesigner16 license key
  5. Android开发艺术探索之初探AIDL(一)
  6. AI机器学习面试常见问题与答案
  7. html适合做标题得字体,40个漂亮英文字体-而且适合制作大标题哦
  8. 基于Simulink使用激光雷达数据跟踪车辆仿真(附源码)
  9. 今天上班穿了一只拖鞋和一只凉鞋
  10. 首次参加齐鲁软件设计大赛经验(及总结出的划水要点)