Java Date总结

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

 
一 java中的日期总述

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

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

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

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

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

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

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

 
二 Date类探究

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

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

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

private transient long fastTime;


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

  

//返回系统当前的日期
public Date() {
    this(System.currentTimeMillis());
}
     
//获取Long类型的毫秒数,返回对应的日期
public Date(long time) {
    fastTime = date;
}

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

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;


2 Calendar的使用:

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

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

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

Date now = new Date();
//创建实例
Calendar calendar = Calendar.getInstance();
//获取Date()毫秒数
calendar.setTime(now);
//打印年份
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);
/**
* DAY_OF_MONTH :获取当月的第几天,从1开始
* DAY_OF_WEEK :获取本周第几日 ,Calendar定义的周一至周日是 
* SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY, FRIDAY, and SATURDAY.
* DAY_OF_YEAR :获取当年的第几天,从1开始
*/
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,想转成2013年12月01日这种样式,或者想从2013-12-01这个字符串转成一个date对象,都可以利用DateFormat类。

2 DateFormat类的结构

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

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

3 利用DateFormat进行转换

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

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

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

 

这个系列主要需要注意的两个参数就是style参数和Locale参数。style这个参数决定了你的日期格式的长度,默认的的日期长度为MEDIUM。而最后一个参数就是地区了,决定了你的日期输出语言,中文就是年月日,英文就是单词了,我下面用一个例子说明不同参数的区别。

/**
* DateFormat.SHORT    短日期
* DateFormat.MEDIUM   中日期   默认
* DateFormat.LONG     长日期
* 
* Locale.SIMPLIFIED_CHINESE   输出中文日期
* Locale.ENGLISH              输出英文日期
*/
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 : 2016年11月2日

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和字符串进行转换了。

这个其实不用多说,只要来一个例子就都明白了,这里有一个坑,就是m和M是不一样的,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时,只有你的字符串和SimpleDateFormat的pattern完全匹配才能识别,否则报错。

 
总结:

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值