Java高级日期概念

如果你的Java程序向处在不同时区或者不同国家的用户显示时间和日期,那么你需要了解Java日期类的一些更加高级的方面。在“使用JavaDate和Calendar类计算,定制和解析日期”的这篇文章里我们提供了对日期,日期数据的格式化,日期数据的解析和日期计算的一个概览。对于这些概念的深入的理解对于讨论更高级的诸如时区,国际化标准格式和SQL日期数据等这些有关日期的问题是关键的。

我们在本文中讨论的类将包含java.text.DateFormat,以及java.util.TimeZone和java.util.Locate。我们还将讨论如何使用一个java.util.Date的子类java.sql.Date来从Oracle数据库里提取和保存Java日期数据。

地区的问题
在我们国际化我们的日期数据以前,我们需要进一步的学习Locale类,也就是java.util.Locale。Locale类的一个实例通常包含国家和语言信息。其中的每一个部分都是由基于国际标准化组织(ISO)制定的国家代码ISO-3166和语言代码ISO-639的两字符的字符串构成的。

让我们来创建两个Locale实例,其中一个对应的是美国英语而另一个对应的是法国法语。见表A。

表A


importjava.util.Locale;

publicclassDateExample6{

publicstaticvoidmain(String[]args){
//CreatealocalefortheEnglishlanguageintheUS.
LocalelocaleEN=newLocale("en","US");

System.out.println("DisplayName:"+
localeEN.getDisplayName());
System.out.println("Country:"+localeEN.getCountry());
System.out.println("Language:"+localeEN.getLanguage());

//CreatealocalefortheFrenchlanguageinFrance.
LocalelocaleFR=newLocale("fr","FR");
System.out.println("/nDisplayName:"+
localeFR.getDisplayName());
System.out.println("Country:"+localeFR.getCountry());
System.out.println("Language:"+localeFR.getLanguage());

//DisplaytheEnglish-USlocaleinFrench
System.out.println("/nenDisplayNameinFrench:"+
localeEN.getDisplayName(localeFR));
}
}



在这个例子中,我们用getDisplayName方法来显示Locale的一个更易读的文本。你还应该注意到我们在最后一次调用getDisplayName的时候,我们在对EnglishLocale对象调用getDisplayName的时候同时传递了FrenchLocale对象。这允许我们选择显示Locale对象所用的语言,让我们用英语显示法语Locale对象的内容。下面是这个例子的输出:

DisplayName:English(UnitedStates)
Country:US
Language:en
DisplayName:French(France)
Country:FR
Language:fr
enDisplayNameinFrench:anglais(états-Unis)

多个地域的日期格式化
使用java.util.Locale和java.text.DateFormat类我们就能够格式化日期数据把它显示给在另一个地域的用户,比方法国。表B中的例子为英语和法语各创建了一个完整的日期格式化器。

表B


importjava.util.Locale;
importjava.util.Date;
importjava.text.DateFormat;

publicclassDateExample7{

publicstaticvoidmain(String[]args){
//Getthecurrentsystemdateandtime.
Datedate=newDate();

//GetaFrancelocaleusingaLocaleconstant.
LocalelocaleFR=Locale.FRANCE;

//CreateanEnglish/USlocaleusingtheconstructor.
LocalelocaleEN=newLocale("en","US");

//GetadatetimeformatterfordisplayinFrance.
DateFormatfullDateFormatFR=
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL,
localeFR);

//GetadatetimeformatterfordisplayintheU.S.
DateFormatfullDateFormatEN=
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL,
localeEN);

System.out.println("Locale:"+localeFR.getDisplayName());
System.out.println(fullDateFormatFR.format(date));
System.out.println("Locale:"+localeEN.getDisplayName());
System.out.println(fullDateFormatEN.format(date));
}
}



这个例子的输出是:

Locale:French(France)
vendredi5octobre200121h05GMT-04:00
Locale:English(UnitedStates)
Friday,October5,20019:05:54PMEDT

注意这个输出包括了时区信息:GMT-04:00和PMEDT。这个时区是人系统的时区设置里捕获的。你可以看见,日期是以那个地区的用户期望的格式显示的。让我们等一下来看看时区的概念

时区
TimeZone类,即java.util.TimeZone类的实例包含了一个与格林威治标准时间(GMT)相比较得出的以微秒为单位的时区偏移量,而且它还处理夏令时
。要获得一个所有支持的进区的列表,你可以使用方法TimeZone.getAvailableIDs,它将返回一个包含了所有进区ID的字符串数组。要知道关于TimeZone类的更多细节,可以参看Sun公司的Web站点。

