这两天看了几篇这方面文章,觉得很不错,特别记录一下(大概我也很弱,对这方面踩的坑不多)
本文参考了 闲谈为什么慎用 Date 和 全面掌握 Java 时间日期 API ,感谢两位作者
旧API的坑
@Test
public void test1() {
Date date = new Date();// Date date = new Date(System.currentTimeMillis()); // 与上等价System.out.println(date);
Date date1 = new Date(System.currentTimeMillis());
System.out.println(date.getYear() + "-" + date.getMonth() + "-" + date.getDay());
System.out.println(date.getDate());
System.out.println(date.getDay());
System.out.println(date1);
}
结果:
119-0-3
9 //第九天
3 //第三周
Wed Jan 09 16:02:14 CST 2019
查阅博客资料,原来年份的值是当前年份距离1900年在数值上的差值(这一点 Java 参考了 C),月份是从 0 开始计算的(这一点也是参考了 C),而当前日的取值笔者使用的是 getDay(),它的取值是 day-of-week,实际上 Date 还提供了 getDate(),它的取值是 day-of-month。
Date的问题
Date 这个类给开发者的第一印象应该是日期,也就是记录到年月日的一个类,但是注释里面却提到
The class Date represents a specific instant in time, with millisecond precision.
-
这其实说明Date是时间轴上的一个瞬间,按理说是夜歌不可变类,就和String一样。
但是与此同时 Date 类竟然并不是 final 的,这意味着开发者还可以通过 setTime() 去改变「瞬间」 -
衡量一个瞬间除了记录年月日时分秒之外,还应该记录时区,但是 Date 对象中并没有包含时区这个关键属性,而仅仅是在 toString() 方法中 new 了一个时区对象并打印出来,这明显是不符合常理的。实际上由于标toString()方法按照JVM的默认时区输出时间和日期,有些开发人员把它误认为是时区敏感的。
然后旧的日期 API 中 Date 有 java.util.Date 和 java.sql.Date,两者的关系是 java.sql.Date 继承 java.util.Date(这个以前还真没有注意过)。为了把前者转成后者,需要使用如下代码:
@Test
public void test2() {
Date date = new Date();
java.sql.Date d = new java.sql.Date(date.getTime());
//System.out.println(d.getHours()); 报错
//System.out.println(d.getMinutes()); 报错
System.out.println(d.getSeconds()); 报错
}
结果呢:
报错
Exception in thread "main" java.lang.IllegalArgumentException
java.sql.Date 是 SQL 中的单纯的日期类型,不会有时分秒,这就是为什么把 java.sql.Date 通过 JDBC 插入数据库,会发现时分秒都没有了(匪夷所思)。因此如果你同时需要日期和时间,你应该使用 Timestamp,它也是 java.util.Date 的子类,Timestamp 则包含时间戳的完整信息。
3. Data 这个类扮演着诸多角色,它提供了操作时刻的方法,提供了操作年月日日期的方法,甚至还有关时区的方法。就是职责过宽,导致什么也做不好
4. 还有类似线程安全的问题,比如simpleDateformat问题
Joda_Time
老实说,上个小项目,我才开始用这个库,的确很香!计算时间的时候真的是简洁!
特点如下:
- 不可变性: Joda 类具有不可变性,因此它们的实例无法被修改。(不可变类的一个优点就是它们是线程安全的)
- 瞬间性: Instant 表示时间上的某个精确的时刻,使用从 epoch 开始计算的毫秒表示。这一定义与 JDK 相同,这就是为什么任何 Joda Instant 子类都可以与 JDK Date 和 Calendar 类兼容的原因
- 时区: DateTimeZone 是 Joda 库用于封装位置概念的类。许多日期和时间计算都可以在不涉及时区的情况下完成,但是仍然需要了解 DateTimeZone如何影响 Joda 的操作
最重要的一点,可以与JDK中的Date api兼容!!!
Date date = dateTime.toDate();
Calendar calendar = dateTime.toCalendar(Locale.CHINESE);
//通过jdk时间对象构造
Date date = new Date();
DateTime dateTime = new DateTime(date);
Calendar calendar = Calendar.getInstance();
dateTime = new DateTime(calendar);
然后后面贴一下网上找的demo
package com.bijian.study;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JodaTest {
public static void main(String[] args) {
// 初始化时间
DateTime dateTime = new DateTime(2012, 12, 13, 18, 23, 55);
// 年,月,日,时,分,秒,毫秒
DateTime dt3 = new DateTime(2011, 2, 13, 10, 30, 50, 333);
// 2010年2月13日10点30分50秒333毫秒
// 下面就是按照一点的格式输出时间
String str2 = dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa");
String str3 = dateTime.toString("dd-MM-yyyy HH:mm:ss");
String str4 = dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa");
String str5 = dateTime.toString("MM/dd/yyyy HH:mm ZZZZ");
String str6 = dateTime.toString("MM/dd/yyyy HH:mm Z");
DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
// 时间解析
DateTime dateTime2 = DateTime.parse("2012-12-21 23:22:45", format);
// 时间格式化,输出==> 2012/12/21 23:22:45 Fri
String string_u = dateTime2.toString("yyyy/MM/dd HH:mm:ss EE");
System.out.println(string_u);
// 格式化带Locale,输出==> 2012年12月21日 23:22:45 星期五
String string_c = dateTime2.toString("yyyy年MM月dd日 HH:mm:ss EE",
Locale.CHINESE);
System.out.println(string_c);
DateTime dt1 = new DateTime();// 取得当前时间
// 根据指定格式,将时间字符串转换成DateTime对象,这里的格式和上面的输出格式是一样的
DateTime dt2 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.parseDateTime("2012-12-26 03:27:39");
// 计算两个日期间隔的天数
LocalDate start = new LocalDate(2012, 12, 14);
LocalDate end = new LocalDate(2013, 01, 15);
int days = Days.daysBetween(start, end).getDays();
// 计算两个日期间隔的小时数,分钟数,秒数
// 增加日期
DateTime dateTime1 = DateTime.parse("2012-12-03");
dateTime1 = dateTime1.plusDays(30);
dateTime1 = dateTime1.plusHours(3);
dateTime1 = dateTime1.plusMinutes(3);
dateTime1 = dateTime1.plusMonths(2);
dateTime1 = dateTime1.plusSeconds(4);
dateTime1 = dateTime1.plusWeeks(5);
dateTime1 = dateTime1.plusYears(3);
// Joda-time 各种操作.....
dateTime = dateTime.plusDays(1) // 增加天
.plusYears(1)// 增加年
.plusMonths(1)// 增加月
.plusWeeks(1)// 增加星期
.minusMillis(1)// 减分钟
.minusHours(1)// 减小时
.minusSeconds(1);// 减秒数
// 判断是否闰月
DateTime dt4 = new DateTime();
org.joda.time.DateTime.Property month = dt4.monthOfYear();
System.out.println("是否闰月:" + month.isLeap());
// 取得 3秒前的时间
DateTime dt5 = dateTime1.secondOfMinute().addToCopy(-3);
dateTime1.getSecondOfMinute();// 得到整分钟后,过的秒钟数
dateTime1.getSecondOfDay();// 得到整天后,过的秒钟数
dateTime1.secondOfMinute();// 得到分钟对象,例如做闰年判断等使用
// DateTime与java.util.Date对象,当前系统TimeMillis转换
DateTime dt6 = new DateTime(new Date());
Date date = dateTime1.toDate();
DateTime dt7 = new DateTime(System.currentTimeMillis());
dateTime1.getMillis();
Calendar calendar = Calendar.getInstance();
dateTime = new DateTime(calendar);
}
}
结果:
2012/12/21 23:22:45 星期五
2012年12月21日 23:22:45 星期五
是否闰月:true