Java Date总结

来源:互联网 发布:海康威视4g网络摄像头 编辑:程序博客网 时间:2024/05/21 00:20

在日常的程序中,我们经常会用到日期时间,常常会从字符串和日期进行转换,因此本文决定深入学习一下javaDate相关部分,我这里用的jdk8.

 

一 java中的日期总述

在编程中,一般涉及到日期的操作有三种:

1日期的表示,2日期的转换,3日期的设定修改。

 

JAVAjdk1.1 之前,Date类负责这三个功能。但是jdk1.1后,java把这三个功能分成了三个类,其中:

Date类负责时间的表示,在计算机中,时间的表示是一个较大的概念,现有的系统基本都是利用从1970.1.1 00:00:00 到当前时间的毫秒数进行计时,这个时间称为epoch。在后文中如果没有明确说明,毫秒数就是指从1970年到对应时间的毫秒数。在Java Date类内部其实也是一个毫秒数,对外表现为一个Date对象,后面我将对Date类进行深入探究。

Calendar是一个工具类,负责对Date类进行修改等操作,以及从Date类中提取年月日等时间的特定信息。

DateFormat 则负责日期的转换,比如读取特定格式的字符串,转换成date对象,或者将date对象按照指定的格式转成字符串。

 

由于DateCalendarDateFormat这几个类关联不大,因此我这里分别对各个类进行探究,就不画统一的类图了。

 

二 Date类探究

为了更好的理解Date,可以从jdk中看一下Date类的结构。

Date类的方法还是比较多的,但是大多数都是Deprecated,也就是我上面所说的从Jdk1.1开始,将其他的功能都分流到了CalendarDateFormat类中。

正如我们之前讲过的,Date类内部其实是一个1970到其代表的时间之间的毫秒数,那就必然有一个filed要表示这个毫秒数,这就是 fastTime这个域的作用了。

private transient long fastTime;


在我们日常的使用Date类时,必然都要初始化一个Date对象,这时看看Date的两个剩余的构造函数,一个是无参的,一个是接收了一个long类型的毫秒数,无参构造函数其实是调用了系统的当前毫秒数。最终都是将fastTime这个属性赋值一个对应时间的毫秒数。

public Date() {    this(System.currentTimeMillis());}public Date(long date) {    fastTime = date;}

Date类还可以对时间进行比较,比如beforeaftercompareTo等方法,都是对时间的先后进行比较的。

Date类还是保留一些工具类的方法的,比如这个静态的getMillisOf()就是获取date对象的毫秒数。

static final long getMillisOf(Date date) {    if (date.cdate == null || date.cdate.isNormalized()) {        return date.fastTime;    }    BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();    return gcal.getTime(d);}

 Calendar

1 Calendar类的作用

在程序内部一个时间可以表示为一个毫秒数,但是对于我们日常程序中,可能需要用到这个时间点的年份,月份,小时数等详细信息,这时Calendar类就走上了舞台。

 

Calendar类前面说是一个工具类,其实它比工具类还是更深一步的,它更像是一个加强版的Date类。一般的工具类会提供一堆static方法,工具类本身并不存储对象。但是Calendar类不是像一般的工具类只提供一堆static方法,而是在其内部本身就有一个毫秒数,所以它不是对外部Date对象操作,而是对内部的毫秒数进行转化,所以说Calendar本身就包含了日期时间信息,像一个装饰者模式。

 

在Calendar类中的这个毫秒数就是下面这个field。

@SuppressWarnings("ProtectedField")protected long          time;


Calendar的使用:

Calendar本身是一个抽象类,不能直接实例化,但是Calendar类提供一个工厂方法,即getInstance来创建一个Calendar实例,通过setTime()设定一个Calendar内部的毫秒数,之后就可以对这个毫秒数进行分析,进而得到它的年月日信息。同时,我们也可以对Calendar直接设定年月日属性,从而获取对应的Date对象。

