JAVA面试题解惑系列(七)——日期和时间的处理

JAVA面试题解惑系列(七)——日期和时间的处理


日期和时间的处理不仅在面试题中会考到,在实际项目开发中也是我们经常需要处理的问题,似乎没有哪个项目可以避开它们,我们常常在处理用户的出生年月日、注册日期,订单的创建时间等属性时用到,由此可见其重要性。 

java.util.Date类 

提到日期和时间,我想大家最先想到应该是java.util.Date类吧。Date类可以精确到毫秒数,这个毫秒数是相对于格林威治标准时间“1970-01-01 00:00:00.000 GMT”的差值。那么,什么是格林威治标准时间呢?要回答这个问题,我们需要先来了解一下世界时间标准方面的知识。 

世界时间标准主要有UTC,即Coordinated Universal Time(中文名译作世界协调时间、世界统一时间或世界标准时间),以及GMT,即Greenwich Mean Time(中文名译作格林威治标准时间或格林威治平均时间)两种。严格来讲,UTC比GMT更加精确一些,不过它们的差值不会超过0.9秒,如果超过了,将会为UTC增加闰秒以与GMT,也就是地球自转周期保持一致。所以在日常使用中,我们可以把UTC和GMT一样看待。 

日期和时间的表示是与我们所处的时区相关联的,如果我们不指定时区,那么它们将以系统默认的时区来显示。我们先来看看如何创建日期对象。Date类有很多个构造器方法,大部分已经不被赞成使用了(Deprecated),不过还剩下两个可以使用的: 

Java代码 复制代码
  1. public Date() {   
  2.     this(System.currentTimeMillis());   
  3. }   
  4.   
  5. public Date(long date) {   
  6.     //other code   
  7. }  
[java] view plaincopy
  1. public Date() {  
  2.     this(System.currentTimeMillis());  
  3. }  
  4.   
  5. public Date(long date) {  
  6.     //other code  
  7. }  

第一个是无参构造器,使用系统当前时间的毫秒数来创建Date对象,它调用了java.lang.System类的currentTimeMillis()来取得系统的当前时间的毫秒值。这是个本地方法,它的定义如下: 
Java代码 复制代码
  1. public static native long currentTimeMillis();  
[java] view plaincopy
  1. public static native long currentTimeMillis();  

第二个构造器是根据给定的毫秒数来创建一个与之对应的Date对象,这个毫秒数决定了被创建对象的年、月、日、时、分、秒属性的值。 

我们来看看日期和时间在默认时区下的显示效果: 
Java代码 复制代码
  1. import java.util.Date;   
  2.   
  3. public class DateTest {   
  4.     public static void main(String[] args) {   
  5.         Date d = new Date();   
  6.         // 在默认时区下输出日期和时间值   
  7.         System.out.println(d);   
  8.     }   
  9. }  
[java] view plaincopy
  1. import java.util.Date;  
  2.   
  3. public class DateTest {  
  4.     public static void main(String[] args) {  
  5.         Date d = new Date();  
  6.         // 在默认时区下输出日期和时间值  
  7.         System.out.println(d);  
  8.     }  
  9. }  

运行结果: 
  • Tue Jul 22 10:44:47 CST 2008


大家应该注意到了年份前的“CST”标识,它是China Standard Time的缩写,指的是中国标准时间,也就是我们常说的北京时间。它与UTC的时差是UTC+8:00,就是说北京时间比世界标准时间早8个小时,如果世界标准时间是早上1点,北京时间就是早上9点。一般情况下我们不需要关心时区问题。 

在创建完Date对象之后,我们可以通过调用getTime()方法来获得该对象的毫秒数值,调用setTime(long time)方法来设置它的毫秒数值,从而影响年、月、日、时、分、秒这些属性。这两个方法的定义如下:

Java代码 复制代码
  1. public long getTime() {   
  2.     //other code   
  3. }   
  4.   
  5. public void setTime(long time) {   
  6.     //other code   
  7. }  
[java] view plaincopy
  1. public long getTime() {  
  2.     //other code  
  3. }  
  4.   
  5. public void setTime(long time) {  
  6.     //other code  
  7. }  


既然Date对象可以表示盛相对于“1970-01-01 00:00:00.000 GMT”的毫秒数,我们自然可以通过这个值来比较两个日期的大小了,不过对于日期来讲,前后的说法应该更为恰当。而Date类已经为我们提供了这样的方法:

Java代码 复制代码
  1. public boolean before(Date when) {   
  2.     //other code   
  3. }   
  4.   
  5. public boolean after(Date when) {   
  6.     //other code   
  7. }   
  8.   
  9. public int compareTo(Date anotherDate) {   
  10.     //other code   
  11. }  
[java] view plaincopy
  1. public boolean before(Date when) {  
  2.     //other code  
  3. }  
  4.   
  5. public boolean after(Date when) {  
  6.     //other code  
  7. }  
  8.   
  9. public int compareTo(Date anotherDate) {  
  10.     //other code  
  11. }  


before()是判断当前日期是否在参数日期之前,即当前日期毫秒数小于参数日期毫秒数;after()是判断当前日期是否在参数日期之后,即当前日期毫秒数大于参数日期毫秒数。而compareTo()是将当前日期与参数日期比较后,返回一个int型值,它的返回值有三种可能:-1、0和1。如果返回-1则表示当前日期在参数日期之前;如果返回0则表示两个日期是同一时刻;返回1则表示当前日期在参数日期之后。虽然我们可以用compareTo()方法来比较两个Date对象,但是它的设计实际是另有用途的,我们在后面的章节将会讲到。 

下面我们就用一个示例来检验一下以上方法的用法:

