通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用java新的日期时间API重写农历LunarDate。

1. version 0.1版本 农历原始算法来自网络,有2个问题:

(1)com.xkzhangsan.time.LunarDate.lunarInfo 数据有误,导致个别农历计算不准确。

(2)没有二十四节气计算。

2.version 0.2版本修改了上面问题:

package com.xkzhangsan.time;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.util.Date; import com.xkzhangsan.time.calculator.DateTimeCalculatorUtil;
import com.xkzhangsan.time.converter.DateTimeConverterUtil;
import com.xkzhangsan.time.holiday.ChineseHolidayEnum; /**
* 农历日期
* 仅支持公历1901-1950年的农历转换
* @ClassName: LunarDate
* @Description: LunarDate
* @author xkzhangsan
* @date 2019年12月30日
* @version 0.2 试用
*/
public final class LunarDate implements Temporal{ /**
* 农历信息
*/
private static final long[] lunarInfo = new long[] { 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, 0x0a5b0,
0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263,
0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0,
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,
0x14b63 }; /**
* 农历月份列表
*/
public static final String[] lunarMonth = new String[] { "", "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬",
"腊" }; /**
* 天干列表
*/
private static final String[] tianGan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" }; /**
* 地支列表
*/
private static final String[] diZhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" }; /**
* 生肖列表
*/
private static final String[] animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" }; /**
* 中文数字0-9
*/
public static final String[] numStr = new String[] { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"}; /**
* 二十四节气
*/
public static final String[] solarTerms = new String[] {"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"}; /**
* 二十四节气数据
*/
private static final long[] solarTermInfo = new long[] {0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758}; /**
* 标准日期
*/
private final LocalDate localDate; /**
* 农历日期,中文
*/
private String lDateCn; /**
* 岁次
*/
private String suiCi; /**
* 生肖
*/
private String lAnimal; /**
* 农历年
*/
private int lYear; /**
* 农历月
*/
private int lMonth; /**
* 农历日
*/
private int lDay; /**
* 农历年,中文
*/
private String lYearCn; /**
* 农历月,中文
*/
private String lMonthCn; /**
* 农历日,中文
*/
private String lDayCn; /**
* 星期,中文
*/
private String weekCn; /**
* 二十四节气
*/
private String solarTerm; /**
* 当前日期月份是否为闰月,是 为"闰"
*/
private String leapMonthCn; private LunarDate(LocalDate localDate) {
super();
this.localDate = localDate;
initialize();
} /**
* 初始化农历日期
*/
public void initialize() {
int year = localDate.getYear();
int month = localDate.getMonthValue();
int day = localDate.getDayOfMonth();
long[] l = calElement(year, month, day); this.lYear = (int) l[0];
this.lMonth = (int) l[1];
this.lDay = (int) l[2]; this.suiCi = cyclical(this.lYear);
this.lAnimal = animalsYear(this.lYear); this.lYearCn = getChinaYear(this.lYear);
this.lMonthCn = lunarMonth[this.lMonth];
this.lDayCn = getChinaDay(this.lDay); this.weekCn = getWeekCn(localDate.getDayOfWeek().getValue());
if(l[7] != -1){
this.solarTerm = solarTerms[(int)l[7]];
}else{
this.solarTerm = "";
}
if(l[6] == 1){
this.leapMonthCn = "闰";
}else{
this.leapMonthCn = "";
}
this.lDateCn = this.lYearCn + "年" + this.leapMonthCn + this.lMonthCn + "月" + this.lDayCn;
} /**
* 通过LocalDateTime创建LunarDate
* @param localDateTime
* @return
*/
public static LunarDate from(LocalDateTime localDateTime) {
return new LunarDate(DateTimeConverterUtil.toLocalDate(localDateTime));
} /**
* 通过LocalDate创建LunarDate
* @param localDate
* @return
*/
public static LunarDate from(LocalDate localDate) {
return new LunarDate(localDate);
} /**
* 通过Instant创建LunarDate
* @param instant
* @return
*/
public static LunarDate from(Instant instant) {
return new LunarDate(DateTimeConverterUtil.toLocalDate(instant));
} /**
* 通过Date创建LunarDate
* @param date
* @return
*/
public static LunarDate from(Date date) {
return new LunarDate(DateTimeConverterUtil.toLocalDate(date));
} public static LunarDate from(Temporal temporal) {
return new LunarDate(DateTimeConverterUtil.toLocalDate(temporal));
} /**
* 传回农历year年的总天数
*
* @param year
* @return
*/
private static final int lunarYearDays(int year) {
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
if ((lunarInfo[year - 1900] & i) != 0)
sum += 1;
}
return (sum + leapMonthDays(year));
} /**
* 传回农历 year年闰月的天数
*
* @param year
* @return
*/
private static final int leapMonthDays(int year) {
if (leapMonth(year) != 0) {
if ((lunarInfo[year - 1900] & 0x10000) != 0)
return 30;
else
return 29;
} else
return 0;
} /**
* 传回农历 year年闰哪个月 1-12 , 没闰传回 0
*
* @param year
* @return
*/
private static final int leapMonth(int year) {
return (int) (lunarInfo[year - 1900] & 0xf);
} /**
* 传回农历 year年month月的总天数
*
* @param year
* @param month
* @return
*/
private static final int monthDays(int year, int month) {
if ((lunarInfo[year - 1900] & (0x10000 >> month)) == 0)
return 29;
else
return 30;
} /**
* 传回农历 year年的生肖
*
* @param year
* @return
*/
public static final String animalsYear(int year) {
return animals[(year - 4) % 12];
} /**
* 传入 月日的offset 传回干支,0=甲子
*
* @param num
* @return
*/
private static final String cyclicalm(int num) {
return (tianGan[num % 10] + diZhi[num % 12]);
} /**
* 传入 offset 传回干支, 0=甲子
*
* @param year
* @return
*/
public static final String cyclical(int year) {
int num = year - 1900 + 36;
return (cyclicalm(num));
} /**
* 计算某年第n个节气的天
* @param year 公历年
* @param n
* @return
*/
public static final int solarTerm(int year, int n){
LocalDateTime startLocalDateTime = LocalDateTime.of(1900,1,6,2,5);
long millis = (long) ((31556925974.7*(year-1900) + solarTermInfo[n]*60000));
LocalDateTime tempLocalDateTime = DateTimeCalculatorUtil.plusMillis(startLocalDateTime, millis);
return tempLocalDateTime.getDayOfMonth();
} /**
* 传出year年month月day日对应的农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5
* .isLeap6.solarTermIndex7
*
* @param year
* @param month
* @param day
* @return
*/
public static final long[] calElement(int year, int month, int day) {
long[] nongDate = new long[8];
int i = 0, temp = 0, leap = 0;
LocalDateTime baseDate = LocalDate.of(1900, 1, 31).atStartOfDay();
LocalDateTime objDate = LocalDate.of(year, month, day).atStartOfDay();
long offset = DateTimeCalculatorUtil.betweenTotalDays(baseDate, objDate);
nongDate[5] = offset + 40;
nongDate[4] = 14;
for (i = 1900; i < 2050 && offset > 0; i++) {
temp = lunarYearDays(i);
offset -= temp;
nongDate[4] += 12;
}
if (offset < 0) {
offset += temp;
i--;
nongDate[4] -= 12;
}
nongDate[0] = i;
nongDate[3] = i - 1864;
leap = leapMonth(i); // 闰哪个月
nongDate[6] = 0;
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
--i;
nongDate[6] = 1;
temp = leapMonthDays((int) nongDate[0]);
} else {
temp = monthDays((int) nongDate[0], i);
}
// 解除闰月
if (nongDate[6] == 1 && i == (leap + 1))
nongDate[6] = 0;
offset -= temp;
if (nongDate[6] == 0)
nongDate[4]++;
}
if (offset == 0 && leap > 0 && i == leap + 1) {
if (nongDate[6] == 1) {
nongDate[6] = 0;
} else {
nongDate[6] = 1;
--i;
--nongDate[4];
}
}
if (offset < 0) {
offset += temp;
--i;
--nongDate[4];
}
nongDate[1] = i;
nongDate[2] = offset + 1; //二十四节气
int solarTermIndex = -1;
int tempMonth = month - 1;
int firstSolarTermOfMonth = solarTerm(year, tempMonth*2);
int secondSolarTermOfMonth = solarTerm(year, tempMonth*2+1);
if(day == firstSolarTermOfMonth){
solarTermIndex = tempMonth*2;
}else if(day == secondSolarTermOfMonth){
solarTermIndex = tempMonth*2 + 1;
}
nongDate[7] = solarTermIndex;
return nongDate;
} /**
* 获取农历中文年
* @param year
* @return
*/
public final static String getChinaYear(int year) {
String ge = numStr[year % 10];
String shi = numStr[year / 10 % 10];
String bai = numStr[year / 100 % 10];
String qian = numStr[year / 1000 % 10];
return qian + bai + shi + ge;
}
/**
* 获取农历中文日期
* @param day
* @return
*/
public final static String getChinaDay(int day) {
String a = "";
if (day == 10)
return "初十";
if (day == 20)
return "二十";
if (day == 30)
return "三十";
int two = (int) ((day) / 10);
if (two == 0)
a = "初";
if (two == 1)
a = "十";
if (two == 2)
a = "廿";
if (two == 3)
a = "三";
int one = (int) (day % 10);
switch (one) {
case 1:
a += "一";
break;
case 2:
a += "二";
break;
case 3:
a += "三";
break;
case 4:
a += "四";
break;
case 5:
a += "五";
break;
case 6:
a += "六";
break;
case 7:
a += "七";
break;
case 8:
a += "八";
break;
case 9:
a += "九";
break;
default:
a += "";
break;
}
return a;
} /**
* 获取中文星期
* @param week
* @return
*/
public final static String getWeekCn(int week) {
String weekCn = "";
switch (week) {
case 1:
weekCn = "星期一";
break;
case 2:
weekCn = "星期二";
break;
case 3:
weekCn = "星期三";
break;
case 4:
weekCn = "星期四";
break;
case 5:
weekCn = "星期五";
break;
case 6:
weekCn = "星期六";
break;
case 7:
weekCn = "星期日";
break;
default:
weekCn = "";
break;
}
return weekCn;
} /**
* 以当前时间创建农历日期LunarDate
* @return
*/
public static LunarDate now() {
LocalDate today = LocalDate.now();
return new LunarDate(today);
} public LocalDate getLocalDate() {
return localDate;
} public String getlDateCn() {
return lDateCn;
} public String getSuiCi() {
return suiCi;
} public String getlAnimal() {
return lAnimal;
} public int getlYear() {
return lYear;
} public int getlMonth() {
return lMonth;
} public int getlDay() {
return lDay;
} public String getlYearCn() {
return lYearCn;
} public String getlMonthCn() {
return lMonthCn;
} public String getlDayCn() {
return lDayCn;
} public String getWeekCn() {
return weekCn;
} public String getSolarTerm() {
return solarTerm;
} public String getLeapMonthCn() {
return leapMonthCn;
} @Override
public String toString() {
return "LunarDate [localDate=" + localDate + ",lDateCn=" + lDateCn + ", suiCi=" + suiCi + ", lAnimal=" + lAnimal + ", lYear=" + lYear
+ ", lMonth=" + lMonth + ", lDay=" + lDay + ", lYearCn=" + lYearCn + ", lMonthCn=" + lMonthCn
+ ", lDayCn=" + lDayCn + ", weekCn=" + weekCn + ", solarTerm=" + solarTerm + ", leapMonthCn=" + leapMonthCn + "]";
} /**
* 格式化输出,如:庚子鼠年 二〇二〇年正月初一 星期六 春节
* @return
*/
public String formatLongCnWithChineseHoliday(){
return suiCi + lAnimal + "年 " + lDateCn + " " + weekCn + " " + ChineseHolidayEnum.getHoliday(localDate).getName();
} /**
* 格式化输出,如: 己亥猪年 二〇一九年腊月初六 星期二
* @return
*/
public String formatLongCn(){
return suiCi + lAnimal + "年 " + lDateCn + " " + weekCn;
} /**
* 格式化输出,如: 0101
* @return
*/
public String formatShort(){
return String.format("%02d", lMonth) + String.format("%02d", lDay);
} @Override
public boolean isSupported(TemporalField field) {
return localDate.isSupported(field);
} @Override
public long getLong(TemporalField field) {
return localDate.getLong(field);
} @Override
public boolean isSupported(TemporalUnit unit) {
return localDate.isSupported(unit);
} @Override
public Temporal with(TemporalField field, long newValue) {
return localDate.with(field, newValue);
} @Override
public Temporal plus(long amountToAdd, TemporalUnit unit) {
return localDate.plus(amountToAdd, unit);
} @Override
public long until(Temporal endExclusive, TemporalUnit unit) {
return localDate.until(endExclusive, unit);
} public static void main(String[] args) {
String str =LunarDate.now().toString();
System.out.println(str);
} }

输出:

LunarDate [localDate=2020-03-22,lDateCn=二〇二〇年二月廿九, suiCi=庚子, lAnimal=鼠, lYear=2020, lMonth=2, lDay=29, lYearCn=二〇二〇, lMonthCn=二, lDayCn=廿九, weekCn=星期日, solarTerm=, leapMonthCn=]

源码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate的更多相关文章

  1. 在swt中获取jar包中的文件 uri is not hierarchical

    uri is not hierarchical 学习了:http://blog.csdn.net/zdsdiablo/article/details/1519719 在swt中获取jar包中的文件: ...

  2. API接口自动化之3 同一个war包中多个接口做自动化测试

    同一个war包中多个接口做自动化测试 一个接口用一个测试类,每个测试用例如下,比如下面是4个测试用例,每个详细的测试用例中含有请求入参,返回体校验,以此来判断每条测试用例是否通过 一个war包中,若含 ...

  3. Andriod项目开发实战(1)——如何在Eclipse中的一个包下建新包

    最开始是想将各个类分门别类地存放在不同的包中,所以想在项目源码包中新建几个不同功能的包eg:utils.model.receiver等,最后的结果应该是下图左边这样的:   很明显建立项目后的架构是上 ...

  4. Mac 如何导出ipa文件中Assets.car包中的切图

    在之前 获取 AppStore 中 应用 的 IPA 包文件(Mac OS 13+)中获取到应用的 IPA 包,可以取出应用的部分图片(如 Logo),如果项目工程中把图片添加到 Assets.xca ...

  5. JDK中的Atomic包中的类及使用

    引言 Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作.原子变量的底层使用了处理器提供的原子指令,但是不同的CPU ...

  6. 【转】Eclipse中查看jar包中的源码

    (简单的方式:通过jd-gui来进行反编译,最简单!,参考我的另一篇博文, 地址:http://www.cnblogs.com/gmq-sh/p/4277991.html) Java Decompil ...

  7. Package.json中dependencies依赖包中^符号和~符号前缀的区别

    刚git了webpack的包发现package.json里面dependencies依赖包的版本号前面的符号有两种,一种是~,一种是^,如下图标记: 然后搜了下在stackoverflow上找到一个比 ...

  8. Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  9. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

随机推荐

  1. Apache的虚拟主机功能(基于IP地址、基于虚拟主机、基于端口)

    1. 安装Apache服务程序(系统用户,1-199之间) 第一步:在虚拟机软件里选中光盘镜像: 第二步:将光盘设备挂载到/media/cdrom目录 输入:mkdir -p /media/cdrom ...

  2. js遍历传参到html

    <p id="subp" hidden><button id= "upsub"shiro:hasPermission="sys:me ...

  3. contextField 键盘只允许输入数字和小数点,并且现在小数点后位数

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementS ...

  4. MyBatis逆向工程的使用(非插件方式)

    一.概述 MyBatis是目前流行的优秀持久层框架,其逆向工程更是大大缩减了开发时间.所谓逆向工程,指的是mybatis根据数据库设计好的表,自动生成对应model.mapper及mapper.xml ...

  5. 使用MQTTBox连接阿里云平台

    这篇只做一个简单的介绍,和上一篇没有根本的区别.只是就两个客户端的差异介绍一下. 一.需要参考的内容: 使用MQTT.fx连接阿里云平台: https://www.cnblogs.com/mhtc/p ...

  6. 三分钟让你秒懂.Net生态系统

    提到.Net的时候,大多数人的第一反应可能就是.Net Framework和Visual Studio..Net Framework的第一个版本发布与2002年2月13日,这对于科技发展日新月异的时代 ...

  7. JQuery DOM操作:设置内容&属性&添加元素&插入元素&包裹&克隆&移除&替换

    JQuery text().html().val() $(elem).text(str):添加文本内容str到elem类型元素,返回jQuery对象 $(elem).text():返回第一个elem标 ...

  8. WLAN配置SKC

    1.关于SKC WLC支持粘滞密钥缓存(Sticky Key Caching,SKC). 通过SKC,客户端为其关联的每个AP接收并存储不同的PMKID. AP还维护发布给客户端的PMKID数据库. ...

  9. PW数据库ER图

  10. 洛谷P1192台阶问题(DP)

    题目描述 有NNN级的台阶,你一开始在底部,每次可以向上迈最多KKK级台阶(最少111级),问到达第NNN级台阶有多少种不同方式. 输入格式 两个正整数N,K. 输出格式 一个正整数,为不同方式数,由 ...