需要注意的是,Calendar的一月是从0开始的,即你设定月份为4时,其实是五月。

下面是一个Calendar的简单示例。

Date now = new Date();Calendar calendar = Calendar.getInstance();calendar.setTime(now);calendar.get(Calendar.YEAR);System.out.println("the year is "+calendar.get(Calendar.YEAR));System.out.println("the month is "+calendar.get(Calendar.MONTH));calendar.set(Calendar.YEAR, 2014);calendar.set(Calendar.MONTH, 2);calendar.set(Calendar.DAY_OF_MONTH, 12);System.out.println("calendar date is "+calendar.getTime());


输出:

the year is 2016

the month is 9

calendar date is Wed Mar 12 22:17:50 CST 2014

 

在讲到Calendar就不可避免的涉及到java的国际化问题和时区的问题。

1) 国际化

Locale 表示地区,每一个Locale对象都代表了一个特定的地理、政治和文化地区。

你可以用如下代码看看你的系统默认地区。

Locale locale = Locale.getDefault();locale.getCountry();locale.getLanguage();System.out.println("default locale is "+locale);System.out.println("default country is "+locale.getCountry());System.out.println("default language is "+locale.getLanguage());

比如我这里的输出就是:

default locale is zh_CN

default country is CN

default language is zh

说明了我所在的国家时CN,语言是zh

 

(2) 时区

java中用java.util.TimeZone类来表示一个时区。每一个时区都一个id,可以利用TimeZone.getAvailableIDs()这个方法获取所有的id

你可以试试利用如下代码看看你的系统默认时区。

TimeZone timeZone = TimeZone.getDefault();System.out.println("default time zone is "+ timeZone.getDisplayName());

本文的默认时区是

default time zone is 中国标准时间


3 Calendar的工厂构造方法

前面说到,Calendar是一个抽象类,提供了static的工厂构造方法来提供一个实例。

Calendar有多个的工厂构造方法:

public static Calendar getInstance(){    return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));}public static Calendar getInstance(Locale aLocale){    return createCalendar(TimeZone.getDefault(), aLocale);}public static Calendar getInstance(TimeZone zone, Locale aLocale){    return createCalendar(zone, aLocale);}

从上面的代码看出,Calendar的实例构造最终都是调用了这个方法

private static Calendar createCalendar(TimeZone zone, Locale aLocale)

这个方法接收两个参数,一个是时区,一个是地区。这个方法中通过对地区的判定返回不同的Calendar的子类(实现类),由于涉及到一些地区的问题,本文不做深究。

 

当我们有了Calendar的实例后,就可以对Date对象进行分析,提取出对应的年月日;也可以通过设定对应的年月日从而获取对应的Date对象。

 

 三 DateFormat类

1 DateFormat类的作用

DateFormat用来在Date对象和字符串之间进行转化

比如,我有一个date,想转成20131201日这种样式,或者想从2013-12-01这个字符串转成一个date对象,都可以利用DateFormat类。

 

2 DateFormat类的结构

DateFormat本身是一个抽象类,但是定义好了所有的方法,我们一般都是使用它的子类SimpleDateFormat,这也是一个标准的模板模式(template pattern)。

DateFormat中定义了众多的方法,最重要的就是parse()format(),这两个方法一个是将字符串转成Date对象,一个是将Date对象按照指定的模式进行转换字符串。

 

利用DateFormat进行转换

DateFormat虽然是个抽象类,我们在日常中可以使用它的子类SimpleDateFormat类,但DateFormat还是提供了一些static方法构建DateFormat实例,进行简单的转换日期功能。

DateFormat提供的转换格式分为两种,一种是只转换Date部分,一种是转换Date和Time两个部分。

 

先看只转换Date部分的,从代码中能看出,你可以调用getDateInstance()这个系列方法,最后其实调用的都是get方法。