Java代码 复制代码
  1. import java.util.Date;   
  2.   
  3. public class DateTest {   
  4.     public static void main(String[] args) {   
  5.         // 2008-08-08 20:00:00对应的毫秒数   
  6.         long t2008 = 1218196800000L;   
  7.         // 1900-01-01 20:00:00对应的毫秒数   
  8.         long t1900 = -2208945952000L;   
  9.   
  10.         // 指定毫秒数创建Date对象   
  11.         Date d2008 = new Date(t2008);   
  12.         // 使用系统默认时间创建Date对象   
  13.         Date d1900 = new Date();   
  14.         // 通过设置毫秒数改变日期和时间   
  15.         d1900.setTime(t1900);   
  16.   
  17.         System.out.println("调用方法:d1900.before(d2008)");   
  18.         System.out   
  19.                 .print("比较结果:/"1900-01-01 20:00:00/"在/"2008-08-08 20:00:00/"");   
  20.         // 使用before()方法比较   
  21.         if (d1900.before(d2008)) {   
  22.             System.out.println("之前");   
  23.         } else {   
  24.             System.out.println("之后");   
  25.         }   
  26.            
  27.         System.out.println();   
  28.            
  29.         System.out.println("调用方法:d2008.after(d1900)");   
  30.         System.out   
  31.                 .print("比较结果:/"2008-08-08 20:00:00/"在/"1900-01-01 20:00:00/"");   
  32.         // 使用after()方法比较   
  33.         if (d2008.after(d1900)) {   
  34.             System.out.println("之后");   
  35.         } else {   
  36.             System.out.println("之前");   
  37.         }   
  38.            
  39.         System.out.println();   
  40.            
  41.         System.out.println("调用方法:d1900.compareTo(d2008)");   
  42.         System.out   
  43.                 .print("比较结果:/"1900-01-01 20:00:00/"在/"2008-08-08 20:00:00/"");   
  44.         // 使用compareTo()方法比较   
  45.         int i = d1900.compareTo(d2008);   
  46.         if (i == -1) {   
  47.             System.out.println("之前");   
  48.         } else if (i == 1) {   
  49.             System.out.println("之后");   
  50.         } else if (i == 0) {   
  51.             System.out.println("是同一时刻");   
  52.         }   
  53.     }   
  54. }  
[java] view plaincopy
  1. import java.util.Date;  
  2.   
  3. public class DateTest {  
  4.     public static void main(String[] args) {  
  5.         // 2008-08-08 20:00:00对应的毫秒数  
  6.         long t2008 = 1218196800000L;  
  7.         // 1900-01-01 20:00:00对应的毫秒数  
  8.         long t1900 = -2208945952000L;  
  9.   
  10.         // 指定毫秒数创建Date对象  
  11.         Date d2008 = new Date(t2008);  
  12.         // 使用系统默认时间创建Date对象  
  13.         Date d1900 = new Date();  
  14.         // 通过设置毫秒数改变日期和时间  
  15.         d1900.setTime(t1900);  
  16.   
  17.         System.out.println("调用方法:d1900.before(d2008)");  
  18.         System.out  
  19.                 .print("比较结果:/"1900-01-01 20:00:00/"在/"2008-08-08 20:00:00/"");  
  20.         // 使用before()方法比较  
  21.         if (d1900.before(d2008)) {  
  22.             System.out.println("之前");  
  23.         } else {  
  24.             System.out.println("之后");  
  25.         }  
  26.           
  27.         System.out.println();  
  28.           
  29.         System.out.println("调用方法:d2008.after(d1900)");  
  30.         System.out  
  31.                 .print("比较结果:/"2008-08-08 20:00:00/"在/"1900-01-01 20:00:00/"");  
  32.         // 使用after()方法比较  
  33.         if (d2008.after(d1900)) {  
  34.             System.out.println("之后");  
  35.         } else {  
  36.             System.out.println("之前");  
  37.         }  
  38.           
  39.         System.out.println();  
  40.           
  41.         System.out.println("调用方法:d1900.compareTo(d2008)");  
  42.         System.out  
  43.                 .print("比较结果:/"1900-01-01 20:00:00/"在/"2008-08-08 20:00:00/"");  
  44.         // 使用compareTo()方法比较  
  45.         int i = d1900.compareTo(d2008);  
  46.         if (i == -1) {  
  47.             System.out.println("之前");  
  48.         } else if (i == 1) {  
  49.             System.out.println("之后");  
  50.         } else if (i == 0) {  
  51.             System.out.println("是同一时刻");  
  52.         }  
  53.     }  
  54. }  


运行结果:

  1. 调用方法:d1900.before(d2008)
  2. 比较结果:"1900-01-01 20:00:00"在"2008-08-08 20:00:00"之前
  3. 调用方法:d2008.after(d1900)
  4. 比较结果:"2008-08-08 20:00:00"在"1900-01-01 20:00:00"之后
  5. 调用方法:d1900.compareTo(d2008)
  6. 比较结果:"1900-01-01 20:00:00"在"2008-08-08 20:00:00"之前


那么如果我们想直接获取或者改变年、月、日、时、分、秒等等这些属性的值时怎么办呢?Date类当然有完成这些操作的方法,不过遗憾的是它们也都已经不被赞成使用了。我们必须换一个能够提供这些操作的类,这个类就是java.util.Calendar。 

公历历法java.util.GregorianCalendar 

Calendar是一个抽象类,我们无法直接实例化它,它有一个具体子类实体类java.util.GregorianCalendar,这个类实现的就是我们日常所用的公历历法,或者叫做阳历。我们可以直接使用new命令创建它的实例,或者使用Calendar类的这个方法来获得它实例:

Java代码 复制代码
  1. public static Calendar getInstance(){   
  2.     //other code   
  3. }  
[java] view plaincopy
  1. public static Calendar getInstance(){  
  2.     //other code  
  3. }  


采用上面这个方法时,我们创建的Calendar对象的日期和时间值是对象被创建时系统日期和时间值。当使用new命令时,我们有两种选择,一种是使用系统当前的日期和时间值初始化GregorianCalendar对象;另一种是通过给定年、月、日、时、分、秒等属性值来对其进行初始化。请看下面的例子:

Java代码 复制代码
  1. import java.text.DateFormat;   
  2. import java.text.SimpleDateFormat;   
  3. import java.util.Calendar;   
  4. import java.util.GregorianCalendar;   
  5.   
  6. public class DateTest {   
  7.     /**  
  8.      * 以一种较为友好的方式格式化日期时间值  
  9.      *   
  10.      * @param c  
  11.      *            日期时间对象  
  12.      * @return 格式化后的日期时间字符串  
  13.      */  
  14.     public static String toFriendlyString(Calendar c) {   
  15.         if (c != null) {   
  16.             DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");   
  17.             return df.format(c.getTime());   
  18.         }   
  19.         return null;   
  20.     }   
  21.   
  22.     public static void main(String[] args) {   
  23.         Calendar c1 = Calendar.getInstance();   
  24.         System.out.println("创建方式:Calendar.getInstance()");   
  25.         System.out.println("日期时间:" + DateTest.toFriendlyString(c1));   
  26.         System.out.println();   
  27.   
  28.         Calendar c2 = new GregorianCalendar();   
  29.         System.out.println("创建方式:new GregorianCalendar()");   
  30.         System.out.println("日期时间:" + DateTest.toFriendlyString(c2));   
  31.         System.out.println();   
  32.   
  33.         // 参数含义依次为:年、月、日   
  34.         Calendar c3 = new GregorianCalendar(200888);   
  35.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8)");   
  36.         System.out.println("日期时间:" + DateTest.toFriendlyString(c3));   
  37.         System.out.println();   
  38.   
  39.         // 参数含义依次为:年、月、日、时、分   
  40.         Calendar c4 = new GregorianCalendar(200888610);   
  41.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8, 6, 10)");   
  42.         System.out.println("日期时间:" + DateTest.toFriendlyString(c4));   
  43.         System.out.println();   
  44.   
  45.         // 参数含义依次为:年、月、日、时、分、秒   
  46.         Calendar c5 = new GregorianCalendar(20088818105);   
  47.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8, 18, 10, 5)");   
  48.         System.out.println("日期时间:" + DateTest.toFriendlyString(c5));   
  49.     }   
  50. }  
[java] view plaincopy
  1. import java.text.DateFormat;  
  2. import java.text.SimpleDateFormat;  
  3. import java.util.Calendar;  
  4. import java.util.GregorianCalendar;  
  5.   
  6. public class DateTest {  
  7.     /** 
  8.      * 以一种较为友好的方式格式化日期时间值 
  9.      *  
  10.      * @param c 
  11.      *            日期时间对象 
  12.      * @return 格式化后的日期时间字符串 
  13.      */  
  14.     public static String toFriendlyString(Calendar c) {  
  15.         if (c != null) {  
  16.             DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");  
  17.             return df.format(c.getTime());  
  18.         }  
  19.         return null;  
  20.     }  
  21.   
  22.     public static void main(String[] args) {  
  23.         Calendar c1 = Calendar.getInstance();  
  24.         System.out.println("创建方式:Calendar.getInstance()");  
  25.         System.out.println("日期时间:" + DateTest.toFriendlyString(c1));  
  26.         System.out.println();  
  27.   
  28.         Calendar c2 = new GregorianCalendar();  
  29.         System.out.println("创建方式:new GregorianCalendar()");  
  30.         System.out.println("日期时间:" + DateTest.toFriendlyString(c2));  
  31.         System.out.println();  
  32.   
  33.         // 参数含义依次为:年、月、日  
  34.         Calendar c3 = new GregorianCalendar(200888);  
  35.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8)");  
  36.         System.out.println("日期时间:" + DateTest.toFriendlyString(c3));  
  37.         System.out.println();  
  38.   
  39.         // 参数含义依次为:年、月、日、时、分  
  40.         Calendar c4 = new GregorianCalendar(200888610);  
  41.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8, 6, 10)");  
  42.         System.out.println("日期时间:" + DateTest.toFriendlyString(c4));  
  43.         System.out.println();  
  44.   
  45.         // 参数含义依次为:年、月、日、时、分、秒  
  46.         Calendar c5 = new GregorianCalendar(20088818105);  
  47.         System.out.println("创建方式:new GregorianCalendar(2008, 8, 8, 18, 10, 5)");  
  48.         System.out.println("日期时间:" + DateTest.toFriendlyString(c5));  
  49.     }  
  50. }  


