From 0767caa6de53fd52678a6cf6ffc1ff2f0336dd2b Mon Sep 17 00:00:00 2001 From: zhangzhiguo Date: Tue, 31 Dec 2024 18:30:11 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E8=81=8C=E5=91=98=E5=87=BA?= =?UTF-8?q?=E5=B7=AE=E5=A4=A9=E6=95=B0=E7=BB=9F=E8=AE=A1=E5=8F=B0=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operate/DailyreimbursHomeCheckOp.java | 27 +- .../plugin/report/EmpTravelRptListPlugin.java | 97 +++++ .../report/EmpTravelRptQueryPlugin.java | 353 ++++++++++++++++++ 3 files changed, 465 insertions(+), 12 deletions(-) create mode 100644 code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptListPlugin.java create mode 100644 code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptQueryPlugin.java diff --git a/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/operate/DailyreimbursHomeCheckOp.java b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/operate/DailyreimbursHomeCheckOp.java index 4962d41..7f6a6e8 100644 --- a/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/operate/DailyreimbursHomeCheckOp.java +++ b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/operate/DailyreimbursHomeCheckOp.java @@ -168,13 +168,15 @@ public class DailyreimbursHomeCheckOp extends AbstractOperationServicePlugIn { return belongMonth.equals(startDate) || belongMonth.equals(endDate); } + /** * 获取差旅费报销单 + * * @param bxmonth * @param applierId * @return */ - public DataSet getTripreimbursebill(Date bxmonth,long applierId){ + public DataSet getTripreimbursebill(Date bxmonth, long applierId) { //查询非暂存、废弃的数据 List billStatuslist = new ArrayList<>(); billStatuslist.add("B"); @@ -187,11 +189,11 @@ public class DailyreimbursHomeCheckOp extends AbstractOperationServicePlugIn { LocalDate lastDayOfMonth = getLastDayOfMonth(bxmonth); QFilter[] filterArray = new QFilter[5]; //查询申请人下的今年的探亲差旅单据 - filterArray[0] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDayOfMonth); - filterArray[1] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDayOfMonth); - filterArray[2] = new QFilter("applier", QCP.equals, applierId); - filterArray[3] = new QFilter(prefix+"_is_include_home", QCP.equals, true); - filterArray[4] = new QFilter("billstatus", QCP.in, billStatuslist); + filterArray[0] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDayOfMonth); + filterArray[1] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDayOfMonth); + filterArray[2] = new QFilter("applier", QCP.equals, applierId); + filterArray[3] = new QFilter(prefix + "_is_include_home", QCP.equals, true); + filterArray[4] = new QFilter("billstatus", QCP.in, billStatuslist); DataSet dateSet = QueryServiceHelper.queryDataSet( this.getClass().getName(), "er_tripreimbursebill", @@ -205,11 +207,12 @@ public class DailyreimbursHomeCheckOp extends AbstractOperationServicePlugIn { /** * 获取费用报销单 + * * @param bxmonth * @param applierId * @return */ - public DataSet getDailyreimbursebill(Date bxmonth,long applierId){ + public DataSet getDailyreimbursebill(Date bxmonth, long applierId) { //查询非暂存、废弃的数据 List billStatuslist = new ArrayList<>(); billStatuslist.add("B"); @@ -223,11 +226,11 @@ public class DailyreimbursHomeCheckOp extends AbstractOperationServicePlugIn { LocalDate lastDayOfMonth = getLastDayOfMonth(bxmonth); QFilter[] filterArray = new QFilter[5]; //查询申请人下的今年的探亲差旅单据 - filterArray[0] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDayOfMonth); - filterArray[1] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDayOfMonth); - filterArray[2] = new QFilter("applier", QCP.equals, applierId); - filterArray[3] = new QFilter(prefix+"_is_home", QCP.equals, true); - filterArray[4] = new QFilter("billstatus", QCP.in, billStatuslist); + filterArray[0] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDayOfMonth); + filterArray[1] = new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDayOfMonth); + filterArray[2] = new QFilter("applier", QCP.equals, applierId); + filterArray[3] = new QFilter(prefix + "_is_home", QCP.equals, true); + filterArray[4] = new QFilter("billstatus", QCP.in, billStatuslist); DataSet dateSet = QueryServiceHelper.queryDataSet( this.getClass().getName(), "er_dailyreimbursebill", diff --git a/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptListPlugin.java b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptListPlugin.java new file mode 100644 index 0000000..a09afcf --- /dev/null +++ b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptListPlugin.java @@ -0,0 +1,97 @@ +package zcgj.zcdev.zcdev.fs.plugin.report; + +import kd.bos.context.RequestContext; +import kd.bos.entity.datamodel.IDataModel; +import kd.bos.entity.datamodel.events.PackageDataEvent; +import kd.bos.entity.report.FilterInfo; +import kd.bos.entity.report.ReportQueryParam; +import kd.bos.report.events.CellStyleRule; +import kd.bos.report.plugin.AbstractReportFormPlugin; +import kd.sdk.plugin.Plugin; + +import java.util.Date; +import java.util.List; + +/** + * 职员出差天数统计台账 + * 报表格式化插件 + */ +public class EmpTravelRptListPlugin extends AbstractReportFormPlugin implements Plugin { + + private static final String DEV_KEY="zcgj"; + private static final String MERGECOLUM= DEV_KEY+"_username";//合并单元格字段 + //预算与汇总报表上的所有字段 + private static final String[] FIELDS={ + DEV_KEY+"_user", DEV_KEY+"_username", + DEV_KEY+"_january",DEV_KEY+"_february",DEV_KEY+"_march",DEV_KEY+"_april", + DEV_KEY+"_may", DEV_KEY+"_june", DEV_KEY+"_july",DEV_KEY+"_august", + DEV_KEY+"_september",DEV_KEY+"_october",DEV_KEY+"_november",DEV_KEY+"_december", + DEV_KEY+"_total" + }; + + @Override + public void setMergeColums(List columns) { + columns.add(MERGECOLUM); + super.setMergeColums(columns); + } + + @Override + public void packageData(PackageDataEvent packageDataEvent) { + super.packageData(packageDataEvent); + } + + @Override + public void initDefaultQueryParam(ReportQueryParam queryParam) { + super.initDefaultQueryParam(queryParam); + IDataModel model = this.getModel(); + //获取当前登陆人所在组织 + long orgId = RequestContext.get().getOrgId(); + model.setValue("zcgj_query_org",orgId); + model.setValue("zcgj_query_year",new Date()); + } + + @Override + public boolean verifyQuery(ReportQueryParam queryParam) { + FilterInfo filter = queryParam.getFilter(); + StringBuilder sb = new StringBuilder(); + if (filter.getValue("zcgj_query_org") == null){ + this.getView().showTipNotification("请选择查询组织!"); + return false; + } + if (filter.getValue("zcgj_query_year") == null){ + this.getView().showTipNotification("请选择查询年度!"); + return false; + } + return true; + } + + + + @Override + public void setCellStyleRules(List cellStyleRules) { + for (String field : FIELDS) { + CellStyleRule cellStyleRule = new CellStyleRule(); + cellStyleRule.setFieldKey(field);// 字段标识 + cellStyleRule.setForeColor("#666666");// 前景色 + cellStyleRule.setBackgroundColor("#ffc000");// 背景色 + cellStyleRule.setDegree(100);// 透明度 + cellStyleRule.setCondition(DEV_KEY+"_username = '合计'");// 前置条件,值与表达式计算器一致 + cellStyleRules.add(cellStyleRule); + } + super.setCellStyleRules(cellStyleRules); + } + + /** + * 设置过滤排序列 + * + * @param allColumns 报表列 + */ + /*@Override + public void setSortAndFilter(List allColumns) { + super.setSortAndFilter(allColumns); + for (SortAndFilterEvent ent : allColumns) { + ent.setFilter(true); + ent.setSort(true); + } + }*/ +} diff --git a/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptQueryPlugin.java b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptQueryPlugin.java new file mode 100644 index 0000000..8a346f6 --- /dev/null +++ b/code/zcdev/zcgj-zcdev-zcdev-fs/src/main/java/zcgj/zcdev/zcdev/fs/plugin/report/EmpTravelRptQueryPlugin.java @@ -0,0 +1,353 @@ +package zcgj.zcdev.zcdev.fs.plugin.report; + +import kd.bos.algo.*; +import kd.bos.algo.input.CollectionInput; +import kd.bos.dataentity.entity.DynamicObject; +import kd.bos.dataentity.entity.DynamicObjectCollection; +import kd.bos.entity.report.AbstractReportListDataPlugin; +import kd.bos.entity.report.FilterItemInfo; +import kd.bos.entity.report.ReportQueryParam; +import kd.bos.logging.Log; +import kd.bos.logging.LogFactory; +import kd.bos.orm.query.QCP; +import kd.bos.orm.query.QFilter; +import kd.bos.servicehelper.QueryServiceHelper; +import kd.bos.servicehelper.user.UserServiceHelper; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 职员出差天数统计台账 + * 报表取数插件 + */ +public class EmpTravelRptQueryPlugin extends AbstractReportListDataPlugin { + private static final Log logger = LogFactory.getLog(EmpTravelRptQueryPlugin.class); + + private static final String DEV_KEY="zcgj"; + + @Override + public DataSet query(ReportQueryParam reportQueryParam, Object o) throws Throwable { + List filters = reportQueryParam.getFilter().getFilterItems(); + Set applierId = new HashSet<>(); + Long orgId = null; + Date queryYear = null; + boolean istax = false; + for (FilterItemInfo filterItem : filters) { + switch (filterItem.getPropName()) { + case DEV_KEY+"_query_users": + DynamicObjectCollection users = (DynamicObjectCollection)filterItem.getValue(); + if(users != null){ + for (DynamicObject user : users) { + applierId.add(Long.valueOf(String.valueOf(user.getPkValue()))); + } + } + break; + case DEV_KEY+"_query_year": + queryYear = filterItem.getDate(); + break; + case DEV_KEY+"_query_org": + orgId = (filterItem.getValue() == null) ? null :Long.valueOf(String.valueOf(((DynamicObject) filterItem.getValue()).getPkValue())); + break; + case DEV_KEY+"_query_istax": + istax = filterItem.getBoolean(); + break; + default: + break; + } + } + // 报表字段及数据类型 + String[] FIELDS = { + DEV_KEY+"_user", DEV_KEY+"_username", + DEV_KEY+"_january",DEV_KEY+"_february",DEV_KEY+"_march",DEV_KEY+"_april", + DEV_KEY+"_may", DEV_KEY+"_june", DEV_KEY+"_july",DEV_KEY+"_august", + DEV_KEY+"_september",DEV_KEY+"_october",DEV_KEY+"_november",DEV_KEY+"_december", + DEV_KEY+"_total" + }; + DataType[] DATATYPES = { + DataType.LongType,DataType.StringType, + DataType.StringType, DataType.StringType,DataType.StringType,DataType.IntegerType, + DataType.StringType, DataType.StringType, DataType.StringType,DataType.StringType, + DataType.StringType, DataType.StringType, DataType.StringType,DataType.StringType, + DataType.StringType + }; + // 初始化 DataSet + RowMeta rowMeta = RowMetaFactory.createRowMeta(FIELDS, DATATYPES); + Collection coll = new ArrayList<>(); + CollectionInput inputs = new CollectionInput(rowMeta, coll); + DataSet resultDataSet = Algo.create(this.getClass().getName()).createDataSet(inputs); + + if(orgId==null || queryYear == null){ + return resultDataSet; + } + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + //获取公司下的所有人 + List orgIds = new ArrayList<>(); + orgIds.add(orgId); + List allUsersOfOrg = UserServiceHelper.getAllUsersOfOrg(orgIds); + if(!applierId.isEmpty()){ + //通过查询用户过滤组织下的人 + allUsersOfOrg = allUsersOfOrg.stream().filter(applierId::contains).collect(Collectors.toList()); + } + LocalDate localDate = dateToLocalDate(queryYear); + int year = localDate.getYear(); + Set userSet = new HashSet<>(); + // 用 Map 来按照报销人、单据编号、费用发生日期分组 + Map reportMap = new LinkedHashMap<>(); + Map> userMonthDaysMap = new HashMap<>(); + for (Long userId : allUsersOfOrg) { + Map monthDaysMap = null; + if(userMonthDaysMap.containsKey(userId)){ + monthDaysMap = userMonthDaysMap.get(userId); + }else{ + monthDaysMap = new HashMap<>(); + for (int i = 1; i <= 12; i++) { + monthDaysMap.put(i,0); + } + userMonthDaysMap.put(userId,monthDaysMap); + } + + DataSet tripreimbursebill = getTripreimbursebill(queryYear, userId); + for (Row row : tripreimbursebill) { + String billno = row.getString("billno"); + int kccbdays = row.getInteger("kccbdays");//扣除餐补天数(周六日、节假日) + + String startdateStr = dateFormat.format(row.getDate("startdate"));// + String enddateStr = dateFormat.format(row.getDate("enddate")); + String bxmonthStr = dateFormat.format(row.getDate("bxmonth"));//归属月份 + + LocalDate bxmonth = dateToLocalDate(row.getDate("bxmonth")); + if(!skip(row.getDate("startdate"), row.getDate("enddate"))){ + int days = calculateDaysBetween(row.getDate("startdate"), row.getDate("enddate")); + if(days >= kccbdays){ + monthDaysMap.put(bxmonth.getMonth().getValue(), + monthDaysMap.getOrDefault(bxmonth.getMonth().getValue(), 0) + (days-kccbdays)); + } + } + } + + DataSet dailyreimbursebill = getDailyreimbursebill(queryYear, userId); + for (Row row : dailyreimbursebill) { + String billno = row.getString("billno"); + int kccbdays = row.getInteger("kccbdays");//扣除餐补天数(周六日、节假日) + + String startdateStr = dateFormat.format(row.getDate("startdate"));// + String enddateStr = dateFormat.format(row.getDate("enddate")); + String bxmonthStr = dateFormat.format(row.getDate("bxmonth"));//归属月份 + + LocalDate bxmonth = dateToLocalDate(row.getDate("bxmonth")); + if(!skip(row.getDate("startdate"), row.getDate("enddate"))){ + int days = calculateDaysBetween(row.getDate("startdate"), row.getDate("enddate")); + if(days >= kccbdays){ + monthDaysMap.put(bxmonth.getMonth().getValue(), + monthDaysMap.getOrDefault(bxmonth.getMonth().getValue(), 0) + (days-kccbdays)); + } + } + } + System.out.println(); + } + + for (Long userId : userMonthDaysMap.keySet()) { + Map integerIntegerMap = userMonthDaysMap.get(userId); + Map userInfoByID = UserServiceHelper.getUserInfoByID(userId); + String username = String.valueOf(userInfoByID.get("name"));//报销人 + Object [] tempData = new Object [FIELDS.length]; + coll.add(tempData); + + tempData[0] = userId; + tempData[1] = username; + int index = 2; + int totalDays = 0; + for (int i = 1; i <=12 ; i++) { + totalDays += integerIntegerMap.get(i); + tempData[index] = integerIntegerMap.get(i) == 0 ?null:integerIntegerMap.get(i)+""; + index++; + } + if(totalDays!=0){ + tempData[14] = totalDays; + } + } + + return resultDataSet; + } + + /** + * 获取差旅费报销单 + * + * @param applierId + * @return + */ + public DataSet getTripreimbursebill(Date queryYear,Long applierId) { + LocalDate localDate = dateToLocalDate(queryYear); + LocalDate firstDay = getFirstDayOfYear(localDate.getYear()); + LocalDate lastDay = getLastDayOfYear(localDate.getYear()); + //查询非暂存、废弃的数据 + List billStatuslist = new ArrayList<>(); + //billStatuslist.add("A"); //暂存 + //billStatuslist.add("B"); //已提交 + //billStatuslist.add("C"); //审核中 + //billStatuslist.add("D"); //审核未通过 + billStatuslist.add("E"); //审核通过 + billStatuslist.add("F"); //等待付款 + billStatuslist.add("G"); //已付款 + //billStatuslist.add("H"); //废弃 + billStatuslist.add("I"); //关闭 + //查询申请人下的今年的探亲差旅单据 + List searchFilterList = new ArrayList<>(); + searchFilterList.add(new QFilter("applier", QCP.equals, applierId)); + searchFilterList.add(new QFilter( "zcgj_is_include_home", QCP.equals, true)); + //searchFilterList.add(new QFilter("billstatus", QCP.in, billStatuslist)); + searchFilterList.add( new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDay)); + searchFilterList.add(new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDay)); + DataSet dateSet = QueryServiceHelper.queryDataSet( + this.getClass().getName(), + "er_tripreimbursebill", + "id,billno,zcgj_kccbdays as kccbdays,zcgj_homeentity,zcgj_homeentity.zcgj_bxmonth as bxmonth," + + "zcgj_homeentity.zcgj_startdate as startdate,zcgj_homeentity.zcgj_enddate as enddate," + + "zcgj_homeentity.zcgj_homebz as homebz", + searchFilterList.toArray(new QFilter [] {}), null + ); + return dateSet; + } + + /** + * 获取费用报销单 + * + * @return + */ + public DataSet getDailyreimbursebill(Date queryYear,Long applierId) { + LocalDate localDate = dateToLocalDate(queryYear); + LocalDate firstDay = getFirstDayOfYear(localDate.getYear()); + LocalDate lastDay = getLastDayOfYear(localDate.getYear()); + //查询非暂存、废弃的数据 + List billStatuslist = new ArrayList<>(); + //billStatuslist.add("A"); //暂存 + //billStatuslist.add("B"); //已提交 + //billStatuslist.add("C"); //审核中 + //billStatuslist.add("D"); //审核未通过 + billStatuslist.add("E"); //审核通过 + billStatuslist.add("F"); //等待付款 + billStatuslist.add("G"); //已付款 + //billStatuslist.add("H"); //废弃 + billStatuslist.add("I"); //关闭 + + List searchFilterList = new ArrayList<>(); + //查询申请人下的今年的探亲差旅单据 + searchFilterList.add(new QFilter("applier", QCP.equals, applierId)); + searchFilterList.add(new QFilter( "zcgj_is_home", QCP.equals, true)); + //searchFilterList.add(new QFilter("billstatus", QCP.in, billStatuslist)); + searchFilterList.add( new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.large_equals, firstDay)); + searchFilterList.add(new QFilter("zcgj_homeentity.zcgj_bxmonth", QCP.less_equals, lastDay)); + DataSet dateSet = QueryServiceHelper.queryDataSet( + this.getClass().getName(), + "er_dailyreimbursebill", + "id,billno,zcgj_kccbdays as kccbdays,zcgj_homeentity,zcgj_homeentity.zcgj_bxmonth as bxmonth," + + "zcgj_homeentity.zcgj_startdate as startdate,zcgj_homeentity.zcgj_enddate as enddate," + + "zcgj_homeentity.zcgj_homebz as homebz", + searchFilterList.toArray(new QFilter [] {}), null + ); + return dateSet; + } + + public boolean skip(Date startDate, Date endDate) throws Exception{ + // 日期格式化 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + // 使用 Calendar 类进行日期操作 + Calendar startCalendar = Calendar.getInstance(); + Calendar endCalendar = Calendar.getInstance(); + + startCalendar.setTime(startDate); + endCalendar.setTime(endDate); + + // 特殊情况处理:如果开始日期是周五且结束日期是周一,跳过统计 + if (startCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY && + endCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { + return true; + } + return false; + } + + // 计算开始日期和结束日期之间的天数 + public static int calculateDaysBetween(Date startDate, Date endDate) throws Exception { + // 日期格式化 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + // 使用 Calendar 类来处理日期 + Calendar startCalendar = Calendar.getInstance(); + Calendar endCalendar = Calendar.getInstance(); + + startCalendar.setTime(startDate); + endCalendar.setTime(endDate); + + // 计算两个日期之间的天数差 + long startMillis = startCalendar.getTimeInMillis(); + long endMillis = endCalendar.getTimeInMillis(); + + // 计算天数差,注意加1天因为天数是区间的数量(包含开始日期) + long diffMillis = endMillis - startMillis; + int diffDays = (int) (diffMillis / (24 * 60 * 60 * 1000)); + + return diffDays + 1; // 因为差值是天数之间的差,包含开始日期 + } + + // 计算工作日天数 + public static int calculateWorkdays(Date startDate, Date endDate) throws Exception { + // 使用 Calendar 类进行日期操作 + Calendar startCalendar = Calendar.getInstance(); + Calendar endCalendar = Calendar.getInstance(); + + startCalendar.setTime(startDate); + endCalendar.setTime(endDate); + + // 特殊情况处理:如果开始日期是周五且结束日期是周一,返回0 + if (startCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY && + endCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { + return 0; + } + + // 计算工作日天数 + int workdays = 0; + + // 从开始日期到结束日期遍历 + while (!startCalendar.after(endCalendar)) { + int dayOfWeek = startCalendar.get(Calendar.DAY_OF_WEEK); + // 只统计周一到周五(排除周六和周日) + if (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY) { + workdays++; + } + startCalendar.add(Calendar.DAY_OF_MONTH, 1); // 移动到下一天 + } + + return workdays; + } + + // 获取某年份的第一天 + public static LocalDate getFirstDayOfYear(int year) { + return LocalDate.of(year, 1, 1); + } + + // 获取某年份的最后一天 + public static LocalDate getLastDayOfYear(int year) { + return LocalDate.of(year, 12, 31); + } + + /** + * 将 java.util.Date 转换为 java.time.LocalDate + * @param date java.util.Date + * @return java.time.LocalDate + */ + public static LocalDate dateToLocalDate(Date date) { + if (date == null) { + throw new IllegalArgumentException("日期不能为 null"); + } + return date.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + } +}