参考资料: https://mp.weixin.qq.com/s/xAPik92FU37Ap2PRiUIPyw
Java 8 中的 LocalDate 用于表示当天日期,比如: 今天的日期2022-08-12
,格式是yyyy-MM-dd
/**
* 获取今天的日期(只有年月日)
*/
@Test
public void getCurrentLocalDate() {
log.info("今天的日期:" + LocalDate.now());
//今天的日期:2022-08-12
//可以用于做链路追踪
MDC.put("xx", "1000112234343");
}
private LocalDate today;
@Before
public void init() {
log.info("单元测试初始化~~~~~~");
today = LocalDate.now();
}
/**
* 获取年
*/
@Test
public void getYear() {
int year = today.getYear();
log.info("当前时间:{},获取年:{}", today, year);
//当前时间:2022-08-12,获取年:2022
}
/**
* 获取月
*/
@Test
public void getMonth() {
Month month = today.getMonth();
int value = month.getValue();
//或者直接调用 getMonthValue() 得到对应的值
int monthValue = today.getMonthValue();
log.info("当前时间:{},获取月:{},value:{}", today, month, value);
//当前时间:2022-08-12,获取月:AUGUST,value:8
}
/**
* 获取日
*/
@Test
public void getDay() {
int dayOfMonth = today.getDayOfMonth();
log.info("当前时间:{},获取日:{}", today, dayOfMonth);
}
通过静态工厂方法 now(),创建了当天日期;还可以调用另一个有用的工厂方法 LocalDate.of() 创建任意日期, 该方法需要传入年、月、日做参数,返回对应的 LocalDate 实例。
/**
* 处理待定日期
*/
@Test
public void undeterminedDay() {
//java.time.DateTimeException: Invalid value for DayOfMonth (valid values 1 - 28/31): 33
//LocalDate of = LocalDate.of(2022, 2, 33);
//java.time.DateTimeException: Invalid date 'FEBRUARY 31'
//LocalDate of = LocalDate.of(2022, 2, 31);
//java.time.DateTimeException: Invalid date 'FEBRUARY 30'
//LocalDate of = LocalDate.of(2022, 2, 30);
//java.time.DateTimeException: Invalid date 'February 29' as '2022' is not a leap year
//LocalDate of = LocalDate.of(2022, 2, 29);
LocalDate of = LocalDate.of(2022, 2, 28);
//自定义时间:2022-02-28,年:2022,月:2,日:28,所属星期几:1
log.info("自定义时间:{},年:{},月:{},日:{},所属星期几:{}", of, of.getYear(), of.getMonthValue(), of.getDayOfMonth(), of.getDayOfWeek().getValue());
LocalDate of2 = LocalDate.of(2022, 2, 27);
int value = of2.getDayOfWeek().getValue();
//自定义时间:2022-02-27,所属星期几:7
log.info("自定义时间:{},所属星期几:{}", of2, value);
LocalDate of3 = LocalDate.of(2022, 2, 26);
int value2 = of3.getDayOfWeek().getValue();
//自定义时间:2022-02-26,所属星期几:6
log.info("自定义时间:{},所属星期几:{}", of3, value2);
LocalDate now = LocalDate.now();
int dayOfYear = now.getDayOfYear();
//当前时间:2022-08-12,在这年中属于第几天:224
log.info("当前时间:{},在这年中属于第几天:{}", now, dayOfYear);
}
/**
* 获取季度
*/
@Test
public void getQuarter(){
//LocalDate start = LocalDate.now();
LocalDate start = LocalDate.of(2022,6,7);
int quarter = (start.getMonthValue()-1)/3 + 1;
//当前时间:2022-06-07,所属季度:2
log.info("当前时间:{},所属季度:{}",start,quarter);
}
/**
* 比较2个时间是否相等
* LocalDate 格式是: 'yyyy-MM-dd' 年月日
*/
@Test
public void isEquals2Day() {
LocalDate one = LocalDate.now();
LocalDate tow = LocalDate.now();
//第一个时间:2022-08-12,第二个时间:2022-08-12相等
if (one.equals(tow)) {
log.info("第一个时间:{},第二个时间:{}相等", one, tow);
} else {
log.info("第一个时间:{},第二个时间:{}不相等", one, tow);
}
}
只要当天的日期和生日匹配,无论是哪一年都会打印出祝贺信息。
/**
* 检查像生日这种周期性事件
*/
@Test
public void periodDay() {
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2018, 8, 12);
MonthDay birthday = MonthDay.of(date2.getMonth(), date2.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(date1);
if (currentMonthDay.equals(birthday)) {
log.info("是你的生日");
} else {
log.info("你的生日还没有到");
}
}
LocalDate 日期不包含时间信息,它的 plus() 方法用来增加天、周、月
/**
* 计算一周后的日期
*/
@Test
public void addWeek(){
LocalDate today = LocalDate.now();
//今天的日期为:2022-08-12
log.info("今天的日期为:"+today);
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
//一周后的日期为:2022-08-19
log.info("一周后的日期为:"+nextWeek);
log.info("--------------------------><------------------------------");
LocalDate localDate = today.plusDays(2);
//当前时间:2022-08-12,增加2天:2022-08-14
log.info("当前时间:{},增加2天:{}",today,localDate);
LocalDate localDate1 = today.plusYears(1);
//当前时间:2022-08-12,增加1年:2023-08-12
log.info("当前时间:{},增加1年:{}",today,localDate1);
LocalDate localDate2 = today.plusMonths(1);
//当前时间:2022-08-12,增加1月:2022-09-12
log.info("当前时间:{},增加1月:{}",today,localDate2);
LocalDate localDate3 = today.plusWeeks(2);
//当前时间:2022-08-12,增加2周:2022-08-26
log.info("当前时间:{},增加2周:{}",today,localDate3);
}
利用 minus() 方法计算一年前的日期
LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("一年前的日期 : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("一年后的日期:"+nextYear);
Clock 时钟类用于获取当时的时间戳,或当前时区下的日期时间信息
//以前用到 System.currentTimeInMillis()
// 和 TimeZone.getDefault() 的地方都可用 Clock 替换。
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock.millis());
// Returns time based on system clock zone
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + defaultClock.millis());
如何判断给定的一个日期是大于某天还是小于某天
LocalDate 类有两类方法 isBefore() 和 isAfter() 用于比较日期。调用 isBefore() 方法时,如果给定日期小于当前日期则返回 true。
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018,2,6);
if(tomorrow.isAfter(today)){
System.out.println("之后的日期:"+tomorrow);
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("之前的日期:"+yesterday);
}
有一个常见日期操作是计算两个日期之间的天数、周数或月数。在 Java 8 中可以用 java.time.Period 类来做计算。
计算了当天和将来某一天之间的月数:
LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2018, 12, 14);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : "
+ periodToNextJavaRelease.getMonths() );
Instant 类有一个静态工厂方法 now() 会返回当前的时间戳;时间戳信息里同时包含了日期和时间,这和 java.util.Date 很像。实际上 Instant 类确实等同于 Java 8 之前的 Date 类,你可以使用 Date 类和 Instant 类各自的转换方法互相转换。例如:Date.from(Instant) 将 Instant 转换成 java.util.Date,Date.toInstant() 则是将 Date 类转换成 Instant 类。
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp.toEpochMilli());
String dayAfterTommorrow = "20180205";
LocalDate formatted = LocalDate.parse(dayAfterTommorrow,
DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(dayAfterTommorrow+" 格式化后的日期为: "+formatted);
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//日期转字符串
String str = date.format(format1);
System.out.println("日期转换为字符串:"+str);
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//字符串转日期
LocalDate date2 = LocalDate.parse(str,format2);
System.out.println("日期类型:"+date2);
/**
* 获取当前时间小时、分钟、秒
*/
@Test
public void getHouseMinuteSecond() {
//获取系统的当前小时、分钟、秒,同时可以设置时区
LocalTime now = LocalTime.now();
//获取当前的时间,不含有日期:11:05:13.249
log.info("获取当前的时间,不含有日期:" + now);
}
通过增加小时、分、秒来计算将来的时间;Java 8 除了不变类型和线程安全的好处之外,还提供了更好的 plusHours() 方法替换 add(),并且是兼容的
**注意:**这些方法返回一个全新的 LocalTime 实例,由于其不可变性,返回后一定要用变量赋值
/**
* 增加小时、分、秒来计算将来的时间
*/
@Test
public void getFutureDayInfo(){
LocalTime now = LocalTime.now();
LocalTime localTime = now.plusHours(3);
//当前时间信息:11:21:12.972,增加3个小时:14:21:12.972
log.info("当前时间信息:{},增加3个小时:{}",now,localTime);
LocalTime localTime1 = now.plusMinutes(20);
//当前时间信息:11:21:12.972,增加20分钟:11:41:12.972
log.info("当前时间信息:{},增加20分钟:{}",now,localTime1);
LocalTime localTime2 = now.plusSeconds(10);
//当前时间信息:11:21:12.972,增加10秒:11:21:22.972
log.info("当前时间信息:{},增加10秒:{}",now,localTime2);
}
计算一周后的日期:
/**
* 计算一周后的日期
*/
@Test
public void addWeek(){
LocalDate today = LocalDate.now();
//今天的日期为:2022-08-12
log.info("今天的日期为:"+today);
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
//一周后的日期为:2022-08-19
log.info("一周后的日期为:"+nextWeek);
}
单独的类如 ZoneId 来处理特定时区,ZoneDateTime 类来表示某时区下的时间
// Date and time with timezone in Java 8
ZoneId america = ZoneId.of("America/New_York");
LocalDateTime localtDateAndTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america );
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInNewYork);
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
YearMonth与 MonthDay 检查重复事件的例子相似,YearMonth 是另一个组合类,用于表示信用卡到期日、FD 到期日、期货期权到期日等。
还可以用这个类得到当月共有多少天,YearMonth 实例的 lengthOfMonth() 方法可以返回当月的天数,在判断 2 月有 28 天还是 29 天时非常有用。
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2019, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2018 is not a Leap year");
}
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.8.0.M4version>
dependency>
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import org.springframework.util.StringUtils;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
/**
* 日期扩展工具类
*
* @author TOM
* @date 2022/5/05
*/
public class DateUtilsExt {
/**
* 获取当月第一天
*/
private static LocalDateTime getFirstLocalDayOfMonth(LocalDateTime localDateTime) {
return localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
}
/**
* 获取当月第一周 以第一个周一为准
*/
private static LocalDateTime getFirstMonday(LocalDateTime sourceTime) {
LocalDateTime firstMondayOfMonth = getFirstLocalDayOfMonth(sourceTime);
for (int i = 0; i < 6; i++) {
DayOfWeek dayOfWeekTemp = firstMondayOfMonth.getDayOfWeek();
if (dayOfWeekTemp.equals(DayOfWeek.MONDAY)) {
break;
}
//往后推一天
firstMondayOfMonth = firstMondayOfMonth.plusDays(1);
}
return firstMondayOfMonth;
}
/**
* 字符串转换成LocalDateTime
*
* @param dateStr 时间字符串
* @param datePattern 默认时间格式:yyyy-MM-dd HH:mm:ss
* 时间字符串格式: yyyy-MM-dd HH:mm:ss | yyyy/MM/dd HH:mm:ss
*/
public static LocalDateTime strConverToLocalDateTime(String dateStr, String datePattern) {
if (StringUtils.isEmpty(datePattern)) {
datePattern = "yyyy-MM-dd HH:mm:ss";
}
return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(datePattern));
}
/**
* 获取几月份的第几周 [X月份第X周]
*/
public static String getMonthNoAndWeekNoInfo(LocalDateTime sourceTime) {
String monthNoAndWeekNo;
//获取当月的第一天
//获取月第一个周一,从当月第一天开始找
LocalDateTime firstMondayOfMonth = getFirstMonday(sourceTime);
//比较当月的第一个星期一 < = 参数时间
if (firstMondayOfMonth.isBefore(sourceTime) || firstMondayOfMonth.isEqual(sourceTime)) {
//当月第一个周一在当前时间之前 firstMondayOfMonth<=sourceTime
//计算两个时间间隔天数
int dayOfMonthFirstMonday = firstMondayOfMonth.getDayOfMonth();
int dayOfMonthSourceTime = sourceTime.getDayOfMonth();
int diffDays = dayOfMonthSourceTime - dayOfMonthFirstMonday;
//第几周weekNo
int weekNo = (diffDays / 7) + 1;
//月份
int monthNo = sourceTime.getMonth().getValue();
monthNoAndWeekNo = monthNo + "月份" + "第" + weekNo + "周";
} else {
//如果当月的第一个周一大于参数时间,则要计算到上个月份去
//获取上一个月的第一个周一
LocalDateTime lastMontLocalDateTime = sourceTime.minusMonths(1);
//上个月的第一天
//从上个月的第一天开始找周一
LocalDateTime firstMondayOfMonthLast = getFirstMonday(lastMontLocalDateTime);
// 计算两个时间间隔天数 (上月第一个周一 减去 当前时间)
Duration duration = Duration.between(firstMondayOfMonthLast, sourceTime);
long diffDays = duration.toDays(); //相差的天数
//第几周weekNo
long weekNo = (diffDays / 7) + 1;
//月份
int monthNo = firstMondayOfMonthLast.getMonth().getValue();//汉字版月份
monthNoAndWeekNo = monthNo + "月份" + "第" + weekNo + "周";
}
return monthNoAndWeekNo;
}
private static Long getMonthNoAndWeekNo(LocalDateTime sourceTime) {
long weekNo;
//获取当月的第一天
//获取月第一个周一,从当月第一天开始找
LocalDateTime firstMondayOfMonth = getFirstMonday(sourceTime);
//比较当月的第一个星期一 < = 参数时间
if (firstMondayOfMonth.isBefore(sourceTime) || firstMondayOfMonth.isEqual(sourceTime)) {
//当月第一个周一在当前时间之前 firstMondayOfMonth<=sourceTime
//计算两个时间间隔天数
int dayOfMonthFirstMonday = firstMondayOfMonth.getDayOfMonth();
int dayOfMonthSourceTime = sourceTime.getDayOfMonth();
int diffDays = dayOfMonthSourceTime - dayOfMonthFirstMonday;
//第几周weekNo
weekNo = (diffDays / 7) + 1;
} else {
//如果当月的第一个周一大于参数时间,则要计算到上个月份去
//获取上一个月的第一个周一
LocalDateTime lastMontLocalDateTime = sourceTime.minusMonths(1);
//上个月的第一天
//从上个月的第一天开始找周一
LocalDateTime firstMondayOfMonthLast = getFirstMonday(lastMontLocalDateTime);
// 计算两个时间间隔天数 (上月第一个周一 减去 当前时间)
Duration duration = Duration.between(firstMondayOfMonthLast, sourceTime);
long diffDays = duration.toDays(); //相差的天数
//第几周weekNo
weekNo = (diffDays / 7) + 1;
}
return weekNo;
}
//-------------------------------------------------------------------
/**
* 时间转换成LocalDateTime
*
* @param date java.util.Date
* @return LocalDateTime
*/
public static LocalDateTime dateConverLocalDateTime(Date date) {
DateTime dt = DateUtil.date(date);
// Date对象转换为LocalDateTime
LocalDateTime of = LocalDateTimeUtil.of(dt);
return of;
}
/**
* 获取年月日 yyyy-MM-dd
*/
public static String getYearMonthDay(Date date) {
return DateUtil.format(date, "yyyy-MM-dd");
}
/**
* 获得年的部分
*
* @param date java.util.Date
* @return 年份
*/
public static int getYear(Date date) {
//获得年的部分
return DateUtil.year(date);
}
/**
* 获取月
*
* @param date java.util.Date
* @return 月份
*/
public static int getMonth(Date date) {
//获得月份,从0开始计数
return DateUtil.month(date) + 1;
}
/**
* 获取日部分
*/
public static int getDayofMonth(Date date) {
return dateConverLocalDateTime(date).getDayOfMonth();
}
/**
* 获得指定日期的小时数部分
*/
public static int getHouse(Date date) {
return DateUtil.hour(date, true);
}
/**
* 获取指定日期的分钟数部分
*/
public static int getMinute(Date date) {
return DateUtil.minute(date);
}
/**
* 获取指定日期的秒部分
*/
public static int getSecond(Date date) {
return DateUtil.second(date);
}
/**
* 获得指定日期是所在月份的第几周
*/
public static Long getWeekOfMonth(Date date) {
return getMonthNoAndWeekNo(dateConverLocalDateTime(date));
}
/**
* 获得指定日期所属季度,从1开始计数
*
* @return 第几个季度
*/
public static int getQuarter(Date date) {
return DateUtil.quarter(date);
}
/**
* 当前时间是星期几
* 获得指定日期是星期几,0表示周日,1表示周一
*/
public static int getWeek(Date date){
return DateUtil.dayOfWeek(date)-1;
}
/**
* 指定时间的前一天
*/
public static Date beforeDate(Date date){
return DateUtil.offsetDay(date, -1).toJdkDate();
}
/**
* 时间格式化
*/
public static String dateFormate(Date date,String patterStr){
String format = DateUtil.format(date, patterStr);
return format;
}
}