运行结果如下:

  1. 创建方式:Calendar.getInstance()
  2. 日期时间:2008年07月22日 11:54:48
  3. 创建方式:new GregorianCalendar()
  4. 日期时间:2008年07月22日 11:54:48
  5. 创建方式:new GregorianCalendar(2008, 8,
  6. 日期时间:2008年09月08日 00:00:00
  7. 创建方式:new GregorianCalendar(2008, 8, 8, 6, 10)
  8. 日期时间:2008年09月08日 06:10:00
  9. 创建方式:new GregorianCalendar(2008, 8, 8, 18, 10, 5)
  10. 日期时间:2008年09月08日 18:10:05


为了便于阅读,我们增加一个toFriendlyString(Calendar c)方法,它将日期时间值格式化为一种更加友好易懂的形式,我们将在接下来的内容中讲解它的实现原理。分析运行结果后,我们发现有两个地方需要注意:

  1. 在创建GregorianCalendar对象时,月份值都设定为8,但打印结果都是9月份。这并不是我们的代码有问题,而是因为JAVA表示的月份是从0开始的,也就是说它用来表示月份的数值总是比实际月份值小1。因此我们要表示8月份,就是应该设置8-1=7这个值。
  2. GregorianCalendar的小时数是24小时制的。


为了避免出现因为忘记处理1的差值而设置了错误的月份,也让代码看起来更加直观,推荐大家使用定义在Calendar类的的这些常量来代替直接用数字表示月份:

  • 一月:Calendar.JANUARY = 0
  • 二月:Calendar.FEBRUARY = 1
  • 三月:Calendar.MARCH = 2
  • 四月:Calendar.APRIL = 3
  • 五月:Calendar.MAY = 4
  • 六月:Calendar.JUNE = 5
  • 七月:Calendar.JULY = 6
  • 八月:Calendar.AUGUST = 7
  • 九月:Calendar.SEPTEMBER = 8
  • 十月:Calendar.OCTOBER = 9
  • 十一月:Calendar.NOVEMBER = 10
  • 十二月:Calendar.DECEMBER = 11


如果我们想要从Calendar对象获得各种属性的值,就需要调用它的get(int field)方法,这个方法接收一个int型的参数,并且根据这个给定参数的值来返回相应的属性的值。该方法的定义如下:

Java代码 复制代码
  1. public int get(int field){   
  2.     //other code   
  3. }  
[java] view plaincopy
  1. public int get(int field){  
  2.     //other code  
  3. }  


我们以一个示例来说明get(int field)方法所能接受的一些常用参数的含义及用法:

Java代码 复制代码
  1. import java.text.DateFormat;   
  2. import java.text.SimpleDateFormat;   
  3. import java.util.Calendar;   
  4.   
  5. public class DateTest {   
  6.     /**  
  7.      * 以一种较为友好的方式格式化日期时间值  
  8.      *   
  9.      * @param c  
  10.      *            日期时间对象  
  11.      * @return 格式化后的日期时间字符串  
  12.      */  
  13.     public static String toFriendlyString(Calendar c) {   
  14.         if (c != null) {   
  15.             DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss.SSS");   
  16.             return df.format(c.getTime());   
  17.         }   
  18.         return null;   
  19.     }   
  20.   
  21.     public static void main(String[] args) {   
  22.         Calendar c = Calendar.getInstance();   
  23.         System.out.println("当前时刻:" + DateTest.toFriendlyString(c));   
  24.         System.out.println();   
  25.   
  26.         System.out.println("属性名称:Calendar.AM_PM");   
  27.         System.out.println("代表含义:上下午标识,上午返回Calendar.AM=0,下午返回Calendar.PM=1");   
  28.         System.out.println("测试结果:" + c.get(Calendar.AM_PM));   
  29.         System.out.println();   
  30.   
  31.         System.out.println("属性名称:Calendar.DATE");   
  32.         System.out.println("代表含义:一个月中的第几天,同Calendar.DAY_OF_MONTH");   
  33.         System.out.println("测试结果:" + c.get(Calendar.DATE));   
  34.         System.out.println();   
  35.   
  36.         System.out.println("属性名称:Calendar.DAY_OF_MONTH");   
  37.         System.out.println("代表含义:一个月中的第几天,同Calendar.DATE");   
  38.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_MONTH));   
  39.         System.out.println();   
  40.   
  41.         System.out.println("属性名称:Calendar.DAY_OF_WEEK");   
  42.         System.out.println("代表含义:一周中的第几天,对应星期几,第一天为星期日,于此类推。");   
  43.         System.out.println("星期日:Calendar.SUNDAY=1");   
  44.         System.out.println("星期一:Calendar.MONDAY=2");   
  45.         System.out.println("星期二:Calendar.TUESDAY=3");   
  46.         System.out.println("星期三:Calendar.WEDNESDAY=4");   
  47.         System.out.println("星期四:Calendar.THURSDAY=5");   
  48.         System.out.println("星期五:Calendar.FRIDAY=6");   
  49.         System.out.println("星期六:Calendar.SATURDAY=7");   
  50.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_WEEK));   
  51.         System.out.println();   
  52.   
  53.         System.out.println("属性名称:Calendar.DAY_OF_WEEK_IN_MONTH");   
  54.         System.out.println("代表含义:这一天所对应的星期几在该月中是第几次出现");   
  55.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_WEEK_IN_MONTH));   
  56.         System.out.println();   
  57.   
  58.         System.out.println("属性名称:Calendar.DAY_OF_YEAR");   
  59.         System.out.println("代表含义:一年中的第几天");   
  60.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_YEAR));   
  61.         System.out.println();   
  62.   
  63.         System.out.println("属性名称:Calendar.HOUR");   
  64.         System.out.println("代表含义:12小时制下的小时数,中午和午夜表示为0");   
  65.         System.out.println("测试结果:" + c.get(Calendar.HOUR));   
  66.         System.out.println();   
  67.   
  68.         System.out.println("属性名称:Calendar.HOUR_OF_DAY");   
  69.         System.out.println("代表含义:24小时制下的小时数,午夜表示为0");   
  70.         System.out.println("测试结果:" + c.get(Calendar.HOUR_OF_DAY));   
  71.         System.out.println();   
  72.   
  73.         System.out.println("属性名称:Calendar.MILLISECOND");   
  74.         System.out.println("代表含义:毫秒数");   
  75.         System.out.println("测试结果:" + c.get(Calendar.MILLISECOND));   
  76.         System.out.println();   
  77.   
  78.         System.out.println("属性名称:Calendar.MINUTE");   
  79.         System.out.println("代表含义:分钟");   
  80.         System.out.println("测试结果:" + c.get(Calendar.MINUTE));   
  81.         System.out.println();   
  82.   
  83.         System.out.println("属性名称:Calendar.MONTH");   
  84.         System.out.println("代表含义:月份,从0到11表示12个月份,比实际月份值小1");   
  85.         System.out.println("测试结果:" + c.get(Calendar.MONTH));   
  86.         System.out.println();   
  87.   
  88.         System.out.println("属性名称:Calendar.SECOND");   
  89.         System.out.println("代表含义:秒");   
  90.         System.out.println("测试结果:" + c.get(Calendar.SECOND));   
  91.         System.out.println();   
  92.   
  93.         System.out.println("属性名称:Calendar.WEEK_OF_MONTH");   
  94.         System.out.println("代表含义:一个月中的第几个星期");   
  95.         System.out.println("测试结果:" + c.get(Calendar.WEEK_OF_MONTH));   
  96.         System.out.println();   
  97.   
  98.         System.out.println("属性名称:Calendar.WEEK_OF_YEAR");   
  99.         System.out.println("代表含义:一年中的第几个星期");   
  100.         System.out.println("测试结果:" + c.get(Calendar.WEEK_OF_YEAR));   
  101.         System.out.println();   
  102.   
  103.         System.out.println("属性名称:Calendar.YEAR");   
  104.         System.out.println("代表含义:年份");   
  105.         System.out.println("测试结果:" + c.get(Calendar.YEAR));   
  106.     }   
  107. }  
