Java8 在 java.time 包中增加了时间日期相关的API,弥补了 Java8 以前对日期、时间处理的不足。

在介绍Java8新的时间日期API前,先看看 java8 以前我们操作日期时间常用到的 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat

1 java.util.Date

1.1 java.util.Date常用API介绍

java.util.Date从JDK1.0开始就已经存在了,在开发中经常会接触到,进入 java.util.Date 的源码,我们可以看到好多方法都已经过时了。

下面我们介绍一下Date中未过时的方法。

  • Date() // Date 空参构造器,调用的构造器 Date(long date),入参是 System.currentTimeMillis()

  • Date(long date) // 带时间戳入参的构造器,初始化一个 Date对象,入参 date 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数

  • long getTime() // 返回 1970年1月1日00:00:00 GMT 到当前 Date 的毫秒数

  • void setTime(long time) //设置Date的时间,入参 time 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数

  • boolean before(Date when) // 测试此日期是否早于入参指定的日期。

  • boolean after(Date when) // 测试此日期是否晚于入参指定的日期。

  • int compareTo(Date anotherDate) // 当前日期与入参指定日期进行比较,当前日期小于入参日期,返回 -1;当前日期等于入参日期,返回0;当前日期大于入参日期,返回 1;

  • static Date from(Instant instant) // 将一个 Instant 实例转为 Date 实例

  • Instant toInstant() // 将一个 Date 实例转为 Instant 实例

Date源码

public class Date implements Serializable, Cloneable, Comparable<Date> {...// Date 空参构造器,调用的构造器 Date(long date),入参是 System.currentTimeMillis()public Date() {this(System.currentTimeMillis());    }

// 通过时间戳,初始化一个 Date对象,入参 date 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数public Date(long date) {        fastTime = date;    }

// 返回 1970年1月1日00:00:00 GMT 到当前 Date 的毫秒数public long getTime() {return getTimeImpl();    }

//设置Date的时间,入参 time 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数public void setTime(long time) {        fastTime = time;        cdate = null;    }

// 测试此日期是否早于入参指定的日期。public boolean before(Date when) {return getMillisOf(this) < getMillisOf(when);    }

// 测试此日期是否晚于入参指定的日期。public boolean after(Date when) {return getMillisOf(this) > getMillisOf(when);    }

// 当前日期与入参指定日期进行比较,// 当前日期小于入参日期,返回 -1;当前日期等于入参日期,返回0;当前日期大于入参日期,返回 1;public int compareTo(Date anotherDate) {long thisTime = getMillisOf(this);long anotherTime = getMillisOf(anotherDate);return (thisTime1 : (thisTime==anotherTime ? 0 : 1));    }// 将一个 Instant 实例转为 Date 实例public static Date from(Instant instant) {try {return new Date(instant.toEpochMilli());        } catch (ArithmeticException ex) {throw new IllegalArgumentException(ex);        }    }// 将一个 Date 实例转为 Instant 实例public Instant toInstant() {return Instant.ofEpochMilli(getTime());    }...}

1.2 java.util.Date简单使用

public class DateCalendarTest {

/**     * 测试 java.util.Date     */@Testpublic void testDateAPI() {// 1、Date()  Date 空参构造器,调用的构造器 Date(long date),入参是 System.currentTimeMillis()        Date date1 = new Date();        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");// 用时间戳入参的构造器// 2、Date(long date) 入参 date 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数        Date date2 = new Date(0);        System.out.println("空参构造器:" + dateFormat.format(date1));        System.out.println("时间戳入参构造器:" + dateFormat.format(date2));

// 3、getTime()  // 返回 1970年1月1日00:00:00 GMT 到当前 Date 的毫秒数long time = date1.getTime();        System.out.println("date1的毫秒数:" + time);

//  setTime(long time) 入参 time 表示自1970年1月1日00:00:00 GMT(格林尼治标准时间)以来的毫秒数        date2.setTime(System.currentTimeMillis());        System.out.println("date2设置时间后的毫秒数:" + date2.getTime());

// before(Date when) 测试此日期是否早于入参指定的日期。boolean before = date1.before(date2);        System.out.println("data1 before date2 ? " + before);

// after(Date when) 测试此日期是否晚于入参指定的日期。boolean after = date1.after(date2);        System.out.println("data1 after date2 ? " + after);

        Instant instant = date1.toInstant();        System.out.println("date1.toInstant(): " + instant);

        Date from = Date.from(instant);        System.out.println("Date.from(instant): " + from.getTime());    }}

运行结果:

空参构造器:2020-09-03时间戳入参构造器:1970-01-01date1的毫秒数:1599102000943date2设置时间后的毫秒数:1599102000949data1 before date2 ? truedata1 after date2 ? falsedate1.toInstant(): 2020-09-03T03:00:00.943ZDate.from(instant): 1599102000943

2 java.util.Calendar

Calendar提供了操作日历相关的API。month是从0开始的,1-12月份的值是 0-11。

2.1 java.util.Calendar 常用API介绍

  • Calendar getInstance() // 使用默认时区和区域设置获取日历

  • void add(int field,int amount) //根据日历的规则,为给定的日历字段添加或减去指定的时间量。

  • Date getTime() // 返回表示当前日历时间的 Date

  • void setTime(Date date) // 通过给定的 date 设置 Calendar 的时间

  • long getTimeInMillis() // 返回 Calendar 时间对应的毫秒数

  • void setTimeInMillis(long millis) // 用给定的毫秒数设置日历的当前时间

  • int get(int field) // 返回指定日历字段的值。

  • void set(int field,int value) // 将给定的日历字段设置为给定值。

  • void set(int year,int month,int date) // 设置Calendar对象的年、月、日3个字段的值。