这个系列主要需要注意的两个参数就是style参数和Locale参数。这个style参数,这个参数决定了你的日期格式的长度,默认的的default2,从DateFormat类中定义了几个常数,这个2就是medium,也可以设置为LONG。而最后一个参数就是地区了,决定了你的日期输出语言,中文就是年月日,英文就是单词了,我下面用一个例子说明不同参数的区别。

DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT, Locale.SIMPLIFIED_CHINESE);DateFormat format2 = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.SIMPLIFIED_CHINESE);DateFormat format3 = DateFormat.getDateInstance(DateFormat.LONG, Locale.SIMPLIFIED_CHINESE);DateFormat format4 = DateFormat.getDateInstance(DateFormat.SHORT, Locale.ENGLISH);DateFormat format5 = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.ENGLISH);DateFormat format6 = DateFormat.getDateInstance(DateFormat.LONG, Locale.ENGLISH);try {    System.out.println("format : " +format.format(new Date()));    System.out.println("format2 : "+format2.format(new Date()));    System.out.println("format3 : "+format3.format(new Date()));    System.out.println("format4 : "+format4.format(new Date()));    System.out.println("format5 : "+format5.format(new Date()));    System.out.println("format6 : "+format6.format(new Date()));} catch (Exception e) {    e.printStackTrace();}

输出:

format : 16-11-2

format2 : 2016-11-2

format3 : 2016112

format4 : 11/2/16

format5 : Nov 2, 2016

format6 : November 2, 2016

 

上面的例子,对构造DateFormat的地区和style参数就进行了说明,可以看出当style参数设为SHORT时,中英文的日期表示也是不一样的。

 

再说说DateFormat的转换日期和时间格式,即转换的Date对象同时包含日期和时间数据。这也是一个系列的方法,与上面说的getDateInstance()系列类似。

与只转换日期格式的Date有个重要的地方就是这里有两个sytle,一个是日期style,一个是时间style,可以根据自己的需要自由组合日期和时间style

我这里就不说了,有兴趣可以去看看源码。

public final static DateFormat getDateTimeInstance(){    return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));}public final static DateFormat getDateTimeInstance(int dateStyle,  int timeStyle){    return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));}public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale){    return get(timeStyle, dateStyle, 3, aLocale);}


四 SimpleDateFormat

1 SimpleDateFormat使用

其实这个SimpleDateFormat类是我们日常转换字符串和Date对象最常用的类。

我们如果用DateFormat进行转换格式,只能用它规定的几种格式进行转换,非常的不直观,从字面我们看不出来从Date转出来的日期是怎样的格式。

但是如果用SimpleDateFormat就不一样了,在构造SimpleDateFormat我们可以直接传一个pattern,只要pattern符合要求且是合理的,就可以对Date和字符串进行转换了。

这个其实不用多说,只要来一个例子就都明白了,这里有一个坑,就是mM是不一样的,m是分钟(minute),而M是月份,用的时候一定要注意。

String dateString = "2013-02-12T12:22:33";SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");System.out.println("simpleDate format " + simpleDateFormat.format(new Date()));try {    System.out.println("simpleDate parse "+ simpleDateFormat.parse(dateString));} catch (ParseException e) {    e.printStackTrace();}

输出:

simpleDate format 2016-11-02T09:19:58

simpleDate parse Tue Feb 12 00:22:33 CST 2013

 

还有就是当parse时,只有你的字符串和SimpleDateFormatpattern完全匹配才能识别,否则报错。

 

总结:

当我们只需要一个日期时,或从系统取得,或从数据库查询,都可以放入一个Date对象。

当我们需要对Date进行详细分析,获取其中的年月日分秒各个部分的信息,用Calendar类。

当我们需要对一个字符串转成Date对象,或者想让一个Date对象按照我们预期的格式进行输出字符串时,需要用DateFormat或它的子类SimpleDateFormat。

1 0
原创粉丝点击