由于種種原因邑雅,簡(jiǎn)書等第三方平臺(tái)博客不再保證能夠同步更新片橡,歡迎移步 GitHub:https://github.com/kingcos/Perspective/。謝謝淮野!
注:
由于目前個(gè)人對(duì) Java 的理解應(yīng)用僅限于皮毛捧书,故若有不妥吹泡,望及時(shí)告知,會(huì)及時(shí)修正经瓷。
- Info:
- JDK 1.8
- Eclipse EE neon
- Oracle 10g XE
前言
暑假學(xué)校培訓(xùn)爆哑,因此整理一下之前在學(xué)習(xí)過(guò)程中比較困惑的地方。方便未來(lái)查閱了嚎,也使自己能夠更深入了解 Java泪漂。這次來(lái)說(shuō)一說(shuō)日期與時(shí)間,因?yàn)閿?shù)據(jù)庫(kù)和 Java 本身都有許多存儲(chǔ)日期或時(shí)間的類型歪泳,那么如何選擇合適的類型萝勤,并正確的存入以及讀取便很重要。網(wǎng)上的資料也有些參差不齊呐伞,因此我個(gè)人整理于此敌卓,并附上可以實(shí)際運(yùn)行的代碼。
Java 中的日期與時(shí)間類型簡(jiǎn)介
子父類關(guān)系
java.lang.Object | java.lang.Object | java.lang.Object |
---|---|---|
java.util.Date | java.util.Date | java.util.Date |
- | java.sql.Timestamp | java.sql.Date |
精度
類型 | java.util.Date |
java.sql.Timestamp |
java.sql.Date |
---|---|---|---|
精度 | 年 月 日 時(shí) 分 秒 | 年 月 日 時(shí) 分 秒 毫微秒 | 年 月 日 |
初始化
public class TestInitTime {
public static void main(String[] args) {
java.util.Date utilDate_1 = new java.util.Date();
java.util.Date utilDate_2 = new java.util.Date(System.currentTimeMillis());
java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(System.currentTimeMillis());
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());
System.out.println("utilDate_1 =\t" + utilDate_1);
System.out.println("utilDate_2 =\t" + utilDate_2);
System.out.println("sqlTimestamp =\t" + sqlTimestamp);
System.out.println("sqlDate =\t" + sqlDate);
}
}
// Console:
// utilDate_1 = Sun Jul 17 09:26:07 CST 2016
// utilDate_2 = Sun Jul 17 09:26:07 CST 2016
// sqlTimestamp = 2016-07-17 09:26:07.342
// sqlDate = 2016-07-17
上述的初始化均使用了各自未過(guò)時(shí)的構(gòu)造函數(shù)伶氢,輸出打印后趟径,可以看到明顯的精度區(qū)別。
PS
System.currentTimeMillis()
: 返回以毫秒為單位的當(dāng)前時(shí)間癣防。
CST
代表 China Standard Time(中國(guó)標(biāo)準(zhǔn)時(shí)間蜗巧,即東八區(qū),北京時(shí)間)
多種日期類型轉(zhuǎn)換
String
-> 時(shí)間
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class TransformDateOrTime {
public static void main(String[] args) {
String date = "2016-7-17 14:30:05";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
java.util.Date utilDate = null;
try {
utilDate = dateFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("utilDate: " + utilDate);
java.sql.Timestamp sqlTimestamp = java.sql.Timestamp.valueOf("2016-7-17 14:30:05");
java.sql.Date sqlDate = java.sql.Date.valueOf("2016-7-17");
System.out.println("sqlTimestamp: " + sqlTimestamp);
System.out.println("sqlDate: " + sqlDate);
}
}
// Console:
// utilDate: Sun Jul 17 14:30:05 CST 2016
// sqlTimestamp: 2016-07-17 14:30:05.0
// sqlDate: 2016-07-17
java.util.Date
與 java.sql.Timestamp
getTime()
: 返回調(diào)用對(duì)象表示的自 1970 年 1 月 1 日 00:00:00 GMT 以來(lái)的毫秒數(shù)蕾盯。
// java.util.Date -> java.sql.Timestamp
java.util.Date utilDate_1 = null;
try {
utilDate_1 = dateFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
java.sql.Timestamp sqlTimestamp_1 = new java.sql.Timestamp(utilDate_1.getTime());
System.out.println(utilDate_1 + " 轉(zhuǎn)換為 " + sqlTimestamp_1);
// java.util.Date <- java.sql.Timestamp (精度丟失)
java.sql.Timestamp sqlTimestamp_2 = new java.sql.Timestamp(System.currentTimeMillis());
java.util.Date utilDate_2 = new java.util.Date(sqlTimestamp_2.getTime());
System.out.println(sqlTimestamp_2 + " 轉(zhuǎn)換為 " + utilDate_2);
// Console:
// Sun Jul 17 14:30:05 CST 2016 轉(zhuǎn)換為 2016-07-17 14:30:05.0
// 2016-07-17 10:09:38.736 轉(zhuǎn)換為 Sun Jul 17 10:09:38 CST 2016
java.util.Date
與 java.sql.Date
// java.util.Date -> java.sql.Date
java.sql.Date sqlDate_1 = new java.sql.Date(utilDate_1.getTime());
System.out.println(utilDate_1 + " 轉(zhuǎn)換為 " + sqlDate_1);
// java.util.Date <- java.sql.Date
java.sql.Date sqlDate_2 = new java.sql.Date(System.currentTimeMillis());
java.util.Date utilDate_3 = new java.util.Date(sqlDate_2.getTime());
System.out.println(sqlDate_2 + " 轉(zhuǎn)換為 " + utilDate_3);
// Console:
// Sun Jul 17 14:30:05 CST 2016 轉(zhuǎn)換為 2016-07-17
// 2016-07-17 轉(zhuǎn)換為 Sun Jul 17 11:14:15 CST 2016
如何選擇幕屹?
在上面最后由 java.sql.Date
轉(zhuǎn)換為 java.util.Date
中,雖然我們之前查到 java.sql.Date
只能保存年月日级遭,但是這里卻可以轉(zhuǎn)換為帶有時(shí)分秒的 java.util.Date
望拖。而 java.sql.Date
中的 getHours()
,getMinutes()
挫鸽,getSeconds()
(也包括對(duì)應(yīng)的 setter)方法均已過(guò)時(shí)说敏,如果調(diào)用會(huì)有 java.lang.IllegalArgumentException
異常。所以 java.sql.Date
只是屏蔽了時(shí)間中的時(shí)分秒丢郊,為了和數(shù)據(jù)庫(kù)中的 DATE
類型匹配盔沫,查看其源代碼就可以得知,java.sql.Date
繼承但沒有重寫 getTime()
方法枫匾,而本身的 public Date(long date)
構(gòu)造方法也是調(diào)用了父類的構(gòu)造方法迅诬。
而與此不同的是 java.sql.Timestamp
,其對(duì)父類做了擴(kuò)充婿牍,通過(guò)查看其源代碼侈贷,我們可以發(fā)現(xiàn),其 getTime()
中增加了納秒(1s = 1E9nanos),而且單獨(dú)增加了 getNanos()
方法俏蛮。
因此 java.sql.Date
只是屏蔽年月日撑蚌,而不是移除,而 java.sql.Timestamp
對(duì)父類進(jìn)行了擴(kuò)充搏屑。在下面的 Demo 中争涌,會(huì)實(shí)際操作數(shù)據(jù)庫(kù),這樣一存一取就可以將其特點(diǎn)展現(xiàn)辣恋。
在這里以 Oracle 數(shù)據(jù)庫(kù)為例亮垫,Oracle 中有兩種主要日期與時(shí)間類型,DATE
以及 TIMESTAMP
伟骨。
DATE
: 僅存 年 月 日
TIMESTAMP
: 保存 年 月 日 時(shí) 分 秒 納秒
所以對(duì)應(yīng) Java 中饮潦,我們就應(yīng)該在保存合適精度的時(shí)間下,選擇合適的類型携狭。Java 中的 java.util.Date
更為靈活继蜡,我們可以在恰當(dāng)?shù)臅r(shí)候?qū)⑵滢D(zhuǎn)為合適的類型存入數(shù)據(jù)庫(kù),或者在取出時(shí)轉(zhuǎn)為該類型逛腿。
Demo
SQL
-- 建表
DROP TABLE T_TIME;
CREATE TABLE T_TIME (
ID NUMBER(10,0) PRIMARY KEY,
date_1 DATE,
timestamp_1 TIMESTAMP,
date_2 DATE,
timestamp_2 TIMESTAMP
);
-- 創(chuàng)建自增序列
drop sequence time_id;
create sequence time_id
increment by 1
start with 1
nomaxvalue
nominvalue
nocache
實(shí)體類:TimeEntity.java
public class TimeEntity {
private int id;
private java.util.Date date_1;
private java.sql.Date date_2;
private java.util.Date timestamp_1;
private java.sql.Timestamp timestamp_2;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public java.util.Date getDate_1() {
return date_1;
}
public void setDate_1(java.util.Date date_1) {
this.date_1 = date_1;
}
public java.sql.Date getDate_2() {
return date_2;
}
public void setDate_2(java.sql.Date date_2) {
this.date_2 = date_2;
}
public java.util.Date getTimestamp_1() {
return timestamp_1;
}
public void setTimestamp_1(java.util.Date timestamp_1) {
this.timestamp_1 = timestamp_1;
}
public java.sql.Timestamp getTimestamp_2() {
return timestamp_2;
}
public void setTimestamp_2(java.sql.Timestamp timestamp_2) {
this.timestamp_2 = timestamp_2;
}
public String toString() {
return "TimeEntity [id=" + id + ", date_1=" + date_1 + ", date_2=" + date_2 + ", timestamp_1=" + timestamp_1
+ ", timestamp_2=" + timestamp_2 + "]";
}
}
測(cè)試類:TestTimeDateType.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class TestTimeDateType {
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// url 中的地址要替換為自己數(shù)據(jù)的地址
String url = "jdbc:oracle:thin:@localhost:1521:XE";
// 數(shù)據(jù)庫(kù)用戶名及密碼需要設(shè)置為自己的
String user = "demo";
String password = "123456";
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = DriverManager.getConnection(url, user, password);
String sql = "insert into t_time values (time_id.nextVal, ?, ?, ?, ?)";
ps = connection.prepareStatement(sql);
ps = setAll(ps);
ps.executeUpdate();
// 這里我們只運(yùn)行一次稀并,為方便起見,因此僅查詢 id 為 1 的記錄
sql = "select * from t_time where id = 1";
ps = connection.prepareStatement(sql);
TimeEntity te = new TimeEntity();
rs = ps.executeQuery();
while (rs.next()) {
te.setId(rs.getInt(1));
te.setDate_1(rs.getDate(2));
te.setTimestamp_1(rs.getTimestamp(3));
te.setDate_2(rs.getDate(4));
te.setTimestamp_2(rs.getTimestamp(5));
}
System.out.println(te);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
ps.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
static PreparedStatement setAll(PreparedStatement ps) throws Exception {
ps.setDate(1, returnSqlDateWithSqlDate());
ps.setTimestamp(2, returnTimestampWithTimestamp());
ps.setDate(3, new java.sql.Date(returnSqlDateWithUtilDate().getTime()));
ps.setTimestamp(4,new java.sql.Timestamp(returnTimestampWithUtilDate().getTime()));
return ps;
}
static java.sql.Date returnSqlDateWithSqlDate() {
java.sql.Date sqlDate = java.sql.Date.valueOf("2012-2-2");
return sqlDate;
}
static java.sql.Timestamp returnTimestampWithTimestamp() {
java.sql.Timestamp timestamp = java.sql.Timestamp.valueOf("2015-5-5 5:55:55.555");
return timestamp;
}
static java.util.Date returnSqlDateWithUtilDate() throws Exception {
String date = "2013-3-3 3:33:33";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
java.util.Date utilDate = dateFormat.parse(date);
return utilDate;
}
static java.util.Date returnTimestampWithUtilDate() throws Exception {
String date = "2016-6-6 6:6:6";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
java.util.Date utilDate = dateFormat.parse(date);
return utilDate;
}
}
// Console:
// TimeEntity [id=1, date_1=2012-02-02, date_2=2013-03-03, timestamp_1=2015-05-05 05:55:55.555, timestamp_2=2016-06-06 06:06:06.0]
小結(jié)
從上面實(shí)例中单默,就可以基本清楚這幾個(gè)類型的差別碘举,以及其中的轉(zhuǎn)換,因此在實(shí)際使用中便可以通過(guò)需要的不同精度搁廓,來(lái)確定所選的類型即可引颈。
java.util.Date 與 Calendar
在 java.util.Date
中有許多過(guò)時(shí)方法,查看其注釋枚抵,有許多都被 Calendar
所代替。由于在現(xiàn)實(shí)中明场,java.util.Date
不再能勝任國(guó)際化的操作汽摹,因此建議使用 Calendar
進(jìn)行日期與時(shí)間處理。由于 Calendar
類是抽象類苦锨,且 Calendar
類的構(gòu)造方法是 protected
的逼泣,所以無(wú)法使用Calendar類的構(gòu)造方法來(lái)創(chuàng)建對(duì)象,但提供了 getInstance()
靜態(tài)方法來(lái)創(chuàng)建對(duì)象舟舒。
轉(zhuǎn)化
測(cè)試類:TestCalendar.java
import java.util.Calendar;
import java.util.Date;
public class TestCalendar {
public static void main(String[] args) {
// Calendar 轉(zhuǎn)化為 Date
Calendar calendar_1 = Calendar.getInstance();
System.out.println(calendar_1.getTimeInMillis());
Date date_1 = calendar_1.getTime();
System.out.println("Calendar -> Date" + date_1);
// Date 轉(zhuǎn)化為 Calendar
Date date_2 = new Date();
Calendar calendar_2 = Calendar.getInstance();
calendar_2.setTime(date_2);
System.out.println("Date -> Calendar " + calendar_2);
}
}
// Console:
1468741779943
Calendar -> DateSun Jul 17 15:49:39 CST 2016
Date -> Calendar java.util.GregorianCalendar[time=1468741779978,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2016,MONTH=6,WEEK_OF_YEAR=30,WEEK_OF_MONTH=4,DAY_OF_MONTH=17,DAY_OF_YEAR=199,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=3,HOUR_OF_DAY=15,MINUTE=49,SECOND=39,MILLISECOND=978,ZONE_OFFSET=28800000,DST_OFFSET=0]