[java] view plaincopy
  1. import java.text.DateFormat;  
  2. import java.text.SimpleDateFormat;  
  3. import java.util.Calendar;  
  4.   
  5. public class DateTest {  
  6.     /** 
  7.      * 以一种较为友好的方式格式化日期时间值 
  8.      *  
  9.      * @param c 
  10.      *            日期时间对象 
  11.      * @return 格式化后的日期时间字符串 
  12.      */  
  13.     public static String toFriendlyString(Calendar c) {  
  14.         if (c != null) {  
  15.             DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss.SSS");  
  16.             return df.format(c.getTime());  
  17.         }  
  18.         return null;  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.         Calendar c = Calendar.getInstance();  
  23.         System.out.println("当前时刻:" + DateTest.toFriendlyString(c));  
  24.         System.out.println();  
  25.   
  26.         System.out.println("属性名称:Calendar.AM_PM");  
  27.         System.out.println("代表含义:上下午标识,上午返回Calendar.AM=0,下午返回Calendar.PM=1");  
  28.         System.out.println("测试结果:" + c.get(Calendar.AM_PM));  
  29.         System.out.println();  
  30.   
  31.         System.out.println("属性名称:Calendar.DATE");  
  32.         System.out.println("代表含义:一个月中的第几天,同Calendar.DAY_OF_MONTH");  
  33.         System.out.println("测试结果:" + c.get(Calendar.DATE));  
  34.         System.out.println();  
  35.   
  36.         System.out.println("属性名称:Calendar.DAY_OF_MONTH");  
  37.         System.out.println("代表含义:一个月中的第几天,同Calendar.DATE");  
  38.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_MONTH));  
  39.         System.out.println();  
  40.   
  41.         System.out.println("属性名称:Calendar.DAY_OF_WEEK");  
  42.         System.out.println("代表含义:一周中的第几天,对应星期几,第一天为星期日,于此类推。");  
  43.         System.out.println("星期日:Calendar.SUNDAY=1");  
  44.         System.out.println("星期一:Calendar.MONDAY=2");  
  45.         System.out.println("星期二:Calendar.TUESDAY=3");  
  46.         System.out.println("星期三:Calendar.WEDNESDAY=4");  
  47.         System.out.println("星期四:Calendar.THURSDAY=5");  
  48.         System.out.println("星期五:Calendar.FRIDAY=6");  
  49.         System.out.println("星期六:Calendar.SATURDAY=7");  
  50.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_WEEK));  
  51.         System.out.println();  
  52.   
  53.         System.out.println("属性名称:Calendar.DAY_OF_WEEK_IN_MONTH");  
  54.         System.out.println("代表含义:这一天所对应的星期几在该月中是第几次出现");  
  55.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_WEEK_IN_MONTH));  
  56.         System.out.println();  
  57.   
  58.         System.out.println("属性名称:Calendar.DAY_OF_YEAR");  
  59.         System.out.println("代表含义:一年中的第几天");  
  60.         System.out.println("测试结果:" + c.get(Calendar.DAY_OF_YEAR));  
  61.         System.out.println();  
  62.   
  63.         System.out.println("属性名称:Calendar.HOUR");  
  64.         System.out.println("代表含义:12小时制下的小时数,中午和午夜表示为0");  
  65.         System.out.println("测试结果:" + c.get(Calendar.HOUR));  
  66.         System.out.println();  
  67.   
  68.         System.out.println("属性名称:Calendar.HOUR_OF_DAY");  
  69.         System.out.println("代表含义:24小时制下的小时数,午夜表示为0");  
  70.         System.out.println("测试结果:" + c.get(Calendar.HOUR_OF_DAY));  
  71.         System.out.println();  
  72.   
  73.         System.out.println("属性名称:Calendar.MILLISECOND");  
  74.         System.out.println("代表含义:毫秒数");  
  75.         System.out.println("测试结果:" + c.get(Calendar.MILLISECOND));  
  76.         System.out.println();  
  77.   
  78.         System.out.println("属性名称:Calendar.MINUTE");  
  79.         System.out.println("代表含义:分钟");  
  80.         System.out.println("测试结果:" + c.get(Calendar.MINUTE));  
  81.         System.out.println();  
  82.   
  83.         System.out.println("属性名称:Calendar.MONTH");  
  84.         System.out.println("代表含义:月份,从0到11表示12个月份,比实际月份值小1");  
  85.         System.out.println("测试结果:" + c.get(Calendar.MONTH));  
  86.         System.out.println();  
  87.   
  88.         System.out.println("属性名称:Calendar.SECOND");  
  89.         System.out.println("代表含义:秒");  
  90.         System.out.println("测试结果:" + c.get(Calendar.SECOND));  
  91.         System.out.println();  
  92.   
  93.         System.out.println("属性名称:Calendar.WEEK_OF_MONTH");  
  94.         System.out.println("代表含义:一个月中的第几个星期");  
  95.         System.out.println("测试结果:" + c.get(Calendar.WEEK_OF_MONTH));  
  96.         System.out.println();  
  97.   
  98.         System.out.println("属性名称:Calendar.WEEK_OF_YEAR");  
  99.         System.out.println("代表含义:一年中的第几个星期");  
  100.         System.out.println("测试结果:" + c.get(Calendar.WEEK_OF_YEAR));  
  101.         System.out.println();  
  102.   
  103.         System.out.println("属性名称:Calendar.YEAR");  
  104.         System.out.println("代表含义:年份");  
  105.         System.out.println("测试结果:" + c.get(Calendar.YEAR));  
  106.     }  
  107. }  


