关于对时间和日期进行处理的类
Java自带日期时间类库
日期和时间的处理,在实际开发中十分常见,尽管现在的框架已经十分强大,对时间和日期的处理,正常编程时可能都感觉不到。但是框架使用的也是Java底层的对时间日期处理的类。所以了解学习一下基础,还是十分有必要的。由于日期和时间类使用的十分频繁,Java自身已经有很多类库来处理日期和时间了。
Date类
Date类从jdk1.0时就已经存在了,正是因为它历史悠久,所以这个类里大部分的构造器和方法都已经过时,不推荐使用。
简单介绍一个现在还在用的的构造器以及方法。
//生成一个代表当前日期的Date对象 格式 Sat Jun 06 08:36:05 CST 2020
Date date = new Date();
//返回该时间对应的long型整数。
long time = date.getTime();
//根据传入的long型整数生成一个Date对象
Date date2 = new Date(time);
//获取当前系统时间.返回值为一个long型整数
long currentTimeMillis = System.currentTimeMillis();
总体来说,Date这个类设计的有点糟糕,这可不是我说的,是Java官方自己说的。推荐使用Calendar工具类
Calendar类
根据给定的Date对象,Calendar类可以以整数(如:YEAR、MONTH和DATE)的形式检索信息。它是抽象类,因此无法像Date类一样实例化。
Calendar对象提供为特定语言或日历样式实现日期格式化所需的所有时间字段值。
Calendar c = Calendar.getInstance();
// 取出年
System.out.println(c.get(YEAR));
// 取出月份
System.out.println(c.get(MONTH));
// 取出日
System.out.println(c.get(DATE));
// 分别设置年、月、日、小时、分钟、秒
c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23
System.out.println(c.getTime());
// 将Calendar的年前推1年
c.add(YEAR , -1); //2002-11-23 12:32:23
System.out.println(c.getTime());
// 将Calendar的月前推8个月
c.roll(MONTH , -8); //2002-03-23 12:32:23
System.out.println(c.getTime());
Calendar cal1 = Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23
cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
System.out.println(cal1.getTime());
Calendar cal2 = Calendar.getInstance();
cal2.set(2003, 7, 31, 0, 0 , 0); // 2003-8-31
// 因为进位到后月份改为2月,2月没有31日,自动变成29日
cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29
System.out.println(cal2.getTime());
Calendar cal3 = Calendar.getInstance();
cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
// MONTH字段“进位”,但YEAR字段并不增加
cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23
System.out.println(cal3.getTime());
Calendar cal4 = Calendar.getInstance();
cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
// MONTH字段“进位”后变成2,2月没有31日,
// YEAR字段不会改变,2003年2月只有28天
cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28
System.out.println(cal4.getTime());
Calendar很强大。
格式化时间日期类
直接输出的Date类往往对国人不是十分友好,我们需要对时间和日期进行格式化,
DateFormat类
11.5.3 DateFormat类
在java.util.Date类中实际上取得的时间是一个非常正确的时间。但是因为其显示的格式不理想,所以无法符合中国人的习惯要求,那么实际上此时就可以为此类进行格式化操作,变为符合于中国人习惯的日期格式。
另外,要提醒读者的是DateFormat类与MessageFormat类都属于Format类的子类,专门用于格式化数据使用。DateFormat类的定义如下:
. public abstract class DateFormat extends Format
从定义上看DateFormat类是一个抽象类,所以肯定无法直接实例化,但是在此抽象类中提供了一个静态方法,可以直接取得本类的实例,个与这个类的常用方法
序 号 | 方 法 | 类 型 | 描 述 |
---|---|---|---|
1 | public static final DateFormat getDateInstance() | 普通 | 得到默认的对象 |
2 | public static final DateFormat getDateInstance(int style, Locale aLocale) | 普通 | 根据 Locale 得到对象 |
3 | public static final DateFormat getDateTimeInstance() | 普通 | 得到日期时间对象 |
4 | public static final DateFormat getDateTimeInstance(int dateStyle,inttimeStyle,Locale aLocale) | 普通 | 根据 Locale得到日期时间对象 |
以上4个方法可以构造DateFormat类的对象,但是发现以上方法中需要传递若干个参数,这些参数表示日期地域或日期的显示形式。下面通过几段代码来了解DateFormat类的操作。
范例:观察DateFormat中的默认操作
package com.datedemo;
import java.util.Calendar;
import java.util.Date;
public class DateTestDemo {
public static void main(String[] args) {
DateFormat df1 = null;
// 声明DateFormat类对象
DateFormat df2 = null;
// 声明DateFormat类对象
df1 = DateFormat.getDateInstance();
// 取得日期
df2 = DateFormat.getDateTimeInstance(); // 取得日期时间
System.out.println("DATE:" + df1.format(new Date()));// 格式化日期
System.out.println("DATETIME:" + df2.format(new Date()));
}
}
程序运行结果:
DATE:2008-12-2
DATETIME:2008-12-2 16:25:11
从程序的运行结果中发现,第2个DATETIME显示了时间,但还不是比较合理的中文显示格式。如果想取得更加合理的时间,则必须在构造DateFormat对象时传递若干个参数。
范例:指定显示的风格
package com.datedemo;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
public class DateTestDemo {
public static void main(String[] args) {
DateFormat df1 = null;
// 声明DateFormat对象
DateFormat df2 = null;
// 声明DateFormat对象
df1 = DateFormat.getDateInstance(DateFormat.YEAR_FIELD, new Locale("zh", "CN"));
// 取得日期,并设置日期显示风格
// 取得日期时间,设置日期的显示格式、时间的显示格式
df2 = DateFormat.getDateTimeInstance(DateFormat.YEAR_FIELD, DateFormat.ERA_FIELD, new Locale("zh", "CN"));
System.out.println("DATE:" + df1.format(new Date()));
System.out.println("DATETIME:" + df2.format(new Date()));
}
}
程序运行结果:
DATE:2008年12月2日
DATETIME:2008年12月2日 下午04时30分29秒 CST
可以发现,以上的日期时间已经被格式化,格式是其默认的时间显示格式,但是如果现在要想得到用户自己需要的日期显示格式,则必须通过DateFormat的子类SimpleDateFormat类完成。
SimpleDateFormat类
在项目开发中,会经常将一个日期格式转换为另外一种日期格式,例如,原日期为2008-10-19 10:11:30.345,转换后日期为2008年10月19日10时11分30秒345毫秒。从这两个日期可以发现,日期的数字完全一样,只是日期格式有所不同,要想实现转换就必须使用java.text包中的SimpleDateFormat类完成。
首先必须先定义出一个完整的日期转化模板,在模板中通过特定的日期标记可以将一个日期格式中的日期数字提取出来,
日期格式化模板标记如下所示
序 号 | 标 记 | 描 述 |
---|---|---|
1 | y | 年,年份是 4 位数字,所以需要使用 yyyy 表示 |
2 | M | 年中的月份,月份是两位数字,所以需要使用 MM 表示 |
3 | d | 月中的天数,天数是两位数字,所以需要使用 dd 表示 |
4 | H | 一天中的小时数( 24 小时),小时是两位数字,使用 HH 表示 |
5 | m | 小时中的分钟数,分钟是两位数字,使用 mm 表示 |
6 | s | 分钟中的秒数,秒是两位数字,使用 ss 表示 |
7 | S | 毫秒数,毫秒数是 3位数字,使用 SSS 表示 |
8 | y | 年,年份是 4 位数字,所以需要使用 yyyy 表示 |
此外,还需要SimpleDateFormat类中的方法才可以完成,SimpleDateFormat类的常用方法如下所示。
SimpleDateFormat类中的常用方法
序号 | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public SimpleDateFormat(String pattern) | 构造 | 通过一个指定的模板构造对象 |
2 | public Date parse(String source) throws ParseException | 普通 | 将一个包含日期的字符串变为 Date 类型 |
3 | public final String format(Date date) | 普通 | 将一个 Date 类型按照指定格式变为 String 类型 |
范例:格式化日期操作
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTestDemo {
public static void main(String[] args) {
String strDate = "2008-10-19 10:11:30.345";
// 定义日期时间的字符串
// 准备第1个模板,从字符串中提取日期数字
String pat1 = "yyyy-MM-dd HH:mm:ss.SSS";
// 准备第2个模板,将提取后的日期数字变为指定的格式
String pat2 = "yyyy年MM月dd日HH时mm分ss秒SSS毫秒";
SimpleDateFormat sdf1 = new SimpleDateFormat(pat1);// 实例化模板对象
SimpleDateFormat sdf2 = new SimpleDateFormat(pat2);// 实例化模板对象
Date d = null;
try {
d = sdf1.parse(strDate);
// 将给定字符串中的日期提取出来
} catch (ParseException e) {
// 如果提供的字符串格式有错误,则进行异常处理
e.printStackTrace();
}
System.out.println(sdf2.format(d));// 将日期变为新的格式 *
}
}
程序运行结果:
2008年10月19日10时11分30秒345毫秒
以上程序中,首先使用第1个模板将字符串中表示的日期数字取出,然后再使用第2个模板将这些日期数字重新转化为新的格式表示。
SimpleDateFormat类经常用于将String变为Date型数据
在实际的开发中,用户所输入的各个数据都是以String的方式进行接收的,所以此时为了可以正确地将String变为Date型数据,可以依靠SimpleDateFormat类完成。
范例:将String型数据变为Date型数据
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTestDemo {
public static void main(String[] args) throws ParseException {
// 所有异常 抛出
String strDate = "2008-10-19 10:11:30.345";
// 定义日期时间的字符串
String pat = "yyyy-MM-dd HH:mm:ss.SSS";
// 定义模板
SimpleDateFormat sdf = new SimpleDateFormat(pat); // 实例化模板对象
Date d = sdf.parse(strDate);
// 将给定字符串中的日期 提取出来
System.out.println(d);
// 输出Date对象
}
}
程序运行结果:
Sun Oct 19 10:11:30 CST 2008
以上程序已经实现了String向Date的转型操作,这样的操作在Java数据库编程时将会经常使用。
实例操作–取得完整日期
实现一:基于Calendar类
以上已经为读者清楚地介绍了如何取得一个系统的日期以及对日期格式的转化操作,但是如果所有的程序都按Calendar程序那样取得日期,则代码肯定会重复很多次,所以可以考虑单独去设计一个类,此类可以取得当前系统的日期时间。但是在使用Calendar类得到时间时有一个问题,例如,现在的月份是9月,正确的日期格式应该是09,但是因为得到日期的方法返回的是int类型,所以最终的返回结果是9,也就是说要想达到正确的显示效果,则必须在9前补一个0。
设计一个取得日期的类,此类可以取得系统的当前时间和时间戳
package com.datedemo;
import java.text.ParseException;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class DateTestDemo {
public static void main(String[] args) throws ParseException {
DateTime dt = new DateTime();
// 实例化DateTime对象
System.out.println("系统日期:" + dt.getDate());
System.out.println("中文日期::" + dt.getDateComplete());
System.out.println("时间戳:" + dt.getTimeStamp());
}
}
class DateTime {
private Calendar calendar = null;
// 定义一个Calendar对象,可以 取得时间
public DateTime() {
this.calendar = new GregorianCalendar();// 通过Calendar类的子类实例化
}
public String getDate() { // 得到完整的日期,格式为:yyyy-MM-dd HH:mm:ss.SSS
// 考虑到程序要频繁修改字符串,所以使用StringBuffer提升性能
StringBuffer buf = new StringBuffer();
// 依次取得时间
buf.append(calendar.get(Calendar.YEAR)).append("-");
buf.append(this.addZero(calendar.get(Calendar.MONTH) + 1, 2));
buf.append("-");
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH), 2));
buf.append(" ");
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY), 2));
buf.append(":");
buf.append(this.addZero(calendar.get(Calendar.MINUTE), 2));
buf.append(":");
buf.append(this.addZero(calendar.get(Calendar.SECOND), 2));
buf.append(".");
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND), 3));
return buf.toString();
}
// 得到完整的日期,格式为:yyyy年MM月dd日HH时mm分ss秒SSS毫秒
public String getDateComplete() {
StringBuffer buf = new StringBuffer();
buf.append(calendar.get(Calendar.YEAR)).append("年");
buf.append(this.addZero(calendar.get(Calendar.MONTH) + 1, 2));
buf.append("月");
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH), 2));
buf.append("日 ");
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY), 2));
buf.append("时");
buf.append(this.addZero(calendar.get(Calendar.MINUTE), 2));
buf.append("分");
buf.append(this.addZero(calendar.get(Calendar.SECOND), 2));
buf.append("秒");
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND), 3));
buf.append("毫秒");
return buf.toString();
}
// 考虑到日期中有前导0,所以在此处加上了补零的方法
private String addZero(int num, int len) {
StringBuffer s = new StringBuffer();
s.append(num);
while (s.length() < len) { // 如果长度不足,则继续补0
s.insert(0, "0"); // 在第1个位置处补0
}
return s.toString();
}
public String getTimeStamp() { // 得到时间戳:yyyyMMddHHmmssSSS
StringBuffer buf = new StringBuffer();
buf.append(calendar.get(Calendar.YEAR));
buf.append(this.addZero(calendar.get(Calendar.MONTH) + 1, 2));
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH), 2));
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY), 2));
buf.append(this.addZero(calendar.get(Calendar.MINUTE), 2));
buf.append(this.addZero(calendar.get(Calendar.SECOND), 2));
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND), 3));
return buf.toString();
}
};
程序运行结果:
系统日期:2008-10-19 10:42:50.562
中文日期::2008年10月19日 10时42分50秒562毫秒
时间戳:20081019104250562
以上程序已经完成了设计的要求,但程序代码太长、太复杂,那么有没有更好的方式呢?实际上是有的,SimpleDateFormat类中可以对一个Date类型进行格式修改的方法,直接使用此方法就可以将一个当前日期的Date类型变为指定的日期格式。
实现二:基于SimpleDateFormat类
使用SimpleDateFormat类可以方便地把一个日期变为指定格式,所以直接使用此类操作是最简单、最合适的。
范例:修改之前的程序
package com.datedemo;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class DateTestDemo {
public static void main(String[] args) throws ParseException {
DateTime dt = new DateTime(); // 实例化DateTime对象
System.out.println("系统日期:" + dt.getDate());
System.out.println("中文日期::" + dt.getDateComplete());
System.out.println("时间戳:" + dt.getTimeStamp());
}
}
class DateTime {
// 声明日期格式化操作对象,直接对new Date()进行实例化
private SimpleDateFormat sdf = null;
// 得到完整的日期,格式为:yyyy-MM-dd HH:mm:ss.SSS
public String getDate() {
this.sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return this.sdf.format(new Date());
}
// 得到完整的日期,格式为:yyyy年MM月dd日HH时mm分ss秒SSS毫秒
public String getDateComplete() {
this.sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒SSS毫秒");
return this.sdf.format(new Date());
}
public String getTimeStamp() { // 得到时间戳:yyyyMMddHHmmssSSS
this.sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
return this.sdf.format(new Date());
}
};
程序运行结果:
系统日期:2008-10-19 10:47:48.610
中文日期::2008年10月19日 10时47分48秒610毫秒
时间戳:20081019104748610
第二种代码显而易见的简洁,推荐使用实现二这种方法。