Java工具-获取某月份天数、某月最后一天、某月工作日天数(支持自定义节假日)
Java工具-获取某月份天数、某月最后一天、某月工作日天数(支持自定义节假日)
因为之前在项目中有一个工作日志的功能,所以在网上找了一些相关的工具类,都是零零散散,我在这总结一下。废话不多说,上代码!
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;/*** @ClassName WorkDayUtil 计算日期、工作日相关的工具类* @Auther JunKai* @Date 2019/12/24*/
public class WorkDayUtil {/** 预设工作日数据的开始年份 */private static final int START_YEAR = 2017;/** 预设工作日数据的结束年份 */private static final int END_YEAR = 5020;/** 工作日map,true为补休,false为放假 */public static final Map<Integer, Boolean> WORKDAY_MAP = new HashMap<>();private static final SegmentTree SEGMENT_TREE;private WorkDayUtil() {}/** 获取一个月天数 */public static int getDaysOfMonth(Date date) {Calendar calendar = Calendar.getInstance();calendar.setTime(date);return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);}/** 获取一个月的最后一天 */public static String getLastDay(Date date) {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");Calendar calendar = Calendar.getInstance();calendar.setTime(date);int lastDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);Date time = calendar.getTime();time.setDate(lastDays);return df.format(time);}/** 获取一个月的第一天 */public static String getFirstDay(Date date) {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");Calendar calendar = Calendar.getInstance();calendar.setTime(date);//calendar.add(Calendar.MONTH, -1);calendar.set(Calendar.DAY_OF_MONTH, 1);String time = df.format(calendar.getTime());return time;}/*** 计算两个日期之间有多少个工作日<br/>* @param startDate* @param endDate* @return*/public static int howManyWorkday(Date startDate, Date endDate) {if (startDate.after(endDate)) {return howManyWorkday(endDate, startDate);}Calendar startCalendar = Calendar.getInstance();startCalendar.setTime(startDate);int startDays = getDaysAfterStartYear(startCalendar) - 1; // 第一天从0开始Calendar endCalendar = Calendar.getInstance();endCalendar.setTime(endDate);int endDays = getDaysAfterStartYear(endCalendar) - 1; // 第一天从0开始if (startDays == endDays) { // 如果开始日期和结束日期在同一天的话return isWorkDay(startDate) ? 1 : 0; // 当天为工作日则返回1天,否则0天}if (!START_DATE_HANDLING_STRATEGY.ifCountAsOneDay(startDate)) { // 根据处理策略,如果开始日期不算一天的话++startDays; // 起始日期向后移一天}if (!END_DATE_HANDLING_STRATEGY.ifCountAsOneDay(endDate)) { // 根据处理策略,如果结束日期不算一天的话--endDays; // 结束日期向前移一天}return SEGMENT_TREE.query(startDays, endDays);}static {initWorkday(); // 初始化工作日map// 计算从START_YEAR到END_YEAR一共有多少天int totalDays = 0;for (int year = START_YEAR; year <= END_YEAR; ++year) {totalDays += getDaysOfYear(year);}int[] workdayArray = new int[totalDays]; // 将工作日的数据存入到数组Calendar calendar = new GregorianCalendar(START_YEAR, 0, 1);for (int i = 0; i < totalDays; ++i) {// 将日期转为yyyyMMdd格式的intint datestamp = calendar.get(Calendar.YEAR) * 10000 + (calendar.get(Calendar.MONTH) + 1) * 100 + calendar.get(Calendar.DAY_OF_MONTH);Boolean isWorkDay = WORKDAY_MAP.get(datestamp);if (isWorkDay != null) { // 如果在工作日map里有记录,则按此判断工作日workdayArray[i] = isWorkDay ? 1 : 0;} else { // 如果在工作日map里没记录,则按是否为周末判断工作日int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);workdayArray[i] = (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY) ? 1 : 0;}calendar.add(Calendar.DAY_OF_YEAR, 1);}SEGMENT_TREE = new SegmentTree(workdayArray); // 生成线段树}/*** 判断某一日期是否为工作日* @param date* @return*/public static boolean isWorkDay(int date) {if(WORKDAY_MAP.get(date)== null) {Calendar calendar = Calendar.getInstance();SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");try {calendar.setTime(sdf.parse(String.valueOf(date)));} catch (ParseException e) {e.printStackTrace();}//如果当天不是补休也不是放假,但是为周末,则为非工作日if(calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){return false;}} else {//判断如何当天是法定假日,则为非工作日if(WORKDAY_MAP.get(date) == false) {return false;}//判断如何当天是补休,则为工作日if(WORKDAY_MAP.get(date)== true) {return true;}}return true;}/*** 是否为工作日* @param date* @return*/public static boolean isWorkDay(Date date) {Calendar calendar = Calendar.getInstance();calendar.setTime(date);int days = getDaysAfterStartYear(calendar) - 1;return SEGMENT_TREE.query(days, days) == 1;}/*** 计算从开始年份到这个日期有多少天* @param calendar* @return*/private static int getDaysAfterStartYear(Calendar calendar) {int year = calendar.get(Calendar.YEAR);if (year < START_YEAR || year > END_YEAR) {throw new IllegalArgumentException(String.format("系统目前仅支持计算%d年至%d年之间的工作日,无法计算%d年!", START_YEAR, END_YEAR, year));}int days = 0;for (int i=START_YEAR; i<year; ++i) {days += getDaysOfYear(i);}days += calendar.get(Calendar.DAY_OF_YEAR);return days;}/*** 计算该年有几天,闰年返回366,平年返回365* @param year* @return*/private static int getDaysOfYear(int year) {return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 366 : 365;}/*** 初始化工作日Map<br/>* 日期格式必须为yyyyMMdd,true为补休,false为放假,如果本来就是周末的节假日则不需再设置* 手动进行维护*/private static void initWorkday() {// ---------------2020------------------WORKDAY_MAP.put(20200101, false);WORKDAY_MAP.put(20200124, false);WORKDAY_MAP.put(20200125, false);WORKDAY_MAP.put(20200126, false);WORKDAY_MAP.put(20200127, false);WORKDAY_MAP.put(20200128, false);WORKDAY_MAP.put(20200129, false);WORKDAY_MAP.put(20200130, false);WORKDAY_MAP.put(20200201, true);// ---------------2019------------------WORKDAY_MAP.put(20190101, false);WORKDAY_MAP.put(20190202, true);WORKDAY_MAP.put(20190203, true);WORKDAY_MAP.put(20190204, false);WORKDAY_MAP.put(20190205, false);WORKDAY_MAP.put(20190206, false);WORKDAY_MAP.put(20190207, false);WORKDAY_MAP.put(20190208, false);WORKDAY_MAP.put(20190209, false);WORKDAY_MAP.put(20190210, false);WORKDAY_MAP.put(20190405, false);WORKDAY_MAP.put(20190501, false);WORKDAY_MAP.put(20190502, false);WORKDAY_MAP.put(20190503, false);WORKDAY_MAP.put(20190505, true);WORKDAY_MAP.put(20190607, false);WORKDAY_MAP.put(20190913, false);WORKDAY_MAP.put(20190929, true);WORKDAY_MAP.put(20191001, false);WORKDAY_MAP.put(20191002, false);WORKDAY_MAP.put(20191003, false);WORKDAY_MAP.put(20191004, false);WORKDAY_MAP.put(20191007, false);WORKDAY_MAP.put(20191012, true);// ------------------2018----------------WORKDAY_MAP.put(20180101, false);WORKDAY_MAP.put(20180211, true);WORKDAY_MAP.put(20180215, false);WORKDAY_MAP.put(20180216, false);WORKDAY_MAP.put(20180219, false);WORKDAY_MAP.put(20180220, false);WORKDAY_MAP.put(20180221, false);WORKDAY_MAP.put(20180224, true);WORKDAY_MAP.put(20180405, false);WORKDAY_MAP.put(20180406, false);WORKDAY_MAP.put(20180408, true);WORKDAY_MAP.put(20180428, true);WORKDAY_MAP.put(20180430, false);WORKDAY_MAP.put(20180501, false);WORKDAY_MAP.put(20180618, false);WORKDAY_MAP.put(20180924, false);WORKDAY_MAP.put(20180929, true);WORKDAY_MAP.put(20180930, true);WORKDAY_MAP.put(20181001, false);WORKDAY_MAP.put(20181002, false);WORKDAY_MAP.put(20181003, false);WORKDAY_MAP.put(20181004, false);WORKDAY_MAP.put(20181005, false);}/*** 边界日期处理策略<br/>* 在计算两个日期之间有多少个工作日时,有的特殊需求是如果开始/结束的日期在某个时间之前/后(如中午十二点前),则不把当天算作一天<br/>* 因此特将此逻辑分离出来,各自按照不同需求实现该接口即可* @Auther JunKai* @Date 2019/12/24*/private interface BoundaryDateHandlingStrategy {/** 是否把这个日期算作一天 */boolean ifCountAsOneDay(Date date);}/*** zkw线段树* @author Corvey*/private static class SegmentTree {private int[] data; // 线段树数据private int numOfLeaf; // 叶子结点个数public SegmentTree(int[] srcData) {for (numOfLeaf = 1; numOfLeaf < srcData.length; numOfLeaf <<= 1);data = new int[numOfLeaf << 1];for (int i = 0; i < srcData.length; ++i) {data[i + numOfLeaf] = srcData[i];}for (int i = numOfLeaf - 1; i > 0; --i) {data[i] = data[i << 1] + data[i << 1 | 1];}}/** [left, right]区间求和,left从0开始 */public int query(int left, int right) {if (left > right) {return query(right, left);}left = left + numOfLeaf - 1;right = right + numOfLeaf + 1;int sum = 0;for (; (left ^ right ^ 1) != 0; left >>= 1, right >>= 1) {if ((~left & 1) == 1) sum += data[left ^ 1];if ((right & 1) == 1) sum += data[right ^ 1];}return sum;}}/** 起始日期处理策略 */private static final BoundaryDateHandlingStrategy START_DATE_HANDLING_STRATEGY = date -> {Calendar calendar = Calendar.getInstance();calendar.setTime(date);return calendar.get(Calendar.HOUR_OF_DAY) < 12; // 如果开始时间在中午12点前,则当天也算作一天,否则不算};/** 结束日期处理策略 */private static final BoundaryDateHandlingStrategy END_DATE_HANDLING_STRATEGY = date -> {return true; // 结束时间无论几点,都算作1天};}
好了,这工具类就完事了!
每天进步一点点
Java工具-获取某月份天数、某月最后一天、某月工作日天数(支持自定义节假日)相关推荐
- java 和 mysql 获取周 星期 的第一天 最后一天 或者 月的 日期(字符串转日期,日期转字符串,日期加减)...
获取周的第一天,最后一天 System.out.println(getStartEndDate("2016-05-01", 1)); 获取星期的第一天和最后一天 System.ou ...
- java里获取当前月份_Java如何获取当前月份的名称?
要从系统获取当前月份的名称,我们可以使用java.util.Calendarclass.Calendar.get(Calendar.MONTH)从0开始的第一个月和11作为上月的整数返回月份的值.这意 ...
- java代码获取当前月第一天和最后一天的毫秒值
Calendar calendar = Calendar.getInstance();//获取当前日期calendar.add(Calendar.MONTH, 0);//n代表和本月偏移 0本月.1后 ...
- 【Android 安全】DEX 加密 ( Java 工具开发 | apk 文件签名 )
文章目录 一.生成 jks 文件 二.签名命令 三.执行结果 四.处理 Unsupported major.minor version 52.0 错误 参考博客 : [Android 安全]DEX 加 ...
- js获取一个月份最大天数和获取月的最后一天
代码如下: <html xmlns=http://www.w3.org/1999/xhtml > <head> <title>标题页</tit ...
- DateUtils 工具类:获取指定月份第一天时间,最后一天时间
获取指定月份第一天时间 getMinDateMonth ,最后一天时间 getMaxDateMonth ,将时间区间按照月份分组,拆分多个片段 getDateSplitMonth 指定月份的下个月 g ...
- Java获取指定月份的最后一天
https://blog.csdn.net/itmyhome1990/article/details/85619804 Java获取指定月份的最后一天 麦田 2019-01-02 17:43:38 ...
- 练习-Java多路分支之月份天数计算
任务描述 本关任务:根据给定的年份和月份,获取该月份的天数. 提示:在求二月份的天数时,需要判断年份是否是闰年.闰年的条件是,年份是否能够被 400 整除,或者年份能够被 4 整除但是不能被 100 ...
- Java获取指定月份第一周第一天
Java获取指定月份第一周第一天 思路: 1.获取当前月份第一天 2.获取第一天对应周几 3.根据周几减去对应天数得到指定日期 @Testpublic void test2(){Date lastWe ...
最新文章
- 时间源服务器|授时仪|GPS时钟同步系统
- WCF服务开发与调用的完整示例
- C和指针之strcat函数 strchr函数 strcmp函数 strcpy函数 strnchr函数 strstr函数实现
- python变量和常量_Python数学模块常量和示例
- “有意思的前端函数面试题”第一题答案原理解析
- 如何使用cURL一次测量请求和响应时间?
- POJ 2393 Yogurt factory
- 天勤数据结构代码——排序
- 中国居民身份证、通行证(含香港、澳门、台湾)资料整理,含编码规则
- bgp (二)改变下一跳本地,
- Kafka学习之Replication tools之Reassign Partitions Tool
- 轻论坛StartBBS、YouBBS、Xiuno对比
- 如何快速的把m4a转换成mp3格式
- iTween基础之Move(移动)
- 盘一盘 Python 系列 - SciPy
- VMware CentOS6.5 安装VMware Tools
- 喜闻乐见之Activity生命周期
- Visual Studio滚动条设置
- 条码WMS系统与ERP接口实现方法
- FFT从入门到使用(ACM/OI)