JDK8 之前日期时间API

首先我们需要知道时区的概念,同一时刻不同时区他们的表上的时间是不一样的。所以,我们在存取时间的时候,尽量存时间戳而不是时间字符串。特别是国际化的项目,一定是存时间戳(Epoch Time),而不能是时间字符串。

在java中,用长整型来存放时间戳(毫秒数);

标准库API

我们再来看一下Java标准库提供的API。Java标准库有两套处理日期和时间的API:

  • 一套定义在java.util这个包里面,主要包括DateCalendarTimeZone这几个类;
  • 一套新的API是在Java 8引入的,定义在java.time这个包里面,主要包括LocalDateTimeZonedDateTimeZoneId等。

为什么会有新旧两套API呢?因为历史遗留原因,旧的API存在很多问题,所以引入了新的API。

那么我们能不能跳过旧的API直接用新的API呢?如果涉及到遗留代码就不行,因为很多遗留代码仍然使用旧的API,所以目前仍然需要对旧的API有一定了解,很多时候还需要在新旧两种对象之间进行转换。

获取当前时间戳

在java中获取当前时间戳的最简单方法就是System.currentTimeMillis()。

Date

java.util.Date表示特定的瞬间,精确到毫秒。

对于Date类,我们只需掌握两种构造器的使用,以及两个常用方法

下面,我们来看Date类的构造方法如何使用。该构造方法可以传入一个参数——时间戳。如果不传,则表示当前时间戳。

new Date(); // 没有参数,则表示当前时间戳
new Date(1609380374486L); // 传入一个毫秒时间戳

getTime()方法用来获取时间戳。通过该方法,也可以获取当前的时间戳。

Date d = new Date(); 
long t = d.getTime();

setTime()方法用来重新设置时间戳。

SimpleDateFormat

java.text.SimpleDateFormat

Date类是用来表示时间戳的,对于如何将Date格式化指定日期格式,以及从一个字符串日期格式解析出一个Date,就需要SimpleDateFormat。

我们需要掌握它的一个构造器的使用,以及两个方法的使用:

  • public SimpleDateFormat(String pattern) :该构造方法可以用参数pattern指定的格式创建一个对象
  • public String format(Date date) :格式化日期对象Date
  • public Date parse(String source) :从给定字符串的开始解析文本,以生成一个日期对象。

首先来看看构造器的使用,构造器里传入一个指定的格式,文档里展示的一些常用的格式如下表:

Date and Time Pattern Result
"yyyy.MM.dd G 'at' HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy" Wed, Jul 4, '01
"h:mm a" 12:08 PM
"hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
"K:mm a, z" 0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ" 010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" 2001-07-04T12:08:56.235-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX" 2001-07-04T12:08:56.235-07:00
"YYYY-'W'ww-u" 2001-W27-3

一般来说,字母越长,输出越长。以M为例,假设当前月份是9月:

  • M:输出9
  • MM:输出09
  • MMM:输出Sep
  • MMMM:输出September

我们开发中经常用到的格式总结如下:

Date and Time Pattern Result
"yyyy-MM-dd HH:mm:ss" 2020-02-01 19:32:12
"mm.ss.SSS"` | `03:46:345

下面看两个例子,格式化Date以及从一个日期时间字符串解析出Date,获取时间戳。

案例一:

// 格式化日期
var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
var date = new Date();

System.out.println(sdf.format(date));
// 2021-02-26 19:06:51

案例二:

// 解析Date
var dateStr = "2019-01-03 32:23:00";
var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

var date = sdf.parse(dateStr);  
System.out.println(date.getTime());  // 1546561380000

Calendar

java.util.Calendar

Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。获取Calendar实例的方法:

  • 使用Calendar.getInstance()方法
  • 调用它的子类GregorianCalendar的构造器。

一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、MINUTE、SECOND

注意:

  • 获取月份时:一月是0,二月是1,以此类推,12月是11
  • 获取星期时:周日是1,周二是2 , 。。。。周六是7

对于Calendar,我们需要掌握其5个方法:

  • public void get(int field)

  • public void set(int field,int value)

  • public void add(int field,int amount)

  • public final Date getTime()

  • public final void setTime(Date date)

get用法

 // 获取当前时间:
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR);
int m = 1 + c.get(Calendar.MONTH);
int d = c.get(Calendar.DATE);
int w = c.get(Calendar.DAY_OF_WEEK) - 1;
int hh = c.get(Calendar.HOUR_OF_DAY);
int mm = c.get(Calendar.MINUTE);
int ss = c.get(Calendar.SECOND);
int ms = c.get(Calendar.MILLISECOND);

System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);

set用法

set方法可以设置我们想要的日期时间

// 设置为2018-08-23
public class T10
{
    public static void main (String[] args) throws Exception
    {
        // 设置为2018-08-23
        var c = Calendar.getInstance();
        c.set(Calendar.YEAR, 2018);
        c.set(Calendar.MONTH, 7);
        c.set(Calendar.DATE, 23);

        printDate(c);  // 2018-8-23 4 20:10:18.471
    }

    private static void printDate (Calendar c)
    {
        int y = c.get(Calendar.YEAR);
        int m = 1 + c.get(Calendar.MONTH);
        int d = c.get(Calendar.DATE);
        int w = c.get(Calendar.DAY_OF_WEEK) - 1;
        int hh = c.get(Calendar.HOUR_OF_DAY);
        int mm = c.get(Calendar.MINUTE);
        int ss = c.get(Calendar.SECOND);
        int ms = c.get(Calendar.MILLISECOND);

        System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
    }
}

add用法

add可以非常的方便获取一周前、三天后这样的时间。

// 设置为2018-08-23
var c = Calendar.getInstance();
// 加5天并减去2小时:
c.add(Calendar.DAY_OF_MONTH, 5);
c.add(Calendar.HOUR_OF_DAY, -2);

printDate(c);  // 2021-3-3 3 18:18:2.600

getTime、setTime

这两个方法没什么好说的了,一个用于获取Date对象,一个用于从Date对象来设置时间。