为了演示这个概念,我们将创建三个时区对象。第一个对象将使用getDefault从系统时钟返回时区数据;第二个和第三个对象将传入一个时区字符串ID。见表C中的代码。

表C


importjava.util.TimeZone;
importjava.util.Date;
importjava.text.DateFormat;
importjava.util.Locale;

publicclassDateExample8{

publicstaticvoidmain(String[]args){
//Getthesystemtimezone.
TimeZonetimeZoneFL=TimeZone.getDefault();
System.out.println("/n"+timeZoneFL.getDisplayName());
System.out.println("RawOffset:"+timeZoneFL.getRawOffset());
System.out.println("Usesdaylightsaving:"+timeZoneFL.useDaylightTime());

TimeZonetimeZoneLondon=TimeZone.getTimeZone("Europe/London");
System.out.println("/n"+timeZoneLondon.getDisplayName());
System.out.println("RawOffset:"+timeZoneLondon.getRawOffset());
System.out.println("Usesdaylightsaving:"+timeZoneLondon.useDaylightTime());

燭imeZonetimeZoneParis=TimeZone.getTimeZone("Europe/Paris");
System.out.println("/n"+timeZoneParis.getDisplayName());
System.out.println("RawOffset:"+timeZoneParis.getRawOffset());
System.out.println("Usesdaylightsaving:"+timeZoneParis.useDaylightTime());
}
}



其输出如下:

EasternStandardTime
RawOffset:-18000000
Usesdaylightsaving:true
GMT+00:00
RawOffset:0
Usesdaylightsaving:true

CentralEuropeanStandardTime
RawOffset:3600000
Usesdaylightsaving:true

正如你所看见的,TimeZone对象给我们的是原始的偏移量,也就是与GMT相差的微秒数,而且还会告诉我们这个时区是否使用夏令时。有个这个信息,我们就能够继续将时区对象和日期格式化器结合在一起在其它的时区和其它的语言显示时间了。

国际化的时期显示了时区转换
让我们来看一个结合了国际化显示,时区和日期格式化的例子。表D为一个在迈阿密和巴黎拥有办公室的公司显示了当前的完整日期和时间。对于迈阿密的办公室,我们将在每个办公室里用英语显示完整的日期和时间。对于巴黎的办公室,我们将用法语显示完整的当前日期和时间。

表D


importjava.util.TimeZone;
importjava.util.Date;
importjava.util.Locale;
importjava.text.DateFormat;

publicclassDateExample9{

publicstaticvoidmain(String[]args){
LocalelocaleEN=Locale.US;
LocalelocaleFrance=Locale.FRANCE;

TimeZonetimeZoneMiami=TimeZone.getDefault();
TimeZonetimeZoneParis=TimeZone.getTimeZone("Europe/Paris");

DateFormatdateFormatter=DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL,
localeEN);
DateFormatdateFormatterParis=DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL,
localeFrance);

DatecurDate=newDate();

System.out.println("DisplayforMiamioffice.");
//PrinttheMiamitimezonedisplaynameinEnglish
System.out.println(timeZoneMiami.getDisplayName(localeEN));
//SetthetimezoneofthedateFormattertoMiamitimezone.
dateFormatter.setTimeZone(timeZoneMiami);
//Printtheformatteddate.
System.out.println(dateFormatter.format(curDate));

//SetthetimezoneofthedateformattertoParistimezone.
dateFormatter.setTimeZone(timeZoneParis);
//PrinttheParistimezonedisplaynameinEnglish.
System.out.println(timeZoneParis.getDisplayName(localeEN));
//PrinttheParistimeinenglish.
System.out.println(dateFormatter.format(curDate));

System.out.println("/nDisplayforParisoffice.");
//PrinttheMiamitimezonedisplaynameinFrench
System.out.println(timeZoneMiami.getDisplayName(localeFrance));
//Setthetimezoneofthe
//dateFormatterParistoMiamitimezone.
dateFormatterParis.setTimeZone(timeZoneMiami);
//PrinttheformatteddateinFrench.
燬ystem.out.println(dateFormatterParis.format(curDate));

//SetthetimezoneofthedateformattertoParistimezone.
dateFormatterParis.setTimeZone(timeZoneParis);
//PrinttheParistimezonedisplaynameinFrench.
System.out.println(timeZoneParis.getDisplayName(localeFrance));
//PrinttheParistimeinFrench.
System.out.println(dateFormatterParis.format(curDate));
}
}



这个例子的输出是:

