Java中的日期和时间

2019-10-22  本文已影响0人  仲伦

根据个人目前正在编写的《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> {
    
}

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 类中绝大多数实例方法都已经被废弃(不赞成使用),仅存的几个可用的实例方法如下:

获取 Date 实例内部存储的毫秒值。

设置 Date 实例内部存储的毫秒值。

将当前 Date 实例所存储的毫秒值转换为以下形式的 字符串:

dow mon dd hh:mm:ss zzz yyyy

其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。

Date 类重写了从 Object 类继承的 equals 方法用于判断当前 Date 实例与另外一个对象是否"相等"。

测试 当前 Date 实例 所表示的时间 是否在 指定Date实例 所表示的时间之后。

测试 当前 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 类为<b style="color:blue;">特定瞬间</b>与<b style="color:blue;">日历字段</b>之间的转换提供了一些方法,并为操作日历字段提供了一些方法

瞬间可用毫秒值来表示,它是距历元的偏移量。

历元(epoch) 是指 格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000 ( 格里高利历 ) 。

15.3.1、日历字段

日历字段是 Calendar 类中声明的用来表示日期时间中指定部分的常量。
常用的日历字段如下:

比如罗马儒略历中的 AD 或 BC ( 中文表示为 公元 或 公元前 )

月份从 0 开始计数,0 表示 January (一月),1 表示 February ( 二月 )

日期从 1 开始计数,有效范围为 1 ~ 31 。

小时从 0 开始计数,有效范围为 0 ~ 23 。

分钟从 0 开始计数,有效范围为 0 ~ 59 。

秒数从 0 开始计数,有效范围为 0 ~ 60 。(要注意闰秒)

毫秒数从 0 开始计数,有效范围为 0 ~ 999 。

日期从 1 开始计数,有效范围为 1 ~ 31 。

小时从 0 开始计数,有效范围为 0 ~ 11 。

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

该字段可取的值可以是 SUNDAYMONDAYTUESDAYWEDNESDAYTHURSDAYFRIDAYSATURDAY

指示当前年中的天数。一年中第一天的值为 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 实例:

举例:

Calendar c = Calendar.getInstance();
System.out.println( c );

举例:

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 实例,其步骤为

举例:

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 实例,可以使用两种方法:

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 表示日期的模式。

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

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 类中定义了大量的实例方法,其中比较常用的是:

举例:

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<LocalTime>, 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 类中定义了大量的实例方法,其中比较常用的是:

举例:

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<LocalDate>,
                  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 );

    }

}

以上举例,实际上完成了以下几种转换:

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

    }

}
上一篇下一篇

猜你喜欢

热点阅读