  • void set(int year,int month,int date,int hour,int minute,int second) // 设置Calendar对象的年、月、日、时、分、秒6个字段的值。

2.2 java.util.Calendar简单使用

/**     * 测试 java.util.Calendar     */@Testpublic void testCalendarAPI() {        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");        Calendar cal = Calendar.getInstance();        System.out.println("当前日历时间:" + simpleDateFormat.format(cal.getTime()));//年        System.out.println("年:" + cal.get(Calendar.YEAR));//月:month从0开始        System.out.println("月(month从0开始):" + cal.get(Calendar.MONTH));//日        System.out.println("日:" + cal.get(Calendar.DATE));//设置年、月、日、时、分、秒        cal.set(2020, 10, 1, 8, 0, 0);        System.out.println("设置后的时间:" + simpleDateFormat.format(cal.getTime()));//年份+1        cal.add(Calendar.YEAR, 1);        System.out.println("将年份+1:" + simpleDateFormat.format(cal.getTime()));    }

运行结果:

当前日历时间:2020-09-03当前日历时间的毫秒数:1599103912759年:2020月(month从0开始):8日:3设置后的时间:2020-11-01将年份+1:2021-11-01

3 SimpleDateFormat

SimpleDateFormat是常用的日期格式化类,将日期字符串解析成Date实例,或者Date格式化为某种模式的字符串。

3.1 SimpleDateFormat 常用API

  • SimpleDateFormat(String pattern) // 构造器,入参是时间字符串对应的模式 pattern

  • String format(Date date) // 把给定的 date 按照 pattern 指定的模式,格式化为字符串

  • Date parse(String source) // 把给定的日期字符串 source 解析成Date实例

SimpleDateFormat定义 pattern 时,各个字母分别对应的含义

Date and Time Pattern:pattern定义的样例
Result:pattern 对应时间字符串的样式

3.2 SimpleDateFormat 简单使用

    /**     * 测试 SimpleDateFormat     */@Testpublic void testSimpleDateFormatAPI() throws ParseException {//定义时间字符串的pattern        String pattern = "yyyy-MM-dd HH:mm:ss";        SimpleDateFormat format = new SimpleDateFormat(pattern);

//把字符串解析为Date        Date date = format.parse("2020-09-03 12:30:29");        System.out.println("String to Date:"+date);

//打印 Date 的时间字符串        Date now = new Date();        System.out.println("Date to String:"+format.format(now));    }

运行结果:

String to Date:Thu Sep 03 12:30:29 CST 2020Date to String:2020-09-03 12:57:16

4 Date、Calendar、SimpleDateFormat不足

  • Calendar的month从0开始计算,开发者很容易忽略;

  • Date 和 Calendar 所提供用于操作时间和日期的API太少了,运算比较麻烦,比如求当前日期的下周六;

  • SimpleDateFormate 也是线程不安全的。

4.1 演示 SimpleDateFormate 线程不安全

/**     * 演示SimpleDateFormat类线程不安全     */@Testpublic void testSimpleDateFormatUnSafe() throws InterruptedException {// 闭锁:主线程等待所有子线程运行完后,再继续往下运行// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍        CountDownLatch latch = new CountDownLatch(5);

//定义时间字符串的pattern        String pattern = "yyyy-MM-dd HH:mm:ss";        SimpleDateFormat format = new SimpleDateFormat(pattern);

for (int i = 1; i <= 5; i++) {int millis = i * 1000;new Thread(() -> {                Date date = new Date(millis);                String strDateTime = format.format(date);                System.out.println("当前线程" + Thread.currentThread().getName() + " 对应的时间字符串:" + strDateTime);// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍                latch.countDown();//闭锁数值减一            }).start();        }// 主线程阻塞,等待所有子线程运行完后,再继续往下运行// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍        latch.await();    }

因为 SimpleDateFormat 线程不安全,运行结果:

当前线程Thread-0 对应的时间字符串:1970-01-01 08:00:03当前线程Thread-1 对应的时间字符串:1970-01-01 08:00:03当前线程Thread-3 对应的时间字符串:1970-01-01 08:00:03当前线程Thread-4 对应的时间字符串:1970-01-01 08:00:03当前线程Thread-2 对应的时间字符串:1970-01-01 08:00:03

线程安全的话,正确的结果应该是:

当前线程Thread-2 对应的时间字符串:1970-01-01 08:00:03当前线程Thread-4 对应的时间字符串:1970-01-01 08:00:05当前线程Thread-0 对应的时间字符串:1970-01-01 08:00:01当前线程Thread-1 对应的时间字符串:1970-01-01 08:00:02当前线程Thread-3 对应的时间字符串:1970-01-01 08:00:04

5 Java8 提供新时间日期API

5.1 时间日期相关API:

LocalDate、LocalTime、LocalDateTime、Instant 的实例,都是不可变的对象,就算进行一些时间调整操作,如 plus/minus操作,返回的实例都是一个新的对象。
所以这些类的操作都是线程安全的

LocalDate、LocalDateTime 获取月份返回的是 Month 的枚举,通过 Month 枚举的getValue 返回 1-12 的数值表示 1-12 月份。

  • LocalDate //日期类,不包含时间

  • LocalTime //时间类,不包含日期

  • LocalDateTime // 日期时间类,包含日期和时间

  • Instant // 某个时间点,可以获取到毫秒数,能够与 LocalDateTime 相互转换

5.2 两个时间或日期之差

  • Duration // 两个时间 Instance 之间的间隔

  • Period // 两个日期之间的间隔

5.3 日期操作类

  • TemporalAdjuster // 调整时间或日期,如:调整到这个月的第一个星期一,调整后生成一个新的时间或日期实例

  • TemporalAdjusters //好多静态方法,用于提供常用的 TemporalAdjuster 实例

5.4 日期或时间解析和格式化

  • DateTimeFormatter // 线程安全的日期或时间解析和格式化

5.5 时区

  • ZonedDateTime // 带时区的日期时间

  • ZoneId // 时区对应的ID,格式为:{区域}/{城市},如:Asia/Shanghai

下面,我们对上门的类详细介绍。

6 LocalDate 日期类

LocalDate 方法 用途
static LocalDate now()
static LocalDate of(int year, int month, int dayOfMonth)
从默认时区的系统时钟获取当前日期。
从给定的年、月和日获取LocalDate的实例。
static LocalDate parse(CharSequence text, DateTimeFormatter formatter) 通过给定的字符串和 DateTimeFormatter 解析成 LocalDate
LocalDateTime atTime(int hour, int minute, int second) 这将返回一个 LocalDateTime ,日期为当前日期,时间为指定的小时、分钟和秒
long getLong(TemporalField field) 返回指定字段的值,
TemporalField接口的实现类 ChronoField 是个枚举类,定义了很多常用的时间字段TemporalField,LocalDate 中只能使用:,
DAY_OF_WEEK ,
ALIGNED_DAY_OF_WEEK_IN_MONTH,
ALIGNED_DAY_OF_WEEK_IN_YEAR,
DAY_OF_MONTH,
DAY_OF_YEAR,
EPOCH_DAY,
ALIGNED_WEEK_OF_MONTH,
ALIGNED_WEEK_OF_YEAR,
MONTH_OF_YEAR,
PROLEPTIC_MONTH,
YEAR_OF_ERA,
YEAR,
ERA
int getDayOfMonth()
DayOfWeek getDayOfWeek()
int getDayOfYear()
返回月份中第几天
返回 DayOfWeek 枚举,表示周几
返回年份中第几天
Month getMonth()
int getMonthValue()
返回 Month 枚举,表示月份
返回月份对应的数值 1-12
int getYear() 返回年份
LocalDate minusDays(long daysToSubtract)
LocalDate minusMonths(long monthsToSubtract)
LocalDate minusWeeks(long weeksToSubtract)
LocalDate minusYears(long yearsToSubtract)
当前日期减去多少天,返回新的LocalDate实例
当前日期减去多少月,返回新的LocalDate实例
当前日期减去多少周,返回新的LocalDate实例
当前日期减去多少年,返回新的LocalDate实例
LocalDate plusDays(long daysToAdd)
LocalDate plusMonths(long monthsToAdd)
LocalDate plusWeeks(long weeksToAdd)
LocalDate plusYears(long yearsToAdd)
当前日期加上多少天,返回新的LocalDate实例
当前日期加上多少月,返回新的LocalDate实例
当前日期加上多少周,返回新的LocalDate实例
当前日期加上多少年,返回新的LocalDate实例
LocalDate withDayOfMonth(int dayOfMonth)
LocalDate withDayOfYear(int dayOfYear)
LocalDate withMonth(int month)
LocalDate withYear(int year)
调整月份中的天,返回新的LocalDate实例
调整年份中的年,返回新的LocalDate实例
调整日期中的月份,返回新的LocalDate实例
调整日期中的年份,返回新的LocalDate实例
boolean isLeapYear() 如果年份是闰年,则为true,否则为false
boolean isAfter(ChronoLocalDate other) 如果晚于给定的日期,则为true,否则为false
boolean isBefore(ChronoLocalDate other) 如果早于给定的日期,则为true,否则为false

6.1 LocalDate 简单使用

/**     * 测试 LocalDate     */@Testpublic void testLocalDate() {// 从给定的年、月和日获取LocalDate的实例。        LocalDate ldOf = LocalDate.of(2020,9,3);        System.out.println("从给定的年、月和日获取LocalDate的实例: "+ldOf);// 从默认时区的系统时钟获取当前日期        LocalDate ldNow = LocalDate.now();        System.out.println("从默认时区的系统时钟获取当前日期: "+ldNow);// 返回一个 LocalDateTime ,日期为当前日期,时间为指定的小时、分钟和秒        LocalDateTime localDateTime = ldNow.atTime(1, 2, 30);        System.out.println("返回一个 LocalDateTime日期为当前日期,时间为指定的小时、分钟和秒:" + localDateTime);

// 返回月份中第几天        System.out.println("返回月份中第几天: "+ldNow.getDayOfMonth());// 返回 DayOfWeek 枚举,表示周几        System.out.println("返回 DayOfWeek 枚举,表示周几: "+ldNow.getDayOfWeek());// 返回年份中第几天        System.out.println("返回年份中第几天: "+ldNow.getDayOfYear());

// 返回 Month 枚举,表示月份        System.out.println("返回 Month 枚举,表示月份: " + ldNow.getMonth());// 返回月份对应的数值 1-12        System.out.println("返回月份对应的数值 1-12 : " + ldNow.getMonthValue());

// 当前日期减去多少天,返回新的LocalDate实例        System.out.println("当前日期减去5天,返回新的LocalDate实例: " + ldNow.minusDays(5));

// 当前日期减去多少月,返回新的LocalDate实例        System.out.println("当前日期减去1月,返回新的LocalDate实例: " + ldNow.minusMonths(1));

// 当前日期加上多少周,返回新的LocalDate实例        System.out.println("当前日期加上1周,返回新的LocalDate实例: " + ldNow.plusWeeks(1));// 当前日期加上多少年,返回新的LocalDate实例        System.out.println("当前日期加上2年,返回新的LocalDate实例: " + ldNow.plusYears(2));

// 如果年份是闰年,则为true,否则为false        System.out.println("今年是否是闰年?" + ldNow.isLeapYear());

// 如果早于给定的日期,则为true,否则为false        System.out.println("当前日期是否早于2020-9-3?" + ldNow.isBefore(ldOf));// 如果晚于给定的日期,则为true,否则为false        System.out.println("当前日期是否晚于2020-9-3?" + ldNow.isAfter(ldOf));    }

运行结果:

从给定的年、月和日获取LocalDate的实例: 2020-09-03从默认时区的系统时钟获取当前日期: 2020-09-04返回一个 LocalDateTime日期为当前日期,时间为指定的小时、分钟和秒:2020-09-04T01:02:30返回月份中第几天: 4返回 DayOfWeek 枚举,表示周几: FRIDAY返回年份中第几天: 248返回 Month 枚举,表示月份: SEPTEMBER返回月份对应的数值 1-12 : 9当前日期减去5天,返回新的LocalDate实例: 2020-08-30当前日期减去1月,返回新的LocalDate实例: 2020-08-04当前日期加上1周,返回新的LocalDate实例: 2020-09-11当前日期加上2年,返回新的LocalDate实例: 2022-09-04今年是否是闰年?true当前日期是否早于2020-9-3?false当前日期是否晚于2020-9-3?true

7 LocalTime 时间类

因为篇幅问题,只列出常用的API。

LocalTime 方法 用途
static LocalTime now()
static LocalTime of(int hour, int minute, int second)
static LocalTime of(int hour, int minute, int second, int nanoOfSecond)
从默认时区的系统时钟获取当前时间。
从给定的hour, minute 和 second获取LocalTime的实例。
从给定的hour, minute, second 和 nanosecond(纳秒)获取LocalTime的实例。
static LocalTime parse(CharSequence text, DateTimeFormatter formatter) 通过给定的字符串和 DateTimeFormatter 解析成 LocalTime
LocalDateTime atDate(LocalDate date) 这将返回一个 LocalDateTime ,日期为给定的LocalDate,时间为指定的当前时间
long getLong(TemporalField field) 返回指定字段的值,
TemporalField接口的实现类 ChronoField 是个枚举类,定义了很多常用的时间字段TemporalField,LocalTime 中只能使用:
NANO_OF_SECOND,
NANO_OF_DAY,
MICRO_OF_SECOND,
MICRO_OF_DAY,
MILLI_OF_SECOND,
MILLI_OF_DAY,
SECOND_OF_MINUTE,
SECOND_OF_DAY,
MINUTE_OF_HOUR,
MINUTE_OF_DAY,
HOUR_OF_AMPM,
CLOCK_HOUR_OF_AMPM,
HOUR_OF_DAY, hour,
CLOCK_HOUR_OF_DAY,
AMPM_OF_DAY
int getHour()
int getMinute()
int getSecond()
getNano()
返回小时
返回分钟
返回秒
返回纳秒
LocalTime minusHours(long hoursToSubtract)
LocalTime minusMinutes(long minutesToSubtract)
LocalTime minusSeconds(longsecondsToSubtract)
LocalTime minusNanos(long nanosToSubtract)
当前时间减去多少小时,返回新的LocalTime实例
当前时间减去多少分钟,返回新的LocalTime实例
当前时间减去多少秒,返回新的LocalTime实例
当前时间减去多少纳秒,返回新的LocalTime实例
LocalTime plusHours(long hoursToAdd)
LocalTime plusMinutes(long minutesToAdd)
LocalTime plusSeconds(long secondstoAdd)
LocalTime plusNanos(long nanosToAdd)
当前时间加上多少小时,返回新的LocalTime实例
当前时间加上多少分钟,返回新的LocalTime实例
当前时间加上多少秒,返回新的LocalTime实例
当前时间加上多少纳秒,返回新的LocalTime实例
LocalTime withHour(int hour)
LocalTime withMinute(int minute)
LocalTime withSecond(int second)
LocalTime withNano(int nanoOfSecond)
调整小时,返回新的LocalTime实例
调整分钟,返回新的LocalTime实例
跳整秒数,返回新的LocalTime实例
调整纳秒,返回新的LocalTime实例
boolean isAfter(LocalTime other) 如果晚于给定的时间,则为true,否则为false
boolean isBefore(LocalTime other) 如果早于给定的时间,则为true,否则为false

7.1 LocalTime的简单使用

    /**     * 测试 LocalTime     */@Testpublic void testLocalTime() {// 从给定的hour, minute 和 second获取LocalTime的实例。        LocalTime ltOf = LocalTime.of(1,5,23);        System.out.println("从给定的hour, minute 和 second获取LocalTime的实例: "+ltOf);// 从默认时区的系统时钟获取当前时间        LocalTime ltNow = LocalTime.now();        System.out.println("从默认时区的系统时钟获取当前时间: "+ltNow);// 这将返回一个 LocalDateTime ,日期为给定的LocalDate,时间为指定的当前时间        LocalDateTime localDateTime = ltNow.atDate(LocalDate.now());        System.out.println("这将返回一个 LocalDateTime ,日期为今天(2020-09-04),时间为指定的当前时间:" + localDateTime);

// 返回小时        System.out.println("返回小时: "+ltNow.getHour());// 返回分钟        System.out.println("返回分钟: "+ltNow.getMinute());// 返回秒        System.out.println("返回秒: "+ltNow.getSecond());

// 返回纳秒        System.out.println("返回纳秒: " + ltNow.getNano());

// 当前时间减去多少小时,返回新的LocalTime实例        System.out.println("当前时间减去1小时,返回新的LocalTime实例: " + ltNow.minusHours(1));

// 当前时间减去多少分钟,返回新的LocalTime实例        System.out.println("当前时间减去20分钟,返回新的LocalTime实例: " + ltNow.minusMinutes(20));

// 当前时间减去多少秒,返回新的LocalTime实例        System.out.println("当前时间加上10秒,返回新的LocalTime实例: " + ltNow.plusSeconds(10));// 当前时间减去多少纳秒,返回新的LocalTime实例        System.out.println("当前时间加上999纳秒,返回新的LocalTime实例: " + ltNow.plusNanos(999));

// 调整小时,返回新的LocalTime实例        System.out.println("调整小时到3时,返回新的LocalTime实例:" + ltNow.withHour(3));    }

运行结果:

从给定的hour, minute 和 second获取LocalTime的实例: 01:05:23从默认时区的系统时钟获取当前时间: 01:24:16.666这将返回一个 LocalDateTime ,日期为今天(2020-09-04),时间为指定的当前时间:2020-09-04T01:24:16.666返回小时: 1返回分钟: 24返回秒: 16返回纳秒: 666000000当前时间减去1小时,返回新的LocalTime实例: 00:24:16.666当前时间减去20分钟,返回新的LocalTime实例: 01:04:16.666当前时间加上10秒,返回新的LocalTime实例: 01:24:26.666当前时间加上999纳秒,返回新的LocalTime实例: 01:24:16.666000999调整小时到3时,返回新的LocalTime实例:03:24:16.666

8 LocalDateTime 时间日期类

LocalDateTime 表示日期时间,可以理解为包含了 LocalDate 和 LocalTime。

LocalDateTime中的API 与 LocalDate 和 LocalTime的相似,同样包含 :

  • now(),

  • ofXX(xx),

  • minusXX(xx),

  • plusXX(xx),

  • withXX(xx)方法,

  • isAfter(xx),

  • isBefore(xx)

  • static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) // 解析时间字符串成LocalDateTime

  • long getLong(TemporalField field) // 返回指定字段的值

8.1 LocalDateTime简单使用

/**     * 测试 LocalDateTime     */@Testpublic void testLocalDateTime() {// 从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例。        LocalDateTime ldtOf = LocalDateTime.of(2020, 9, 3, 1, 5, 23);        System.out.println("从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例: " + ldtOf);// 从默认时区的系统时钟获取当前日期时间 LocalDateTime        LocalDateTime ldtNow = LocalDateTime.now();        System.out.println("从默认时区的系统时钟获取当前日期时间 LocalDateTime: " + ldtNow);// 这将返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区        ZonedDateTime zonedDateTime = ldtNow.atZone(ZoneId.systemDefault());        System.out.println("返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区:" + zonedDateTime);// 通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例        ZonedDateTime shZonedDateTime = ldtNow.atZone(ZoneId.of("Asia/Shanghai"));        System.out.println("通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例:" + shZonedDateTime);

//返回周几long dayOfWeek = ldtNow.getLong(ChronoField.DAY_OF_WEEK);        System.out.println("返回周几:" + dayOfWeek);

//日期在天中的毫秒数long milliOfDay = ldtNow.getLong(ChronoField.MILLI_OF_DAY);        System.out.println("日期在天中的毫秒数:" + milliOfDay);        LocalDateTime endExclusive = ldtNow.withHour(0).withMinute(0).withSecond(0).withNano(0);        System.out.println("日期在天中的毫秒数 Duration:" + Duration.between(endExclusive, ldtNow).toMillis());

//当前日期是年份中的第几天long dayOfYear = ldtNow.getLong(ChronoField.DAY_OF_YEAR);        System.out.println("getLong(TemporalField field)方式获取当前日期是年份中的第几天:" + dayOfYear);

// 返回月份中第几天        System.out.println("返回月份中第几天: " + ldtNow.getDayOfMonth());// 返回 DayOfWeek 枚举,表示周几        System.out.println("返回 DayOfWeek 枚举,表示周几: " + ldtNow.getDayOfWeek());// 返回年份中第几天        System.out.println("返回年份中第几天: " + ldtNow.getDayOfYear());

// 返回 Month 枚举,表示月份        System.out.println("返回 Month 枚举,表示月份: " + ldtNow.getMonth());// 返回月份对应的数值 1-12        System.out.println("返回月份对应的数值 1-12 : " + ldtNow.getMonthValue());

// 返回小时        System.out.println("返回小时: " + ldtNow.getHour());// 返回分钟        System.out.println("返回分钟: " + ldtNow.getMinute());// 返回秒        System.out.println("返回秒: " + ldtNow.getSecond());// 返回纳秒        System.out.println("返回纳秒: " + ldtNow.getNano());

// 当前日期减去多少天,返回新的LocalDateTime实例        System.out.println("当前日期减去5天,返回新的LocalDateTime实例: " + ldtNow.minusDays(5));

// 当前日期减去多少月,返回新的LocalDateTime实例        System.out.println("当前日期减去1月,返回新的LocalDateTime实例: " + ldtNow.minusMonths(1));

// 当前日期加上多少周,返回新的LocalDateTime实例        System.out.println("当前日期加上1周,返回新的LocalDateTime实例: " + ldtNow.plusWeeks(1));// 当前日期加上多少年,返回新的LocalDateTime实例        System.out.println("当前日期加上2年,返回新的LocalDateTime实例: " + ldtNow.plusYears(2));

// 当前日期时间减去多少小时,返回新的LocalDateTime实例        System.out.println("当前日期时间减去1小时,返回新的LocalDateTime实例: " + ldtNow.minusHours(1));

// 当前日期时间减去多少分钟,返回新的LocalDateTime实例        System.out.println("当前日期时间减去20分钟,返回新的LocalDateTime实例: " + ldtNow.minusMinutes(20));

// 当前日期时间减去多少秒,返回新的LocalDateTime实例        System.out.println("当前日期时间加上10秒,返回新的LocalDateTime实例: " + ldtNow.plusSeconds(10));// 当前日期时间减去多少纳秒,返回新的LocalDateTime实例        System.out.println("当前日期时间加上999纳秒,返回新的LocalDateTime实例: " + ldtNow.plusNanos(999));

// 如果早于给定的日期,则为true,否则为false        System.out.println("当前日期是否早于2020-9-3?" + ldtNow.isBefore(ldtOf));// 如果晚于给定的日期,则为true,否则为false        System.out.println("当前日期是否晚于2020-9-3?" + ldtNow.isAfter(ldtOf));// 调整小时,返回新的LocalDateTime实例        System.out.println("调整月份到8月,返回新的LocalDateTime实例:" + ldtNow.withMonth(8));

// with(TemporalAdjuster adjuster) 通过TemporalAdjuster去调整到对应的时间点,返回新的Instant实例//  调整当前日期到下个月第一天        LocalDateTime firstDayOfNextMonth = ldtNow.with(TemporalAdjusters.firstDayOfNextMonth());        System.out.println("通过TemporalAdjuster去调整到到下个月第一天:" + firstDayOfNextMonth);

// LocalDateTime 转为 LocalDate        LocalDate localDate = ldtNow.toLocalDate();        System.out.println("LocalDateTime 转为 LocalDate: " + localDate);

// LocalDateTime 转为 LocalTime        LocalTime localTime = ldtNow.toLocalTime();        System.out.println("LocalDateTime 转为 LocalTime: " + localTime);

// LocalDateTime 转为 Instant        Instant instant = ldtNow.atZone(ZoneId.systemDefault()).toInstant();// instant打印的是格林威治时间,会小8小时,但是毫秒数(时间戳)和当前时区的毫秒数是一样的        System.out.println("LocalDateTime 转为 Instant: " + instant);    }

运行结果:

从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例: 2020-09-03T01:05:23从默认时区的系统时钟获取当前日期时间 LocalDateTime: 2020-09-04T14:10:08.476返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区:2020-09-04T14:10:08.476+08:00[Asia/Shanghai]通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例:2020-09-04T14:10:08.476+08:00[Asia/Shanghai]返回周几:5日期在天中的毫秒数:51008476日期在天中的毫秒数 Duration:51008476getLong(TemporalField field)方式获取当前日期是年份中的第几天:248返回月份中第几天: 4返回 DayOfWeek 枚举,表示周几: FRIDAY返回年份中第几天: 248返回 Month 枚举,表示月份: SEPTEMBER返回月份对应的数值 1-12 : 9返回小时: 14返回分钟: 10返回秒: 8返回纳秒: 476000000当前日期减去5天,返回新的LocalDateTime实例: 2020-08-30T14:10:08.476当前日期减去1月,返回新的LocalDateTime实例: 2020-08-04T14:10:08.476当前日期加上1周,返回新的LocalDateTime实例: 2020-09-11T14:10:08.476当前日期加上2年,返回新的LocalDateTime实例: 2022-09-04T14:10:08.476当前日期时间减去1小时,返回新的LocalDateTime实例: 2020-09-04T13:10:08.476当前日期时间减去20分钟,返回新的LocalDateTime实例: 2020-09-04T13:50:08.476当前日期时间加上10秒,返回新的LocalDateTime实例: 2020-09-04T14:10:18.476当前日期时间加上999纳秒,返回新的LocalDateTime实例: 2020-09-04T14:10:08.476000999当前日期是否早于2020-9-3?false当前日期是否晚于2020-9-3?true调整月份到8月,返回新的LocalDateTime实例:2020-08-04T14:10:08.476通过TemporalAdjuster去调整到到下个月第一天:2020-10-01T14:10:08.476LocalDateTime 转为 LocalDate: 2020-09-04LocalDateTime 转为 LocalTime: 14:10:08.476LocalDateTime 转为 Instant: 2020-09-04T06:10:08.476Z

9 Instant 某个时间点

Instant 某个时间点,可以获取到毫秒数,能够与 LocalDateTime 相互转换

Instant 方法 用途
static Instant now() 返回当前时间对应的 Instant 实例
static Instant ofEpochMilli(long epochMilli) 通过给定的毫秒数(milliseconds from 1970-01-01T00:00:00Z),返回 Instant 实例
ZonedDateTime atZone(ZoneId zone) 将当前 Instant 和给定的时区ID ZoneId 结合返回 ZonedDateTime
int get(TemporalField field) 返回指定字段的值,
TemporalField接口的实现类 ChronoField 是个枚举类,定义了很多常用的时间字段TemporalField,Instant中只能使用:
NANO_OF_SECOND,
MICRO_OF_SECOND,
MILLI_OF_SECOND,
INSTANT_SECOND,
举例解释常用字段的作用:
MILLI_OF_SECOND: 秒内的毫秒数,从0到999
INSTANT_SECONDS: 1970-01-01T00:00Z(ISO)开始到当前Instant实例的秒数
boolean isAfter(Instant otherInstant) 如果当前 Instant 晚于给定的Instant,则为true,否则为false
boolean isBefore(Instant otherInstant) 如果当前 Instant 早于给定的Instant,则为true,否则为false
Instant minus(long amountToSubtract, TemporalUnit unit) 减去给定的时间量,返回新的Instant实例
Instant plus(long amountToAdd, TemporalUnit unit) 增加给定的时间量,返回新的Instant实例
Instant with(TemporalField field, long newValue) 调整给定时间属性的值 ,返回新的Instant实例
Instant with(TemporalAdjuster adjuster) 通过TemporalAdjuster去调整到对应的时间点,返回新的Instant实例
long toEpochMilli() 返回当前时间点对应的毫秒数,也就是时间戳

9.1 Instant 简单使用

   /**     * 测试 Instant     * 注意:Instant.toString() 调用的是 DateTimeFormatter.ISO_INSTANT.format(this)     *       instant打印的是格林威治时间,会小8小时,但是毫秒数(时间戳)和当前时区的毫秒数是一样的     */@Testpublic void testInstant() {// 返回当前时间对应的 Instant 实例        Instant instantNow = Instant.now();        System.out.println("返回当前时间对应的 Instant 实例: " + instantNow);// 这将返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区        ZonedDateTime zonedDateTime = instantNow.atZone(ZoneId.systemDefault());        System.out.println("返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区:" + zonedDateTime);// 通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例        ZonedDateTime shZonedDateTime = instantNow.atZone(ZoneId.of("Asia/Shanghai"));        System.out.println("通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例:" + shZonedDateTime);

//秒内的毫秒数,从0到999long milliOfSecond = instantNow.getLong(ChronoField.MILLI_OF_SECOND);        System.out.println("秒内的毫秒数,从0到999:" + milliOfSecond);

//1970-01-01T00:00Z(ISO)开始到当前Instant实例的秒数long instantSeconds = instantNow.getLong(ChronoField.INSTANT_SECONDS);        System.out.println("1970-01-01T00:00Z(ISO)开始到当前Instant实例的秒数:" + instantSeconds);

//1970-01-01T00:00Z(ISO)开始到当前Instant实例的毫秒数long milli = instantNow.toEpochMilli();        System.out.println("开始到当前Instant实例的毫秒数:" + milli);

// 当前日期减去多少天,返回新的Instant实例        System.out.println("当前日期减去5天,返回新的Instant实例: " + instantNow.minus(5, ChronoUnit.DAYS));

// 当前日期减去1小时        System.out.println("当前日期减去1小时,返回新的Instant实例: " + instantNow.minus(1, ChronoUnit.HOURS));

// 当前日期时间减去多少秒,返回新的Instant实例        System.out.println("当前日期时间加上10秒,返回新的Instant实例: " + instantNow.plusSeconds(10));// 当前日期时间减去多少纳秒,返回新的Instant实例        System.out.println("当前日期时间加上999纳秒,返回新的Instant实例: " + instantNow.plusNanos(999));

// 2020-9-3 对应的 Instant        Instant otherInstant = LocalDateTime.of(2020, 9, 3, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant();// 如果早于给定的日期,则为true,否则为false        System.out.println("当前日期是否早于2020-9-3?" + instantNow.isBefore(otherInstant));// 如果晚于给定的日期,则为true,否则为false        System.out.println("当前日期是否晚于2020-9-3?" + instantNow.isAfter(otherInstant));

// with(ChronoField.INSTANT_SECONDS, 0)):设置1970-01-01T00:00Z(ISO)开始到当前Instant实例的秒数// 也就是调整到 1970-01-01T00:00Z(ISO)        System.out.println("调整到 1970-01-01T00:00Z(ISO):" + instantNow.with(ChronoField.INSTANT_SECONDS, 0).with(ChronoField.NANO_OF_SECOND,0));

// Instant 转为 LocalDateTime        LocalDateTime localDateTime = LocalDateTime.ofInstant(instantNow, ZoneId.systemDefault());        System.out.println("Instant 转为 LocalDateTime: "+localDateTime);

    }

运行结果:

返回当前时间对应的 Instant 实例: 2020-09-04T06:06:10.851Z返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区:2020-09-04T14:06:10.851+08:00[Asia/Shanghai]通过给定 Asia/Shanghai 时区,返回 ZonedDateTime 实例:2020-09-04T14:06:10.851+08:00[Asia/Shanghai]秒内的毫秒数,从0到999:8511970-01-01T00:00Z(ISO)开始到当前Instant实例的秒数:1599199570开始到当前Instant实例的毫秒数:1599199570851当前日期减去5天,返回新的Instant实例: 2020-08-30T06:06:10.851Z当前日期减去1小时,返回新的Instant实例: 2020-09-04T05:06:10.851Z当前日期时间加上10秒,返回新的Instant实例: 2020-09-04T06:06:20.851Z当前日期时间加上999纳秒,返回新的Instant实例: 2020-09-04T06:06:10.851000999Z当前日期是否早于2020-9-3?false当前日期是否晚于2020-9-3?true调整到 1970-01-01T00:00Z(ISO):1970-01-01T00:00:00ZInstant 转为 LocalDateTime: 2020-09-04T14:06:10.851

10 Duration 时间间隔

Duration:时间间隔,表示两个时间点之间的时间间隔长度。

Duration 方法 用途
static Duration between(Temporal startInclusive, Temporal endExclusive) 返回两个时间点之间的间隔Duration。
参数可以是:LocalTime、LocalDateTime、Instant
注意:LocalDate不可以作为入参
static Instant ofEpochMilli(long epochMilli) 通过给定的毫秒数(milliseconds from 1970-01-01T00:00:00Z),返回 Instant 实例
of(long amount, TemporalUnit unit)
static Duration ofDays(long days)
static Duration ofHours(long hours)
static Duration ofMinutes(long minutes)
static Duration ofSeconds(long seconds)
static Duration ofSeconds(long seconds)
通过给定时间单位 TemporalUnit 的时间长度 amount,返回Duration实例
Duration minus(long amountToSubtract, TemporalUnit unit) 减去给定的时间量,返回新的Duration实例
Duration plus(long amountToAdd, TemporalUnit unit) 增加给定的时间量,返回新的Duration实例
long toDays()
long toHours()
long toMinutes()
long toMillis()
Duration 时间长度转为 天数/小时数/分钟数/毫秒数

10.1 Duration 简单使用

    /**     * 测试 Duration     */@Testpublic void testDuration() {// 从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例。        LocalDateTime ldtOf = LocalDateTime.of(2020, 9, 4, 10, 0, 0);        System.out.println("从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例: " + ldtOf);// 从默认时区的系统时钟获取当前日期时间 LocalDateTime        LocalDateTime ldtNow = LocalDateTime.now();        System.out.println("从默认时区的系统时钟获取当前日期时间 LocalDateTime: " + ldtNow);

// 返回两个时间点之间的间隔Duration//        参数可以是:LocalTime、LocalDateTime、Instant//        注意:LocalDate不可以作为入参        Duration duration = Duration.between(ldtOf, ldtNow);// 打印 Duration 时间长度转为 天数/小时数/分钟数/毫秒数        System.out.println("Duration 时间间隔天数:" + duration.toDays());        System.out.println("Duration 时间间隔小时数:" + duration.toHours());        System.out.println("Duration 时间间隔分钟数:" + duration.toMinutes());        System.out.println("Duration 时间间隔毫秒数:" + duration.toMillis());    }

运行结果:

从给定的year, month, day, hour, minute 和 second 获取LocalDateTime的实例: 2020-09-04T10:00从默认时区的系统时钟获取当前日期时间 LocalDateTime: 2020-09-04T14:24:22.692Duration 时间间隔天数:0Duration 时间间隔小时数:4Duration 时间间隔分钟数:264Duration 时间间隔毫秒数:15862692

11 Period 日期间隔

Period 方法 用途
static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) 返回两个日期之间的间隔 Period,入参是:LocalDate 类型
static Period of(int years, int months, int days) 通过给定的 years, months 和 days 生成Period
Period minusDays(long daysToSubtract)
Period minusMonths(long monthsToSubtract)
Period minusYears(long yearsToSubtract)
period 实例中 days字段- daysToSubtract\ months字段-daysToSubtract\ years字段-yearsToSubtract
Period plusDays(long daysToAdd)
Period plusMonths(long monthsToAdd)
Period plusYears(long yearsToAdd)
period 实例中 days字段+ daysToSubtract\ months字段+daysToSubtract\ years字段+yearsToSubtract
long getDays()
int getMonths()
int getYears()
获 period 实例的 days/months/years 字段值,这里不是间隔的长度,只是字段值,看测试用例会更容易理解
Period withDays(int days)
Period withMonths(int months)
Period withYears(int years)
调整 Period中的 days,months,years 字段为给定值,返回新的 Period 实例
long toTotalMonths() 返回 Period 转换过来总的月数。
如:Period period = Period.of(1, 1, 1);
period.toTotalMonths() //13

11.1 Period 简单使用

    /**     * 测试 Period     */@Testpublic void testPeriod() {// 从给定的年、月和日获取LocalDate的实例。        LocalDate ldOf = LocalDate.of(2018, 9, 3);        System.out.println("从给定的年、月和日获取LocalDate的实例: " + ldOf);// 从默认时区的系统时钟获取当前日期        LocalDate ldNow = LocalDate.now();        System.out.println("从默认时区的系统时钟获取当前日期: " + ldNow);// 返回两个时间点之间的间隔Period//        参数类型是:LocalDate        Period period = Period.between(ldOf, ldNow);// 打印 Period 时间长度转为 天数/月数/年数        System.out.println("period 实例 days 字段值:" + period.getDays());        System.out.println("period 实例 months 字段值:" + period.getMonths());        System.out.println("period 实例 years 字段值:" + period.getYears());

// Period 日期间隔长度转换为总的月数        System.out.println("Period 日期间隔长度转换为总的月数:" + period.toTotalMonths());    }

运行结果:

从给定的年、月和日获取LocalDate的实例: 2018-09-03从默认时区的系统时钟获取当前日期: 2020-09-04period 实例 days 字段值:1period 实例 months 字段值:0period 实例 years 字段值:2Period 日期间隔长度转换为总的月数:24

12 日期操作类 TemporalAdjuster 和 TemporalAdjusters

前面介绍过:

  • TemporalAdjuster // 调整时间或日期,如:调整到这个月的第一个星期一,调整后生成一个新的时间或日期实例

  • TemporalAdjusters //好多静态方法,用于提供常用的 TemporalAdjuster

Instant、LocalDate、LocalTime、LocalDateTime 或者其他实现了 Temporal 接口的类中都有一个 with(TemporalAdjuster adjuster) 方法,入参为 TemporalAdjuster,也就是要进行的时间调整操作,返回新的时间日期实例。

TemporalAdjusters 提供了好多静态方法用于生成常用的 TemporalAdjuster 实例

TemporalAdjusters 静态方法 用途
static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) 调整返回新日期实例,调整到当前日期月份的第几个周几,ordinal表示第几个,DayOfWeek是枚举类,表示周几
static TemporalAdjuster firstDayOfMonth() 调整返回新日期实例,调整到当前日期当前月份第一天
static TemporalAdjuster firstDayOfNextMonth() 调整返回新日期实例,调整到当前日期下一月份的第一天
static TemporalAdjuster firstDayOfNextYear() 调整返回新日期实例,调整到当前日期下一年份的第一天
static TemporalAdjuster firstDayOfYear() 调整返回新日期实例,调整到当前日期当前年份的第一天
static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) 调整返回新日期实例,调整到当前日期当前月份的第一个周几
static TemporalAdjuster lastDayOfMonth() 调整返回新日期实例,调整到当前日期当前月份的最后一天
static TemporalAdjuster lastDayOfYear() 调整返回新日期实例,调整到当前日期当前年份的最后一天
static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) 调整返回新日期实例,调整到当前日期当前月份的最后一个周几
static TemporalAdjuster next(DayOfWeek dayOfWeek) 调整返回新日期实例,调整到下一个周几
static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) 如果当前日期刚好符合是入参指定周几(DayOfWeek),返回当前日期实例;否则调整到下一个周几,返回新日期实例
static TemporalAdjuster ofDateAdjuster(UnaryOperator dateBasedAdjuster) 通过函数式接口 UnaryOperator ,把当前日期实例作为抽象方法入参,进行日期操作后返回新的 LocalDate
static TemporalAdjuster previous(DayOfWeek dayOfWeek) 调整返回新日期实例,调整到前一个周几
static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) 如果当前日期刚好符合是入参指定周几(DayOfWeek),返回当前日期实例;否则调整到前一个周几,返回新日期实例

12.1 TemporalAdjusters简单使用

   /**     * 测试 TemporalAdjuster     */@Testpublic void testTemporalAdjuster() {// 从默认时区的系统时钟获取当前日期        LocalDate ldNow = LocalDate.now();        System.out.println("当前日期: " + ldNow);

// 调整到当前日期当前月份第一天        LocalDate firstDayOfMonth = ldNow.with(TemporalAdjusters.firstDayOfMonth());        System.out.println("当前月份第一天: " + firstDayOfMonth);// 当前日期刚好符合是入参指定周几(DayOfWeek),返回当前日期实例;否则调整到下一个周几,返回新日期实例        LocalDate nextOrSameFriday = ldNow.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY));        System.out.println("当前日期刚好符合是入参指定周五(DayOfWeek),返回当前日期实例: " + nextOrSameFriday);        LocalDate nextOrSameMonday = ldNow.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));        System.out.println("当前日期不符合是入参指定周一(DayOfWeek),调整到下一个周一,返回新日期实例: " + nextOrSameMonday);// 下一个周五        LocalDate nextFriday = ldNow.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));        System.out.println("下一个周五: " + nextFriday);// 当前月份的最后一天        LocalDate lastDayOfMonth = ldNow.with(TemporalAdjusters.lastDayOfMonth());        System.out.println("当前月份的最后一天: " + lastDayOfMonth);// 下一月份的第一天        LocalDate firstDayOfNextMonth = ldNow.with(TemporalAdjusters.firstDayOfNextMonth());        System.out.println("下一月份的第一天: " + firstDayOfNextMonth);

    }

运行结果:

当前日期: 2020-09-04当前月份第一天: 2020-09-01当前日期刚好符合是入参指定周五(DayOfWeek),返回当前日期实例: 2020-09-04当前日期不符合是入参指定周一(DayOfWeek),调整到下一个周一,返回新日期实例: 2020-09-07下一个周五: 2020-09-11当前月份的最后一天: 2020-09-30下一月份的第一天: 2020-10-01

13 DateTimeFormatter 日期或时间解析和格式化

DateTimeFormatter 用途
static DateTimeFormatter ofPattern(String pattern) 通过日期时间格式 pattern 构建一个 DateTimeFormatter
String format(TemporalAccessor temporal) 将 LocalTime、LocalDate、LocalDateTime 作为入参,格式化为日期时间字符串

LocalDate、LocalTime、LcoalDateTime中都有 static LocalDate/LocalTime/LcoalDateTime parse(CharSequence text, DateTimeFormatter formatter)方法,可以将时间字符串,解析为 LocalDate/LocalTime/LcoalDateTime 实例。

定义 Pattern 相关字母和符号的含义

13.1 DateTimeFormatter 简单使用

/**     * 测试 DateTimeFormatter     */@Testpublic void testDateTimeFormatter() {// 通过日期时间格式 pattern 构建一个 DateTimeFormatter        DateTimeFormatter ldtFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");        LocalDateTime ldt = LocalDateTime.now();        String strLdt = ldtFormat.format(ldt);// 格式化 LocalDateTime        System.out.println("format LocalDateTime : " + strLdt);        System.out.println("parse to LocalDateTime : " + LocalDateTime.parse("2020-10-01 08:00:06 666", ldtFormat));//解析为LocalDateTime

        DateTimeFormatter ldFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");        LocalDate ld = LocalDate.now();        String strLd = ldFormat.format(ld);// 格式化 LocalDateTime        System.out.println("format LocalDate : " + strLd);        System.out.println("parse to LocalDate : " + LocalDate.parse("2020-10-01", ldFormat));//解析为LocalDate

        DateTimeFormatter ltFormat = DateTimeFormatter.ofPattern("HH:mm:ss SSS");        LocalTime lt = LocalTime.now();        String strLt = ltFormat.format(lt);// 格式化 LocalDateTime        System.out.println("format LocalDate : " + strLt);        System.out.println("parse to LocalTime : " + LocalTime.parse("08:00:06 666", ltFormat));//解析为LocalTime

    }

运行结果:

format LocalDateTime : 2020-09-04 14:57:57 294parse to LocalDateTime : 2020-10-01T08:00:06.666format LocalDate : 2020-09-04parse to LocalDate : 2020-10-01format LocalDate : 14:57:57 294parse to LocalTime : 08:00:06.666

13.2 DateTimeFormatter 线程安全,解决 SimpleDateFormate 线程不安全问题

4.1小节已经演示了 SimpleDateFormate 线程不安全问题,但是 DateTimeFormatter 时线程安全的,看下面代码:

    /**     * 演示 DateTimeFormatter 类线程安全     */@Testpublic void testDateTimeFormatterSafe() throws InterruptedException {// 闭锁:主线程等待所有子线程运行完后,再继续往下运行// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍        CountDownLatch latch = new CountDownLatch(5);

//定义时间字符串的pattern        String pattern = "yyyy-MM-dd HH:mm:ss";        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

for (int i = 1; i <= 5; i++) {int seconds = i;new Thread(() -> {                LocalDateTime of = LocalDateTime.of(2020, 9, 3, 12, 14, 30);                of = of.plusSeconds(seconds);//每个线程分别增加传进来的秒数                String strDateTime = formatter.format(of);                System.out.println("当前线程" + Thread.currentThread().getName() + " 对应的时间字符串:" + strDateTime);// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍                latch.countDown();//闭锁数值减一            }).start();        }// 主线程阻塞,等待所有子线程运行完后,再继续往下运行// 不了解 CountDownLatch 可以忽略 CountDownLatch 的相关代码,后面会有系列文章介绍        latch.await();    }

运行结果:

当前线程Thread-0 对应的时间字符串:2020-09-03 12:14:31当前线程Thread-3 对应的时间字符串:2020-09-03 12:14:34当前线程Thread-1 对应的时间字符串:2020-09-03 12:14:32当前线程Thread-4 对应的时间字符串:2020-09-03 12:14:35当前线程Thread-2 对应的时间字符串:2020-09-03 12:14:33

14 时区 ZonedDateTime 和 ZoneId

  • ZonedDateTime // 带时区的日期时间

  • ZoneId // 时区对应的ID,格式为:{区域}/{城市},如:Asia/Shanghai

在 Instant 和 LocalDateTime 中有实例方法 ZonedDateTime atZone(ZoneId zone),返回一个带时区的日期时间实例 ZonedDateTime

ZoneId 中的两个常用方法:

  • getAvailableZoneIds() : 可以获取所有时区信息

  • of(id) : 用指定的时区信息获取ZoneId 对象

14.1 ZonedDateTime 和 ZoneId 简单使用

    /**     * 测试 时区     */@Testpublic void testZone() {        ZoneId systemDefaultZoneId = ZoneId.systemDefault();// 系统默认时区        ZoneId shZoneId = ZoneId.of("Asia/Shanghai");// 上海时区

        System.out.println("系统默认时区:" + systemDefaultZoneId);        System.out.println("上海时区:" + shZoneId);

        LocalDateTime ldt = LocalDateTime.now();// 这将返回一个带时区的日期时间实例 ZonedDateTime,入参是系统默认时区        ZonedDateTime zdtFromLdt = ldt.atZone(systemDefaultZoneId);        System.out.println(" ZonedDateTime from LocalDateTime:" + zdtFromLdt);

        Instant instant = Instant.now();// 这将返回一个带时区的日期时间实例 ZonedDateTime,入参是上海时区        ZonedDateTime zdtFromInstant = instant.atZone(shZoneId);        System.out.println(" ZonedDateTime from Instant In Asia/Shanghai :" + zdtFromInstant);

// 获取所有时时区信息        Set availableZoneIds = ZoneId.getAvailableZoneIds();// 打印所有时区信息        System.out.println("所有时区信息: ");        availableZoneIds.forEach(System.out::println);    }

运行结果:

系统默认时区:Asia/Shanghai上海时区:Asia/Shanghai ZonedDateTime from LocalDateTime:2020-09-04T15:11:04.685+08:00[Asia/Shanghai] ZonedDateTime from Instant In Asia/Shanghai :2020-09-04T15:11:04.685+08:00[Asia/Shanghai]所有时区信息:Asia/AdenAmerica/CuiabaEtc/GMT+9Etc/GMT+8Africa/NairobiAmerica/MarigotAsia/AqtauPacific/KwajaleinAmerica/El_SalvadorAsia/Pontianak...

15 结语

这篇文章写之前,Java8相关的时间日期API 在项目中经常使用到,以为写起来会很简单,但是真正整理思路时,才发现好多细节繁琐的事项。整理编辑思路,各个章节需要循序渐进,收集资料,看 Oracle 官网的 JAVA API docs,看源码进一步理解各个API 的使用,写DEMO,测试,开始编辑码字。

硬肝:3个深夜搞到1点半,3个早晨7点到8点半,3个中午 12点半到13点半。致敬自己!

这篇文章已经把实战中经常用到的大部分API进行介绍,还有一些特殊的API,有兴趣的朋友,可以看源码理解。

代码:
https://github.com/wengxingxia/001java8.git

[慕课手记同步:03-时间日期类] https://www.imooc.com/article/310260

提示:根据相关法律法规和平台规则要求,自2018年2月12日起,新注册的微信公众帐号无法再开通留言功能。
有问题或希望交流的朋友,可以到 [慕课手记同步:03-时间日期类] https://www.imooc.com/article/310260 下评论留言,一起学习进步。


欢迎关注公众号"黑桃"

date日期相减 java_03时间日期类相关推荐

  1. Vue3.0定时任务显示实时日期相减后时间,vue日期相减天数时分秒

    需求概述:就是两个日期相减,把得到的天时分秒显示在页面中并实时更新时间走动. 效果: 代码: <template><h2><span>世界上最甜的崽</spa ...

  2. oracle日期相减工作日_oracle 日期相减 转载

    转自 http://hi.baidu.com/juanjuan_66/blog/item/cf48554c9331fbe6d62afc6a.html oracle日期相减 2012-02-10 12: ...

  3. mysql时间相减得到天数保留两位_mysql 中两个日期相减获得 天 小时 分钟 或者 小时:分钟的格式...

    /**有一个需求,要求获得两个日期想减的天数,小时数,分钟数.通过查找资料,于是乎我写出了如下代码,来获得两个字段.*/ IFNULL(CONCAT( IF(aib.`forecast_reply_t ...

  4. mysql时间相减得到天数保留两位_[转]Mysql日期函数-日期相减返回天数

    MySQL datediff(date1,date2):两个日期相减 date1 - date2,返回天数. select datediff('2008-08-08', '2008-08-01'); ...

  5. C#.Net工作笔记008---c# 日期时间大小比较_日期相减

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 /// <summary>         /// 比较两个日期大小         ...

  6. oracle日期相减工作日_Oracle 计算两个日期间隔的天数、月数和年数

    在Oracle中计算两个日期间隔的天数.月数和年数: 一.天数: 在Oracle中,两个日期直接相减,便可以得到天数: select to_date('08/06/2015','mm/dd/yyyy' ...

  7. Excel 日期相减 DATEDIF 函数用法实例

    Excel 日期相减 DATEDIF 函数用法实例 如图所示 在C1列输入 =DATEDIF(A1,B1,"y")&"年"&DATEDIF(A1 ...

  8. mysql当前日期减去天数_mysql日期函数-日期相减返回天数

    一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+时间(date + time)函数:now() mysql> select now(); +-------------------- ...

  9. 日期相减计算年_函数 | Excel有个“秘密”函数,计算年龄工龄特方便

    工作中经常会遇到涉及日期间隔的计算问题,比如计算两个日期之间的天数.月数.年数,这时需要用到Excel中一个秘密函数. 说到"秘密",是因为你在微软Excel提供的的函数列表里是找 ...

最新文章

  1. 自适应高度Textarea
  2. webpack——解决当前 Web 开发面临的困境||webpack 概述
  3. php中 一行上显示多个数字,php – 打印图案以显示最多5行和5列的数字,如5 4 3 2 1和下一行4 3 2 1 5到第5行...
  4. 在华为云服务器的Linux系统中搭建开发环境
  5. Java技术:收集16 条 yyds 的代码规范,值得一读!
  6. 【Luogu3931】SAC E#1 - 一道难题 Tree
  7. 网络流专题(最大流与费用流)(一)
  8. MATLAB飞机大战第二版,windows程序设计——飞机大战札记(单文档文件登陆界面)...
  9. 前端学习(2425):复习
  10. Why Redis 4.0?
  11. 功夫小子实践开发-Menu家族学习及开始菜单场景的实现
  12. 【水果识别】基于matalb GUI水果分类系统【含Matlab源码 174期】
  13. 82、组合分配式气体灭火系统所需的气体单向阀的数量
  14. 纪念小企鹅──fcitx
  15. 小型电商平台的项目估算
  16. 我曾经遇见过一个我最想照顾一生的女孩,后来……没有后来
  17. 【kali Linux 的1024种玩法】一.在VMware Workstation上安装Kali Linux 2020.1(超详细!)
  18. adb 禁止app联网_通过ADB启用和禁用系统应用
  19. 使用 Redis 实现 Feed 流
  20. 公有链规模可扩展性的讨论 PPT

热门文章

  1. oracle split去逗号,行列转换 转载
  2. [转] 大规模服务设计部署经验谈
  3. Android系统广播大全
  4. MaxCompute5个窗口函数限制
  5. apache2.2.25+mod_jk-apache-2.2.2.so+apache-tomcat-7.0.56集群
  6. 今天有点时间,想写一个小说,说说面向对象的故事,主人是人类!(一)
  7. 虚拟化部署之灵活应用Hyper-V快照
  8. 浅谈网络游戏的设计——服务器端编程 (3)
  9. 面了个 32+ 岁 Java 大佬,一言难尽......
  10. 面试官:Spring AOP、AspectJ、CGLIB 都是什么鬼?它们有什么关系?