DisplayforMiamioffice.
EasternStandardTime
Friday,October5,200110:28:02PMEDT
CentralEuropeanStandardTime
Saturday,October6,20014:28:02AMCEST
DisplayforParisoffice.
GMT-05:00
vendredi5octobre200122h28GMT-04:00
GMT+01:00
samedi6octobre200104h28GMT+02:00
在一个SQL数据库中保存和提取日期数据我们将要使用的下一个类是java.sql.Date,它是java.util.Date的子类但它使用了Java数据库连接(JDBC)方法
。让我们来看一个简单的只有一个表单--LAST_ACCESS的ORACLE数据库,它是用下面的SQL创建的:
createtableLAST_ACCESS(
LAST_HITdate
);

这个表单只有一个记录,用下面的插入语句创建:
insertintoLAST_ACCESSvalues(Sysdate);

表E演示了如何修改和提取LAST_HIT数据库域。

表E


importjava.sql.*;
importjava.text.DateFormat;
importjava.util.Date;

publicclassDateExample10{

publicstaticvoidmain(String[]args){
//Getafulldateformatter.
DateFormatdateFormatter=DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL);
//Getthesystemdateandtime.
java.util.DateutilDate=newDate();
//Convertittojava.sql.Date
java.sql.Datedate=newjava.sql.Date(utilDate.getTime());
//Displaythedatebeforestoring.
System.out.println(dateFormatter.format(date));
//Savethedatetothedatabase.
setLastHit(date);
//Getthedatefromthedatabase.
DatedateFromDB=getLastHit();
//Displaythedatefromthedatabase.
System.out.println(dateFormatter.format(dateFromDB));
}

publicstaticvoidsetLastHit(java.sql.Datedate){

try{
//Loadtheclass.
Class.forName("oracle.jdbc.driver.OracleDriver");
//Getaconnection.
燙onnectionconnection=DriverManager.getConnection(
//DatabaseURL
"jdbc:oracle:thin:@localhost:1521:buzz2",
"web_site",//Username
"web_site");//Password
try{
/Getapreparedstatementfromtheconnection
//specifyingtheupdateSQL.
PreparedStatementps=connection.prepareStatement(
"updateLAST_ACCESSsetLAST_HIT=");
try{
/setthedatelettingJDBCtotheworkof
//formattingtheSQLappropriately.
ps.setDate(1,date);
//Executetheupdatestatement.
intiRowsUpdated=ps.executeUpdate();
System.out.println("Rowsupdated:"+iRowsUpdated);
}finally{
ps.close();
}
}finally{
connection.close();
}
}catch(Exceptionex){
System.out.println("Error:"+ex.getMessage());
}
}

publicstaticjava.sql.DategetLastHit(){
java.sql.DatereturnDate=null;

try{
//Loadthedriverclass.
Class.forName("oracle.jdbc.driver.OracleDriver");
//Gettheconnection.
Connectionconnection=DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:buzz2",
"web_site","web_site");
try{
/Getthepreparedstatementspecifyingthe
//selectSQL.
PreparedStatementps=connection.prepareStatement(
"selectLAST_HITfromLAST_ACCESS");
try{
//ExecutetheSQLandgettheResultSetobject.
ResultSetrs=ps.executeQuery();
try{
//Retreivetherecord.
if(rselse{
燬ystem.out.println("Didnotgetlasthit.");
}
}
finally{
rs.close();
}

}finally{
ps.close();

}finally{
connection.close();
}
}catch(Exceptionex){
System.out.println("Error:"+ex.getMessage());
}
returnreturnDate;
}

}



这个例子的输出如下:

Friday,October5,200110:42:34PMEDT
Rowsupdated:1
Successfullyretrievedlasthit.
Friday,October5,200112:00:00AMEDT

虽然这个例子没有为保存和提取日期数据提供性能上优良的方法,但它确实示范了如何为一条更新和删除语句将Java日期数据转换成SQL日期数据。从一个java.util.Date对象设置Oracledate数据域的过程是由以下的语句处理的:
ps.setDate(1,date);

它是我们预定义语句接口java.sql.PreparedStatement.setDate的一个方法。

这行代码出现在我们的setLastHit方法里。它将Java以微秒为单位的长整型日期值转换成ORACLE的SQL日期格式。当我们能够在getLastHit方法里用java.sql.PreparedStatement.getDate从数据库取得日期数据的时候这种转换就能够完成。

你还应该注意到只有日期被设置了。小时,分钟,秒,和微秒都没有包括在从Java日期数据到SQL日期数据的转换过程中。

结论
一旦你掌握了这些概念,你就应该能够基于系统时间或者一个输入的时间创建日期对象了。另外,你还应该能够使用标准和定制的格式化过程格式化日期数据,将文本的日期数据解析成日期对象,并以多种语言和多种时区显示一个日期数据。最后,你将能够在一个SQL数据库里保存和提取日期值

你可能感兴趣的:(java)