921 lines
21 KiB
Java
921 lines
21 KiB
Java
package com.nlf.calendar;
|
||
|
||
import java.util.*;
|
||
|
||
import com.nlf.calendar.util.HolidayUtil;
|
||
import com.nlf.calendar.util.LunarUtil;
|
||
import com.nlf.calendar.util.SolarUtil;
|
||
|
||
/**
|
||
* 阳历日期
|
||
*
|
||
* @author 6tail
|
||
*/
|
||
public class Solar {
|
||
/**
|
||
* 时区
|
||
*/
|
||
public static final TimeZone TIME_ZONE = TimeZone.getTimeZone("GMT+8");
|
||
|
||
/**
|
||
* 2000年儒略日数(2000-1-1 12:00:00 UTC)
|
||
*/
|
||
public static final double J2000 = 2451545;
|
||
|
||
/**
|
||
* 年
|
||
*/
|
||
private final int year;
|
||
|
||
/**
|
||
* 月
|
||
*/
|
||
private final int month;
|
||
|
||
/**
|
||
* 日
|
||
*/
|
||
private final int day;
|
||
|
||
/**
|
||
* 时
|
||
*/
|
||
private final int hour;
|
||
|
||
/**
|
||
* 分
|
||
*/
|
||
private final int minute;
|
||
|
||
/**
|
||
* 秒
|
||
*/
|
||
private final int second;
|
||
|
||
/**
|
||
* 默认使用当前日期初始化
|
||
*/
|
||
public Solar() {
|
||
this(new Date());
|
||
}
|
||
|
||
/**
|
||
* 通过年月日初始化
|
||
*
|
||
* @param year 年
|
||
* @param month 月,1到12
|
||
* @param day 日,1到31
|
||
*/
|
||
public Solar(int year, int month, int day) {
|
||
this(year, month, day, 0, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* 通过年月日初始化
|
||
*
|
||
* @param year 年
|
||
* @param month 月,1到12
|
||
* @param day 日,1到31
|
||
* @param hour 小时,0到23
|
||
* @param minute 分钟,0到59
|
||
* @param second 秒钟,0到59
|
||
*/
|
||
public Solar(int year, int month, int day, int hour, int minute, int second) {
|
||
if (1582 == year && 10 == month) {
|
||
if (day > 4 && day < 15) {
|
||
throw new IllegalArgumentException(String.format("wrong solar year %d month %d day %d", year, month, day));
|
||
}
|
||
}
|
||
if (month < 1 || month > 12) {
|
||
throw new IllegalArgumentException(String.format("wrong month %d", month));
|
||
}
|
||
if (day < 1) {
|
||
throw new IllegalArgumentException(String.format("wrong day %d", day));
|
||
}
|
||
int days = SolarUtil.getDaysOfMonth(year, month);
|
||
if (day > days) {
|
||
throw new IllegalArgumentException(String.format("only %d days in solar year %d month %d", days, year, month));
|
||
}
|
||
if (hour < 0 || hour > 23) {
|
||
throw new IllegalArgumentException(String.format("wrong hour %d", hour));
|
||
}
|
||
if (minute < 0 || minute > 59) {
|
||
throw new IllegalArgumentException(String.format("wrong minute %d", minute));
|
||
}
|
||
if (second < 0 || second > 59) {
|
||
throw new IllegalArgumentException(String.format("wrong second %d", second));
|
||
}
|
||
this.year = year;
|
||
this.month = month;
|
||
this.day = day;
|
||
this.hour = hour;
|
||
this.minute = minute;
|
||
this.second = second;
|
||
}
|
||
|
||
/**
|
||
* 通过日期初始化
|
||
*
|
||
* @param date 日期
|
||
*/
|
||
public Solar(Date date) {
|
||
Calendar c = Calendar.getInstance(TIME_ZONE);
|
||
c.setTime(date);
|
||
c.set(Calendar.MILLISECOND, 0);
|
||
year = c.get(Calendar.YEAR);
|
||
month = c.get(Calendar.MONTH) + 1;
|
||
day = c.get(Calendar.DATE);
|
||
hour = c.get(Calendar.HOUR_OF_DAY);
|
||
minute = c.get(Calendar.MINUTE);
|
||
second = c.get(Calendar.SECOND);
|
||
}
|
||
|
||
/**
|
||
* 通过日历初始化
|
||
*
|
||
* @param calendar 日历
|
||
*/
|
||
public Solar(Calendar calendar) {
|
||
calendar.set(Calendar.MILLISECOND, 0);
|
||
year = calendar.get(Calendar.YEAR);
|
||
month = calendar.get(Calendar.MONTH) + 1;
|
||
day = calendar.get(Calendar.DATE);
|
||
hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||
minute = calendar.get(Calendar.MINUTE);
|
||
second = calendar.get(Calendar.SECOND);
|
||
}
|
||
|
||
/**
|
||
* 通过儒略日初始化
|
||
*
|
||
* @param julianDay 儒略日
|
||
*/
|
||
public Solar(double julianDay) {
|
||
int d = (int) (julianDay + 0.5);
|
||
double f = julianDay + 0.5 - d;
|
||
int c;
|
||
|
||
if (d >= 2299161) {
|
||
c = (int) ((d - 1867216.25) / 36524.25);
|
||
d += 1 + c - (int) (c * 1D / 4);
|
||
}
|
||
d += 1524;
|
||
int year = (int) ((d - 122.1) / 365.25);
|
||
d -= (int) (365.25 * year);
|
||
int month = (int) (d * 1D / 30.601);
|
||
d -= (int) (30.601 * month);
|
||
int day = d;
|
||
if (month > 13) {
|
||
month -= 13;
|
||
year -= 4715;
|
||
} else {
|
||
month -= 1;
|
||
year -= 4716;
|
||
}
|
||
f *= 24;
|
||
int hour = (int) f;
|
||
|
||
f -= hour;
|
||
f *= 60;
|
||
int minute = (int) f;
|
||
|
||
f -= minute;
|
||
f *= 60;
|
||
int second = (int) Math.round(f);
|
||
if (second > 59) {
|
||
second -= 60;
|
||
minute++;
|
||
}
|
||
if (minute > 59) {
|
||
minute -= 60;
|
||
hour++;
|
||
}
|
||
if (hour > 23) {
|
||
hour -= 24;
|
||
day += 1;
|
||
}
|
||
this.year = year;
|
||
this.month = month;
|
||
this.day = day;
|
||
this.hour = hour;
|
||
this.minute = minute;
|
||
this.second = second;
|
||
}
|
||
|
||
/**
|
||
* 通过指定日期获取阳历
|
||
*
|
||
* @param date 日期
|
||
* @return 阳历
|
||
*/
|
||
public static Solar fromDate(Date date) {
|
||
return new Solar(date);
|
||
}
|
||
|
||
/**
|
||
* 通过指定日历获取阳历
|
||
*
|
||
* @param calendar 日历
|
||
* @return 阳历
|
||
*/
|
||
public static Solar fromCalendar(Calendar calendar) {
|
||
return new Solar(calendar);
|
||
}
|
||
|
||
/**
|
||
* 通过指定儒略日获取阳历
|
||
*
|
||
* @param julianDay 儒略日
|
||
* @return 阳历
|
||
*/
|
||
public static Solar fromJulianDay(double julianDay) {
|
||
return new Solar(julianDay);
|
||
}
|
||
|
||
/**
|
||
* 通过指定年月日获取阳历
|
||
*
|
||
* @param year 年
|
||
* @param month 月,1到12
|
||
* @param day 日,1到31
|
||
* @return 阳历
|
||
*/
|
||
public static Solar fromYmd(int year, int month, int day) {
|
||
return new Solar(year, month, day);
|
||
}
|
||
|
||
/**
|
||
* 通过指定年月日时分获取阳历
|
||
*
|
||
* @param year 年
|
||
* @param month 月,1到12
|
||
* @param day 日,1到31
|
||
* @param hour 小时,0到23
|
||
* @param minute 分钟,0到59
|
||
* @param second 秒钟,0到59
|
||
* @return 阳历
|
||
*/
|
||
public static Solar fromYmdHms(int year, int month, int day, int hour, int minute, int second) {
|
||
return new Solar(year, month, day, hour, minute, second);
|
||
}
|
||
|
||
/**
|
||
* 通过八字获取阳历列表(晚子时日柱按当天,起始年为1900)
|
||
*
|
||
* @param yearGanZhi 年柱
|
||
* @param monthGanZhi 月柱
|
||
* @param dayGanZhi 日柱
|
||
* @param timeGanZhi 时柱
|
||
* @return 符合的阳历列表
|
||
*/
|
||
public static List<Solar> fromBaZi(String yearGanZhi, String monthGanZhi, String dayGanZhi, String timeGanZhi) {
|
||
return fromBaZi(yearGanZhi, monthGanZhi, dayGanZhi, timeGanZhi, 2);
|
||
}
|
||
|
||
/**
|
||
* 通过八字获取阳历列表(起始年为1900)
|
||
*
|
||
* @param yearGanZhi 年柱
|
||
* @param monthGanZhi 月柱
|
||
* @param dayGanZhi 日柱
|
||
* @param timeGanZhi 时柱
|
||
* @param sect 流派,2晚子时日柱按当天,1晚子时日柱按明天
|
||
* @return 符合的阳历列表
|
||
*/
|
||
public static List<Solar> fromBaZi(String yearGanZhi, String monthGanZhi, String dayGanZhi, String timeGanZhi, int sect) {
|
||
return fromBaZi(yearGanZhi, monthGanZhi, dayGanZhi, timeGanZhi, sect, 1900);
|
||
}
|
||
|
||
/**
|
||
* 通过八字获取阳历列表
|
||
*
|
||
* @param yearGanZhi 年柱
|
||
* @param monthGanZhi 月柱
|
||
* @param dayGanZhi 日柱
|
||
* @param timeGanZhi 时柱
|
||
* @param sect 流派,2晚子时日柱按当天,1晚子时日柱按明天
|
||
* @param baseYear 起始年
|
||
* @return 符合的阳历列表
|
||
*/
|
||
public static List<Solar> fromBaZi(String yearGanZhi, String monthGanZhi, String dayGanZhi, String timeGanZhi, int sect, int baseYear) {
|
||
sect = (1 == sect) ? 1 : 2;
|
||
List<Solar> l = new ArrayList<Solar>();
|
||
// 月地支距寅月的偏移值
|
||
int m = LunarUtil.find(monthGanZhi.substring(1), LunarUtil.ZHI, -1) - 2;
|
||
if (m < 0) {
|
||
m += 12;
|
||
}
|
||
// 月天干要一致
|
||
if (((LunarUtil.find(yearGanZhi.substring(0, 1), LunarUtil.GAN, -1) + 1) * 2 + m) % 10 != LunarUtil.find(monthGanZhi.substring(0, 1), LunarUtil.GAN, -1)) {
|
||
return l;
|
||
}
|
||
// 1年的立春是辛酉,序号57
|
||
int y = LunarUtil.getJiaZiIndex(yearGanZhi) - 57;
|
||
if (y < 0) {
|
||
y += 60;
|
||
}
|
||
y++;
|
||
// 节令偏移值
|
||
m *= 2;
|
||
// 时辰地支转时刻,子时按零点算
|
||
int h = LunarUtil.find(timeGanZhi.substring(1), LunarUtil.ZHI, -1) * 2;
|
||
int[] hours = {h};
|
||
if (0 == h && 2 == sect) {
|
||
hours = new int[]{0, 23};
|
||
}
|
||
int startYear = baseYear - 1;
|
||
|
||
// 结束年
|
||
Calendar c = Calendar.getInstance(TIME_ZONE);
|
||
c.setTime(new Date());
|
||
c.set(Calendar.MILLISECOND, 0);
|
||
int endYear = c.get(Calendar.YEAR);
|
||
|
||
while (y <= endYear) {
|
||
if (y >= startYear) {
|
||
// 立春为寅月的开始
|
||
List<Solar> jieQiList = new ArrayList<Solar>(Lunar.fromYmd(y, 1, 1).getJieQiTable().values());
|
||
// 节令推移,年干支和月干支就都匹配上了
|
||
Solar solarTime = jieQiList.get(4 + m);
|
||
if (solarTime.getYear() >= baseYear) {
|
||
// 日干支和节令干支的偏移值
|
||
int d = LunarUtil.getJiaZiIndex(dayGanZhi) - LunarUtil.getJiaZiIndex(solarTime.getLunar().getDayInGanZhiExact2());
|
||
if (d < 0) {
|
||
d += 60;
|
||
}
|
||
if (d > 0) {
|
||
// 从节令推移天数
|
||
solarTime = solarTime.next(d);
|
||
}
|
||
for (int hour : hours) {
|
||
int mi = 0;
|
||
int s = 0;
|
||
if (d == 0 && hour == solarTime.getHour()) {
|
||
// 如果正好是节令当天,且小时和节令的小时数相等的极端情况,把分钟和秒钟带上
|
||
mi = solarTime.getMinute();
|
||
s = solarTime.getSecond();
|
||
}
|
||
// 验证一下
|
||
Solar solar = Solar.fromYmdHms(solarTime.getYear(), solarTime.getMonth(), solarTime.getDay(), hour, mi, s);
|
||
Lunar lunar = solar.getLunar();
|
||
String dgz = (2 == sect) ? lunar.getDayInGanZhiExact2() : lunar.getDayInGanZhiExact();
|
||
if (lunar.getYearInGanZhiExact().equals(yearGanZhi) && lunar.getMonthInGanZhiExact().equals(monthGanZhi) && dgz.equals(dayGanZhi) && lunar.getTimeInGanZhi().equals(timeGanZhi)) {
|
||
l.add(solar);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
y += 60;
|
||
}
|
||
return l;
|
||
}
|
||
|
||
/**
|
||
* 是否闰年
|
||
*
|
||
* @return true/false 闰年/非闰年
|
||
*/
|
||
public boolean isLeapYear() {
|
||
return SolarUtil.isLeapYear(year);
|
||
}
|
||
|
||
/**
|
||
* 获取星期,0代表周日,1代表周一
|
||
*
|
||
* @return 0123456
|
||
*/
|
||
public int getWeek() {
|
||
return ((int) (getJulianDay() + 0.5) + 7000001) % 7;
|
||
}
|
||
|
||
/**
|
||
* 获取星期的中文
|
||
*
|
||
* @return 日一二三四五六
|
||
*/
|
||
public String getWeekInChinese() {
|
||
return SolarUtil.WEEK[getWeek()];
|
||
}
|
||
|
||
/**
|
||
* 获取节日,有可能一天会有多个节日
|
||
*
|
||
* @return 劳动节等
|
||
*/
|
||
public List<String> getFestivals() {
|
||
List<String> l = new ArrayList<String>();
|
||
//获取几月几日对应的节日
|
||
String f = SolarUtil.FESTIVAL.get(month + "-" + day);
|
||
if (null != f) {
|
||
l.add(f);
|
||
}
|
||
//计算几月第几个星期几对应的节日
|
||
int weeks = (int) Math.ceil(day / 7D);
|
||
//星期几,0代表星期天
|
||
int week = getWeek();
|
||
f = SolarUtil.WEEK_FESTIVAL.get(month + "-" + weeks + "-" + week);
|
||
if (null != f) {
|
||
l.add(f);
|
||
}
|
||
if (day + 7 > SolarUtil.getDaysOfMonth(year, month)) {
|
||
f = SolarUtil.WEEK_FESTIVAL.get(month + "-0-" + week);
|
||
if (null != f) {
|
||
l.add(f);
|
||
}
|
||
}
|
||
return l;
|
||
}
|
||
|
||
/**
|
||
* 获取非正式的节日,有可能一天会有多个节日
|
||
*
|
||
* @return 非正式的节日列表,如中元节
|
||
*/
|
||
public List<String> getOtherFestivals() {
|
||
List<String> l = new ArrayList<String>();
|
||
List<String> fs = SolarUtil.OTHER_FESTIVAL.get(month + "-" + day);
|
||
if (null != fs) {
|
||
l.addAll(fs);
|
||
}
|
||
return l;
|
||
}
|
||
|
||
/**
|
||
* 获取星座
|
||
*
|
||
* @return 星座
|
||
* @deprecated 使用getXingZuo
|
||
*/
|
||
public String getXingzuo() {
|
||
return getXingZuo();
|
||
}
|
||
|
||
/**
|
||
* 获取星座
|
||
*
|
||
* @return 星座
|
||
*/
|
||
public String getXingZuo() {
|
||
int index = 11;
|
||
int y = month * 100 + day;
|
||
if (y >= 321 && y <= 419) {
|
||
index = 0;
|
||
} else if (y >= 420 && y <= 520) {
|
||
index = 1;
|
||
} else if (y >= 521 && y <= 621) {
|
||
index = 2;
|
||
} else if (y >= 622 && y <= 722) {
|
||
index = 3;
|
||
} else if (y >= 723 && y <= 822) {
|
||
index = 4;
|
||
} else if (y >= 823 && y <= 922) {
|
||
index = 5;
|
||
} else if (y >= 923 && y <= 1023) {
|
||
index = 6;
|
||
} else if (y >= 1024 && y <= 1122) {
|
||
index = 7;
|
||
} else if (y >= 1123 && y <= 1221) {
|
||
index = 8;
|
||
} else if (y >= 1222 || y <= 119) {
|
||
index = 9;
|
||
} else if (y <= 218) {
|
||
index = 10;
|
||
}
|
||
return SolarUtil.XINGZUO[index];
|
||
}
|
||
|
||
/**
|
||
* 获取年份
|
||
*
|
||
* @return 如2015
|
||
*/
|
||
public int getYear() {
|
||
return year;
|
||
}
|
||
|
||
/**
|
||
* 获取月份
|
||
*
|
||
* @return 1到12
|
||
*/
|
||
public int getMonth() {
|
||
return month;
|
||
}
|
||
|
||
/**
|
||
* 获取日期
|
||
*
|
||
* @return 1到31之间的数字
|
||
*/
|
||
public int getDay() {
|
||
return day;
|
||
}
|
||
|
||
/**
|
||
* 获取小时
|
||
*
|
||
* @return 0到23之间的数字
|
||
*/
|
||
public int getHour() {
|
||
return hour;
|
||
}
|
||
|
||
/**
|
||
* 获取分钟
|
||
*
|
||
* @return 0到59之间的数字
|
||
*/
|
||
public int getMinute() {
|
||
return minute;
|
||
}
|
||
|
||
/**
|
||
* 获取秒钟
|
||
*
|
||
* @return 0到59之间的数字
|
||
*/
|
||
public int getSecond() {
|
||
return second;
|
||
}
|
||
|
||
/**
|
||
* 获取农历
|
||
*
|
||
* @return 农历
|
||
*/
|
||
public Lunar getLunar() {
|
||
return new Lunar(this);
|
||
}
|
||
|
||
/**
|
||
* 获取儒略日
|
||
*
|
||
* @return 儒略日
|
||
*/
|
||
public double getJulianDay() {
|
||
int y = this.year;
|
||
int m = this.month;
|
||
double d = this.day + ((this.second * 1D / 60 + this.minute) / 60 + this.hour) / 24;
|
||
int n = 0;
|
||
boolean g = y * 372 + m * 31 + (int) d >= 588829;
|
||
if (m <= 2) {
|
||
m += 12;
|
||
y--;
|
||
}
|
||
if (g) {
|
||
n = (int) (y * 1D / 100);
|
||
n = 2 - n + (int) (n * 1D / 4);
|
||
}
|
||
return (int) (365.25 * (y + 4716)) + (int) (30.6001 * (m + 1)) + d + n - 1524.5;
|
||
}
|
||
|
||
@Override
|
||
public String toString() {
|
||
return toYmd();
|
||
}
|
||
|
||
public String toYmd() {
|
||
return String.format("%04d-%02d-%02d", year, month, day);
|
||
}
|
||
|
||
public String toYmdHms() {
|
||
return toYmd() + " " + String.format("%02d:%02d:%02d", hour, minute, second);
|
||
}
|
||
|
||
public String toFullString() {
|
||
StringBuilder s = new StringBuilder();
|
||
s.append(toYmdHms());
|
||
if (isLeapYear()) {
|
||
s.append(" ");
|
||
s.append("闰年");
|
||
}
|
||
s.append(" ");
|
||
s.append("星期");
|
||
s.append(getWeekInChinese());
|
||
for (String f : getFestivals()) {
|
||
s.append(" (");
|
||
s.append(f);
|
||
s.append(")");
|
||
}
|
||
for (String f : getOtherFestivals()) {
|
||
s.append(" (");
|
||
s.append(f);
|
||
s.append(")");
|
||
}
|
||
s.append(" ");
|
||
s.append(getXingZuo());
|
||
s.append("座");
|
||
return s.toString();
|
||
}
|
||
|
||
/**
|
||
* 阳历日期相减,获得相差天数
|
||
*
|
||
* @param solar 阳历
|
||
* @return 天数
|
||
*/
|
||
public int subtract(Solar solar) {
|
||
return SolarUtil.getDaysBetween(solar.getYear(), solar.getMonth(), solar.getDay(), year, month, day);
|
||
}
|
||
|
||
/**
|
||
* 阳历日期相减,获得相差分钟数
|
||
*
|
||
* @param solar 阳历
|
||
* @return 分钟数
|
||
*/
|
||
public int subtractMinute(Solar solar) {
|
||
int days = subtract(solar);
|
||
int cm = hour * 60 + minute;
|
||
int sm = solar.getHour() * 60 + solar.getMinute();
|
||
int m = cm - sm;
|
||
if (m < 0) {
|
||
m += 1440;
|
||
days--;
|
||
}
|
||
m += days * 1440;
|
||
return m;
|
||
}
|
||
|
||
/**
|
||
* 是否在指定日期之后
|
||
*
|
||
* @param solar 阳历
|
||
* @return true/false
|
||
*/
|
||
public boolean isAfter(Solar solar) {
|
||
if (year > solar.getYear()) {
|
||
return true;
|
||
}
|
||
if (year < solar.getYear()) {
|
||
return false;
|
||
}
|
||
if (month > solar.getMonth()) {
|
||
return true;
|
||
}
|
||
if (month < solar.getMonth()) {
|
||
return false;
|
||
}
|
||
if (day > solar.getDay()) {
|
||
return true;
|
||
}
|
||
if (day < solar.getDay()) {
|
||
return false;
|
||
}
|
||
if (hour > solar.getHour()) {
|
||
return true;
|
||
}
|
||
if (hour < solar.getHour()) {
|
||
return false;
|
||
}
|
||
if (minute > solar.getMinute()) {
|
||
return true;
|
||
}
|
||
if (minute < solar.getMinute()) {
|
||
return false;
|
||
}
|
||
return second > solar.getSecond();
|
||
}
|
||
|
||
/**
|
||
* 是否在指定日期之前
|
||
*
|
||
* @param solar 阳历
|
||
* @return true/false
|
||
*/
|
||
public boolean isBefore(Solar solar) {
|
||
if (year > solar.getYear()) {
|
||
return false;
|
||
}
|
||
if (year < solar.getYear()) {
|
||
return true;
|
||
}
|
||
if (month > solar.getMonth()) {
|
||
return false;
|
||
}
|
||
if (month < solar.getMonth()) {
|
||
return true;
|
||
}
|
||
if (day > solar.getDay()) {
|
||
return false;
|
||
}
|
||
if (day < solar.getDay()) {
|
||
return true;
|
||
}
|
||
if (hour > solar.getHour()) {
|
||
return false;
|
||
}
|
||
if (hour < solar.getHour()) {
|
||
return true;
|
||
}
|
||
if (minute > solar.getMinute()) {
|
||
return false;
|
||
}
|
||
if (minute < solar.getMinute()) {
|
||
return true;
|
||
}
|
||
return second < solar.getSecond();
|
||
}
|
||
|
||
/**
|
||
* 年推移
|
||
*
|
||
* @param years 年数
|
||
* @return 阳历
|
||
*/
|
||
public Solar nextYear(int years) {
|
||
int y = year + years;
|
||
int m = month;
|
||
int d = day;
|
||
if (1582 == y && 10 == m) {
|
||
if (d > 4 && d < 15) {
|
||
d += 10;
|
||
}
|
||
} else if (2 == m) {
|
||
if (d > 28) {
|
||
if (!SolarUtil.isLeapYear(y)) {
|
||
d = 28;
|
||
}
|
||
}
|
||
}
|
||
return fromYmdHms(y, m, d, hour, minute, second);
|
||
}
|
||
|
||
/**
|
||
* 月推移
|
||
*
|
||
* @param months 月数
|
||
* @return 阳历
|
||
*/
|
||
public Solar nextMonth(int months) {
|
||
SolarMonth month = SolarMonth.fromYm(year, this.month).next(months);
|
||
int y = month.getYear();
|
||
int m = month.getMonth();
|
||
int d = day;
|
||
if (1582 == y && 10 == m) {
|
||
if (d > 4 && d < 15) {
|
||
d += 10;
|
||
}
|
||
} else {
|
||
int maxDay = SolarUtil.getDaysOfMonth(y, m);
|
||
if (d > maxDay) {
|
||
d = maxDay;
|
||
}
|
||
}
|
||
return fromYmdHms(y, m, d, hour, minute, second);
|
||
}
|
||
|
||
/**
|
||
* 获取往后推几天的阳历日期,如果要往前推,则天数用负数
|
||
*
|
||
* @param days 天数
|
||
* @return 阳历日期
|
||
*/
|
||
public Solar next(int days) {
|
||
int y = year;
|
||
int m = month;
|
||
int d = day;
|
||
if (1582 == y && 10 == m) {
|
||
if (d > 4) {
|
||
d -= 10;
|
||
}
|
||
}
|
||
if (days > 0) {
|
||
d += days;
|
||
int daysInMonth = SolarUtil.getDaysOfMonth(y, m);
|
||
while (d > daysInMonth) {
|
||
d -= daysInMonth;
|
||
m++;
|
||
if (m > 12) {
|
||
m = 1;
|
||
y++;
|
||
}
|
||
daysInMonth = SolarUtil.getDaysOfMonth(y, m);
|
||
}
|
||
} else if (days < 0) {
|
||
while (d + days <= 0) {
|
||
m--;
|
||
if (m < 1) {
|
||
m = 12;
|
||
y--;
|
||
}
|
||
d += SolarUtil.getDaysOfMonth(y, m);
|
||
}
|
||
d += days;
|
||
}
|
||
if (1582 == y && 10 == m) {
|
||
if (d > 4) {
|
||
d += 10;
|
||
}
|
||
}
|
||
return fromYmdHms(y, m, d, hour, minute, second);
|
||
}
|
||
|
||
/**
|
||
* 取往后推几天的阳历日期,如果要往前推,则天数用负数
|
||
*
|
||
* @param days 天数
|
||
* @param onlyWorkday 是否仅限工作日
|
||
* @return 阳历日期
|
||
*/
|
||
public Solar next(int days, boolean onlyWorkday) {
|
||
if (!onlyWorkday) {
|
||
return next(days);
|
||
}
|
||
Solar solar = fromYmdHms(year, month, day, hour, minute, second);
|
||
if (days != 0) {
|
||
int rest = Math.abs(days);
|
||
int add = days < 0 ? -1 : 1;
|
||
while (rest > 0) {
|
||
solar = solar.next(add);
|
||
boolean work = true;
|
||
Holiday holiday = HolidayUtil.getHoliday(solar.getYear(), solar.getMonth(), solar.getDay());
|
||
if (null == holiday) {
|
||
int week = solar.getWeek();
|
||
if (0 == week || 6 == week) {
|
||
work = false;
|
||
}
|
||
} else {
|
||
work = holiday.isWork();
|
||
}
|
||
if (work) {
|
||
rest -= 1;
|
||
}
|
||
}
|
||
}
|
||
return solar;
|
||
}
|
||
|
||
/**
|
||
* 小时推移
|
||
*
|
||
* @param hours 小时数
|
||
* @return 阳历
|
||
*/
|
||
public Solar nextHour(int hours) {
|
||
int h = hour + hours;
|
||
int n = h < 0 ? -1 : 1;
|
||
int hour = Math.abs(h);
|
||
int days = hour / 24 * n;
|
||
hour = (hour % 24) * n;
|
||
if (hour < 0) {
|
||
hour += 24;
|
||
days--;
|
||
}
|
||
Solar solar = next(days);
|
||
return fromYmdHms(solar.getYear(), solar.getMonth(), solar.getDay(), hour, solar.getMinute(), solar.getSecond());
|
||
}
|
||
|
||
/**
|
||
* 获取薪资比例(感谢 https://gitee.com/smr1987)
|
||
*
|
||
* @return 薪资比例:1/2/3
|
||
*/
|
||
public int getSalaryRate() {
|
||
// 元旦节
|
||
if (month == 1 && day == 1) {
|
||
return 3;
|
||
}
|
||
// 劳动节
|
||
if (month == 5 && day == 1) {
|
||
return 3;
|
||
}
|
||
// 国庆
|
||
if (month == 10 && day >= 1 && day <= 3) {
|
||
return 3;
|
||
}
|
||
Lunar lunar = getLunar();
|
||
// 春节
|
||
if (lunar.getMonth() == 1 && lunar.getDay() >= 1 && lunar.getDay() <= 3) {
|
||
return 3;
|
||
}
|
||
// 端午
|
||
if (lunar.getMonth() == 5 && lunar.getDay() == 5) {
|
||
return 3;
|
||
}
|
||
// 中秋
|
||
if (lunar.getMonth() == 8 && lunar.getDay() == 15) {
|
||
return 3;
|
||
}
|
||
// 清明
|
||
if ("清明".equals(lunar.getJieQi())) {
|
||
return 3;
|
||
}
|
||
Holiday holiday = HolidayUtil.getHoliday(year, month, day);
|
||
if (null != holiday) {
|
||
// 法定假日非上班
|
||
if (!holiday.isWork()) {
|
||
return 2;
|
||
}
|
||
} else {
|
||
// 周末
|
||
int week = getWeek();
|
||
if (week == 6 || week == 0) {
|
||
return 2;
|
||
}
|
||
}
|
||
// 工作日
|
||
return 1;
|
||
}
|
||
}
|