Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate
通过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的更多相关文章
- 在swt中获取jar包中的文件 uri is not hierarchical
uri is not hierarchical 学习了:http://blog.csdn.net/zdsdiablo/article/details/1519719 在swt中获取jar包中的文件: ...
- API接口自动化之3 同一个war包中多个接口做自动化测试
同一个war包中多个接口做自动化测试 一个接口用一个测试类,每个测试用例如下,比如下面是4个测试用例,每个详细的测试用例中含有请求入参,返回体校验,以此来判断每条测试用例是否通过 一个war包中,若含 ...
- Andriod项目开发实战(1)——如何在Eclipse中的一个包下建新包
最开始是想将各个类分门别类地存放在不同的包中,所以想在项目源码包中新建几个不同功能的包eg:utils.model.receiver等,最后的结果应该是下图左边这样的: 很明显建立项目后的架构是上 ...
- Mac 如何导出ipa文件中Assets.car包中的切图
在之前 获取 AppStore 中 应用 的 IPA 包文件(Mac OS 13+)中获取到应用的 IPA 包,可以取出应用的部分图片(如 Logo),如果项目工程中把图片添加到 Assets.xca ...
- JDK中的Atomic包中的类及使用
引言 Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作.原子变量的底层使用了处理器提供的原子指令,但是不同的CPU ...
- 【转】Eclipse中查看jar包中的源码
(简单的方式:通过jd-gui来进行反编译,最简单!,参考我的另一篇博文, 地址:http://www.cnblogs.com/gmq-sh/p/4277991.html) Java Decompil ...
- Package.json中dependencies依赖包中^符号和~符号前缀的区别
刚git了webpack的包发现package.json里面dependencies依赖包的版本号前面的符号有两种,一种是~,一种是^,如下图标记: 然后搜了下在stackoverflow上找到一个比 ...
- Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类
因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
Redis总结(五)缓存雪崩和缓存穿透等问题 前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...
随机推荐
- 【题解】Rusty String [CF827E]
[题解]Rusty String [CF827E] 传送门:\(\text{Rusty String}\) \(\text{[CF827E]}\) [题目描述] 多组数据,每组数据给出一个由 \(V, ...
- php自动读取文件夹下所有图片
$path = 'xxxxx';///当前目录$handle = opendir($path); //当前目录while (false !== ($file = readdir($handle))) ...
- Atcoder Beginner Contest145E(01背包记录路径)
#define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;int a[3007],b[3007];int ...
- Go类型断言
package main import ( "fmt" ) type Point struct { x int y int } func main() { var a interf ...
- Hadoop学习1—浅谈hadoop
大数据这个词越来越热,本人一直想学习一下,正巧最近有时间了解一下.先从hadoop入手,在此记录学习中的点滴. 什么是hadoop? What Is Apache Hadoop? The Apache ...
- python练习:使用二分法查找求近似平方根,使用二分法查找求近似立方根。
python练习:使用二分法查找求近似平方根,使用二分法查找求近似立方根. 重难点:原理为一个数的平方根一定在,0到这个数之间,那么就对这之间的数,进行二分遍历.精确度的使用.通过最高值和最低值确定二 ...
- Codeforces 1045F Shady Lady 凸包+数学
题目链接:https://codeforc.es/contest/1045/problem/F 题意:先给出一个系数不确定的二元多项式,Borna可以给这个多项式的每一项填上正的系数,Ani能从这个多 ...
- ASP.NET Core搭建多层网站架构【9.2-使用Castle.Core实现动态代理拦截器】
2020/01/31, ASP.NET Core 3.1, VS2019, Autofac.Extras.DynamicProxy 4.5.0, Castle.Core.AsyncIntercepto ...
- 【Go语言系列】1.2、GO语言简介:哪些大公司正在使用Go语言
Go语言的强项在于它适合用来开发网络并发方面的服务,比如消息推送.监控.容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言. 1.Google 这个不用多做介绍,作为开发Go ...
- 喵星之旅-狂奔的兔子-基于docker的redis分布式集群
一.docker安装(略) 二.下载redis安装包(redis-4.0.8.tar.gz) 以任何方式获取都可以.自行官网下载. 三.拉取centos7的docker镜像 命令:docker pul ...