Java 日期时间

在编写程序的过程中, 我们经常需要用到时间有关的方法.

比如记录文章的发布时间, 记录某一个操作的操作时间以便将来可以通过特定的时间段找到这些记录.

而在 Java 8 及以后提供了一个新的可靠的, 易用的, 线程安全的时间/日期接口 java.time.* 

具体请参照: Java 8 中的新特性: 新的时间/日期接口

而在 Java 8 以前, Java 中的日期和日期的相关计算, 主要是通过 java.util.Date 和 java.util.Calendar 实现.

本教程也将简单的介绍一下, 早期版本中关于关于时间, 日期的操作方法.

一. 获取当前时间

关于时间的获取有两种方式:

一种是获取当前的系统的Unix时间戳:

Unix时间戳是一种从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数的即使方式.

例如:

时间为格林威治时间1970年01月01日00时00分01秒, 那么 unix 时间戳的值则为 1 .

时间为格林威治时间1970年01月02日00时00分00秒, 那么 unix 时间戳的值则为 86400 .

另一种则是通过:

 java.util.Date 来获取当前时间, 同时  java.util.Date 接受以Unix时间戳精确到毫秒的值为参数获取对应的日期.

一.1 获取当前 UNIX 时间戳

Java 中获取 UNIX 时间戳也是比较容易的, 方法如下:

System.currentTimeMillis()

需要注意的是, 该方法或得到的是以毫秒为单位的时间戳, 如果需要获取到以秒为单位的时间戳, 可以用以下方式:

Math.floorDiv(cal.getTimeInMillis(), 1000)

注: 1秒 = 1000 毫秒

一.2 获取当前 Date 对象 

我们可以使用以下代码初始化一个新的 Date 对象:

Date date = new Date()

我们同样也可以通过以下代码, 通过指定 ms 参数, 来指定 Date 对象的时间戳, 注意时间戳也是以毫秒计数的.

Date date = new Date(long ms)

示例代码:

package com.yi21.course;

import java.util.Date;

public class Yi21DateDemo {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println("当前时间: " + date);
        date = new Date(-43262668800000l);
        System.out.println("李世民出生于: " + date);
    }
}

执行结果:

当前时间: Thu Jun 17 19:52:47 CST 2021
李世民出生于: Wed Jan 21 00:00:00 CST 599

有关获取时间的更多详细内容, 请参见: Java 获取系统当前时间

二. 将日期/时间字符串转换为时间

通过 java.text.SimpleDateFormat 我们能够轻松的将指定的时间格式的时间字符串转换成 Date 对象, 同时通过Date对象获得Unix时间戳. 示例代码如下:

