import java.text.*; //导入包
import java.util.*; //导入包
{
/**
*获取当前时间
* @author 【轰隆隆】
*不熟悉的朋友看看API和下面的实例就会慢慢明白使用方法了
*/
public static void main(String[] args)
{
System.out.println("01:"+new Date());
System.out.println("02:"+new Date().toLocaleString()); //过期!最简单,但是不推荐使用
System.out.println("03:"+DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date()));
System.out.println("04:"+DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(new Date()));
System.out.println("05:"+DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date()));
System.out.println("06:"+DateFormat.getDateInstance(DateFormat.FULL).format(new Date()));
System.out.println("07:"+DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date()));
// y,yy:用2位数字表示的"年"替换。
// yyyy:用4位数字表示的"年"替换。
// M,MM:用2位数字表示的"月"替换。
// MMM:用汉字表示的"月"替换。
// d,dd:用2位数字表示的"日"替换。
// H,HH:用2位数字表示的"时"替换。
// m,mm:用2位数字表示的"分"替换。
// s,ss:用2位数字表示的"秒"替换。
// E:用"星期"替换
// pattern中的普通ASCII字符,必须用单引号“'”字符括起来,如:
// pattern="'time':yyyy-MM-dd";
//
// 用SimpleDateFormat对象调用如下方法可以定制某时间输出格式:
// 实例:
SimpleDateFormat sdf = new SimpleDateFormat("'中华人民共和国时间':yyyy年MM月dd日 HH点mm分ss秒 E",Locale.CHINA);
System.out.println("08:"+sdf.format(new Date()));
System.out.println("09:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E").format(new Date())); //这种方式比较灵活,格式完全可以自己定
Calendar obj=Calendar.getInstance();
System.out.println("10:"+
obj.get(Calendar.YEAR)+"年"+
(obj.get(Calendar.MONTH)+1)+"月"+ //一月用0表示,所以得到的月份要加1,
obj.get(Calendar.DATE)+"日"+
obj.get(Calendar.HOUR_OF_DAY)+"时"+
obj.get(Calendar.MINUTE)+"分"+
obj.get(Calendar.SECOND)+"秒"
);
System.out.print("11:"+obj.getTime());
obj.add(Calendar.MINUTE,30);
System.out.println(" → 再过30分钟时刻:"+obj.getTime());
}
}
-----------------------------------------
执行结果:
01:Thu Aug 06 18:55:30 CST 2009
02:2009-8-6 18:55:30
03:09-8-6 下午6:55
04:2009-8-6 18:55:30
05:2009年8月6日 下午06时55分30秒
06:2009年8月6日 星期四
07:2009年8月6日 星期四 下午06时55分30秒 CST
08:中华人民共和国时间:2009年08月06日 18点55分30秒 星期四
09:2009-08-06 18:55:30 星期四
10:2009年8月6日18时55分30秒
11:Thu Aug 06 18:55:30 CST 2009 → 再过30分钟时刻:Thu Aug 06 19:25:30 CST 2009
******************************************************************************************
在Java中最常用的日期时间操作类有四个:
java.util.Date
java.sql.Date
java.sql.Time
java.sql.Timestamp
为了精确表达业务逻辑,应尽量避免使用父类(java.util.Date)的方法。java.sql包下的三个子类中特有的valueOf()静态方法与toString()方法可以精确表达业务逻辑。
系统时间与本地时间
在中国地区,如果调用以下代码,我们会得到“1970-01-01 08:00:00”的结果
- // 例1
- java.util.Date obj1 = new java.util.Date(0L);
- DateFormat dateFormat =
- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- System.out.println(dateFormat.format(obj1));
- // 打印结果:1970-01-01 08:00:00
看了JDK API之后,您可能会有这样的疑问,为什么 new java.util.Date(0L) 得到的时间不是“1970-01-01 00:00:00”而是“1970-01-01 08:00:00”呢?难到JDK API写错了?
JDK API没有错,关键是创建java.util.Date对象所使用的毫秒数是计算机系统时间,该毫秒数指的是自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数,即格林尼治标准时间(GMT)的1970-01-01 00:00:00。但是当计算机以字符串方式展示给我们看的时候,这个时间已经成为本地时间了,例如中国地区使用GMT+8时区,所以我们看到的是“1970-01-01 08:00:00”的结果!
将上述代码修改一下,我们就可以得到一个更清晰的概念。如:
- // 例2
- java.util.Date obj1 = new java.util.Date(0L);
- DateFormat dateFormat =
- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss 'GMT'Z");
- System.out.println(dateFormat.format(obj1));
- // 打印结果:1970-01-01 08:00:00 GMT+0800
上面的代码我们可以看到“1970-01-01 08:00:00 GMT+0800”的结果,证明我们所处的时区在GMT+8区。当我们改变时区时,相同的系统时间将显示不同的结果。如:
- // 例3
- java.util.Date obj1 = new java.util.Date(0L);
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+0:00"));
- DateFormat dateFormat =
- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss 'GMT'Z");
- System.out.println(dateFormat.format(obj1));
- // 打印结果:1970-01-01 00:00:00 GMT+0000
上面的代码我们可以看到“1970-01-01 00:00:00 GMT+0000”的结果,证明现在所处的时区在GMT+0区。
总之,通过以上的描述,我们可以得出这样几个结论:
- 所有计算机的系统时间概念上是统一的;
- 相同的系统时间会根据不同的时区产生不同的本地时间;
- 当时区为GMT+0时,系统时间与本地时间相同。
精确的业务逻辑
在Java中最常用的日期时间操作类中java.util.Date是其它三个类的父类。因为有这样的继承关系,所有四个类均可以通过系统时间生成对象。例如:
java.util.Date obj = new java.sql.Date(0L);
这种使用系统时间作为数据产生的日时对象在业务逻辑上可能存在问题。例如在时区GMT+0环境下运行如下代码:
- // 例4
- // 将时区设置为GMT+0
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+0:00"));
- // 使用传统构造方法生成日时对象
- java.util.Date obj1 = new java.sql.Date(0L);
- java.util.Date obj2 = new java.sql.Date(3600000L);
- // 业务逻辑相同
- System.out.println(obj1.toString()); // "1970-01-01"
- System.out.println(obj2.toString()); // "1970-01-01"
- // 语法比较不相同
- System.out.println(obj1.equals(obj2)); // false
- System.out.println(obj1.compareTo(obj2)); // -1
上述代码产生的两个对象在业务逻辑上都表示格林尼治标准时间1970-01-01(00:00:00),但在语法上二者时间却相差1小时。出现这种现象的根本原因在于使用了不精确的系统时间来反映日时对象的业务逻辑。
所谓日时对象的业务逻辑,就是以本地时间作为标准的日时信息。例如描述格林尼治标准时间(GMT+0)1970-01-01 00:00:00的精确系统时间是0L毫秒;描述北京时间(GMT+8)1970-01-01 00:00:00的精确系统时间则是-28800000L毫秒。
除java.util.Date外,其它三个类均有属于自己的业务范围,例如:
java.sql.Date的有效成份包括年、月、日
java.sql.Time的有效成份包括时、分、秒
java.sql.Timestamp的有效成份包括年、月、日、时、分、秒、纳秒(毫微秒)
由于四种日时对象内部均使用细化到毫秒的系统时间作为标准数据,势必会造成使用不同的系统时间可以表达相同业务逻辑的现象。那么通过什么方式可以将一个不精确的系统时间转换成能够准确表达业务逻辑的精确系统时间呢?
1. 使用toString()来获得日时对象的业务逻辑
在继承自java.util.Date的三个子类中,传统的构造方法以及getTime()和setTime()两个方法均使用系统时间来实现,也就注定了它们在业务逻辑上的不精确性。如果已经使用了不精确的系统时间创建java.sql包中的日时对象,则toString()是唯一个可以获取精确业务逻辑的方法。例4的代码可以说明这一点。
2. 使用valueOf()构造精确的日时对象
为了能够从本质上使用精确系统时间来准确表达日时对象中的业务逻辑,除java.util.Date外,其它三个类均提供了第二个生成对象的方法,那就是valueOf()静态方法。例如:
java.util.Date obj1 = java.sql.Date.valueOf("2000-01-01");
通过传递一个准确表达日时信息的字符串,valueOf()将产生一个由精确系统时间构成的可以反映准确业务逻辑的日时对象。同样,这种精确的日时对象也可以在语法上进行精确的比较判断,例如:
- // 例5
- // 使用valueOf()生成日时对象
- java.util.Date obj1 = java.sql.Date.valueOf("2000-01-01");
- // 使用精确系统时间生成日时对象
- java.util.Date obj2 = new java.sql.Date(obj1.getTime());
- // 业务逻辑准确
- System.out.println(obj1.toString()); // "2000-01-01"
- System.out.println(obj2.toString()); // "2000-01-01"
- // 语法比较准确
- System.out.println(obj1.equals(obj2)); // true
- System.out.println(obj1.compareTo(obj2)); // 0
通过对valueOf()和toString()的了解,我们自然会想到一种转换方式,可以将不精确的系统时间转换成可以准确表达业务逻辑的精确系统时间。如下面的工具类:
- public class DateTimeUtils {
- /**
- * 取得可以精确表达业务逻辑的日时对象
- *
- * @param obj
- * 不精确的日时对象
- * @return 精确的日时对象
- */
- public static java.sql.Date getLocalDate(java.util.Date obj) {
- if (obj == null)
- return null;
- java.sql.Date tmp = null;
- if (java.sql.Date.class.equals(obj.getClass())) {
- // 如果原始日时对象的类型是java.sql.Date
- // 则转换过程分两步:
- // 第一步,取得java.sql.Date对象的精确业务逻辑值
- String tmpString = obj.toString();
- // 第二步,生成能够精确反映业务逻辑的日时对象
- tmp = java.sql.Date.valueOf(tmpString);
- } else {
- // 如果原始日时对象的类型不是java.sql.Date
- // 则转换过程分三步:
- // 第一步,生成一个不能精确表达业务逻辑的java.sql.Date对象
- obj = new java.sql.Date(obj.getTime());
- // 第二步和第三步与处理java.sql.Date类型的原始日时对象相同
- // 第二步,取得java.sql.Date对象的精确业务逻辑值
- String tmpString = obj.toString();
- // 第三步,生成能够精确反映业务逻辑的日时对象
- tmp = java.sql.Date.valueOf(tmpString);
- }
- return tmp;
- }
- }
上述方法可以简化为:
- public static java.sql.Date getLocalDate(java.util.Date obj) {
- if (obj == null)
- return null;
- java.sql.Date tmp = null;
- if (java.sql.Date.class.equals(obj.getClass())) {
- tmp = java.sql.Date.valueOf(obj.toString());
- } else {
- tmp = getLocalDate(new java.sql.Date(obj.getTime()));
- }
- return tmp;
- }
根据相同道理,也可以得到转换java.sql.Time与java.sql.Timestamp日时对象的方法。最后的版本如下:
- public class DateTimeUtils {
- /**
- * 取得可以精确表达业务逻辑的日期对象<br>
- *
- * 如果原始日时对象的类型是java.sql.Date <br>
- * 则转换过程分两步:<br>
- * 第一步,取得java.sql.Date对象的精确业务逻辑值 <br>
- * 第二步,生成能够精确反映业务逻辑的日时对象<br>
- *
- * 如果原始日时对象的类型不是java.sql.Date<br>
- * 则转换过程分三步:<br>
- * 第一步,生成一个不能精确表达业务逻辑的java.sql.Date对象<br>
- * 第二步和第三步与处理java.sql.Date类型的原始日时对象相同
- *
- * @param obj
- * 不精确的日期对象
- * @return 精确的日时对象
- */
- public static java.sql.Date getLocalDate(java.util.Date obj) {
- if (obj == null)
- return null;
- java.sql.Date tmp = null;
- if (java.sql.Date.class.equals(obj.getClass())) {
- tmp = java.sql.Date.valueOf(obj.toString());
- } else {
- tmp = getLocalDate(new java.sql.Date(obj.getTime()));
- }
- return tmp;
- }
- public static java.sql.Time getLocalTime(java.util.Date obj) {
- if (obj == null)
- return null;
- java.sql.Time tmp = null;
- if (java.sql.Time.class.equals(obj.getClass())) {
- tmp = java.sql.Time.valueOf(obj.toString());
- } else {
- tmp = getLocalTime(new java.sql.Time(obj.getTime()));
- }
- return tmp;
- }
- public static java.sql.Timestamp getLocalTimestamp(java.util.Date obj) {
- if (obj == null)
- return null;
- java.sql.Timestamp tmp = null;
- if (java.sql.Timestamp.class.equals(obj.getClass())) {
- tmp = java.sql.Timestamp.valueOf(obj.toString());
- } else {
- tmp = getLocalTimestamp(new java.sql.Timestamp(obj.getTime()));
- }
- return tmp;
- }
- }
我们可以这样使用:
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00"));
- // 使用三种方法产生的日时对象
- java.util.Date obj1 = java.sql.Date.valueOf("1970-01-01");
- java.util.Date obj2 = new java.util.Date(0L);
- java.util.Date obj3 = new java.sql.Date(0L);
- // 通过相同的方式转换
- obj1 = DateTimeUtils.getLocalDate(obj1);
- obj2 = DateTimeUtils.getLocalDate(obj2);
- obj3 = DateTimeUtils.getLocalDate(obj3);
- // 得到了相同的精确业务逻辑
- System.out.println(obj1.getTime());// -28800000
- System.out.println(obj2.getTime());// -28800000
- System.out.println(obj3.getTime());// -28800000
- // 业务逻辑相同
- System.out.println(obj1.toString()); // 1970-01-01
- System.out.println(obj2.toString()); // 1970-01-01
- // 语法比较准确
- System.out.println(obj1.equals(obj2)); // true
- System.out.println(obj1.compareTo(obj2)); // 0
也可以在不同类型的日时对象之间转换,如:
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00"));
- java.util.Date obj1 =
- java.sql.Timestamp.valueOf("2000-01-01 01:00:00");
- // 将java.sql.Timestamp转换成java.sql.Time
- // 日期信息变成 1970-01-01
- // 时间信息保留
- java.util.Date obj2 = DateTimeUtils.getLocalTime(obj1);
- System.out.println(obj2.toString());// 01:00:00
- System.out.println(obj2.getTime());// -25200000
- // 将java.sql.Time转换成java.sql.Date
- // 日期信息保留
- // 时间信息变成 00:00:00
- java.util.Date obj3 = DateTimeUtils.getLocalDate(obj2);
- System.out.println(obj3.toString());// 1970-01-01
- System.out.println(obj3.getTime());// -28800000