根据个人目前正在编写的《Java核心编程-基础篇》的规划,这部分属于第15章内容,这里沿用了书中的章节编号。另外,因为原文篇幅太长,这里适当做了删减。
15.1、概述
在 Java 8 之前,Java 语言表示时间的方法很简单,几乎都是采用毫秒值
来表示时间。
比如获得系统当前时间可以使用以下方法:
long now = System.currentTimeMillis();
System.out.println( now );
这里获取的毫秒值
是从 格里高利历 的 1970年1月1日 0点0分0秒0毫秒 至现在所经历的毫秒数。
即使是在 java.util.Date
类的实例 或 java.util.Calendar
类的实例中,也仍然是通过毫秒值
来表示时间。
因为 java.util.Date
类的实例 或 java.util.Calendar
类在设计上的缺陷,
从 Java 8 开始提供了一个全新的包 (java.time
) 来表示时区、日期、时间。
接下来我们将从 Date
和 Calendar
说起,来研究 时期、时间的表示方法 以及 日期格式化 等操作。
15.2、Date 类
Date
类的实例表示特定的瞬间( 精确到毫秒 )。
package java.util;
import java.io.Serializable ;
public class Date implements Serializable, Cloneable, Comparable {
}
Date
类实现了 Serializable
、Cloneable
、Comparable
等接口。
15.2.1、实例字段
Date
类中封装了一个 long
类型的字段,用来保存 Date
实例所表示的时间:
private transient long fastTime;
15.2.2、构造方法
目前还有两个未被废弃的构造方法:
public Date( long millis ) {
fastTime = millis ;
}
public Date() {
this( System.currentTimeMillis() );
}
举例:
import java.util.Date;
public class DateTest1 {
public static void main(String[] args) {
// 构造方法内部将 System.currentTimeMillis() 保存到 fastTime 字段中
Date date = new Date();
System.out.println( date ); // CST : China Standard Time
// 构造方法内部将 -1000L 保存到 fastTime 字段中
Date d = new Date( -1000L );
System.out.println( d );
}
}
注意,输出 date 对象的字符串形式时,CST 表示 China Standard Time ,即中国标准时间。
15.2.3、实例方法
Date
类中绝大多数实例方法都已经被废弃(不赞成使用),仅存的几个可用的实例方法如下:
public long getTime()
获取 Date
实例内部存储的毫秒值。
public void setTime( long time )
设置 Date
实例内部存储的毫秒值。
public String toString()
将当前 Date
实例所存储的毫秒值转换为以下形式的 字符串:
dow mon dd hh:mm:ss zzz yyyy
其中: dow
是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat
)。
public boolean equals( Object obj )
Date
类重写了从 Object
类继承的 equals
方法用于判断当前 Date
实例与另外一个对象是否"相等"。
public boolean after( Date when )
测试 当前 Date
实例 所表示的时间 是否在 指定Date
实例 所表示的时间之后。
public boolean before( Date when )
测试 当前 Date
实例 所表示的时间 是否在 指定Date
实例 所表示的时间之前。
15.2.3.1、Date实例是可变的
Date 实例 是 【可变的】,在创建 Date 实例后,其内部的 毫秒值 是可以更改的
import java.util.Date;
public class DateTest2 {
public static void main(String[] args) {
long ms = 1000L * 60 * 60 * 24 * 365 * 30 ;
final Date date = new Date( ms );
System.out.println( date );
birthdate.setTime( 1000 );
System.out.println( date );
}
}
15.2.3.2、比较Date实例
Date
实例的比较,可以通过 equals
、after
、before
方法来实现:
import java.util.Date;
public class DateTest3 {
public static void main(String[] args) {
long ms = 1000L * 60 * 60 * 24 * 365 * 30 ;
Date first = new Date( ms );
System.out.println( first );
Date second = new Date( ms );
System.out.println( second );
System.out.println( first == second ); // false
// java.utl.Date 类 重写了 从 Object 类继承的 equals 方法
System.out.println( first.equals( second ) ); // true
Date now = new Date();
System.out.println( now.after( first ) ); // true
System.out.println( now.after( second ) ); // true
System.out.println( first.before( now ) ); // true
System.out.println( second.before( now ) ); // true
}
}
不建议使用的比较方法是这样子的:
long firstTime = first.getTime() ;
long secondTime = second.getTime() ;
if( firstTime > secondTime ) {
System.out.println( first + " 晚于 " + second );
}
15.3 Calendar类
Calendar
一词表示日历,而 Java 语言中 Calendar
则是一个类,一个声明在 java.util
包中的抽象类。
Calendar
类为特定瞬间与日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法
瞬间
可用毫秒值
来表示,它是距历元
的偏移量。
历元(epoch)
是指 格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000 ( 格里高利历 ) 。
15.3.1、日历字段
日历字段是 Calendar 类中声明的用来表示日期时间中指定部分的常量。
常用的日历字段如下:
-
Calendar.ERA
对应纪元
比如罗马儒略历中的 AD 或 BC ( 中文表示为 公元 或 公元前 )
Calendar.YEAR
对应年份Calendar.MONTH
对应月份
月份从 0 开始计数,0 表示 January
(一月),1 表示 February
( 二月 )
-
Calendar.DATE
对应月份中的日期
日期从 1 开始计数,有效范围为 1 ~ 31 。
-
Calendar.HOUR_OF_DAY
对应一天当中的小时
小时从 0 开始计数,有效范围为 0 ~ 23 。
-
Calendar.MINUTE
对应分钟
分钟从 0 开始计数,有效范围为 0 ~ 59 。
-
Calendar.SECOND
对应秒
秒数从 0 开始计数,有效范围为 0 ~ 60 。(要注意闰秒)
-
Calendar.MILLISECOND
对应毫秒
毫秒数从 0 开始计数,有效范围为 0 ~ 999 。
-
Calendar.DAY_OF_MONTH
对应月份中的日期
日期从 1 开始计数,有效范围为 1 ~ 31 。
-
Calendar.HOUR
对应上午或下午的小时
小时从 0 开始计数,有效范围为 0 ~ 11 。
-
Calendar.DAY_OF_WEEK
对应星期
用于指示一个星期中的某天。
该字段可取的值可以是 SUNDAY
、MONDAY
、TUESDAY
、WEDNESDAY
、THURSDAY
、FRIDAY
和 SATURDAY
。
-
Calendar.DAY_OF_YEAR
对应年份中的天数
指示当前年中的天数。一年中第一天的值为 1,最大值为 366 。
15.3.2、获取Calendar实例
15.3.2.1、通过创建子类实例
的方式
GregorianCalendar
类是 Calendar
类的子类,
通过创建 GregorianCalendar
类的实例即可使用 Calendar
中的方法。
Calendar c = new GregorianCalendar(); // 父类引用 指向 子类对象
System.out.println( c );
15.3.2.2、通过类方法
获取
Calendar
类中定义了大量的类方法用于获取 Calendar
实例:
public static Calendar getInstance()
举例:
Calendar c = Calendar.getInstance();
System.out.println( c );
public static Calendar getInstance( TimeZone zone, Locale locale )
举例:
TimeZone zone = TimeZone.getDefault();
Locale locale = Locale.getDefault() ;
Calendar c = Calendar.getInstance( zone , locale );
System.out.println( c );
15.3.3、从 Calendar 实例中获取时间
Calendar 类中声明了以下方法用于从 特定瞬间
中获取 指定日历字段
对应的值:
public int get( int calendarField )
同时在 Calendar
类中声明了以下方法用于获取 Calendar
实例所表示的瞬间对应的毫秒值:
public long getTimeInMillis()
举例:
import java.util.Calendar;
import java.util.GregorianCalendar;
public class CalendarTest1 {
public static void main(String[] args) {
// 父类引用 指向 子类对象
Calendar c = new GregorianCalendar();
System.out.println( c );
// 从 c 对应的 Calendar 实例中获取 日历字段 ERA 对应的值
int era = c.get( Calendar.ERA ) ;
System.out.println( era );
int year = c.get( Calendar.YEAR );
System.out.println( year );
// 在西方国家,月份的索引从 零 开始,0 表示 1月 , 11 表示12月
int month = c.get( Calendar.MONTH );
System.out.println( month );
int date = c.get( Calendar.DATE );
System.out.println( date );
int hourOfDay = c.get( Calendar.HOUR_OF_DAY );
System.out.println( hourOfDay );
int minute = c.get( Calendar.MINUTE );
System.out.println( minute );
int second = c.get( Calendar.SECOND );
System.out.println( second );
// 仅仅获取 MILLISECOND 字段对应的值,取值范围为 [ 0 , 1000 )
int millis = c.get( Calendar.MILLISECOND );
System.out.println( millis );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
// 获取 当前的 Calendar 实例所表示的瞬间 对应的毫秒值(距离历元的偏移量)
long ms = c.getTimeInMillis();
System.out.println( ms );
}
}
15.3.4、设置 Calendar
实例
Calendar 类中声明了以下方法用于用于为 指定的 日历字段
设置相应的值:
public void set( int calendarField, int value )
同时也提供了以下方法来批量设置年、月、日、小时、分钟、秒、毫秒等 日历字段
的值
public final void set( int year, int month, int date )
public final void set( int year, int month, int date, int hourOfDay )
public final void set( int year, int month, int date, int hourOfDay, int minute,int second )
需要注意的是,这里的 hourOfDay
与 Calendar.HOUR_OF_DAY
对应,表示一天中的小时,取值范围是 0 ~ 23 。
另外,Calendar 类中声明了用于清空所有日历字段
取值的方法:
public final void clear()
Calendar 类中也声明了用于清空指定的 日历字段
取值的方法:
public final void clear( int calendarField )
举例:
import java.util.*;
public class CalendarTest3 {
public static void main(String[] args) {
// 父类引用 指向 子类对象
Calendar c = new GregorianCalendar();
System.out.println( c );
c.set( Calendar.YEAR , 1996 ); // 公元1996年
c.set( Calendar.MONTH , 0 ); // 月份的索引从 0 开始,0表示1月
c.set( Calendar.DATE , 10 );
c.set( Calendar.HOUR_OF_DAY , 11 );
c.set( Calendar.MINUTE , 45 );
c.set( Calendar.SECOND , 0 );
c.set( Calendar.MILLISECOND , 0 );
System.out.println( c );
System.out.println( c.getTimeInMillis() );
System.out.println( c );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
c.clear(); // 清除所有日历字段的值
System.out.println( c );
// YEAR 、MONTH 、HOUR_OF_DAY 、MINUTE、SECOND
c.set( 0 , 0 , 10 , 11 , 45 , 30 );
c.set( Calendar.MILLISECOND , 100 );
System.out.println( c.getTimeInMillis() );
System.out.println( c );
}
}
15.3.5、将 Calendar
实例转换为 Date
类型的实例
Calendar 类中声明了用于将当前的Calendar
实例所表示的瞬间转换为Date
实例的方法:
public final Date getTime()
举例:
import java.util.*;
public class CalendarTest2 {
public static void main(String[] args) {
// 父类引用 指向 子类对象
Calendar c = new GregorianCalendar();
System.out.println( c );
// java.util.Date 类中的 getTime() 方法可以返回一个毫秒值
// java.util.Calendar 类中的 getTime() 用于返回相应的 Date 实例
Date date = c.getTime(); // 返回 当前 Calendar 实例所表示的瞬间 对应的 Date 实例
System.out.println( date );
}
}
15.3.6、获取任意时间对应的Date
实例
截至目前,我们可以借助于 Calendar
实例来获取任意时间对应的 Date
实例,其步骤为
- a>、获得 Calendar 实例
- b>、清空所有日历字段的值
- c>、根据实际需要设置 年月日、时分秒 等日历字段的值
- d>、获取 Calendar 实例所表示的瞬间 对应的 Date 实例
举例:
import java.util.*;
public class CalendarTest4 {
public static void main(String[] args) {
TimeZone zone = TimeZone.getDefault();
Locale locale = Locale.getDefault() ;
// 1、获得 Calendar 实例
Calendar c = Calendar.getInstance( zone , locale );
System.out.println( c );
// 2、清空所有日历字段的值
c.clear();
// 3、根据实际需要设置 年月日、时分秒
c.set( 1998 , 10 , 20 , 5 , 30 , 40 );
c.set( Calendar.MILLISECOND , 0 );
// 4、获取 Calendar 实例所表示的瞬间 对应的 Date 实例
Date date = c.getTime();
System.out.println( date );
}
}
在 Java 8 之前,获得 任意的 年月日、时分秒 对应的 Date 实例,可以使用两种方法:
- 通过将特定格式的字符串解析为
Date
实例 ( 在DateFormat
中讲解 )
- 通过
Calendar
实例来获取
15.4 DateFormat 类
java.text.DateFormat
类提供了用于将日期格式化和解析字符串为Date实例的方法:
public final String format( Date date )
public Date parse(String source) throws ParseException
但是 DateFormat
类是个抽象类,其子类 SimpleDateFormat
是个具体类(非抽象类)。
SimpleDateFormat
类的构造方法:
public SimpleDateFormat()
public SimpleDateFormat( String pattern )
public SimpleDateFormat( String pattern , Locale locale )
public SimpleDateFormat( String pattern , DateFormatSymbols formatSymbols )
其中最常用的是:
public SimpleDateFormat( String pattern )
参数中的 pattern
表示日期的模式。
日期模式的字符串可以使用以下模式字母:
比如 yyyy-MM-dd
对应 1996-12-12
。
15.4.1、日期格式化
日期格式化举例:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 重要: 将 java.util.Date 实例所表示的 【瞬间】 格式化为 【特定模式】的字符串
*/
public class DateFormatTest1 {
public static void main(String[] args) {
long ms = 1000L * 60 * 60 * 24 * 365 * 30 ;
Date birthdate = new Date( ms );
String pattern = "G yyyy年MM月dd日 EEEE HH:mm:ss.SSS" ; // 确定 "日期时间" 的模式
DateFormat df = new SimpleDateFormat( pattern );
String s = df.format( birthdate );
System.out.println( s );
}
}
15.4.2、解析字符串为Date实例
将指定字符串按照特定的模式解析为 Date 实例:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Scanner;
/**
* 重要: 将 字符串 解析为 java.util.Date 实例
*/
public class DateFormatTest2 {
public static void main(String[] args) {
final String pattern = "yyyy-MM-dd" ;
DateFormat df = new SimpleDateFormat( pattern );
Scanner sc = new Scanner( System.in );// 创建扫描器用户读取用户输入的数据
System.out.println( "请输入一个日期( 格式为 " + pattern + " ,比如 2019-09-01 )" );
String s = sc.nextLine(); // 读取用户输入的整行数据
System.out.println( "你输入的是: " + s );
try {
// 将 字符串 解析为 Date 类型的实例
Date date = df.parse( s ); // 可能抛出 ParseException 异常
System.out.println( date );
long time = date.getTime() ;
System.out.println( time );
} catch ( ParseException e ) {
System.out.println( "你输入的日期格式不符合 " + pattern );
e.printStackTrace();
}
sc.close(); // 关闭扫描器
}
}
15.5 LocalDate类
有鉴于 java.util.Date 类 和 java.util.Calendar 类在设计上的缺陷,从 Java 8 开始,JDK 中新增了 java.time 包,其中定义了大量的用来表示日期、时间的类型。
15.5.1、LocalDate
类的设计
java.time.LocalDate
类是一个不可变类,该类是被 final
所修饰,因此该类没有子类。
package java.time;
// 省略 import 语句
public final class LocalDate
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
// 省略其它代码
private final int year; // The year.
private final short month; // The month-of-year.
private final short day; // The day-of-month.
// 省略其它代码
}
在 java.time.LocalDate
类中声明了三个实例字段用来存储 年份、月份、日期:
private final int year;
private final short month;
private final short day;
因为它们都是 final
修饰的,因此一旦创建 LocalDate
实例,其 年份、月份、日期 的值再也不能被更改。
另外,LocalDate
类还声明了以下常量:
public static final LocalDate MIN = LocalDate.of( Year.MIN_VALUE, 1, 1 );
public static final LocalDate MAX = LocalDate.of( Year.MAX_VALUE, 12, 31 );
public static final LocalDate EPOCH = LocalDate.of( 1970, 1, 1 );
从常量命名可知,MAX
、MIN
分别表示 LocalDate
所能表示的日期的最大值和最小值。
而 EPOCH
则表示历元
对应的日期。
15.5.2、获取 LocalDate
实例
java.time.LocalDate
类提供了许多类方法
用于获取 LocalDate
实例,以下是几个常用的方法:
public static LocalDate now()
public static LocalDate of( int year , int month , int dayOfMonth )
public static LocalDate ofYearDay( int year , int dayOfYear )
举例:
import java.time.LocalDate;
public class LocalDateTest1 {
public static void main(String[] args) {
// 通过 LocalDate 类中的 类方法 ( now ) 来获取 LocalDate 实例
LocalDate now = LocalDate.now();
System.out.println( now );
// 通过 LocalDate 类中的 类方法 ( of ) 来获取 LocalDate 实例
LocalDate birthdate = LocalDate.of( 1999 , 12 , 31 );
System.out.println( birthdate );
// 通过 LocalDate 类中的 类方法 ( ofYearDay ) 来获取 LocalDate 实例
LocalDate date = LocalDate.ofYearDay( 2019 , 244 );
System.out.println( date );
}
}
15.5.3、常用实例方法
LocalDate
类中定义了大量的实例方法,其中比较常用的是:
-
public int getYear()
用于获取年份 -
public int getMonthValue()
用于获取月份 ( 取值范围是 1 ~ 12 ) -
public int getDayOfMonth()
用于获取日期 ( 取值范围是 1 ~ 31 ) -
public DayOfWeek getDayOfWeek()
用于获取星期 ( 返回类型为DayOfWeek
) -
public boolean isLeapYear()
用于判断LocalDate
实例对应的年份是否是闰年 -
public int lengthOfYear()
用于获取LocalDate
实例对应的年份的总天数 -
public int lengthOfMonth()
用于获取LocalDate
实例对应的月份的总天数
举例:
import java.time.DayOfWeek;
import java.time.LocalDate;
public class LocalDateTest2 {
public static void main(String[] args) {
LocalDate n = LocalDate.now() ;
System.out.println( n.getYear() + "年" );
System.out.println( n.getMonthValue() + "月" );
System.out.println( n.getDayOfMonth() + "日" );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
DayOfWeek day = n.getDayOfWeek();
System.out.println( day );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
boolean leap = n.isLeapYear();
System.out.println( leap );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
System.out.println( n.lengthOfYear() );
System.out.println( n.lengthOfMonth() );
}
}
同时,LocalDate
类中定义了用于比较 LocalDate
实例的方法:
public boolean equals( Object obj )
public boolean isEqual( ChronoLocalDate other )
public boolean isBefore( ChronoLocalDate other )
public boolean isAfter( ChronoLocalDate other )
另外,LocalDate
类还定义了 在指定的 LocalDate
对应的日期基础上 增加或减少 指定时间的方法:
public LocalDate plusYears( long yearsToAdd )
public LocalDate plusDays( long daysToAdd )
public LocalDate plusMonths( long monthsToAdd )
public LocalDate plusWeeks( long weeksToAdd )
举例:
import java.time.DayOfWeek;
import java.time.LocalDate;
public class LocalDateTest3 {
public static void main(String[] args) {
LocalDate n = LocalDate.now(); // 获得当前日期
System.out.println( n );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
// 在 n 所表示的日期基础上减少18年后返回 新的 LocalDate 实例
LocalDate f = n.plusYears( -18 );
System.out.println( f );
System.out.println( n == f );
System.out.println( n.equals( f ) );
System.out.println( n.isEqual( f ) ); // 比较两个 LocalDate 实例是否相等
System.out.println( n.isAfter( f ) );
System.out.println( n.isBefore( f ) );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
// 在 f 所表示的日期基础上增加18年后返回 新的 LocalDate 实例
LocalDate s = f.plusYears( 18 );
System.out.println( s == n );
System.out.println( s.equals( n ) );
System.out.println( s.isEqual( n ) );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
// 在 n 所表示的日期基础上增加 10天 后返回 新的 LocalDate 实例
LocalDate t = n.plusDays( 10 );
System.out.println( t );
// 在 n 所表示的日期基础上增加 5个月 后返回 新的 LocalDate 实例
LocalDate o = n.plusMonths( 5 );
System.out.println( o );
// 在 n 所表示的日期基础上增加 9周 后返回 新的 LocalDate 实例
LocalDate x = n.plusWeeks( 9 );
System.out.println( x );
}
}
15.6 LocalTime 类
15.6.1、LocalTime
类的设计
java.time.LocalTime
类是一个不可变类,该类是被 final
所修饰,因此该类没有子类。
package java.time;
// 省略 import 语句
public final class LocalTime
implements Temporal, TemporalAdjuster, Comparable, Serializable {
// 省略其它代码
private final byte hour ; // The hour.
private final byte minute ; // The minute.
private final byte second ; // The second.
private final int nano ; // The nanosecond.
// 省略其它代码
}
在 java.time.LocalTime
类中声明了四个实例字段用来存储 小时、分钟、秒、纳秒:
private final byte hour ;
private final byte minute ;
private final byte second ;
private final int nano ;
因为它们都是 final
修饰的,因此一旦创建 LocalTime
实例,其中各个字段的值再也不能被更改。
15.6.2、获取 LocalTime
实例
java.time.LocalTime
类提供了许多类方法
用于获取 LocalTime
实例,以下是几个常用的方法:
public static LocalTime now()
public static LocalTime of( int hour , int minute )
public static LocalTime of( int hour , int minute , int second )
public static LocalTime of( int hour , int minute , int second , int nanoOfSecond)
举例:
import java.time.LocalTime;
public class LocalTimeTest1 {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println( now );
LocalTime f = LocalTime.of( 12,0 );
System.out.println( f );
LocalTime s = LocalTime.of( 12,24 , 36 );
System.out.println( s );
// 1s = 1000ms (毫秒)
// 1ms = 1000us (微秒)
// 1us = 1000ns ( 纳秒 或 毫微秒 )
LocalTime t = LocalTime.of( 12,24 , 36 , 100200300);
System.out.println( t );
}
}
15.6.3、常用实例方法
LocalTime
类中定义了大量的实例方法,其中比较常用的是:
-
public int getHour()
用于获取小时 (取值范围为 0 ~ 23 ) -
public int getMinute()
用于获取分钟 (取值范围为 0 ~ 59 ) -
public int getSecond()
用于获取秒 (取值范围为 0 ~ 59 ) -
public int getNano()
用于获取纳秒 (取值范围为 0 ~ 999999999 )
举例:
import java.time.LocalTime;
public class LocalTimeTest2 {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println( now );
System.out.println( now.getHour() + "时" );
System.out.println( now.getMinute() + "分" );
System.out.println( now.getSecond() + "秒" );
long nano = now.getNano(); // 其返回值为 0 ~ 999999999
long ms = nano / 1000000 ; // 求取毫秒部分的数值( 范围为 0 ~ 999 )
System.out.println( ms + "毫秒" );
long us = nano % 1000000 / 1000 ; // 求取微秒部分的数值( 范围为 0 ~ 999 )
System.out.println( us + "微秒" );
long ns = nano % 1000000 % 1000 ; // 求取纳秒部分的数值( 范围为 0 ~ 999 )
System.out.println( ns + "纳秒" );
}
}
同时,LocalTime
类中定义了用于比较 LocalTime
实例的方法:
public boolean isAfter( LocalTime other )
public boolean isBefore( LocalTime other )
public boolean equals( Object obj )
另外,LocalTime
类还定义了 在指定的 LocalTime
对应的时间基础上 增加或减少 指定时间的方法:
public LocalTime plusHours( long hoursToAdd )
public LocalTime plusMinutes( long minutesToAdd )
public LocalTime plusSeconds( long secondstoAdd )
public LocalTime plusNanos( long nanosToAdd )
举例:
import java.time.LocalTime;
public class LocalTimeTest3 {
public static void main(String[] args) {
LocalTime time = LocalTime.now(); // 获取当前时间
System.out.println( time );
// 在 time 所表示的时间基础上增加 5 小时后返回新的 LocalTime 实例
LocalTime t1 = time.plusHours( 5 );
System.out.println( t1 );
// 在 time 所表示的时间基础上减少 20 分钟 后返回新的 LocalTime 实例
LocalTime t2 = time.plusMinutes( -20 );
System.out.println( t2 );
// 在 time 所表示的时间基础上增加 30 秒 后返回新的 LocalTime 实例
LocalTime t3 = time.plusSeconds( 30 );
System.out.println( t3 );
// 在 time 所表示的时间基础上增加 100200300 纳秒 后返回新的 LocalTime 实例
LocalTime t4 = time.plusNanos( 100200300L );
System.out.println( t4 );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
System.out.println( t1.isAfter( t2 ) );
System.out.println( t2.isBefore( t3 ) );
System.out.println( t3.equals( t4 ) );
}
}
15.7 LocalDateTime类
15.7.1、LocalDateTime
类的设计
java.time.LocalDateTime
类是一个 不可变类,该类是被 final
所修饰,因此该类没有子类。
package java.time;
// 省略 import 语句
public final class LocalDateTime
implements Temporal, TemporalAdjuster, ChronoLocalDateTime,
Serializable {
// 省略其它代码
private final LocalDate date ; // The date part.
private final LocalTime time ; // The time part.
// 省略其它代码
}
在 java.time.LocalDateTime
类中声明了两个实例字段用来存储 日期 和 时间 :
private final LocalDate date ;
private final LocalTime time ;
这里需要注意,不仅仅 date
和 time
字段是 final
修饰的,LocalDate
、LocalTime
类中的实例字段也是 final
修饰的,因此 LocalDateTime
的实例一经创建,其内部的各项取值都是不可更改的。
15.7.2、获取 LocalDateTime
实例
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeTest1 {
public static void main(String[] args) {
LocalDateTime datetime = LocalDateTime.now();
System.out.println( datetime );
LocalDateTime first = LocalDateTime.of( 1996 , 7 , 4 , 7 , 30 ) ;
System.out.println( first );
LocalDateTime second = LocalDateTime.of( 1999 , 11 , 20, 6 , 30 , 7 ) ;
System.out.println( second );
LocalDateTime third = LocalDateTime.of( 1999 , 11 , 20, 6 , 30 , 7 , 0 ) ;
System.out.println( third );
LocalDate date = LocalDate.of( 1997 , 7 , 1 );
LocalTime time = LocalTime.of( 10 , 20 );
LocalDateTime fourth = LocalDateTime.of( date , time );
System.out.println( fourth );
}
}
15.7.3、获取日期时间值
从 LocalDateTime
实例中获取 年份、月份、日期 、星期 、小时、分钟、秒、纳秒举例:
import java.time.LocalDateTime;
public class LocalDateTimeTest2 {
public static void main(String[] args) {
LocalDateTime n = LocalDateTime.now();
System.out.println( n.getYear() + "年" );
System.out.println( n.getMonthValue() + "月" );
System.out.println( n.getDayOfMonth() + "日" );
System.out.println( n.getDayOfWeek() );
int hour = n.getHour() ;
int minute = n.getMinute() ;
int second = n.getSecond() ;
int nanos = n.getNano() ;
System.out.println( hour + ":" + minute + ":" + second + "." + nanos );
}
}
15.7.4、增加或减少指定时间
在指定的时间基础之上增加或减少时间 ( 年、月、周、天、时、分、秒、纳秒 )举例:
import java.time.LocalDateTime;
public class LocalDateTimeTest3 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.now();
System.out.println( dt );
LocalDateTime dt1 = dt.plusYears( -3 ); // 减少 3 年
System.out.println( dt1 );
LocalDateTime dt2 = dt.plusMonths( 5 ); // 增加 5 个月
System.out.println( dt2 );
LocalDateTime dt3 = dt.plusWeeks( 10 ); // 增加 10 周
System.out.println( dt3 );
LocalDateTime dt4 = dt.plusDays( 15 ); // 增加 15 天
System.out.println( dt4 );
LocalDateTime dt5 = dt.plusHours( 8 ); // 增加 8 小时
System.out.println( dt5 );
LocalDateTime dt6 = dt.plusMinutes( 30 ); // 增加 30 分钟
System.out.println( dt6 );
LocalDateTime dt7 = dt.plusSeconds( 50 ); // 增加 50 秒
System.out.println( dt7 );
LocalDateTime dt8 = dt.plusNanos( 100300500L ); // 增加 100300500L 纳秒
System.out.println( dt8 );
}
}
15.8、转换
在 Java 8 提供了新的日期时间API后,我们需要在新旧两套日期时间API之间完成转换。
这里仅列举几个常见的类型之间的转换方法。
15.8.1、LocalDate
转 LocalDateTime
在 LocalDate 实例中已经存在年、月、日的数值,因此将 LocalDate 转换到 LocalDateTime 时需要指定相应的时、分、秒、纳秒等数值,借助于 LocalDate 类中提供的 atStartOfDay
、atTime
等方法可以完成该操作。
import java.time.LocalDate;
import java.time.LocalDateTime;
public class LocalDateTest4 {
public static void main(String[] args) {
LocalDate n = LocalDate.now();
System.out.println( n );
LocalDateTime datetime = n.atStartOfDay();
System.out.println( datetime );
LocalDateTime first = n.atTime( 10 , 20 );
System.out.println( first );
LocalDateTime second = n.atTime( 10 , 20 , 30 );
System.out.println( second );
LocalDateTime third = n.atTime( 10 , 20 , 30 , 100200300 );
System.out.println( third );
}
}
15.8.2、LocalTime
转 LocalDateTime
在 LocalTime 实例中已经存在时、分、秒、纳秒等数值,因此将 LocalTime 转换到 LocalDateTime 时需要指定相应的年、月、日等数值,借助于 LocalTime 类中提供的 atDate
方法可以完成该操作。
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalTimeTest4 {
public static void main(String[] args) {
LocalTime time = LocalTime.now() ;
System.out.println( time );
LocalDate date = LocalDate.of( 2019 , 10 , 10 );
LocalDateTime dateTime = time.atDate( date );
System.out.println( dateTime );
}
}
15.8.3、LocalDateTime
转 LocalDate
或 LocalTime
我们已经知道在 LocalDateTime 实例中封装了一个 LocalDate 实例和一个 LocalTime 实例,因此可以通过 LocalDateTime 提供的方法直接获取相应的 LocalDate 实例和 LocalTime 实例。
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeTest4 {
public static void main(String[] args) {
LocalDateTime datetime = LocalDateTime.now();
System.out.println( datetime );
LocalDate date = datetime.toLocalDate();
System.out.println( date );
LocalTime time = datetime.toLocalTime();
System.out.println( time );
}
}
15.8.4、Date
转 LocalDateTime
将 java.util.Date 类型的实例转换成 LocalDateTime 类型实例的方法不止一种,这里介绍其中一种实现方法,并通过举例,简单了解一下 Instant
、 ZoneId
、ZonedDateTime
三个类的作用。
以下举例说明将 java.util.Date
类型的实例转换为 java.time.LocalDate
类型的实例:
import java.time.*;
public class TransformTest1 {
public static void main(String[] args) {
final long ms = 1000L * 60 * 60 * 24 * 365 * 30 ;
java.util.Date date = new java.util.Date( ms );
System.out.println( date );
System.out.println( "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" );
// 根据指定的 java.util.Date 实例获取与之对应的 java.time.Instant 实例
Instant instant = date.toInstant();
// 根据时区编号(ID)获取相应的 java.time.ZoneId 实例
ZoneId zone = ZoneId.of( "Asia/Shanghai" ) ;
// 根据 Instant 实例获取带有时区的日期时间对象( ZonedDateTime 实例 )
ZonedDateTime zonedDateTime = instant.atZone( zone );
// 根据 带有时区的日期时间对象 ( ZonedDateTime 实例 ) 获取 LocalDateTime 实例
LocalDateTime datetime = zonedDateTime.toLocalDateTime() ;
System.out.println( datetime );
// 根据 带有时区的日期时间对象 ( ZonedDateTime 实例 ) 获取 LocalDate 实例
LocalDate d = zonedDateTime.toLocalDate();
System.out.println( d );
// 根据 带有时区的日期时间对象 ( ZonedDateTime 实例 ) 获取 LocalTime 实例
LocalTime t = zonedDateTime.toLocalTime();
System.out.println( t );
}
}
以上举例,实际上完成了以下几种转换:
- 将 java.util.Date 实例 转换为 java.time.LocalDateTime 实例
- 将 java.util.Date 实例 转换为 java.time.LocalDate 实例
- 将 java.util.Date 实例 转换为 java.time.LocalTime 实例
15.8.5、LocalDateTime
转 Date
在了解将 java.util.Date
实例转换为 java.time.LocalDateTime
实例的基础上,我们可以实现将 java.time.LocalDateTime
实例转换为 java.util.Date
实例 ( 仅列举一种方法 )。
import java.time.*;
import java.util.Date;
public class TransformTest2 {
public static void main(String[] args) {
LocalDateTime datetime = LocalDateTime.of( 1999 , 11 , 22 , 6 , 30 , 7 );
// 获取系统平台默认的时区编号对应的 java.time.ZoneId 实例
ZoneId zone = ZoneId.systemDefault() ;
// 根据 LocalDateTime 实例获取带有时区的日期时间对象 ( ZonedDateTime 实例 )
ZonedDateTime zonedDateTime = ZonedDateTime.of( datetime , zone ) ;
// 根据 带有时区的日期时间对象 ( ZonedDateTime 实例 ) 获取与其相应的 Instant 实例
Instant instant = Instant.from( zonedDateTime );
// 使用 java.util.Date 类提供的 from 方法获取与指定 Instant 实例对应的 Date 实例
java.util.Date date = Date.from( instant );
System.out.println( date );
}
}