运行结果如下:

  1. 当前时刻:2008年07月22日 13:16:07.421
  2. 属性名称:Calendar.AM_PM
  3. 代表含义:上下午标识,上午返回Calendar.AM=0,下午返回Calendar.PM=1
  4. 测试结果:1
  5. 属性名称:Calendar.DATE
  6. 代表含义:一个月中的第几天,同Calendar.DAY_OF_MONTH
  7. 测试结果:22
  8. 属性名称:Calendar.DAY_OF_MONTH
  9. 代表含义:一个月中的第几天,同Calendar.DATE
  10. 测试结果:22
  11. 属性名称:Calendar.DAY_OF_WEEK
  12. 代表含义:一周中的第几天,对应星期几,第一天为星期日,于此类推。
  13. 星期日:Calendar.SUNDAY=1
  14. 星期一:Calendar.MONDAY=2
  15. 星期二:Calendar.TUESDAY=3
  16. 星期三:Calendar.WEDNESDAY=4
  17. 星期四:Calendar.THURSDAY=5
  18. 星期五:Calendar.FRIDAY=6
  19. 星期六:Calendar.SATURDAY=7
  20. 测试结果:3
  21. 属性名称:Calendar.DAY_OF_WEEK_IN_MONTH
  22. 代表含义:这一天所对应的星期几在该月中是第几次出现
  23. 测试结果:4
  24. 属性名称:Calendar.DAY_OF_YEAR
  25. 代表含义:一年中的第几天
  26. 测试结果:204
  27. 属性名称:Calendar.HOUR
  28. 代表含义:12小时制下的小时数,中午和午夜表示为0
  29. 测试结果:1
  30. 属性名称:Calendar.HOUR_OF_DAY
  31. 代表含义:24小时制下的小时数,午夜表示为0
  32. 测试结果:13
  33. 属性名称:Calendar.MILLISECOND
  34. 代表含义:毫秒数
  35. 测试结果:421
  36. 属性名称:Calendar.MINUTE
  37. 代表含义:分钟
  38. 测试结果:16
  39. 属性名称:Calendar.MONTH
  40. 代表含义:月份,从0到11表示12个月份,比实际月份值小1
  41. 测试结果:6
  42. 属性名称:Calendar.SECOND
  43. 代表含义:秒
  44. 测试结果:7
  45. 属性名称:Calendar.WEEK_OF_MONTH
  46. 代表含义:一个月中的第几个星期
  47. 测试结果:4
  48. 属性名称:Calendar.WEEK_OF_YEAR
  49. 代表含义:一年中的第几个星期
  50. 测试结果:30
  51. 属性名称:Calendar.YEAR
  52. 代表含义:年份
  53. 测试结果:2008


其中Calendar.DAY_OF_WEEK_IN_MONTH代表的含义比较难理解一些,它表示“这一天所对应的星期几在该月中是第几次出现”。比如2008年8月8日是星期五,在它之前的8月1日也是星期五,因此它是8月份的第二个星期五。所以这时调用get(Calendar.DAY_OF_WEEK_IN_MONTH)就会返回2。这里存在一个简单易记的规律:对于每月的1-7号,它们一定占全了星期一到星期日,所以不管是它们中的哪一天,也不管这一天是星期几,它总是第一个,因此返回1;8-14号也同样占全了星期一到星期日,但由于1-7号的关系,对于它们总是返回2;以此类推,15-21号返回3,22-28号返回4,29-31号返回5。 

Calendar对象和Date对象可以通过Calendar类的如下两个方法进行相互转换:

Java代码 复制代码
  1. public final Date getTime() {   
  2.     //other code   
  3. }   
  4.   
  5. public final void setTime(Date date) {   
  6.     //other code   
  7. }  
[java] view plaincopy
  1. public final Date getTime() {  
  2.     //other code  
  3. }  
  4.   
  5. public final void setTime(Date date) {  
  6.     //other code  
  7. }  


日期格式化与解析 

我们回头再来看看在上面的例子中定义的toFriendlyString(Calendar c)方法,它将一个Calendar对象的日期时间值以一种很友好的方式来展现,使人们很容易看懂,也符合我们中国人的习惯。这完全得益于抽象类DateFormat以及它的子类实体类SimpleDateFormat的帮助。这两个类都位于java.text包中,是专门用于日期格式化和解析的类。而这两项工作的核心就是我们为此设定的Pattern,我们可以称之为“日期格式表达式”。 

理论上讲日期格式表达式包含全部26个英文字母的大小写,不过它们中的一些字母只是被预留了,并没有确切的含义。目前有效的字母及它们所代表的含义如下:

  • G:年代标识,表示是公元前还是公元后
  • y:年份
  • M:月份
  • d:日
  • h:小时,从1到12,分上下午
  • H:小时,从0到23
  • m:分钟
  • s:秒
  • S:毫秒
  • E:一周中的第几天,对应星期几,第一天为星期日,于此类推   
  • z:时区
  • D:一年中的第几天
  • F:这一天所对应的星期几在该月中是第几次出现
  • w:一年中的第几个星期
  • W:一个月中的第几个星期
  • a:上午/下午标识
  • k:小时,从1到24
  • K:小时,从0到11,区分上下午


在日期格式表达式中出现的所有字母,在进行日期格式化操作后,都将被其所代表的含义对应的属性值所替换,并且对某些字母来说,重复次数的不同,格式化后的结果也会有所不同。请看下面的例子:

Java代码 复制代码
  1. import java.text.SimpleDateFormat;   
  2. import java.util.Date;   
  3.   
  4. public class DateTest {   
  5.     public static void main(String[] args) {   
  6.         // 使用系统当前日期时间值创建一个Date对象   
  7.         Date now = new Date();   
  8.   
  9.         // 创建一个日期格式表达式   
  10.         String pattern = "年代:G;年份:y;月份:M;日:d;时(1~12):h;时(0~23):H;分:m;秒:s;毫秒:S;星期:E;上/下午:a;时区:z";   
  11.         // 使用日期格式表达式创建一个SimpleDateFormat对象   
  12.         SimpleDateFormat df = new SimpleDateFormat(pattern);   
  13.         // 调用SimpleDateFormat类的format(Date date)方法对Date对象进行格式化,并返回格式化后的字符串。   
  14.         // 该方法继承自java.text.DateFormat类   
  15.         System.out.println("1位:" + df.format(now));   
  16.   
  17.         // 创建一个新的日期格式表达式   
  18.         pattern = "年代:GG;年份:yy;月份:MM;日:dd;时(1~12):hh;时(0~23):HH;分:mm;秒:ss;毫秒:SS;星期:EE;上/下午:aa;时区:zz";   
  19.         // 调用SimpleDateFormat的applyPattern(String pattern)方法用新创建的日期格式表达式替换其原有的   
  20.         df.applyPattern(pattern);   
  21.         System.out.println("2位:" + df.format(now));   
  22.   
  23.         pattern = "年代:GGG;年份:yyy;月份:MMM;日:ddd;时(1~12):hhh;时(0~23):HHH;分:mmm;秒:sss;毫秒:SSS;星期:EEE;上/下午:aaa;时区:zzz";   
  24.         df.applyPattern(pattern);   
  25.         System.out.println("3位:" + df.format(now));   
  26.   
  27.         pattern = "年代:GGGG;年份:yyyy;月份:MMMM;日:dddd;时(1~12):hhhh;时(0~23):HHHH;分:mmmm;秒:ssss;毫秒:SSSS;星期:EEEE;上/下午:aaaa;时区:zzzz";   
  28.         df.applyPattern(pattern);   
  29.         System.out.println("4位:" + df.format(now));   
  30.   
  31.         pattern = "年代:GGGGG;年份:yyyyy;月份:MMMMM;日:ddddd;时(1~12):hhhhh;时(0~23):HHHHH;分:mmmmm;秒:sssss;毫秒:SSSSS;星期:EEEEE;上/下午:aaaaa;时区:zzzzz";   
  32.         df.applyPattern(pattern);   
  33.         System.out.println("5位:" + df.format(now));   
  34.   
  35.         pattern = "年代:GGGGGG;年份:yyyyyy;月份:MMMMMM;日:dddddd;时(1~12):hhhhhh;时(0~23):HHHHHH;分:mmmmmm;秒:ssssss;毫秒:SSSSSS;星期:EEEEEE;上/下午:aaaaaa;时区:zzzzzz";   
  36.         df.applyPattern(pattern);   
  37.         System.out.println("6位:" + df.format(now));   
  38.     }   
  39. }  
