Java中的日期概述
日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式都是非常复杂的问题。
在Java中,操作日期主要涉及到一下几个类:
1、java.util.Date
类 Date 表示特定的瞬间,精确到毫秒。从 JDK 1.1 开始,应该使用 Calendar 类实现日期和时间字段之间转换,使用 DateFormat 类来格式化和分析日期字符串。Date 中的把日期解释为年、月、日、小时、分钟和秒值的方法已废弃。
2、java.text.DateFormat(抽象类)
DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并分析日期或时间。日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期 -> 文本)、分析(文本-> 日期)和标准化。将日期表示为 Date 对象,或者表示为从 GMT(格林尼治标准时间)1970 年,1 月 1 日 00:00:00 这一刻开始的毫秒数。
3、java.text.SimpleDateFormat(DateFormat的直接子类)
SimpleDateFormat 是一个以与语言环境相关的方式来格式化和分析日期的具体类。它允许进行格式化(日期 -> 文本)、分析(文本 -> 日期)和规范化。
SimpleDateFormat 使得可以选择任何用户定义的日期-时间格式的模式。但是,仍然建议通过 DateFormat 中的 getTimeInstance、getDateInstance 或 getDateTimeInstance 来新的创建日期-时间格式化程序。
4、java.util.Calendar(抽象类)
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。
与其他语言环境敏感类一样,Calendar 提供了一个类方法 getInstance,以获得此类型的一个通用的对象。Calendar 的 getInstance 方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化。
5、java.util.GregorianCalendar(Calendar的直接子类)
GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家使用的标准日历系统。
GregorianCalendar 是一种混合日历,在单一间断性的支持下同时支持儒略历和格里高利历系统,在默认情况下,它对应格里高利日历创立时的格里高利历日期(某些国家是在 1582 年 10 月 15 日创立,在其他国家要晚一些)。可由调用方通过调用 setGregorianChange() 来更改起始日期。
使用 getDateInstance 来获得该国家的标准日期格式。另外还提供了一些其他静态工厂方法。使用 getTimeInstance 可获得该国家的时间格式。使用 getDateTimeInstance 可获得日期和时间格式。可以将不同选项传入这些工厂方法,以控制结果的长度(从 SHORT 到 MEDIUM 到 LONG 再到 FULL)。确切的结果取决于语言环境,但是通常:
- SHORT:完全为数字,如 12.13.52 或 3:30pm
- MEDIUM:较长,如 Jan 12, 1952
- LONG:更长,如 January 12, 1952 或 3:30:32pm
- FULL:是完全指定,如 Tuesday, April 12, 1952 AD 或 3:30:42pm PST。
Date
类 java.util.Date 表示特定的瞬间,精确到毫秒。提供了很多的方法,但是很多已经过时,不推荐使用,下面仅仅列出没有过时的方法:
public void getCurrentDate() {
System.out.println("---获取系统当前时间---");
//创建并初始化一个日期(初始值为当前日期)
Date date = new Date();
System.out.println("现在的日期是 = " + date.toString());
System.out.println("自1970年1月1日0时0分0秒开始至今所经历的毫秒数 = " + date.getTime());
}
Calendar(抽象类)
java.util.Calendar是个抽象类,是系统时间的抽象表示,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。
与其他语言环境敏感类一样,Calendar 提供了一个类方法 getInstance(),以获得此类型的一个通用的对象。Calendar 的 getInstance() 方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化。
一个Calendar的实例是系统时间的抽象表示,从Calendar的实例可以知道年月日星期月份时区等信息。Calendar类中有一个静态方法get(int x),通过这个方法可以获取到相关实例的一些值(年月日星期月份等)信息。参数x是一个产量值,在Calendar中有定义。
Calendar c1 = Calendar.getInstance();
- int year = c1.get(Calendar.YEAR); // 获得年份
- int month = c1.get(Calendar.MONTH) + 1; // 获得月份
- int date = c1.get(Calendar.DATE); // 获得日期
- int hour = c1.get(Calendar.HOUR_OF_DAY); // 获得小时
- int minute = c1.get(Calendar.MINUTE); // 获得分钟
- int second = c1.get(Calendar.SECOND); // 获得秒
- int day = c1.get(Calendar.DAY_OF_WEEK); // 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
Calendar中些陷阱:
- Calendar的星期是从周日开始的,常量值为0。
- Calendar的月份是从一月开始的,常量值为0。
- Calendar的每个月的第一天值为1。
Calendar类对象字段类型
Calendar类中用以下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想
常量 | 描述 |
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
GregorianCalendar类
Calendar类实现了公历日历,GregorianCalendar是Calendar类的一个具体实现。
Calendar 的getInstance()方法返回一个默认用当前的语言环境和时区初始化的GregorianCalendar对象。GregorianCalendar定义了两个字段:AD和BC。这是代表公历定义的两个时代。
Java日期格式类
Java 8有新的Date-Time API来处理日期和时间。 我们应该使用新的Java 8 Date-Time API来格式化和解析日期时间值。
如果我们正在编写与日期和时间相关的新代码,我们应该使用新的Date-Time API。
此部分适用于使用旧日期和日历类的旧代码。
DateFormat
DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并分析日期或时间。日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期 -> 文本)、分析(文本-> 日期)和标准化。将日期表示为 Date 对象,或者表示为从 GMT(格林尼治标准时间)1970 年,1 月 1 日 00:00:00 这一刻开始的毫秒数。
格式样式
Date Format类将五个样式定义为常量:
- DateFormat.DEFAULT
- DateFormat.SHORT
- DateFormat.MEDIUM
- DateFormat.LONG
- DateFormat.FULL
DEFAULT格式与MEDIUM相同。getInstance()使用SHORT。
下表显示了对于美国区域设置以不同样式格式化的相同日期。
样式 | 格式化日期 |
DEFAULT | Mar 27, 2014 |
SHORT | 3/27/14 |
MEDIUM | Mar 26, 2014 |
LONG | March 26, 2014 |
FULL | Sunday, November 2, 2014 |
SimpleDateFormat
SimpleDateFormat 是一个以与语言环境相关的方式来格式化和分析日期的具体类。它允许进行格式化(日期 -> 文本)、分析(文本 -> 日期)和规范化。
SimpleDateFormat 使得可以选择任何用户定义的日期-时间格式的模式。但是,仍然建议通过 DateFormat 中的 getTimeInstance、getDateInstance 或 getDateTimeInstance 来新的创建日期-时间格式化程序。
要创建自定义日期格式,我们可以使用SimpleDateFormat类。
SimpleDateFormat类是对语言环境敏感的。
它的默认构造函数创建一个格式化程序,默认日期格式为默认语言环境。
SimpleDateFormat类中的format()方法执行日期格式。
日期和时间的格式化编码
时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母,定义如下:
字母 | 描述 | 示例 |
G | 纪元标记 | AD |
y | 四位年份 | 2001 |
M | 月份 | July or 07 |
d | 一个月的日期 | 10 |
h | A.M./P.M. (1~12)格式小时 | 12 |
H | 一天中的小时 (0~23) | 22 |
m | 分钟数 | 30 |
s | 秒数 | 55 |
S | 毫秒数 | 234 |
E | 星期几 | Tuesday |
D | 一年中的日子 | 360 |
F | 一个月中第几周的周几 | 2 (second Wed. in July) |
w | 一年中第几周 | 40 |
W | 一个月中第几周 | 1 |
a | A.M./P.M. 标记 | PM |
k | 一天中的小时(1~24) | 24 |
K | A.M./P.M. (0~11)格式小时 | 10 |
z | 时区 | Eastern Standard Time |
' | 文字定界符 | Delimiter |
" | 单引号 | ` |
将文本数据解析成日期对象
假设我们有一个文本字符串包含了一个格式化了的日期对象,我们希望解析这个字符串并从文本日期数据创建一个日期对象。我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类。但是这一次,我们使用格式化解析而不是生成一个文本日期数据。我们的例子显示在下面,将解析文本字符串"3-02-2012"并创建一个值为1330617600000 的日期对象。
@Test
public void sdfTest() {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
String txtDate = "7-26-2018";
try {
Date date = dateFormat.parse(txtDate);
System.out.println(date.getTime());// 1532534400000
System.out.println(dateFormat.format(date));// 07-26-2018
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
使用标准的日期格式化过程
既然我们已经可以生成和解析定制的日期格式了,让我们来看一看如何使用内建的格式化过程。方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过程。下面是我们获取了六个内建的日期格式化过程。它们包括一个空,默认,短的,中等的,长的,完整的日期格式。
@Test
public void dfTest() {
String strDate = null;
Date date = new Date();
System.out.println(date);// Thu Jul 26 14:17:51 CST 2018
strDate = DateFormat.getDateInstance().format(date);
System.out.println(strDate);// 2018-7-26
//Date
strDate = DateFormat.getDateInstance(DateFormat.DEFAULT).format(date);
System.out.println(strDate);// 2018-7-26
strDate = DateFormat.getDateInstance(DateFormat.SHORT).format(date);
System.out.println(strDate);// 18-7-26
strDate = DateFormat.getDateInstance(DateFormat.MEDIUM).format(date);
System.out.println(strDate);// 2018-7-26
strDate = DateFormat.getDateInstance(DateFormat.LONG).format(date);
System.out.println(strDate);// 2018年7月26日
strDate = DateFormat.getDateInstance(DateFormat.FULL).format(date);
System.out.println(strDate);// 2018年7月26日 星期四
//DateTime
strDate = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT).format(date);
System.out.println(strDate);// 2018-7-26 14:17:51
strDate = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date);
System.out.println(strDate);// 18-7-26 下午2:17
strDate = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(date);
System.out.println(strDate);// 2018-7-26 14:17:51
strDate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(date);
System.out.println(strDate);// 2018年7月26日 下午02时17分51秒
strDate = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date);
System.out.println(strDate);// 2018年7月26日 星期四 下午02时17分51秒 CST
}
自定义格式
@Test
public void customDateTest() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
System.out.println(dateFormat.format(date)); // 星期四-七月-26-2018
}
只要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy",我们就能够指明自己想要的格式。格式字符串中的ASCII 字符告诉格式化函数下面显示日期数据的哪一个部分。EEEE是星期,MMMM是月,dd是日,yyyy是年,字符的个数决定了日期是如何格式化的。传递"EE-MM-dd-yy"会显示Friday-March-02-2012。
日期处理
Calendar 类是一个抽象类,它为一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
当前毫秒值是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。
日期加减
// 使用默认时区和语言环境获得一个日历。
private static Calendar calendar;
public static void printResult(String description) {
System.out.print(description + ": ");
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));
calendar = Calendar.getInstance();// 重置为当前时间
}
@Test
public void operateDate() {
calendar = Calendar.getInstance();// 初始化
printResult("当前时间 ");
calendar.add(Calendar.HOUR_OF_DAY, 1);
printResult("增加1小时");
calendar.add(Calendar.DAY_OF_MONTH, 1);
printResult("增加1天 ");
calendar.add(Calendar.MONTH, 1);
printResult("增加1个月");
calendar.add(Calendar.YEAR, 1);
printResult("增加1年 ");
calendar.add(Calendar.YEAR, -2);
printResult("减少2年 ");
}
输出
- 当前时间 : 2018-07-26 14:55:23
- 增加1小时: 2018-07-26 15:55:23
- 增加1天 : 2018-07-27 14:55:23
- 增加1个月: 2018-08-26 14:55:23
- 增加1年 : 2019-07-26 14:55:23
- 减少2年 : 2016-07-26 14:55:23
两个日期相差天数
@Test
public void dateSubtract() {
long millisOfDay = 24 * 60 * 60 * 1000;
Calendar calendar = new GregorianCalendar(2015, 9, 1);
Calendar calendar1 = new GregorianCalendar(2016, 9, 1);
Calendar calendar2 = new GregorianCalendar(2017, 9, 1);
// 2016年是闰年,得到366天
System.out.println((calendar1.getTimeInMillis() - calendar.getTimeInMillis()) / millisOfDay);
// 2017年是平年,得到365天
System.out.println((calendar2.getTimeInMillis() - calendar1.getTimeInMillis()) / millisOfDay);
}
参考:
https://www.cnblogs.com/lcngu/p/5154834.html
https://www.w3cschool.cn/java/java-date-format-class.html
https://blog.csdn.net/u011494050/article/details/44178795
https://baike.xsoftlab.net/view/148.html
http://www.runoob.com/java/java-date-time.html