package com.yi21.course;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Yi21DateDemo2 {
    public static void main(String[] args) {
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd");
        try {
            Date date = ft.parse("599-01-23");
            System.out.println("李世民的生日: " + date);
            System.out.println("对应的时间戳为: " + date.getTime());
        } catch (ParseException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

执行结果结果如下:

李世民的生日: Fri Jan 23 00:00:00 CST 599
对应的时间戳为: -43262496000000

在代码中我们预定了接收的日期格式为, 四位年-两位月-两位日, 同时提供了 599-01-23 的日期.

最终成功转换成了, 对应的 Date 对象.

三. 对时间的操作

三.1 时间的比较

判断一个日式是早于还是晚于另一个日期.

当前日期为 2021-06-17, 代码示例如下:

package com.yi21.course;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Yi21DateDemo3 {
    public static void main(String[] args) {
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd");
        try {
            Date oldDate = ft.parse("2021-01-01");
            Date date = new Date();
            System.out.println(ft.format(date) + " 早于 " + ft.format(oldDate) + ": " + date.before(oldDate));
            System.out.println(ft.format(date) + " 晚于 " + ft.format(oldDate) + ": " + date.after(oldDate));
        } catch (ParseException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

执行结果如下:

2021-06-17 早于 2021-01-01: false
2021-06-17 晚于 2021-01-01: true

三.2 计算时间戳毫秒秒差

这个比较简单, 两个 Date 通过调用 getTime() 相减即可实现, 简单示例代码如下:

SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd");
try {
    Date oldDate = ft.parse("2021-01-01");
    Date date = new Date();
    System.out.println(date.getTime() - oldDate.getTime());
} catch (ParseException e) {
    System.err.println("Error: " + e.getMessage());
}

三.3 计算日期差

日期差的计算, 有时候要依赖于 java.util.Calendarget() 方法获得指定时间单位的值, 有时候需要灵活的运用各种方法计算出需要的结果, 示例代码如下:

package com.yi21.course;

import java.util.Calendar;
import java.util.Date;

public class Yi21DateDemo4 {
    public static void main(String[] args) {
        //代码编执行日期为 2021-06-17
        Calendar cal = Calendar.getInstance();
        Calendar calNow = Calendar.getInstance();
        //1999-12-31
        cal.setTime(new Date(946569600000l));
        System.out.print(cal.get(Calendar.YEAR) + " 距今已经过去 " + (calNow.get(Calendar.YEAR) - cal.get(Calendar.YEAR)) + " 年了, ");
        System.out.println("距今已经过去 " + ((calNow.getTimeInMillis() - cal.getTimeInMillis()) / 8640000) + " 天了");
        //2021-01-01
        cal.setTime(new Date(1612108800000l));
        System.out.println("距今年" + cal.get(Calendar.MONTH) + "月已经过去 " + (calNow.get(Calendar.MONTH) - cal.get(Calendar.MONTH)) + " 个月了");
    }
}

执行结果为:

1999 距今已经过去 22 年了, 距今已经过去 78398 天了
距今年1月已经过去 4 个月了

三. 4 日期的加减

日期的加减, 可以通过 java.util.Calendar 的 add() 方法实现, 该方法的第一参为时间单位, 第二参为第一参时间单位对应的数量, 如果需要减就使用负数, 示例代码如下:

package com.yi21.course;

import java.util.Calendar;
import java.util.Date;

public class Yi21DateDemo5 {
    public static void main(String[] args) {
        //代码编执行日期为 2021-06-17
        Calendar cal = Calendar.getInstance();
        //1999-12-31
        cal.setTime(new Date(946569600000l));
        cal.add(Calendar.DATE, 1);
        System.out.println("1999-12-31 一天后的日子为: " + cal.getTime());
        cal.add(Calendar.MONTH, -5);
        System.out.println("2000-01-01 5个月前的日子为: " + cal.getTime());
    }
}

执行结果如下:

1999-12-31 一天后的日子为: Sat Jan 01 00:00:00 CST 2000
2000-01-01 5个月前的日子为: Sun Aug 01 00:00:00 CST 1999

需要注意的是 Calendar 对象的add 是在自身值上操作的, 并不返回新的值.

三.5 计算程序的执行时间

虽然我们可以通过 System.currentTimeMillis() 来取得纳秒级的时间差, 来计算程序的执行时间, 但是我们更推荐使用更精确的 System.nanoTime() 来获取纳秒级的时间计数, 代码示例如下:

package com.yi21.course;

public class Yi21DateDemo6 {
    public static void main(String[] args) {
        long t1 = System.nanoTime();
        Math.pow(100, 10);
        long t2 = System.nanoTime();
        System.out.println("计算 100 的 10 次方, 消耗了 " + (t2 - t1) + " 纳秒.");
        t1 = System.nanoTime();
        int i = 100 * 10;
        t2 = System.nanoTime();
        System.out.println("计算 100 乘以 10 , 消耗了 " + (t2 - t1) + " 纳秒.");
    }
}

代码结果如下:

计算 100 的 10 次方, 消耗了 13100 纳秒.
计算 100 乘以 10 , 消耗了 300 纳秒.

从示例中我们可以看出, 计算100的10次方需要消耗的时间远比计算100乘以10要多, 这是符合我们认知的.

注意: 1秒 = 1000000000 纳秒 (十亿微秒)

注意2:  System.nanoTime() 实际上有特定的计数参照目标, 这是一种类似unix时间戳式的计算时间差值的计时方式, 同时参照的时间起点也并不固定, 因此不能用此方法来获取当前的系统时间.

四. 程序休眠(sleep)

在程序中, 偶尔我们需要做一些等待的操作, 为了满足这样的需求, Java 为我们提供了线程的休眠方法 Thread.sleep() 用以阻塞当前的线程实现休眠, 代码示例如下:

package com.yi21.course;

public class Yi21SleepDemo {
    public static void main(String[] args) {
        long t1 = System.nanoTime();
        try {
            Thread.sleep(30);
        } catch (InterruptedException e) {
            System.err.println("休眠被打断: " + e.getMessage());
        }
        long t2 = System.nanoTime();
        System.out.println("休眠 30 毫秒, 产生了 " + (t2 - t1) + " 微秒的时间差.");
    }
}

执行结果如下:

休眠 30 毫秒, 产生了 29452100 微秒的时间差.

注意: 1毫秒 = 一百万纳秒

以上就是各种常见的时间操作, 以及示例, 接下来我们将要介绍:

Java 读写文件的操作