JDK8 官方日期、时间 API 笔记,可以看看官方是怎么介绍 date-time 相关工具类的、它的设计思想等
package cn.mrcode.date.jdk8;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author mrcode
* @date 2022
*/
public class Jdk8DateUtil {
/**
* 时区信息
*/
public static ZoneId zoneId = ZoneId.systemDefault();
/**
* 符合中国普遍国情的周数计算; 周 1 为一周的开始,只要有一天是下一年的开始,就认为是下一年的第一周
* <pre>
* 比如:2022-01-01 和 2021-12-30 都认为是 2022年第一周
* </pre>
*/
public final static WeekFields WEEK_FIELDS_CN = WeekFields.of(DayOfWeek.MONDAY, 1);
/**
* 周一为一周的开始,但是必须大于等于 4 天在下一年,才认为是下一年的第一周
*/
public final static WeekFields WEEK_FIELDS_ISO = WeekFields.ISO;
/**
* 年月日 -> 年月日 00:00:00
*
* @param date
* @return
*/
public static Date localDateToDate(LocalDate date) {
return Date.from(date.atStartOfDay(zoneId).toInstant());
}
public static LocalDate dateToLocalDate(Date date) {
return date.toInstant().atZone(zoneId).toLocalDate();
}
/**
* 按指定格式解析为 LocalDate
*
* @param dateStr 日期字符串
* @param pattern 如 yyyy-MM-dd,可以自己实现定义好 DateTimeFormatter 加快速度,并且还可以使用 format, fmt.format(day)
* @return
*/
public static LocalDate localDateParse(String dateStr, String pattern) {
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return LocalDate.parse(dateStr, dateTimeFormatter);
}
/**
* 获取某月第一天
*
* @param date
* @return
*/
public static LocalDate firstDayOfMonth(LocalDate date) {
return date.with(TemporalAdjusters.firstDayOfMonth());
}
/**
* 获取某月的最后一天
*
* @param date
* @return
*/
public static LocalDate lastDayOfMonth(LocalDate date) {
return date.with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 获取下个月的第一天
*
* @return
*/
public static LocalDate firstDayOfNextMonth(LocalDate date) {
return date.with(TemporalAdjusters.firstDayOfNextMonth());
}
/**
* 获取某月的第一天
*
* @param date
* @return
*/
public static LocalDate firstDayOfMonth(YearMonth date) {
return date.atDay(1);
}
/**
* 获取某月最后一天
*
* @param date
* @return
*/
public static LocalDate lastDayOfMonth(YearMonth date) {
return date.atDay(date.lengthOfMonth());
}
public static Date localDateTimeToDate(LocalDateTime time) {
return Date.from(time.atZone(zoneId).toInstant());
}
/**
* 获取该小时的开始时间,2021-08-30 01:05:00,05 -> 2021-08-30 01:00:00,000
*
* @param time
* @return
*/
public static LocalDateTime beginOfHour(LocalDateTime time) {
return LocalDateTime.of(time.toLocalDate(), LocalTime.of(time.getHour(), 0, 0));
}
public static LocalDateTime dateToLocalDateTime(Date date) {
return date.toInstant().atZone(zoneId).toLocalDateTime();
}
/**
* 获取两个时间范围内的每一天的时间,包含 startDay 和 endDay
*
* @param startDay
* @param endDay
* @return
*/
public static List<LocalDate> getDays(LocalDate startDay, LocalDate endDay) {
List<LocalDate> result = new ArrayList<>();
LocalDate currentDay = startDay;
while (currentDay.isBefore(endDay) || currentDay.isEqual(endDay)) {
result.add(currentDay);
currentDay = currentDay.plusDays(1);
}
return result;
}
/**
* 该时间是第几周?所属年份是哪一年?比如 2021-12-31 号所属年则是 2022 年,第一周
*
* @param date
* @return
*/
public static Integer weekBasedYear(LocalDate date) {
return date.get(WEEK_FIELDS_CN.weekBasedYear());
}
/**
* 第几周:该时间是第几周?比如 2021-12-31 号所属周是第 1 周,但是所属年确是第 2022 年
*
* @param date
* @return
*/
public static Integer weekOfWeekBasedYear(LocalDate date) {
return date.get(WEEK_FIELDS_CN.weekOfWeekBasedYear());
}
/**
* 该时间属于哪一年的第几周
* <pre>
* 2021-12-27 ~ 2022-01-02 都属于 202201,2022 年第 1 周
* </pre>
*
* @param date
* @return
*/
public static int dateToWeekInt(LocalDate date) {
Integer weekOfWeekBasedYear = Jdk8DateUtil.weekOfWeekBasedYear(date);
return Integer.valueOf(Jdk8DateUtil.weekBasedYear(date) + "" +
(weekOfWeekBasedYear < 10 ? 0 + "" + weekOfWeekBasedYear : weekOfWeekBasedYear));
}
}
Date 和 JDK8 日期互转可以参考上面的语法,其他的应该也是类似的 API;
系统默认时区的设置方式
关于上面为什么使用 ZoneId.systemDefault()
默认时区而不是使用 ZoneOffset._ofHours_(8);
自定义时区的方式:因为我觉得在全局设置时区会比在某一个里面写死时区会更好。原因有如下:
- 如果不设置系统的默认时区,在获取系统默认时区的时候就会获取到系统上的时区信息,假设系统上是 UTC 时区,你程序要求是东八区,那么就会导致问题出现
- 假设要统一修改时区,这个时候如果散落在各个类里面的时区配置就是灾难
- 时区涉及到了获取当前系统时间的表现形式,和第一条类似,如果设置了默认时区,
new Date()
的时候会将系统时间转化为默认时区的时间
在系统启动时,如果使用 SpringBoot 程序,在 main 方法里面 SpringApplication.run()
方法前调用默认时区的设置,如下代码
import java.util.TimeZone;
// 使用时区名称
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
// 或则使用偏移量
TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.ofHours(8)));
:::warning 需要注意的是:默认时区只能被设置一次,连续调用改变成其他的时区,是不会生效的 :::