Commit 45cda665 authored by ma yanling's avatar ma yanling
Browse files

project commit

parent ad2fb30a
Pipeline #2354 failed with stages
in 0 seconds
package cn.hutool.core.date.chinese;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.TableMap;
import java.util.List;
/**
* 节假日(农历)封装
*
* @author looly
* @since 5.4.1
*/
public class LunarFestival {
//农历节日 *表示放假日
// 来自:https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100
private static final TableMap<Pair<Integer, Integer>, String> L_FTV = new TableMap<>(16);
static {
// 节日
L_FTV.put(new Pair<>(1, 1), "春节");
L_FTV.put(new Pair<>(1, 2), "犬日");
L_FTV.put(new Pair<>(1, 3), "猪日");
L_FTV.put(new Pair<>(1, 4), "羊日");
L_FTV.put(new Pair<>(1, 5), "牛日 破五日");
L_FTV.put(new Pair<>(1, 6), "马日 送穷日");
L_FTV.put(new Pair<>(1, 7), "人日 人胜节");
L_FTV.put(new Pair<>(1, 8), "谷日 八仙日");
L_FTV.put(new Pair<>(1, 9), "天日 九皇会");
L_FTV.put(new Pair<>(1, 10), "地日 石头生日");
L_FTV.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日");
L_FTV.put(new Pair<>(1, 13), "上(试)灯日 关公升天日");
L_FTV.put(new Pair<>(1, 15), "元宵节 上元节");
L_FTV.put(new Pair<>(1, 18), "落灯日");
// 二月
L_FTV.put(new Pair<>(2, 1), "中和节 太阳生日");
L_FTV.put(new Pair<>(2, 2), "龙抬头");
L_FTV.put(new Pair<>(2, 12), "花朝节");
L_FTV.put(new Pair<>(2, 19), "观世音圣诞");
// 三月
L_FTV.put(new Pair<>(3, 3), "上巳节");
// 四月
L_FTV.put(new Pair<>(4, 1), "祭雹神");
L_FTV.put(new Pair<>(4, 4), "文殊菩萨诞辰");
L_FTV.put(new Pair<>(4, 8), "佛诞节");
// 五月
L_FTV.put(new Pair<>(5, 5), "端午节 端阳节");
// 六月
L_FTV.put(new Pair<>(6, 6), "晒衣节 姑姑节");
L_FTV.put(new Pair<>(6, 6), "天贶节");
L_FTV.put(new Pair<>(6, 24), "彝族火把节");
// 七月
L_FTV.put(new Pair<>(7, 7), "七夕");
L_FTV.put(new Pair<>(7, 14), "鬼节(南方)");
L_FTV.put(new Pair<>(7, 15), "中元节");
L_FTV.put(new Pair<>(7, 15), "盂兰盆节 中元节");
L_FTV.put(new Pair<>(7, 30), "地藏节");
// 八月
L_FTV.put(new Pair<>(8, 15), "中秋节");
// 九月
L_FTV.put(new Pair<>(9, 9), "重阳节");
// 十月
L_FTV.put(new Pair<>(10, 1), "祭祖节");
L_FTV.put(new Pair<>(10, 15), "下元节");
// 十一月
L_FTV.put(new Pair<>(11, 17), "阿弥陀佛圣诞");
// 腊月
L_FTV.put(new Pair<>(12, 8), "腊八节");
L_FTV.put(new Pair<>(12, 16), "尾牙");
L_FTV.put(new Pair<>(12, 23), "小年");
L_FTV.put(new Pair<>(12, 30), "除夕");
}
/**
* 获得节日列表
*
* @param year 年
* @param month 月
* @param day 日
* @return 获得农历节日
* @since 5.4.5
*/
public static List<String> getFestivals(int year, int month, int day) {
// 春节判断,如果12月是小月,则29为除夕,否则30为除夕
if (12 == month && 29 == day) {
if (29 == LunarInfo.monthDays(year, month)) {
day++;
}
}
return getFestivals(month, day);
}
/**
* 获得节日列表,此方法无法判断月是否为大月或小月
*
* @param month 月
* @param day 日
* @return 获得农历节日
*/
public static List<String> getFestivals(int month, int day) {
return L_FTV.getValues(new Pair<>(month, day));
}
}
package cn.hutool.core.date.chinese;
import java.time.LocalDate;
/**
* 阴历(农历)信息
*
* @author looly
* @since 5.4.1
*/
public class LunarInfo {
/**
* 1900年
*/
public static final int BASE_YEAR = 1900;
/**
* 1900-01-31,农历正月初一
*/
public static final long BASE_DAY = LocalDate.of(BASE_YEAR, 1, 31).toEpochDay();
/**
* 此表来自:<a href="https://github.com/jjonline/calendar.js/blob/master/calendar.js">https://github.com/jjonline/calendar.js/blob/master/calendar.js</a>
* 农历表示:
* 1. 表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。
* 2-4.为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。
* 5. 表示闰月是大月还是小月,仅当存在闰月的情况下有意义。
*/
private static final long[] LUNAR_CODE = new long[]{
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,//1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,//1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,//1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x16a95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,//1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,//1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0,//1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,//1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6,//1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,//1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0,//1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,//2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,//2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,//2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,//2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,//2040-2049
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0,//2050-2059
0x092e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4,//2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0,//2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160,//2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252,//2090-2099
};
// 支持的最大年限
public static final int MAX_YEAR = BASE_YEAR + LUNAR_CODE.length - 1;
/**
* 传回农历 y年的总天数
*
* @param y 年
* @return 总天数
*/
public static int yearDays(int y) {
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
if ((getCode(y) & i) != 0) {
sum += 1;
}
}
return (sum + leapDays(y));
}
/**
* 传回农历 y年闰月的天数,如果本年无闰月,返回0,区分大小月
*
* @param y 农历年
* @return 闰月的天数
*/
public static int leapDays(int y) {
if (leapMonth(y) != 0) {
return (getCode(y) & 0x10000) != 0 ? 30 : 29;
}
return 0;
}
/**
* 传回农历 y年m月的总天数,区分大小月
*
* @param y 年
* @param m 月
* @return 总天数
*/
public static int monthDays(int y, int m) {
return (getCode(y) & (0x10000 >> m)) == 0 ? 29 : 30;
}
/**
* 传回农历 y年闰哪个月 1-12 , 没闰传回 0<br>
* 此方法会返回润N月中的N,如二月、闰二月都返回2
*
* @param y 年
* @return 润的月, 没闰传回 0
*/
public static int leapMonth(int y) {
return (int) (getCode(y) & 0xf);
}
/**
* 获取对应年的农历信息
*
* @param year 年
* @return 农历信息
*/
private static long getCode(int year) {
return LUNAR_CODE[year - BASE_YEAR];
}
}
package cn.hutool.core.date.chinese;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import java.time.LocalDate;
import java.util.Date;
/**
* 24节气相关信息
*
* @author looly, zak
* @since 5.4.1
*/
public class SolarTerms {
/**
* 1900-2100各年的24节气日期速查表
* 此表来自:https://github.com/jjonline/calendar.js/blob/master/calendar.js
*/
private static final String[] S_TERM_INFO = new String[]{
"9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f",
"97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa",
"97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f",
"b027097bd097c36b0b6fc9274c91aa", "9778397bd19801ec9210c965cc920e", "97b6b97bd19801ec95f8c965cc920f",
"97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd197c36c9210c9274c91aa",
"97b6b97bd19801ec95f8c965cc920e", "97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2",
"9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec95f8c965cc920e", "97bcf97c3598082c95f8e1cfcc920f",
"97bd097bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722",
"9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f",
"97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf97c359801ec95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd097bd07f595b0b6fc920fb0722",
"9778397bd097c36b0b6fc9210c8dc2", "9778397bd19801ec9210c9274c920e", "97b6b97bd19801ec95f8c965cc920f",
"97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e",
"97b6b97bd19801ec95f8c965cc920f", "97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2",
"9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bd07f1487f595b0b0bc920fb0722",
"7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
"9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f531b0b0bb0b6fb0722",
"7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
"97bcf7f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b97bd19801ec9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
"9778397bd097c36b0b6fc9210c91aa", "97b6b97bd197c36c9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722",
"7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e",
"97b6b7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2",
"9778397bd097c36b0b70c9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722",
"7f0e397bd097c35b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721",
"7f0e27f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
"9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
"7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721",
"7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
"97b6b7f0e47f531b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
"9778397bd097c36b0b6fc9210c91aa", "97b6b7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
"7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "977837f0e37f149b0723b0787b0721",
"7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c35b0b6fc9210c8dc2",
"977837f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722",
"7f0e397bd097c35b0b6fc9210c8dc2", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
"7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "977837f0e37f14998082b0787b06bd",
"7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
"977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
"7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
"7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd",
"7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
"977837f0e37f14998082b0723b06bd", "7f07e7f0e37f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
"7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b0721",
"7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f595b0b0bb0b6fb0722", "7f0e37f0e37f14898082b0723b02d5",
"7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f531b0b0bb0b6fb0722",
"7f0e37f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
"7f0e37f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd",
"7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35",
"7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
"7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f149b0723b0787b0721",
"7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0723b06bd",
"7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e37f0e366aa89801eb072297c35",
"7ec967f0e37f14998082b0723b06bd", "7f07e7f0e37f14998083b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
"7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14898082b0723b02d5", "7f07e7f0e37f14998082b0787b0721",
"7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66aa89801e9808297c35", "665f67f0e37f14898082b0723b02d5",
"7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66a449801e9808297c35",
"665f67f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
"7f0e36665b66a449801e9808297c35", "665f67f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd",
"7f07e7f0e47f531b0723b0b6fb0721", "7f0e26665b66a449801e9808297c35", "665f67f0e37f1489801eb072297c35",
"7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722"};
/**
* 24节气
*/
private static final String[] TERMS = {
"小寒", "大寒", "立春", "雨水", "惊蛰", "春分",
"清明", "谷雨", "立夏", "小满", "芒种", "夏至",
"小暑", "大暑", "立秋", "处暑", "白露", "秋分",
"寒露", "霜降", "立冬", "小雪", "大雪", "冬至"
};
/**
* 传入公历y年获得该年第n个节气的公历日期
*
* @param y 公历年(1900-2100)
* @param n 二十四节气中的第几个节气(1~24);从n=1(小寒)算起
* @return getTerm(1987,3) -》4;意即1987年2月4日立春
*/
public static int getTerm(int y, int n) {
if (y < 1900 || y > 2100) {
return -1;
}
if (n < 1 || n > 24) {
return -1;
}
final String _table = S_TERM_INFO[y - 1900];
Integer[] _info = new Integer[6];
for (int i = 0; i < 6; i++) {
_info[i] = Integer.parseInt(_table.substring(i * 5, 5 * (i + 1)), 16);
}
String[] _calday = new String[24];
for (int i = 0; i < 6; i++) {
_calday[4 * i] = _info[i].toString().substring(0, 1);
_calday[4 * i + 1] = _info[i].toString().substring(1, 3);
_calday[4 * i + 2] = _info[i].toString().substring(3, 4);
_calday[4 * i + 3] = _info[i].toString().substring(4, 6);
}
return NumberUtil.parseInt(_calday[n - 1]);
}
/**
* 根据日期获取节气
* @param date 日期
* @return 返回指定日期所处的节气,若不是一个节气则返回空字符串
*/
public static String getTerm(Date date) {
final DateTime dt = DateUtil.date(date);
return getTermInternal(dt.year(), dt.month() + 1, dt.dayOfMonth());
}
/**
* 根据农历日期获取节气
* @param chineseDate 农历日期
* @return 返回指定农历日期所处的节气,若不是一个节气则返回空字符串
*/
public static String getTerm(ChineseDate chineseDate) {
return chineseDate.getTerm();
}
/**
* 根据日期获取节气
* @param date 日期
* @return 返回指定日期所处的节气,若不是一个节气则返回空字符串
*/
public static String getTerm(LocalDate date) {
return getTermInternal(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
}
/**
* 根据年月日获取节气
* @param year 公历年
* @param mouth 公历月,从1开始
* @param day 公历日,从1开始
* @return 返回指定年月日所处的节气,若不是一个节气则返回空字符串
*/
public static String getTerm(int year, int mouth, int day) {
return getTerm(LocalDate.of(year, mouth, day));
}
/**
* 根据年月日获取节气, 内部方法,不对月和日做有效校验
* @param year 公历年
* @param mouth 公历月,从1开始
* @param day 公历日,从1开始
* @return 返回指定年月日所处的节气,若不是一个节气则返回空字符串
*/
private static String getTermInternal(int year, int mouth, int day) {
if (year < 1900 || year > 2100) {
throw new IllegalArgumentException("只支持1900-2100之间的日期获取节气");
}
final String termTable = S_TERM_INFO[year - 1900];
// 节气速查表中每5个字符含有4个节气,通过月份直接计算偏移
final int segment = (mouth + 1) / 2 - 1;
final int termInfo = Integer.parseInt(termTable.substring(segment * 5, (segment + 1) * 5), 16);
final String termInfoStr = String.valueOf(termInfo);
final String[] segmentTable = new String[4];
segmentTable[0] = termInfoStr.substring(0, 1);
segmentTable[1] = termInfoStr.substring(1, 3);
segmentTable[2] = termInfoStr.substring(3, 4);
segmentTable[3] = termInfoStr.substring(4, 6);
// 奇数月份的节气在前2个,偶数月份的节气在后两个
final int segmentOffset = (mouth & 1) == 1 ? 0 : 2;
if (day == Integer.parseInt(segmentTable[segmentOffset])) {
return TERMS[segment * 4 + segmentOffset];
}
if (day == Integer.parseInt(segmentTable[segmentOffset + 1])) {
return TERMS[segment * 4 + segmentOffset + 1];
}
return StrUtil.EMPTY;
}
}
/**
* 农历相关类汇总,包括农历月、天干地支、农历节日、24节气等
*
* @author looly
*
*/
package cn.hutool.core.date.chinese;
\ No newline at end of file
package cn.hutool.core.date.format;
import java.io.Serializable;
import java.util.Locale;
import java.util.TimeZone;
public abstract class AbstractDateBasic implements DateBasic, Serializable {
private static final long serialVersionUID = 6333136319870641818L;
/** The pattern */
protected final String pattern;
/** The time zone. */
protected final TimeZone timeZone;
/** The locale. */
protected final Locale locale;
/**
* 构造,内部使用
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param timeZone 非空时区{@link TimeZone}
* @param locale 非空{@link Locale} 日期地理位置
*/
protected AbstractDateBasic(final String pattern, final TimeZone timeZone, final Locale locale) {
this.pattern = pattern;
this.timeZone = timeZone;
this.locale = locale;
}
// ----------------------------------------------------------------------- Accessors
@Override
public String getPattern() {
return pattern;
}
@Override
public TimeZone getTimeZone() {
return timeZone;
}
@Override
public Locale getLocale() {
return locale;
}
// ----------------------------------------------------------------------- Basics
@Override
public boolean equals(final Object obj) {
if (obj instanceof FastDatePrinter == false) {
return false;
}
final AbstractDateBasic other = (AbstractDateBasic) obj;
return pattern.equals(other.pattern) && timeZone.equals(other.timeZone) && locale.equals(other.locale);
}
@Override
public int hashCode() {
return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode());
}
@Override
public String toString() {
return "FastDatePrinter[" + pattern + "," + locale + "," + timeZone.getID() + "]";
}
}
package cn.hutool.core.date.format;
import java.util.Locale;
import java.util.TimeZone;
/**
* 日期基本信息获取接口
*
* @author Looly
* @since 2.16.2
*/
public interface DateBasic {
/**
* 获得日期格式化或者转换的格式
*
* @return {@link java.text.SimpleDateFormat}兼容的格式
*/
String getPattern();
/**
* 获得时区
*
* @return {@link TimeZone}
*/
TimeZone getTimeZone();
/**
* 获得 日期地理位置
*
* @return {@link Locale}
*/
Locale getLocale();
}
package cn.hutool.core.date.format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
/**
* 日期解析接口,用于解析日期字符串为 {@link Date} 对象<br>
* Thanks to Apache Commons Lang 3.5
* @since 2.16.2
*/
public interface DateParser extends DateBasic{
/**
* 将日期字符串解析并转换为 {@link Date} 对象<br>
* 等价于 {@link java.text.DateFormat#parse(String)}
*
* @param source 日期字符串
* @return {@link Date}
* @throws ParseException 转换异常,被转换的字符串格式错误。
*/
Date parse(String source) throws ParseException;
/**
* 将日期字符串解析并转换为 {@link Date} 对象<br>
* 等价于 {@link java.text.DateFormat#parse(String, ParsePosition)}
*
* @param source 日期字符串
* @param pos {@link ParsePosition}
* @return {@link Date}
*/
Date parse(String source, ParsePosition pos);
/**
* 根据给定格式更新{@link Calendar}
* Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed.
* Not all source text needs to be consumed.
* Upon parse failure, ParsePosition error index is updated to the offset of the source text which does not match the supplied format.
*
* @param source 被转换的日期字符串
* @param pos 定义开始转换的位置,转换结束后更新转换到的位置
* @param calendar The calendar into which to set parsed fields.
* @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated)
* @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is out of range.
*/
boolean parse(String source, ParsePosition pos, Calendar calendar);
/**
* 将日期字符串解析并转换为 {@link Date} 对象<br>
*
* @param source A {@code String} whose beginning should be parsed.
* @return a {@code java.util.Date} object
* @throws ParseException if the beginning of the specified string cannot be parsed.
* @see java.text.DateFormat#parseObject(String)
*/
default Object parseObject(String source) throws ParseException{
return parse(source);
}
/**
* 根据 {@link ParsePosition} 给定将日期字符串解析并转换为 {@link Date} 对象<br>
*
* @param source A {@code String} whose beginning should be parsed.
* @param pos the parse position
* @return a {@code java.util.Date} object
* @see java.text.DateFormat#parseObject(String, ParsePosition)
*/
default Object parseObject(String source, ParsePosition pos){
return parse(source, pos);
}
}
package cn.hutool.core.date.format;
import java.util.Calendar;
import java.util.Date;
/**
* 日期格式化输出接口<br>
* Thanks to Apache Commons Lang 3.5
* @author Looly
* @since 2.16.2
*/
public interface DatePrinter extends DateBasic {
/**
* 格式化日期表示的毫秒数
*
* @param millis 日期毫秒数
* @return the formatted string
* @since 2.1
*/
String format(long millis);
/**
* 使用 {@code GregorianCalendar} 格式化 {@code Date}
*
* @param date 日期 {@link Date}
* @return 格式化后的字符串
*/
String format(Date date);
/**
* <p>
* Formats a {@code Calendar} object.
* </p>
* 格式化 {@link Calendar}
*
* @param calendar {@link Calendar}
* @return 格式化后的字符串
*/
String format(Calendar calendar);
/**
* <p>
* Formats a millisecond {@code long} value into the supplied {@code Appendable}.
* </p>
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
* @return the specified string buffer
*/
<B extends Appendable> B format(long millis, B buf);
/**
* <p>
* Formats a {@code Date} object into the supplied {@code Appendable} using a {@code GregorianCalendar}.
* </p>
*
* @param date the date to format
* @param buf the buffer to format into
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
* @return the specified string buffer
*/
<B extends Appendable> B format(Date date, B buf);
/**
* <p>
* Formats a {@code Calendar} object into the supplied {@code Appendable}.
* </p>
* The TimeZone set on the Calendar is only used to adjust the time offset. The TimeZone specified during the construction of the Parser will determine the TimeZone used in the formatted string.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
* @return the specified string buffer
*/
<B extends Appendable> B format(Calendar calendar, B buf);
}
package cn.hutool.core.date.format;
import cn.hutool.core.date.DatePattern;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* <p>
* FastDateFormat 是一个线程安全的 {@link java.text.SimpleDateFormat} 实现。
* </p>
*
* <p>
* 通过以下静态方法获得此对象: <br>
* {@link #getInstance(String, TimeZone, Locale)}<br>
* {@link #getDateInstance(int, TimeZone, Locale)}<br>
* {@link #getTimeInstance(int, TimeZone, Locale)}<br>
* {@link #getDateTimeInstance(int, int, TimeZone, Locale)}
* </p>
*
* Thanks to Apache Commons Lang 3.5
* @since 2.16.2
*/
public class FastDateFormat extends Format implements DateParser, DatePrinter {
private static final long serialVersionUID = 8097890768636183236L;
/** FULL locale dependent date or time style. */
public static final int FULL = DateFormat.FULL;
/** LONG locale dependent date or time style. */
public static final int LONG = DateFormat.LONG;
/** MEDIUM locale dependent date or time style. */
public static final int MEDIUM = DateFormat.MEDIUM;
/** SHORT locale dependent date or time style. */
public static final int SHORT = DateFormat.SHORT;
private static final FormatCache<FastDateFormat> CACHE = new FormatCache<FastDateFormat>(){
@Override
protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
return new FastDateFormat(pattern, timeZone, locale);
}
};
private final FastDatePrinter printer;
private final FastDateParser parser;
// -----------------------------------------------------------------------
/**
* 获得 FastDateFormat实例,使用默认格式和地区
*
* @return FastDateFormat
*/
public static FastDateFormat getInstance() {
return CACHE.getInstance();
}
/**
* 获得 FastDateFormat 实例,使用默认地区<br>
* 支持缓存
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @return FastDateFormat
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern) {
return CACHE.getInstance(pattern, null, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param timeZone 时区{@link TimeZone}
* @return FastDateFormat
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
return CACHE.getInstance(pattern, timeZone, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param locale {@link Locale} 日期地理位置
* @return FastDateFormat
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final Locale locale) {
return CACHE.getInstance(pattern, null, locale);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param timeZone 时区{@link TimeZone}
* @param locale {@link Locale} 日期地理位置
* @return FastDateFormat
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
return CACHE.getInstance(pattern, timeZone, locale);
}
// -----------------------------------------------------------------------
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateInstance(final int style) {
return CACHE.getDateInstance(style, null, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateInstance(final int style, final Locale locale) {
return CACHE.getDateInstance(style, null, locale);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone 时区{@link TimeZone}
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
return CACHE.getDateInstance(style, timeZone, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style date style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone 时区{@link TimeZone}
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
return CACHE.getDateInstance(style, timeZone, locale);
}
// -----------------------------------------------------------------------
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getTimeInstance(final int style) {
return CACHE.getTimeInstance(style, null, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
return CACHE.getTimeInstance(style, null, locale);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of formatted time
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
return CACHE.getTimeInstance(style, timeZone, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param style time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone optional time zone, overrides time zone of formatted time
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
return CACHE.getTimeInstance(style, timeZone, locale);
}
// -----------------------------------------------------------------------
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone 时区{@link TimeZone}
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) {
return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
}
/**
* 获得 FastDateFormat 实例<br>
* 支持缓存
*
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
* @param timeZone 时区{@link TimeZone}
* @param locale {@link Locale} 日期地理位置
* @return 本地化 FastDateFormat
*/
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
}
// ----------------------------------------------------------------------- Constructor start
/**
* 构造
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param timeZone 非空时区 {@link TimeZone}
* @param locale {@link Locale} 日期地理位置
* @throws NullPointerException if pattern, timeZone, or locale is null.
*/
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
this(pattern, timeZone, locale, null);
}
/**
* 构造
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @param timeZone 非空时区 {@link TimeZone}
* @param locale {@link Locale} 日期地理位置
* @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now - 80 years
* @throws NullPointerException if pattern, timeZone, or locale is null.
*/
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
printer = new FastDatePrinter(pattern, timeZone, locale);
parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
}
// ----------------------------------------------------------------------- Constructor end
// ----------------------------------------------------------------------- Format methods
@Override
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
return toAppendTo.append(printer.format(obj));
}
@Override
public String format(final long millis) {
return printer.format(millis);
}
@Override
public String format(final Date date) {
return printer.format(date);
}
@Override
public String format(final Calendar calendar) {
return printer.format(calendar);
}
@Override
public <B extends Appendable> B format(final long millis, final B buf) {
return printer.format(millis, buf);
}
@Override
public <B extends Appendable> B format(final Date date, final B buf) {
return printer.format(date, buf);
}
@Override
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
return printer.format(calendar, buf);
}
// ----------------------------------------------------------------------- Parsing
@Override
public Date parse(final String source) throws ParseException {
return parser.parse(source);
}
@Override
public Date parse(final String source, final ParsePosition pos) {
return parser.parse(source, pos);
}
@Override
public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
return parser.parse(source, pos, calendar);
}
@Override
public Object parseObject(final String source, final ParsePosition pos) {
return parser.parseObject(source, pos);
}
// ----------------------------------------------------------------------- Accessors
@Override
public String getPattern() {
return printer.getPattern();
}
@Override
public TimeZone getTimeZone() {
return printer.getTimeZone();
}
@Override
public Locale getLocale() {
return printer.getLocale();
}
/**
*估算生成的日期字符串长度<br>
* 实际生成的字符串长度小于或等于此值
*
* @return 日期字符串长度
*/
public int getMaxLengthEstimate() {
return printer.getMaxLengthEstimate();
}
// convert DateTimeFormatter
// -----------------------------------------------------------------------
/**
* 便捷获取 DateTimeFormatter
* 由于 {@link DatePattern} 很大一部分的格式没有提供 {@link DateTimeFormatter},因此这里提供快捷获取方式
* @return DateTimeFormatter
* @author dazer neusoft
* @since 5.6.4
*/
public DateTimeFormatter getDateTimeFormatter() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(this.getPattern());
if (this.getLocale() != null) {
formatter = formatter.withLocale(this.getLocale());
}
if (this.getTimeZone() != null) {
formatter = formatter.withZone(this.getTimeZone().toZoneId());
}
return formatter;
}
// Basics
// -----------------------------------------------------------------------
@Override
public boolean equals(final Object obj) {
if (obj instanceof FastDateFormat == false) {
return false;
}
final FastDateFormat other = (FastDateFormat) obj;
// no need to check parser, as it has same invariants as printer
return printer.equals(other.printer);
}
@Override
public int hashCode() {
return printer.hashCode();
}
@Override
public String toString() {
return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment