本文摘录自:
Java时间日期的处理:Java Date类、Calendar类详解
深入理解Java常用类-----时间日期
- Date类
首先Date中有封装一个long类型的变量,这个变量是整个时间日期操作的对象,也就是我们使用该变量代表时间和日期。
private transient long fastTime;
构造方法:常用构造方法有两个
public Date() { this(System.currentTimeMillis()); }
: 以系统当前时间创建对象,并初始化
public Date(long date) { fastTime = date; }
:表示从 1970 年 1 月 1 日 0 时 0 分 0 秒开始经过参数 date 指定的毫秒数。Date 类的无参数构造方法获取的是系统当前的时间,显示的顺序为星期、月、日、小时、分、秒、年。
Date date1=new Date(); //调用无参数构造函数
System.out.println(date1.toString()); //输出:Wed Oct 23 01:09:07 UTC 2019
Date date2=new Date(60000); //调用含有一个long类型参数的构造函数
System.out.println(date2); //Thu Jan 01 00:01:00 UTC 1970
-
常用方法
- 使用代码测试
import java.io.*;
import java.util.*;
class test
{
public static void main (String[] args) throws java.lang.Exception
{
Scanner input=new Scanner(System.in);
System.out.println("请输入要做的事情:");
String title=input.next();
Date date1=new Date(); //获取当前日期
System.out.println("["+title+"] 这件事发生时间为:"+date1);
try
{
Thread.sleep(60000);//暂停 1 分钟
}
catch(InterruptedException e)
{
e.printStackTrace();
}
Date date2=new Date();
System.out.println("现在时间为:"+date2);
if(date2.before(date1))
{
System.out.println("你还有 "+(date2.getTime()-date1.getTime())/1000+" 秒需要去完成【"+title+"】这件事!");
}
else
{
System.out.println("【"+title+"】事情已经过去了 "+(date2.getTime()-date1.getTime())/1000+" 秒");
}
//进一步测试after
if(date2.after(date1)){
System.out.println("date2比date1要晚 "+(date2.getTime()-date1.getTime())/1000+" 秒");
}
System.out.println("判断两个时间的判断两个时间的大小");
System.out.println("date2.compareTo(date1): "+date2.compareTo(date1));
System.out.println("date1.compareTo(date2): "+date1.compareTo(date2));
System.out.println("date2.equals(date1): "+date2.equals(date1));
System.out.println("date1.equals(date2): "+date1.equals(date2));
}
}
运行结果如下:
[收快递] 这件事发生时间为:Wed Oct 23 09:30:08 CST 2019
现在时间为:Wed Oct 23 09:31:08 CST 2019
【收快递】事情已经过去了 60 秒
date2比date1要晚 60 秒
判断两个时间的判断两个时间的大小
date2.compareTo(date1): 1
date1.compareTo(date2): -1
date2.equals(date1): false
date1.equals(date2): false
- Calendar 类
Calendar 类是一个抽象类,它为特定瞬间与 YEAR、MONTH、DAY_OF_MONTH、HOUR 等日历字段之间的转换提供了一些方法,并为操作日历字段(如获得下星期的日期) 提供了一些方法。
- Calendar目前是日期时间处理中的核心类,接下来我们看看其中源码:
//和Date一样封装了毫秒属性
protected long time;
/**
* The calendar field values for the currently set time for this calendar.
* This is an array of <code>FIELD_COUNT</code> integers, with index values
* <code>ERA</code> through <code>DST_OFFSET</code>.
* @serial
*/
protected int fields[];
//封装了十七个静态常量
public final static int ERA = 0;
public final static int YEAR = 1;
public final static int MONTH = 2;
public final static int WEEK_OF_YEAR = 3;
.........
public final static int DST_OFFSET = 16;
public final static int FIELD_COUNT = 17;
在Calendar的内部封装了17个静态常量,这些常量将会作为索引用来检索fields属性,例如:fields[YEAR]将返回当前毫秒值对应的日期时间的年份部分,fields[MONTH]将返回的是月份部分的值等等。
- 创建 Calendar 对象不能使用 new 关键字,因为 Calendar 类是一个抽象类,但是它提供了一个 getInstance() 方法来获得 Calendar类的对象。getInstance() 方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化。
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
public static Calendar getInstance(TimeZone zone)
{
return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
}
public static Calendar getInstance(Locale aLocale)
{
return createCalendar(TimeZone.getDefault(), aLocale);
}
public static Calendar getInstance(TimeZone zone,
Locale aLocale)
{
return createCalendar(zone, aLocale);
}
主要有四个方法用于创建Calendar实例,其实内部调用的是同一的方法只是传入的参数的值不同。创建一个Calend 实例需要两个参数,一个是TimeZone时区,另一个是Locale语言国家。因为每个国家或地区他们表示时间的形式是不一样的,所以我们需要通过这两个参数确定具体需要使用的格式,当然是以本地时间作为fastTime的值的,如果我们没有指定时区和国家语言,那么将会默认使用本机系统信息。
- 可以获取上述17个属性
public int get(int field)
{
complete();
return internalGet(field);
}
其中complete方法就是调用了本地函数完成对fields属性中没有值的元素赋值。 调用internalGet方法其实就是调用的fields[field],为我们返回指定属性的结果值。我们可以看个例子:
public static void main(String[] args){
Calendar calendar = Calendar.getInstance();
System.out.println("YEAR: "+calendar.get(Calendar.YEAR));
System.out.println("MONTH: "+(calendar.get(Calendar.MONTH)+1));
System.out.println("DAY_OF_MONTH: "+calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("HOUR: "+calendar.get(Calendar.HOUR));
System.out.println("HOUR_OF_DAY: "+calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("MINUTE: "+calendar.get(Calendar.MINUTE));
System.out.println("SECOND: "+calendar.get(Calendar.SECOND));
calendar.set(2019,10,23,13,12,12);
System.out.println("MONTH: "+calendar.get(Calendar.MONTH));
System.out.println("HOUR: "+calendar.get(Calendar.HOUR));
System.out.println("HOUR_OF_DAY: "+calendar.get(Calendar.HOUR_OF_DAY));
}
运行结果如下:
YEAR: 2019
MONTH: 10 //month属性是从0开始的,也就是0表示一月,所有需要加1
DAY_OF_MONTH: 23
HOUR: 10 //12 小时制的小时
HOUR_OF_DAY: 10 //24 小时制的小时
MINUTE: 7
SECOND: 30
MONTH: 10 //如果设置的话,设置值等于输出值
HOUR: 1 //12小时制
HOUR_OF_DAY: 13 //24小时制度
- 除了获取有关日期时间的信息,我们也是有可以用来设置他们的方法的
//为指定属性设置值
public void set(int field, int value)
//设置年月日等,很多重载
public final void set(int year, int month, int date)
......
//清空所有该Calendar实例的属性值
public final void clear() //清空后会输出1970/1/1 00:00:00的对应日期
- 还有一些通过计算来设置Calendar属性的方法:
//为指定属性添加值
abstract public void add(int field, int amount);
public static void main(String[] args){
Calendar calendar = Calendar.getInstance();
System.out.print(calendar.get(Calendar.YEAR)); //2019
calendar.add(Calendar.YEAR,10);
System.out.print(calendar.get(Calendar.YEAR)); //2029
}
- roll()方法
abstract public void roll(int field, boolean up);
//重载
public void roll(int field, int amount)
{
while (amount > 0) {
roll(field, true);
amount--;
}
while (amount < 0) {
roll(field, false);
amount++;
}
}
我们需要记住的是,roll方法完成的工作是和add一样的,只是add方法处理了越界的特殊情况(越界会向上进一位),而roll方法会重新回到初始值再加。例如:
public static void main(String[] args){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, 11);//十二月
System.out.println(calendar.getTime());
//calendar.add(Calendar.MONTH,5);//Sat May 23 10:53:32 CST 2020
//calendar.roll(Calendar.MONTH,5); //Thu May 23 10:53:32 CST 2019
System.out.println(calendar.getTime());
}
注意区分:这里的 getTime()
和Date类中的不太一样,Date中返回的是long
类型,而这里是Date类型
public final Date getTime() { return new Date(getTimeInMillis()); }
还有一些比较函数,和Date类中的类似
public boolean equals(Object obj)
public int compareTo(Calendar anotherCalendar)
public boolean after(Object when)
public boolean before(Object when)
********************获取日期之后我们需要进行格式转换********************
- DateFormat 类
DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期→文本)、解析(文本→日期)和标准化日期。
- 该类主要用于实现Date对象和字符串之间相互转换, 涉及到两个转换的方法:
//将Date类型转换为String类型
public final String format(Date date)
//将String类型转换Date类型
public Date parse(String source)
- 除此之外,DateFormat还提供了四个静态常量,代表着四种不同的风格。不同的风格输出信息的内容详尽程度不同,默认的风格是MEDIUM。
public static final int FULL = 0;
public static final int LONG = 1;
public static final int MEDIUM = 2;
public static final int SHORT = 3;
public static final int DEFAULT = MEDIUM;
- 该类是抽象类,一样需要使用静态工厂获取实例对象。
public final static DateFormat getTimeInstance()
public final static DateFormat getTimeInstance(int style)
public final static DateFormat getTimeInstance(int style,Locale aLocale)
public final static DateFormat getDateInstance()
public final static DateFormat getDateInstance(int style)
public final static DateFormat getDateInstance(int style,Locale aLocale)
public final static DateFormat getDateTimeInstance()
public final static DateFormat getDateTimeInstance(int dateStyle,int timeStyle)
public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
很明显,有三种不同的方式来获取DateFormat实例,每种方式有三个重载,getDateInstance用来处理日期,getTimeInstance用来处理时间,getDateTimeInstance既可以处理日期,也可以处理时间。我们通过一个例子看看他们之间的区别:
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
System.out.println(DateFormat.getDateInstance().format(c.getTime()));
System.out.println(DateFormat.getTimeInstance().format(c.getTime()));
System.out.println(DateFormat.getDateTimeInstance().format(c.getTime()));
}
输出为:
2019-10-23
11:06:52
2019-10-23 11:06:52
这里我们同样用一个例子来区分四种style的输出格式:
public static void main (String[] args) throws java.lang.Exception
{
//获取不同格式化风格和中国环境的日期
DateFormat df1=DateFormat.getDateInstance(DateFormat.SHORT,Locale.CHINA);
DateFormat df2=DateFormat.getDateInstance(DateFormat.FULL,Locale.CHINA);
DateFormat df3=DateFormat.getDateInstance(DateFormat.MEDIUM,Locale.CHINA);
DateFormat df4=DateFormat.getDateInstance(DateFormat.LONG,Locale.CHINA);
//获取不同格式化风格和中国环境的时间
DateFormat df5=DateFormat.getTimeInstance(DateFormat.SHORT,Locale.CHINA);
DateFormat df6=DateFormat.getTimeInstance(DateFormat.FULL,Locale.CHINA);
DateFormat df7=DateFormat.getTimeInstance(DateFormat.MEDIUM,Locale.CHINA);
DateFormat df8=DateFormat.getTimeInstance(DateFormat.LONG,Locale.CHINA);
//将不同格式化风格的日期格式化为日期字符串
String date1=df1.format(new Date());
String date2=df2.format(new Date());
String date3=df3.format(new Date());
String date4=df4.format(new Date());
//将不同格式化风格的时间格式化为时间字符串
String time1=df5.format(new Date());
String time2=df6.format(new Date());
String time3=df7.format(new Date());
String time4=df8.format(new Date());
//输出日期
System.out.println("SHORT:"+date1+" "+time1);
System.out.println("FULL:"+date2+" "+time2);
System.out.println("MEDIUM:"+date3+" "+time3);
System.out.println("LONG:"+date4+" "+time4);
}
运行输出为:
SHORT:19-10-23 上午11:08
FULL:2019年10月23日 星期三 上午11时08分51秒 CST
MEDIUM:2019-10-23 11:08:51
LONG:2019年10月23日 上午11时08分51秒
- 最后我们看一下parse函数
public Date parse(String source) throws ParseException
public static void main (String[] args) throws java.lang.Exception
{
String tmp ="1993-2-2";
DateFormat dateFormat = DateFormat.getDateInstance();
//Tue Feb 02 00:00:00 CST 1993
System.out.println(dateFormat.parse(tmp));
}
但是该函数只能识别"1970-1-1"类型的函数,
public static void main (String[] args) throws java.lang.Exception
{
String tmp ="1993_2_2";
DateFormat dateFormat = DateFormat.getDateInstance();
System.out.println(dateFormat.parse(tmp));
}
会抛出异常
Exception in thread "main" java.text.ParseException: Unparseable date: "1993_2_2"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.q.utils.test.main(test.java:21)
- SimpleDateFormat 类
如果使用 DateFormat 类格式化日期/时间并不能满足要求,那么就需要使用 DateFormat 类的子类——SimpleDateFormat。
- SimpleDateFormat是DateFormat的一个优秀的实现类,它增强了一个重要的性质。它允许自定义格式输出模板。构造SimpleDateFormat实例的时候,可以传入一个pattern作为输出模板。
- 构造函数:
SimpleDateFormat()://用默认的格式和默认的语言环境构造 SimpleDateFormat。
SimpleDateFormat(String pattern)://用指定的格式和默认的语言环境构造 SimpleDateF ormat。
SimpleDateFormat(String pattern,Locale locale)://用指定的格式和指定的语言环境构造 SimpleDateFormat
看个例子:
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
SimpleDateFormat sm = new SimpleDateFormat("yyyy年MM月dd日 E HH时mm分ss秒");
//2019年10月23日 星期三 11时17分51秒
System.out.println(sm.format(c.getTime()));
}
- yyyy表示使用四位数字输出年份
- MM表示使用两位数字表示月份
- dd表示使用两位数字表示日
- E表示星期几
- HH表示使用两位数字表示小时(24以内) hh表示12小时制
- mm和ss分别表示分钟和秒数
public static void main(String[] args) throws ParseException {
Calendar c = Calendar.getInstance();
SimpleDateFormat sm = new SimpleDateFormat("yyyy年MM月dd日 E HH时mm分ss秒");
String s = "2016年11月11日 星期五 00时00分00秒";
//Fri Nov 11 00:00:00 CST 2016
System.out.println(sm.parse(s));
}