Java中的日期和时间

根据个人目前正在编写的《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 ) 来表示时区、日期、时间。

接下来我们将从 DateCalendar 说起,来研究 时期、时间的表示方法 以及 日期格式化 等操作。

15.2、Date 类

Date 类的实例表示特定的瞬间( 精确到毫秒 )。

package java.util;

import java.io.Serializable ;

public class Date implements Serializable, Cloneable, Comparable {
    
}

Date 类实现了 SerializableCloneableComparable 等接口。

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实例的比较,可以通过 equalsafterbefore 方法来实现:

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 对应星期

用于指示一个星期中的某天。

该字段可取的值可以是 SUNDAYMONDAYTUESDAYWEDNESDAYTHURSDAYFRIDAYSATURDAY

  • 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 )

需要注意的是,这里的 hourOfDayCalendar.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 表示日期的模式。

日期模式的字符串可以使用以下模式字母:

Java中的日期和时间_第1张图片
dateformat-pattern.png

比如 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 );

从常量命名可知,MAXMIN 分别表示 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 ;

这里需要注意,不仅仅 datetime 字段是 final 修饰的,LocalDateLocalTime 类中的实例字段也是 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、LocalDateLocalDateTime

在 LocalDate 实例中已经存在年、月、日的数值,因此将 LocalDate 转换到 LocalDateTime 时需要指定相应的时、分、秒、纳秒等数值,借助于 LocalDate 类中提供的 atStartOfDayatTime 等方法可以完成该操作。

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、LocalTimeLocalDateTime

在 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、LocalDateTimeLocalDateLocalTime

我们已经知道在 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、DateLocalDateTime

将 java.util.Date 类型的实例转换成 LocalDateTime 类型实例的方法不止一种,这里介绍其中一种实现方法,并通过举例,简单了解一下 InstantZoneIdZonedDateTime 三个类的作用。

以下举例说明将 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、LocalDateTimeDate

在了解将 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 );

    }

}

你可能感兴趣的:(Java中的日期和时间)