[java] view plaincopy
  1. import java.text.SimpleDateFormat;  
  2. import java.util.Date;  
  3.   
  4. public class DateTest {  
  5.     public static void main(String[] args) {  
  6.         // 使用系统当前日期时间值创建一个Date对象  
  7.         Date now = new Date();  
  8.   
  9.         // 创建一个日期格式表达式  
  10.         String pattern = "年代:G;年份:y;月份:M;日:d;时(1~12):h;时(0~23):H;分:m;秒:s;毫秒:S;星期:E;上/下午:a;时区:z";  
  11.         // 使用日期格式表达式创建一个SimpleDateFormat对象  
  12.         SimpleDateFormat df = new SimpleDateFormat(pattern);  
  13.         // 调用SimpleDateFormat类的format(Date date)方法对Date对象进行格式化,并返回格式化后的字符串。  
  14.         // 该方法继承自java.text.DateFormat类  
  15.         System.out.println("1位:" + df.format(now));  
  16.   
  17.         // 创建一个新的日期格式表达式  
  18.         pattern = "年代:GG;年份:yy;月份:MM;日:dd;时(1~12):hh;时(0~23):HH;分:mm;秒:ss;毫秒:SS;星期:EE;上/下午:aa;时区:zz";  
  19.         // 调用SimpleDateFormat的applyPattern(String pattern)方法用新创建的日期格式表达式替换其原有的  
  20.         df.applyPattern(pattern);  
  21.         System.out.println("2位:" + df.format(now));  
  22.   
  23.         pattern = "年代:GGG;年份:yyy;月份:MMM;日:ddd;时(1~12):hhh;时(0~23):HHH;分:mmm;秒:sss;毫秒:SSS;星期:EEE;上/下午:aaa;时区:zzz";  
  24.         df.applyPattern(pattern);  
  25.         System.out.println("3位:" + df.format(now));  
  26.   
  27.         pattern = "年代:GGGG;年份:yyyy;月份:MMMM;日:dddd;时(1~12):hhhh;时(0~23):HHHH;分:mmmm;秒:ssss;毫秒:SSSS;星期:EEEE;上/下午:aaaa;时区:zzzz";  
  28.         df.applyPattern(pattern);  
  29.         System.out.println("4位:" + df.format(now));  
  30.   
  31.         pattern = "年代:GGGGG;年份:yyyyy;月份:MMMMM;日:ddddd;时(1~12):hhhhh;时(0~23):HHHHH;分:mmmmm;秒:sssss;毫秒:SSSSS;星期:EEEEE;上/下午:aaaaa;时区:zzzzz";  
  32.         df.applyPattern(pattern);  
  33.         System.out.println("5位:" + df.format(now));  
  34.   
  35.         pattern = "年代:GGGGGG;年份:yyyyyy;月份:MMMMMM;日:dddddd;时(1~12):hhhhhh;时(0~23):HHHHHH;分:mmmmmm;秒:ssssss;毫秒:SSSSSS;星期:EEEEEE;上/下午:aaaaaa;时区:zzzzzz";  
  36.         df.applyPattern(pattern);  
  37.         System.out.println("6位:" + df.format(now));  
  38.     }  
  39. }  


输出结果如下:

  1. 1位:年代:公元;年份:08;月份:7;日:22;时(1~12):3;时(0~23):15;分:17;秒:49;毫秒:187;星期:星期二;上/下午:下午;时区:CST
  2. 2位:年代:公元;年份:08;月份:07;日:22;时(1~12):03;时(0~23):15;分:17;秒:49;毫秒:187;星期:星期二;上/下午:下午;时区:CST
  3. 3位:年代:公元;年份:08;月份:七月;日:022;时(1~12):003;时(0~23):015;分:017;秒:049;毫秒:187;星期:星期二;上/下午:下午;时区:CST
  4. 4位:年代:公元;年份:2008;月份:七月;日:0022;时(1~12):0003;时(0~23):0015;分:0017;秒:0049;毫秒:0187;星期:星期二;上/下午:下午;时区:中国标准时间
  5. 5位:年代:公元;年份:02008;月份:七月;日:00022;时(1~12):00003;时(0~23):00015;分:00017;秒:00049;毫秒:00187;星期:星期二;上/下午:下午;时区:中国标准时间
  6. 6位:年代:公元;年份:002008;月份:七月;日:000022;时(1~12):000003;时(0~23):000015;分:000017;秒:000049;毫秒:000187;星期:星期二;上/下午:下午;时区:中国标准时间


如果我们想输出原始的字母,而不是它们所代表含义的替换值,就需要用单引号将它们包含在内,对于预留字母也是如此,虽然它们没有确切的含义。一对单引号可以一次包含多个字母,而两个连续的单引号将输出一个单引号结果,双引号则需要转义后输出。对于26个字母之外的字符,可以放在一对单引号中,也可以直接书写。请看下面的例子:

Java代码 复制代码
  1. import java.text.SimpleDateFormat;   
  2. import java.util.Date;   
  3.   
  4. public class Test {   
  5.     public static void main(String[] args) {   
  6.         Date now = new Date();   
  7.         SimpleDateFormat df = new SimpleDateFormat(   
  8.                 "'YEAR': yyyy 'MONTH:' ''MM'' 'DAY:' /"dd/" ");   
  9.         System.out.println(df.format(now));   
  10.     }   
  11. }  
[java] view plaincopy
  1. import java.text.SimpleDateFormat;  
  2. import java.util.Date;  
  3.   
  4. public class Test {  
  5.     public static void main(String[] args) {  
  6.         Date now = new Date();  
  7.         SimpleDateFormat df = new SimpleDateFormat(  
  8.                 "'YEAR': yyyy 'MONTH:' ''MM'' 'DAY:' /"dd/" ");  
  9.         System.out.println(df.format(now));  
  10.     }  
  11. }  


运行结果:

  • YEAR: 2008 MONTH: '07' DAY: "22"


上面的一些例子中,我们将日期对象转换成一定格式的字符串输出,以得到符合我们习惯的较为友好的表现形式。我们还可以反过来,使用DateFormat类的parse(String source)方法将具有一定格式的字符串转换为一个Date对象,前提是我们利用前面讲到日期格式表达式语法为其找到一个合适的Pattern。例如:

Java代码 复制代码
  1. import java.text.ParseException;   
  2. import java.text.SimpleDateFormat;   
  3. import java.util.Date;   
  4.   
  5. public class DateTest {   
  6.     public static void main(String[] args) throws ParseException {   
  7.         String s = "2008-08-08";   
  8.         System.out.println("原始字符串:" + s);   
  9.         String pattern = "yyyy-MM-dd";   
  10.         System.out.println("对应表达式:" + pattern);   
  11.         SimpleDateFormat df = new SimpleDateFormat(pattern);   
  12.         Date date = df.parse(s);   
  13.         System.out.println("转换后的值:" + date);   
  14.         System.out.println();   
  15.   
  16.         s = "05年2月12日 18:04:33";   
  17.         System.out.println("原始字符串:" + s);   
  18.         pattern = "yy年M月d日 HH:mm:ss";   
  19.         System.out.println("对应表达式:" + pattern);   
  20.         df.applyPattern(pattern);   
  21.         date = df.parse(s);   
  22.         System.out.println("转换后的值:" + date);   
  23.         System.out.println();   
  24.   
  25.         s = "16/5/2004 20:7:2.050";   
  26.         System.out.println("原始字符串:" + s);   
  27.         pattern = "d/M/yyyy HH:m:s.SSS";   
  28.         System.out.println("对应表达式:" + pattern);   
  29.         df.applyPattern(pattern);   
  30.         date = df.parse(s);   
  31.         System.out.println("转换后的值:" + date);   
  32.     }   
  33. }  
[java] view plaincopy
  1. import java.text.ParseException;  
  2. import java.text.SimpleDateFormat;  
  3. import java.util.Date;  
  4.   
  5. public class DateTest {  
  6.     public static void main(String[] args) throws ParseException {  
  7.         String s = "2008-08-08";  
  8.         System.out.println("原始字符串:" + s);  
  9.         String pattern = "yyyy-MM-dd";  
  10.         System.out.println("对应表达式:" + pattern);  
  11.         SimpleDateFormat df = new SimpleDateFormat(pattern);  
  12.         Date date = df.parse(s);  
  13.         System.out.println("转换后的值:" + date);  
  14.         System.out.println();  
  15.   
  16.         s = "05年2月12日 18:04:33";  
  17.         System.out.println("原始字符串:" + s);  
  18.         pattern = "yy年M月d日 HH:mm:ss";  
  19.         System.out.println("对应表达式:" + pattern);  
  20.         df.applyPattern(pattern);  
  21.         date = df.parse(s);  
  22.         System.out.println("转换后的值:" + date);  
  23.         System.out.println();  
  24.   
  25.         s = "16/5/2004 20:7:2.050";  
  26.         System.out.println("原始字符串:" + s);  
  27.         pattern = "d/M/yyyy HH:m:s.SSS";  
  28.         System.out.println("对应表达式:" + pattern);  
  29.         df.applyPattern(pattern);  
  30.         date = df.parse(s);  
  31.         System.out.println("转换后的值:" + date);  
  32.     }  
  33. }  


运行结果:

  1. 原始字符串:2008-08-08
  2. 对应表达式:yyyy-MM-dd
  3. 转换后的值:Fri Aug 08 00:00:00 CST 2008
  4. 原始字符串:05年2月12日 18:04:33
  5. 对应表达式:yy年M月d日 HH:mm:ss
  6. 转换后的值:Sat Feb 12 18:04:33 CST 2005
  7. 原始字符串:16/5/2004 20:7:2.050
  8. 对应表达式:d/M/yyyy HH:m:s.SSS
  9. 转换后的值:Sun May 16 20:07:02 CST 2004

转载:

 

作者:臧圩人(zangweiren) 
网址:http://zangweiren.javaeye.com

 

阅读更多
文章标签: java 面试题
个人分类: java面试题
上一篇JAVA面试题解惑系列(六)——字符串(String)杂谈
下一篇块级元素和行内元素的区别
想对作者说点什么? 我来说一句

JAVA面试题解惑系列合集

2018年01月07日 792KB 下载

JAVA面试题解惑系列

2009年05月19日 34KB 下载

JAVA面试题解惑系列合集.pdf

2010年05月20日 774KB 下载

Java面试题解惑系列

2011年09月21日 507KB 下载

JAVA面试题解惑系列.rar

2012年11月25日 1.16MB 下载

面试\JAVA,JEE基础,面试题汇总

2010年06月15日 478KB 下载

Java面试题(最全,最新)

2010年06月15日 1.47MB 下载

没有更多推荐了,返回首页

关闭
关闭