package com.estate.expert.common.utils; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; import java.time.temporal.WeekFields; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; /** * LocalDateTime 时间时区转换统一工具类 * @Author code * @Date 2020/8/11 17:30 * @Version 1.0 */ @Slf4j public class DateConvertUtils { /** 系统使用的时区 (默认为 CTT 中国上海时区) yml配置:shortZoneId:system 初始化是在: DefaultWebMvcConfig类中*/ public static String systemShortZoneId = "CTT"; /** 需要转换的时区 (默认转换为 PST美国洛杉矶时区) yml配置:shortZoneId:convert 初始化是在: DefaultWebMvcConfig类中*/ public static String convertShortZoneId = "PST"; /** * 获取当前系统使用的时区ID * @return */ public static String getSystemZoneId() { return ZoneId.SHORT_IDS.get(systemShortZoneId); } /** * 获取需要转换使用的时区ID * @return */ public static String getConvertZoneId() { return ZoneId.SHORT_IDS.get(convertShortZoneId); } /** * 获取默认转换时区(convertShortZoneId)后的时间 * @return */ public static LocalDateTime getDefaultZoneTime() { return LocalDateTime.now(Clock.system(ZoneId.of(getConvertZoneId()))); } /** * 根据传入的时间转换成指定配置时区(convertShortZoneId)后的时间 * @param localDateTime * @return */ public static LocalDateTime getZoneTime(LocalDateTime localDateTime) { ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of(getSystemZoneId())).withZoneSameInstant(ZoneId.of(getConvertZoneId())); return zonedDateTime.toLocalDateTime(); } /** * 将指定时间的指定时区转换为目标时区的时间 * @param localDateTime 时间 * @param fromZone 指定时区 * @param toZone 目标时区 * @return */ public static LocalDateTime toZone(LocalDateTime localDateTime, String fromZone, String toZone) { return toZone(localDateTime, ZoneId.of(fromZone), ZoneId.of(toZone)); } /** * 将指定时间的指定时区转换为目标时区的时间 * @param localDateTime 时间 * @param fromZone 指定时区 * @param toZone 目标时区 * @return */ public static LocalDateTime toZone(LocalDateTime localDateTime, ZoneId fromZone, ZoneId toZone) { final ZonedDateTime zonedTime = localDateTime.atZone(fromZone); final ZonedDateTime converted = zonedTime.withZoneSameInstant(toZone); return converted.toLocalDateTime(); } /** * 获取指定配置时区(convertShortZoneId)本周周一的 字符串(yyyy-MM-dd)时间 * @return */ public static String getMondayOfThisWeek() { LocalDateTime monday = getDefaultZoneTime().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(1); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = dateTimeFormatter.format(monday); return date; } /** * 获取指定配置时区(convertShortZoneId)的周一的 LocalDateTime 时间 * @return */ public static LocalDateTime getMondayOfThisWeekToTime() { LocalDateTime monday = getDefaultZoneTime().with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); return LocalDateTime.of(monday.toLocalDate(), LocalTime.MIN); } /** * 获取指定配置时区(convertShortZoneId)且 指定周的 周一的 LocalDateTime 时间 * @return */ public static LocalDateTime getMondayOfWeekToTime(WeekEnum weekEnum) { LocalDateTime monday = getDefaultZoneTime().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)); return LocalDateTime.of(monday.plusDays(weekEnum.day).toLocalDate(), LocalTime.MIN); } public static void main(String[] args) { System.out.println(getZoneCurrentDayMinTime(LocalDateTime.now())); System.out.println(getZoneCurrentMonday(LocalDateTime.now())); // System.out.println(getMondayOfThisWeekToTime()); System.out.println(getDefaultZoneTime()); System.out.println(getMondayOfThisWeek()); System.out.println(getLastMonday(LocalDateTime.now())); System.out.println(getLocalDateTimeByDayOfWeek(DayOfWeek.WEDNESDAY)); System.out.println(getLocalDateTimeByDayOfWeek(DayOfWeek.SATURDAY)); System.out.println(getLocalDateTimeByDayOfWeek(DayOfWeek.SUNDAY)); } /** * 获取指定配置时区(convertShortZoneId)当前的年数(注意跨年的问题:已解决) * @return */ public static int getWeekDeductionYear() { LocalDateTime now = getDefaultZoneTime(); WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,4); int year = now.get(weekFields.weekBasedYear()); return year; } /** * 获取指定配置时区(convertShortZoneId)当前年中的周数(注意跨年的问题:已解决) * @return */ public static int getWeekDeductionYearWeek() { LocalDateTime now = getDefaultZoneTime(); WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,4); int week = now.get(weekFields.weekOfWeekBasedYear()); return week; } /** * 根据传入的时间不做时区转换进行格式转换(yyyy-MM-dd) * @param localDateTime * @return */ public static String noTimeZoneChangeFormat(LocalDateTime localDateTime) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = dateTimeFormatter.format(localDateTime); return date; } /** * 根据传入的时间不做时区转换进行格式转换(yyyy-MM-dd) * @param localDateTime * @param pattern * @return */ public static String noTimeZoneChangeFormat(LocalDateTime localDateTime, String pattern) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); String date = dateTimeFormatter.format(localDateTime); return date; } /** * 根据传入的时间不做时区转换进行格式转换(yyyy-MM-dd) * @param localDate * @return */ public static String noTimeZoneChangeFormat(LocalDate localDate) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = localDate.format(dateTimeFormatter); return date; } /** * 根据传入的时间不做时区转换进行格式转换(yyyy-MM-dd) * @param date * @return */ public static String noTimeZoneChangeFormat(Date date) { SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd"); String result = dateTimeFormatter.format(date); return result; } /** * 将传入的时间 转换成指定配置时区(convertShortZoneId)格式的字符数据 * @param localDateTime * @param pattern * @return */ public static String formatZone(LocalDateTime localDateTime, String pattern) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); String date = dateTimeFormatter.format(getZoneTime(localDateTime)); return date; } /** * 将传入的时间 转换成指定配置时区(convertShortZoneId)指定格式(yyyy-MM-dd)的字符数据 * @param localDateTime * @return */ public static String formatZone(LocalDateTime localDateTime) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = dateTimeFormatter.format(getZoneTime(localDateTime)); return date; } /** * 获取指定配置时区(convertShortZoneId)的当前时间,并转换成指定格式(yyyy-MM-dd)的字符数据 * @return */ public static String format() { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = dateTimeFormatter.format(getDefaultZoneTime()); return date; } /** * 将传入的时间转换成 转换成指定格式(yyyy-MM-dd)的字符数据 * @param localDateTime * @return */ @Deprecated public static String format(LocalDateTime localDateTime) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String date = dateTimeFormatter.format(localDateTime); return date; } /** * 将传入的时间转换成指定配置时区(convertShortZoneId)的 数字时间(yyyyMMdd) * @param localDateTime * @return */ public static Integer formatZoneToInt(LocalDateTime localDateTime) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String date = dateTimeFormatter.format(getZoneTime(localDateTime)); return Integer.valueOf(date); } /** * 将传入的时间转换成 数字时间(yyyyMMdd) * @param localDateTime * @return */ public static Integer formatToInt(LocalDateTime localDateTime) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String date = dateTimeFormatter.format(localDateTime); return Integer.valueOf(date); } /** * 获取指定配置时区(convertShortZoneId)的当前时间的最小时间 * @return */ public static LocalDateTime getZoneDateMinTime(){ LocalDateTime now = getDefaultZoneTime().with(LocalTime.MIN); return now; } /** * 获取指定配置时区(convertShortZoneId)的当前时间的最大时间 * @return */ public static LocalDateTime getZoneDateMaxTime(){ LocalDateTime now = getDefaultZoneTime().with(LocalTime.MAX); return now; } /** * 获取传入当天的时间获取当天在转换时区后的开始时间 * @param localDateTime 传入配置的时区的时间 * @return */ public static LocalDateTime getZoneCurrentDayMinTime(LocalDateTime localDateTime) { LocalDateTime with = getZoneTime(localDateTime).with(LocalTime.MIN); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取上周 周一的开始时间 * @param localDateTime 传入配置的时区的时间 * @return */ public static LocalDateTime getLastMonday(LocalDateTime localDateTime) { LocalDateTime with = localDateTime.toLocalDate().minusWeeks(1L).with(DayOfWeek.MONDAY).atStartOfDay(); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取上周 周一的开始时间 * @param localDateTime 传入配置的时区的时间 * @return */ public static LocalDateTime getZoneLastMonday(LocalDateTime localDateTime) { LocalDateTime with = localDateTime.toLocalDate().minusWeeks(1L).with(DayOfWeek.MONDAY).atStartOfDay(); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取本周 周一的开始时间 * @param localDateTime 传入配置的时区的时间 * @return */ public static LocalDateTime getZoneCurrentMonday(LocalDateTime localDateTime) { LocalDateTime with = localDateTime.toLocalDate().with(DayOfWeek.MONDAY).atStartOfDay(); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取本周指定周几的开始时间 * @param dayOfWeek * @return */ public static LocalDateTime getLocalDateTimeByDayOfWeek(DayOfWeek dayOfWeek){ LocalDateTime with = getDefaultZoneTime().toLocalDate().with(dayOfWeek).atStartOfDay(); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取上周 周日的结束时间 * @param localDateTime 传入配置的时区的时间 * @return */ public static LocalDateTime getLastSunday(LocalDateTime localDateTime) { LocalDateTime with = localDateTime.toLocalDate().minusWeeks(1L).with(DayOfWeek.SUNDAY).plusDays(1).atStartOfDay(); LocalDateTime toZoneTime = toZone(with, ZoneId.SHORT_IDS.get(convertShortZoneId), ZoneId.SHORT_IDS.get(systemShortZoneId)); return toZoneTime; } /** * 获取两个时间相差的秒数 * @param startTime * @param endTime * @return */ public static Long getTimeDifference(LocalDateTime startTime, LocalDateTime endTime) { Duration duration = Duration.between(startTime, endTime); return duration.getSeconds(); } /** * 获取指定时间的时间戳(单位:秒) * @param localDateTime * @return */ public static Long getTimeSeconds(LocalDateTime localDateTime) { Long seconds = localDateTime.toEpochSecond(ZoneOffset.of("+8")); return seconds; } /** * 根据传入时区的两个时间 获取两个日期相差的周数 * * @param startDate - 开始时间(需要自己转换时区) * @param endDate - 结束时间(需要自己转换时区) * @return */ public static int getWeeksBetweenTime(LocalDateTime startDate, LocalDateTime endDate) { Calendar dateFrom = GregorianCalendar.from(ZonedDateTime.of(startDate, ZoneId.systemDefault())); //设置日历 Calendar dateTo = GregorianCalendar.from(ZonedDateTime.of(endDate, ZoneId.systemDefault())); //获取年份 int yearFrom = dateFrom.get(Calendar.YEAR); int yearTo = dateTo.get(Calendar.YEAR); //获取日期所在年的周数 int weekOfYearFrom = dateFrom.get(Calendar.WEEK_OF_YEAR); if (weekOfYearFrom == 1 && dateFrom.get(Calendar.MONTH) == Calendar.DECEMBER) { //腊月最后几天的周数可能为1 weekOfYearFrom = getWeeksInYear(yearFrom, true); } int weekOfYearTo = dateTo.get(Calendar.WEEK_OF_YEAR); if (weekOfYearTo == 1 && dateTo.get(Calendar.MONTH) == Calendar.DECEMBER) { weekOfYearTo = getWeeksInYear(yearTo, true); } //同年直接返回 if (yearFrom == yearTo) { return weekOfYearTo - weekOfYearFrom; } //不同年: int betweenWeeks = weekOfYearTo; int betweenYears = yearTo - yearFrom; for (int i = 1; i <= betweenYears ; i++) { betweenWeeks += getWeeksInYear(yearFrom+i, false); } betweenWeeks -= weekOfYearFrom; return betweenWeeks; } /** * 获取 某 年共有几周, * @param year - 年份 * @param containLastDays - 腊月最后几天不满一周的,是否算为一周 * @return */ public static int getWeeksInYear(int year, boolean containLastDays){ Calendar calendar = Calendar.getInstance(); calendar.set(year, Calendar.DECEMBER,31); int i = calendar.get(Calendar.WEEK_OF_YEAR); if(i == 1 && containLastDays){ i = 53; } if(i != 53){ i = 52; } return i; } /** * 获取传入时间获取传入时间当前所在周的周一的时间 * @param localDateTime * @return */ public static LocalDateTime getCurrentMonday(LocalDateTime localDateTime) { return localDateTime.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(1).with(LocalTime.MIN); } // /** // * 获取传入时间的上周周一的日期时间 // * @param localDateTime // * @return // */ // public static LocalDate getLastMonday(LocalDateTime localDateTime) { // LocalDate now = localDateTime.toLocalDate(); // LocalDate todayOfLastWeek = now.minusDays(7); // LocalDate monday = todayOfLastWeek.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); // return monday; // } /** * 根据配置的时区 和指定周枚举值 获取周的所有日期时间 * @return */ public static List getAllDaysOfWeekByShortZoneId(WeekEnum weekEnum) { if(weekEnum == null) { return Lists.newArrayList(); } //根据时区来进行判断 如果是美国的时区的话 需要减去一天,其他时区暂时不做扣减,后续需要进行扣减的时间需要在 AllDaysOfTheWeekMinusDaysEnum 枚举中进行配置 return getAllDaysOfWeek(weekEnum, AllDaysOfTheWeekMinusDaysEnum.getMinusDays(convertShortZoneId)); } /** * 获取指定周内的所有日期时间 * @param weekEnum * @param minusDays * @return */ private static List getAllDaysOfWeek(WeekEnum weekEnum, int minusDays) { List days = Lists.newArrayList(); days.add(getDefaultZoneTime().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(weekEnum.day).plusDays(1).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(6).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(5).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(4).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(3).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(2).minusDays(minusDays).with(LocalTime.MIN)); days.add(getDefaultZoneTime().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).plusDays(weekEnum.day).minusDays(1).minusDays(minusDays).with(LocalTime.MIN)); List voList = Lists.newArrayList(); days.forEach(day -> { AllDaysOfTheWeekVo vo = new AllDaysOfTheWeekVo(); vo.setIntDayTime(formatToInt(day)); vo.setDayTime(day); voList.add(vo); }); return voList; } /** * 获取指定年、周数的日期 (参考:https://blog.csdn.net/weixin_44919928/article/details/100008249) * @param year * @param num * @param dayOfWeek(MONDAY TUESDAY) * @return */ public static LocalDate getDateByYearAndWeekNumAndDayOfWeekParam(Integer year, Integer num, DayOfWeek dayOfWeek) { //周数小于10在前面补个0 String numStr = num < 10 ? "0" + String.valueOf(num) : String.valueOf(num); //2019-W01-01获取第一周的周一日期,2019-W02-07获取第二周的周日日期 String weekDate = String.format("%s-W%s-%s", year, numStr, dayOfWeek.getValue()); return LocalDate.parse(weekDate, DateTimeFormatter.ISO_WEEK_DATE); } /** * 周类型枚举 */ public enum WeekEnum { /** * 上周、本周、下周 */ PREVIOUS_WEEK(-6), THIS_WEEK(1), NEXT_WEEK(8), ; int day; WeekEnum(int day) { this.day = day; } } public enum AllDaysOfTheWeekMinusDaysEnum { /** * PST 美国时间的周一是 中国时间的周日 * CTT 中国时间 * */ PST(1), CTT(0), ; int minusDays; AllDaysOfTheWeekMinusDaysEnum(int minusDays) { this.minusDays = minusDays; } public static int getMinusDays(String shortZoneId) { for (AllDaysOfTheWeekMinusDaysEnum allDaysOfTheWeekMinusDaysEnum : AllDaysOfTheWeekMinusDaysEnum.values()) { if(allDaysOfTheWeekMinusDaysEnum.name().equals(shortZoneId)) { return allDaysOfTheWeekMinusDaysEnum.minusDays; } } return 0; } } /** * 周的所有日期时间对象 */ public static class AllDaysOfTheWeekVo { /** * 数字时间 yyyyMMdd */ private Integer intDayTime; private LocalDateTime dayTime; public Integer getIntDayTime() { return intDayTime; } public void setIntDayTime(Integer intDayTime) { this.intDayTime = intDayTime; } public LocalDateTime getDayTime() { return dayTime; } public void setDayTime(LocalDateTime dayTime) { this.dayTime = dayTime; } } }