说明
- 计算周期为每年的12月1号至下一年的12月之前(即12月1号生成下一年的假期,因为一次性生成,避开高并发时段,适合12月1号凌晨执行)。
- 计算时间为一年的休息日(假期)时间,可自己通过代码的注释选择是否包括公休日。
- 本计算基于规则实现,基本是正确的,但是有时一年的放假不按规则出牌,这时候就只能自己修改了,只需要根据日期修改Map集合对应key的值即可。
- 本计算方法一共基于两个类实现,一个计算类VacationDayCalculate,一个日历类Lunar(还有一个日期辅助处理类DataUtils)
- 代码注释较全,请注意查看有助于理解,main方法在计算类VacationDayCalculate最下面,可运行测试。
计算类VacationDayCalculate
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
public class VacationDayCalculate {
private String vacationWeek = "1,6-7-1_0_0;2,7-1-2_1_0;3,1-2-3_2_0;4,4-5-6_0_1;5,5-6-7_0_0;6,6-7-1_0_0;7,6-7-1_0_0";
private String vacationMax = "1,2_0;2,2_0;3,3_0;4,0_3;5,0_2;6,0_2;7,1_1";
public HashMap<String, Boolean> yearVacationDay(Integer year) {
HashMap<String, Boolean> dates = weekVacation(year - 1);
HashMap<Integer, String> weeks = new HashMap<>();
String[] weeksTemp = vacationWeek.split(";");
for (String weekStr : weeksTemp) {
String[] week = weekStr.split(",");
weeks.put(Integer.parseInt(week[0]), week[1]);
}
String vacationDay = year + "-01-01";
setVacationThreeDay(vacationDay, dates, weeks);
int temp = year & 3;
if (temp < 2) {
vacationDay = year + "-04-04";
} else {
vacationDay = year + "-04-05";
}
setVacationThreeDay(vacationDay, dates, weeks);
dates.put("05-01", true);
vacationDay = lunar(year.toString(), 5, 5);
setVacationThreeDay(vacationDay, dates, weeks);
vacationDay = lunar(year.toString(), 8, 15);
setVacationThreeDay(vacationDay, dates, weeks);
weeks.clear();
weeksTemp = vacationMax.split(";");
for (String weekStr : weeksTemp) {
String[] week = weekStr.split(",");
weeks.put(Integer.parseInt(week[0]), week[1]);
}
vacationDay = lunar(year.toString(), 1, 1);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
Long time = format.parse(vacationDay).getTime() - 86399000;
vacationDay = format.format(time);
} catch (ParseException e) {
e.printStackTrace();
}
setVacationSevenDay(vacationDay, dates, weeks);
vacationDay = year + "-10-01";
setVacationSevenDay(vacationDay, dates, weeks);
return dates;
}
private HashMap<String, Boolean> weekVacation(Integer year) {
HashMap<String, Boolean> dates = new LinkedHashMap<>();
Calendar cal = Calendar.getInstance();
cal.setTime(DateUtils.getDateByString(year + "-12-1 12:00:00", "yyyy-MM-dd hh:mm:ss"));
Integer days = 365;
if ((year & 3) == 0) {
days = 366;
}
for (int i = 0, j = 0; i < days; i++, j = 1) {
cal.add(Calendar.DAY_OF_YEAR, j);
String date = DateUtils.getStringDateByString(cal.getTime(), "MM-dd");
dates.put(date, false);
}
return dates;
}
private void setVacationThreeDay(String vacationDay, HashMap<String, Boolean> dates,
HashMap<Integer, String> weeks) {
Integer week = dayForWeek(vacationDay);
String[] vacation = weeks.get(week).split("_");
int indexOf = vacation[0].indexOf(week.toString());
Integer[] interval = dayForWeekThree(indexOf);
Integer incr = Integer.parseInt(vacation[1]);
Integer decr = Integer.parseInt(vacation[2]);
List<String> vacationDate = dayForWeek(vacationDay, interval[0], interval[1]);
for (String day : vacationDate) {
dates.put(day, true);
}
List<String> workDate = dayForWork(vacationDay, interval[0], interval[1], incr, decr);
for (String day : workDate) {
dates.put(day, false);
}
}
private void setVacationSevenDay(String vacationDay, HashMap<String, Boolean> dates,
HashMap<Integer, String> weeks) {
Integer week = dayForWeek(vacationDay);
String[] vacation = weeks.get(week).split("_");
Integer incr = Integer.parseInt(vacation[0]);
Integer decr = Integer.parseInt(vacation[1]);
List<String> vacationDate = dayForWeek(vacationDay, 0, 6);
for (String day : vacationDate) {
dates.put(day, true);
}
List<String> workDate = dayForWork(vacationDay, 0, 6, incr, decr);
for (String day : workDate) {
dates.put(day, false);
}
}
private Integer dayForWeek(String pTime) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
try {
Date tmpDate = format.parse(pTime);
cal.setTime(tmpDate);
} catch (Exception e) {
e.printStackTrace();
}
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
if (w == 0)
w = 7;
return w;
}
private Integer dayForWeek(Long pTime) {
Calendar cal = Calendar.getInstance();
try {
cal.setTime(new Date(pTime));
} catch (Exception e) {
e.printStackTrace();
}
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
if (w == 0)
w = 7;
return w;
}
private Integer[] dayForWeekThree(Integer indexOf) {
Integer incr, decr;
if (indexOf == 0) {
incr = 0;
decr = 2;
} else if (indexOf == 2) {
incr = 1;
decr = 1;
} else {
incr = 2;
decr = 0;
}
return new Integer[] { incr, decr };
}
private List<String> dayForWeek(String pTime, Integer incr, Integer decr) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat rformat = new SimpleDateFormat("MM-dd");
List<String> result = new ArrayList<>(10);
Calendar cal = Calendar.getInstance();
try {
Date tmpDate = format.parse(pTime);
result.add(rformat.format(tmpDate));
cal.setTime(tmpDate);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < incr; i++) {
cal.add(Calendar.DAY_OF_YEAR, -1);
result.add(rformat.format(cal.getTime()));
}
cal.add(Calendar.DAY_OF_YEAR, 1 * incr);
for (int i = 0; i < decr; i++) {
cal.add(Calendar.DAY_OF_YEAR, 1);
result.add(rformat.format(cal.getTime()));
}
return result;
}
private List<String> dayForWork(String pTime, Integer v_incr, Integer v_decr, Integer w_incr, Integer w_decr) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat rformat = new SimpleDateFormat("MM-dd");
Calendar cal = Calendar.getInstance();
try {
Date tmpDate = format.parse(pTime);
cal.setTime(tmpDate);
} catch (Exception e) {
e.printStackTrace();
}
List<String> result = new ArrayList<>(5);
cal.add(Calendar.DAY_OF_YEAR, v_incr * -1);
for (int i = 0; i < w_incr; i++) {
cal.add(Calendar.DAY_OF_YEAR, -1);
result.add(rformat.format(cal.getTime()));
}
cal.add(Calendar.DAY_OF_YEAR, v_incr + w_incr + v_decr);
for (int i = 0; i < w_decr; i++) {
cal.add(Calendar.DAY_OF_YEAR, 1);
result.add(rformat.format(cal.getTime()));
}
return result;
}
public String lunar(String year, Integer month, Integer day) {
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
cal.setTime(sdf.parse(year + "-" + month + "-" + day));
} catch (ParseException e) {
e.printStackTrace();
}
calcuLunar(cal, month, day, new Lunar(true));
return year + "-" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.DAY_OF_MONTH);
}
public static void calcuLunar(Calendar cal, int month, int day, Lunar l) {
Lunar lunar = new Lunar(cal);
if (lunar.getMonth() != month) {
cal.add(Calendar.MONTH, 1);
calcuLunar(cal, month, day, l);
}
if (lunar.getDay() != day && l.isLeap()) {
if (lunar.getDay() > day) {
cal.add(Calendar.DAY_OF_YEAR, -1);
} else {
cal.add(Calendar.DAY_OF_YEAR, 1);
}
calcuLunar(cal, month, day, l);
if (l.isLeap()) {
l.setLeap(false);
}
}
}
public static void main(String[] args) {
HashMap<String, Boolean> map = new VacationDayCalculate().yearVacationDay(2020);
Set<String> keySet = map.keySet();
for (String key : keySet) {
Boolean v = map.get(key);
if (v && key.startsWith("11")) {
System.out.println(key);
}
}
}
}
Lunar日历类
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Lunar {
private int year;
private int month;
private int day;
private boolean leap;
final static String chineseNumber[] = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
static SimpleDateFormat chineseDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
final static 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, 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 };
final private static int yearDays(int y) {
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
if ((lunarInfo[y - 1900] & i) != 0)
sum += 1;
}
return (sum + leapDays(y));
}
final private static int leapDays(int y) {
if (leapMonth(y) != 0) {
if ((lunarInfo[y - 1900] & 0x10000) != 0)
return 30;
else
return 29;
} else
return 0;
}
final private static int leapMonth(int y) {
return (int) (lunarInfo[y - 1900] & 0xf);
}
final private static int monthDays(int y, int m) {
if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)
return 29;
else
return 30;
}
final public String animalsYear() {
final String[] Animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
return Animals[(year - 4) % 12];
}
final private static String cyclicalm(int num) {
final String[] Gan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
final String[] Zhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
return (Gan[num % 10] + Zhi[num % 12]);
}
final public String cyclical() {
int num = year - 1900 + 36;
return (cyclicalm(num));
}
public Lunar(boolean leap) {
this.leap = leap;
}
public Lunar(Calendar cal) {
int yearCyl, monCyl, dayCyl;
int leapMonth = 0;
Date baseDate = null;
try {
baseDate = chineseDateFormat.parse("1900年1月31日");
} catch (ParseException e) {
e.printStackTrace();
}
int offset = (int) ((cal.getTime().getTime() - baseDate.getTime()) / 86400000L);
dayCyl = offset + 40;
monCyl = 14;
int iYear, daysOfYear = 0;
for (iYear = 1900; iYear < 2050 && offset > 0; iYear++) {
daysOfYear = yearDays(iYear);
offset -= daysOfYear;
monCyl += 12;
}
if (offset < 0) {
offset += daysOfYear;
iYear--;
monCyl -= 12;
}
year = iYear;
yearCyl = iYear - 1864;
leapMonth = leapMonth(iYear);
leap = false;
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {
if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap) {
--iMonth;
leap = true;
daysOfMonth = leapDays(year);
} else
daysOfMonth = monthDays(year, iMonth);
offset -= daysOfMonth;
if (leap && iMonth == (leapMonth + 1))
leap = false;
if (!leap)
monCyl++;
}
if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) {
if (leap) {
leap = false;
} else {
leap = true;
--iMonth;
--monCyl;
}
}
if (offset < 0) {
offset += daysOfMonth;
--iMonth;
--monCyl;
}
month = iMonth;
day = offset + 1;
}
public static String getChinaDayString(int day) {
String chineseTen[] = { "初", "十", "廿", "卅" };
int n = day % 10 == 0 ? 9 : day % 10 - 1;
if (day > 30)
return "";
if (day == 10)
return "初十";
else
return chineseTen[day / 10] + chineseNumber[n];
}
public String toString() {
return year + "年" + (leap ? "闰" : "") + chineseNumber[month - 1] + "月" + getChinaDayString(day);
}
public static void calcuLunar(Calendar cal, int month, int day, Lunar l) {
Lunar lunar = new Lunar(cal);
if (lunar.month != month) {
cal.add(Calendar.MONTH, 1);
calcuLunar(cal, month, day, l);
}
if (lunar.day != day && l.isLeap()) {
if (lunar.day > day) {
cal.add(Calendar.DAY_OF_YEAR, -1);
} else {
cal.add(Calendar.DAY_OF_YEAR, 1);
}
calcuLunar(cal, month, day, l);
if (l.isLeap()) {
l.setLeap(false);
}
}
}
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
cal.setTime(sdf.parse("2021-5-5"));
} catch (ParseException e) {
e.printStackTrace();
}
calcuLunar(cal, 5, 5, new Lunar(true));
System.out.println("日期是:" + (cal.get(Calendar.MONTH) + 1) + "月" + cal.get(Calendar.DAY_OF_MONTH) + "日");
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public boolean isLeap() {
return leap;
}
public void setLeap(boolean leap) {
this.leap = leap;
}
}
DateUtils日期处理类
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DateUtils {
public static Date getDateByString(String time,String plan){
Long times = getLongTimeByString(time, plan);
return new Date(times);
}
public static String getStringDateByString(Date time,String plan){
DateFormat format = new SimpleDateFormat(plan);
return format.format(time);
}
public static Long getLongTimeByString(String time,String plan){
DateFormat format = new SimpleDateFormat(plan);
Long result = null;
try {
result = format.parse(time).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return result;
}
}