我是靠谱客的博主 仁爱大门,最近开发中收集的这篇文章主要介绍Java 8的日期、时间类一、Date类二、Calendar类三、Java 8新增的日期、时间包四、使用DateFormat格式化日期、时间五、使用SimpleDateFormat格式化日期六、Java 8新增的日期、时间格式器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Java原本提供了Data和Calendar用于处理日期、时间的类,包括创建日期、时间对象,获取系统当前日期、时间等操作。但Date不仅无法实现国际化,而且它对不同属性也使用了前后矛盾的偏移量,比如月份与小时都是从0开始的,月份中的天则是从1开始的,年又是从1900开始的,而java.util.Calendar则显得过于复杂。从下面介绍可以看到Java对日期、时间处理不足。Java洗浴了Joda-Time库(一个被广泛使用的日期、时间库)的经验,提供了一套全新的日期时间库。

一、Date类

Java提供了Data类来处理日期、时间(此处的Date指的是java.util包下的Date类,而不会死java.sql包下的Date类),Date对象既包含日期,也包含时间。Date类送JDK1.0开始就存在了,但因为它历史悠久,所以它的大部分构造器、方法都已经过时了,不再推荐使用了。

Date类提供了6个构造器,其中4个已经Deprecated(Java不再推荐使用,使用不再推荐的构造器编译器会提出警告信息,并导致程序性能、安全性等方面的问题),剩下的两个构造器如下
Date()生成一个代表当前日期时间的Date对象。该构造器在底层调用了System.currentTimeMillis()获得long整数作为日期参数。

Date(long date)根据指定的long型整数来生成一个Date对象。该构造器的参数表示创建的Date对象和GMT 1970年1月1日00:00:00之间的时间差,以毫秒作为计时单位。

Date对象的大部分方法也已经Deprecated了,剩下为数不多的几个方法。
①boolean after(Date when):测试该日期是否在指定日期when之后。

②boolean before(Date when):测试该日期是否在指定日期when之前。

③long getTime():返回该时间对于的long型整数,即从GMT 1970-01-01 00:00:00之间的时间差,以毫秒作为单位。

④void setTime(long time):设置该Date对象的事件。

下面下程序示范了Date类的用法。

public class DateTest
{
    public static void main(String[] args)
    {
        Date d1 = new Date();
        //获取当前时间后100ms的事件
        Date d2 = new Date(System.currentTimeMillis() + 100);
        System.out.println(d2);
        System.out.println(d1.compareTo(d2));
        System.out.println(d1.before(d2));
    }
}

总体来说,Date是一个设计相当糟糕的类,因此Java官方推荐尽量少用Date的构造器和方法。

二、Calendar类

因为Date类在设计上存在一些缺陷,所以Java提供了Calendar类来更好地处理日期和时间。Calendar是一个抽象类,它用于表示日历。

历史上有着许多种纪年方法,它的差异实在太大了。为了统一计时,全世界通常选择最普及、最通用的日历:Gregorian Calendar,也就是日常介绍年份时常用的“公元几几年”。

Calendar类本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法;但它本身不能直接实例化,程序只能创建Calendar子类的实例,Java本身提供了一个GregorianCalendar类,一个代表格里高利日的子类。

Calendar类是一个抽象类,所以不能使用构造器来创建Calendar对象。但它提供了几个静态getInstance()方法来获取Calendar对象,这些方法根据TimeZone,Locale类来获取特定的Calendar,如果不指定Time、Locale,则使用了默认的TimeZone、Locale来创建Calendar。

Calendar与Date都是表示日期的工具类,它们直接可以自由转换。

    //创建一个默认的Calendar对象
    Calendar calendar = Calendar.getInstance();
    //从Calendar对象中取出Date对象
    Date date = calendar.getTime();
    //通过Date对象获得对于的Calendar对象
    //因为Calendar/GregorianCalendar没有构造函数可以接收Date对象
    //所以必须先获得一个Calendar实例,然后调用其setTime方法
    Calendar calendar2 = Calendar.getInstance();
    calendar2.setTime(date);

Calendar类提供了大量访问、修改日期时间的方法。很多方法需要一个int类型的field,field是Calendar类的类变量,如Calendar.YEAR、Calendar.MONTH等分别代表了年、月、日、小时、分钟、秒等时间字段。
需要注意的是,Calendar.MONTH字段代表月份,月份的起始值不是1,而是0,所以要设置8月时,用7而不是8。如下程序示范了Calendar类的常规用法。

public class CalendarTest
{
    public static void main(String[] args)
    {
        Calendar c = Calendar.getInstance();
        //取出年
        System.out.println(c.get(Calendar.YEAR));
        //取出月份
        System.out.println(c.get(Calendar.MONTH));
        //取出日
        System.out.println(c.get(Calendar.DATE));
        //分别设置年、月、日、小时、分钟、秒
        c.set(2003,10,23,12,32,23);//2003-11-23  12:32:23
        System.out.println(c.getTime());
        //将Calendar往前推1年
        c.add(Calendar.YEAR, -1);//2002-11-23 12:32:23
        //Calendar往前推8个月
        c.roll(Calendar.MONTH, -8);//2002-03-23 12:32:23
        System.out.println(c.getTime());
    }
}

Calendar还有如下几个注意点。
1.add和roll的区别
add(int filed,int amount)的功能非常强大,add主要用于改变Calendar特定字符的值。如果需要增加某字段的值,则让amount为正数;如果需要减少某字段的值,则让amount为负数即可。

add(int field,int amount)有如下两条规则、
当被修改的字段超出它所允许的范围时,会发生进位,即上一级字段也会增大。例如:

Calendar cal1 = Calendar.getInstance();
cal1.set(2003,7,23,0,0,0);//2003-8-23
cal1.add(Calendar.MONTH,6);//2004-2-23

如果下一字段也需要改变,则该字段会修正到变化最小的值。

Calendar cal2 = Calendar.getInstance();
cal2.set(2003,7,31,0,0,0);//2003-8-31
//因为进位后月份改为2月,2月没有31日,自动变成29日
cal2.add(Calendar.MONTH,6);//2004-2-29

roll()的规则与add()处理规则不同
①当被修改的字段超出它允许的范围时,上一级字段不会增大。

Calendar cal3 = Calendar.getInstance();
cal3.set(2003,7,23,0,0,0);//2003-8-23
//MONTH字段"进位",但YEAR字段并不会增加
cal3.roll(Calendar.MONTH,6);//2003-8-23→2003-2-23

②下一级字段的处理规则,与add()相似

Calendar  cal4 = Calendar.getInstance();
cal4.set(2003,7,31,0,0,0);//2003-8-31
//MONTH字段"进位"后变成2,2没有31日
//YEAR字段不会改变,2003年2月只有28天
cal4.roll(Calendar.MONTH,6);//2003-8-31→2003-2-28

2.设置Calendar的容错性
调用Calendar对象的set()方法来改变指定时间字段的值时,有可能传入一个不合法的参数,例如为MONTH字段设置13。这将会导致怎样的后果呢?

public class LenientTest
{
    public static void main(String[] args)
    {
        Calendar cal = Calendar.getInstance();
        //结果是YEAR字段加1,MONTH字段为1(2月)
        cal.set(Calendar.MONTH, 13);//①
        System.out.println(cal.getTime());
        //关闭容错性
        cal.setLenient(false);
        //导致运行时异常
        cal.set(Calendar.MONTH, 13);//①
        System.out.println(cal.getTime());
    }
}

上面程序①②两处代码完全相似,但它们运行的结果不一样;①处代码可以正常运行,因为MONTH字段为13,将会导致YEAR字段加1;②处代码将会导致运行时异常,因为设置MONTH字段超出了MONTH字段允许的范围。

Calendar提供了一个setLenient()用于设置它的容错性,Calendar默认支持较好的容错性,通过setLenient(false)可以关闭Calendar的容错性,让它进行严格的参数检查

Calendar有两种解释日历字段的模式:
lenient模式和non-lenient模式。
lenient模式:当Calendar处于lenient模式时,每个时间字段可接受超出它允许范围的值;
non-lenient模式:当Calendar处于non-lenient模式时,如果为某个时间字段设置的值超过了它允许的取值范围,程序将会抛出异常。

3.set()方法延迟修改
set(f,value)方法将日历字段f更改为value,此外它还设置了一个内部成员变量,以指示日历字段已经被更改
尽管日历字段f是立即更改的,但该Calendar所代表的时间却不会立即修改,知道下次调用get()、getTime()、getTimeInMillis()、add()或roll()时才会重新计算日历的时间。这杯称为set()方法的延迟修改,采用延迟修改的优势就是多次调用set()不会触发多次不必要的计算(需要计算出一个代表实际时间的long型整数。

下面程序延时了set()方法延迟修改的效果:

public class LazyTest
{
    public static void main(String[] args)
    {
        Calendar cal = Calendar.getInstance();
        cal.set(2003, 7 , 31);
        //将月份设为9,系统会把cal自动调整到10月1日
        //如果立即修改,系统将会把cal改为10月1日
        cal.set(Calendar.MONTH, 8);
        //下面代码输出10月1日
        //System.out.println(cal.getTime());//①
        //设置DATE字段为5
        cal.set(Calendar.DATE, 5);//②
        System.out.println(cal.getTime());//③
    }
}

上面代码中创建了代表2003-8-31的Calendar对象,当把这个对象的MONTH字段加1后,应该得到10-1(因为9月没有31日),如果程序在①号代码处输出当前Calendar的日期,也会看到输出2003-10-1。③号代码则会输出2003-10-5。

如果程序员将①处代码注释起来,因为Calendar的set()方法具有延迟修改的特性,即调用set()方法后Calendar实际上并未计算真实的日期,它只是使用内部成员变量记录MONTH字段被修改为8,接着程序设置DATE字段为5,程序内部再次记录DATE字段为5——也就是9月5日。因此看到③处输出2003-9-5。

三、Java 8新增的日期、时间包

Java 8专门新增了一个java.time包,该包下包含了如下常用的类。

Clock该类用于获取指定时区的当前日期、时间。该类可取代System类的currentTimeMillis()方法,而且提供了更多方法来获取当前日期、时间,

Duration该类代表持续时间。该类可以很方便地获取一段时间。

Instant:代表一个具体的时间,可以精确到纳秒。该类提供了静态的now()方法来获取当前日期,也提供了静态的now(Clock clock)方法了获取clock对应的日期。除此之外,它还提供了minusXxx()方法在当前年份上加上几年、几月、几周或几日等,也提供了plusXxx()方法在当前年份上加上几年、几月几周或几日。

LocalDate:该类代表不带时区的日期,例如2007-12-03。

LocalTime:该类代表不带时区的时间,例如10:15:30。

LocalDateTime:该类代表不带时区的日期、时间。例如2007-12-03T10:15:30。

ZonedDateTime:该类代表一个时区化的日期、时间。

ZoneID:该类代表一个时区。

四、使用DateFormat格式化日期、时间

与NumberFormat相似的是,DateFormat也是一个抽象类,它也提供了如下几个类方法用于获取DateFormat对象

①getDateInstance():返回一个日期格式器,它格式化的字符串只有日期,没有时间,该方法可以传入多个参数,用于指定日期样式和Locale等参数;如果不指定这些参数,则使用默认参数。

②getTimeInstance():返回一个时间格式器,它格式化的字符只有时间,没有日期。该方法可以传入多个参数,用于指定时间样式和Locale等参数;如果不指定这些参数,则所有默认参数。

③getDateFormat():返回一个日期、时间格式器,它格式化后的字符既有日期,也有时间。该方法可以传入多个参数,用于指定日期样式、时间样式和Locale参数;如果不指定这些参数,则使用默认参数。

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class DateFormatTest {
    public static void main(String[] args) {
        //需要被格式化的时间
        Date dt = new Date();
        //创建两个Locale,分别代表中国、美国
        Locale[] locales = {Locale.CHINA,Locale.US};
        DateFormat[] df = new DateFormat[16];
        //为上面两个Locale对象创建16个DateFormat对象
        for(int i = 0;i < locales.length;i++)
        {
            df[i * 8] = DateFormat.getDateInstance(DateFormat.SHORT,locales[i]);
            df[i * 8 + 1] = DateFormat.getDateInstance(DateFormat.MEDIUM,locales[i]);
            df[i * 8 + 2] = DateFormat.getDateInstance(DateFormat.LONG,locales[i]);
            df[i * 8 + 3] = DateFormat.getDateInstance(DateFormat.FULL,locales[i]);
            df[i * 8 + 4] = DateFormat.getTimeInstance(DateFormat.SHORT,locales[i]);
            df[i * 8 + 5] = DateFormat.getTimeInstance(DateFormat.MEDIUM,locales[i]);
            df[i * 8 + 6] = DateFormat.getTimeInstance(DateFormat.LONG,locales[i]);
            df[i * 8 + 7] = DateFormat.getTimeInstance(DateFormat.FULL,locales[i]);
        }

        for(int i = 0;i < locales.length;i++)
        {
            String tip  = i == 0 ? "------中国日期格式-------" : "------美国日期格式-------";
            System.out.println(tip);
            System.out.println("SHORT格式的日期格式:"+ df[i * 8].format(dt));
            System.out.println("MEDIUM格式的日期格式:"+ df[i * 8 + 1].format(dt));
            System.out.println("LONG格式的日期格式:"+  df[i * 8 + 2].format(dt));
            System.out.println("FULL格式的日期格式:"+  df[i * 8 + 3].format(dt));
            System.out.println("SHORT格式的时间格式:"+ df[i * 8 + 4].format(dt));
            System.out.println("MEDIUM格式的时间格式:"+ df[i * 8 + 5].format(dt));
            System.out.println("LONG格式的时间格式:"+  df[i * 8 + 6].format(dt));
            System.out.println("FULL格式的时间格式:"+  df[i * 8 + 7].format(dt));
        }
    }
}

上面程序共创建了16个DateFormat对象,分别为中国和美国两个Locale各创建了8个DateFormat对象,分别是Short、MEDIUM、Long、Full四种样式的日期格式器、时间格式器。

获得了DateFormat之后,还可以调用它的setLenient(boolean lenient)方法来设置该格式器是否采用严格语法。举例来说,如果采用不严格的日期语法(该方法的参数为true),则对于“2004-2-31”会转换成2004年3月2日;如果采用严格的日期语法,解析该字符串时将抛出异常。

DateFormat的parse()方法可以把一个字符串解析成Date对象,但它要求被解析的字符串必须符合日期字符串的要求,否则可能抛出ParseException异常。
例如:

String str1 = "2014-12-12";
String str2 = "2014年12月10日";
//下面输出Fri Dec 12 00:00:00 CST 2014
System.out.println(DateFormat.getDateInstance().
    parse(str1));
//下面输出Wed Dec 10 00:00:00 CST 2014
System.out.println(DateFormat.getDateInstance(LONG).
    parse(str2));
//下面抛出ParseException异常
System.out.println(DateFormat.getDateInstance().
    parse(str2));

上面代码中最后一行代码解析日期字符串时引发ParseException异常,因为”2014年12月10日”是一个LONG样式日期字符串,必须用LONG样式的DateFormat实例解析,否则将抛出异常

五、使用SimpleDateFormat格式化日期

前面介绍的DateFormat的parse()方法可把字符串解析成Date对象,但实际上DateFormat的parse()方法不够灵活——它要求被解析的字符串必须满足特定的格式!为了更好地格式化日期、解析字符串,Java提供了SimpleDateFormat类。

SimpleDateFormat类是DateFormat的子类,正如他的名字所暗示的,它是“简单”的日期格式器。实际上SimpleDateFormat比DateFormat更简单,功能更强大。

SimpleDateFormat可以非常灵活地格式化Date,也可以用于解析各种格式的日期字符串。创建SimpleDateFormat对象时需要传入一个pattern字符串,这个pattern是一个日期模板字符串

Date d = new Date();
        //创建一个SimpleDateFormat对象
        SimpleDateFormat sdf1 = new SimpleDateFormat("Gyyyy年中第D天");
        //将d格式化成日期,输出:公元2016年中第223天
        String dateStr = sdf1.format(d);
        System.out.println(dateStr);

        //一个非常特殊的日期字符串
        String str = "16###八月##10";
        SimpleDateFormat sdf2 = new SimpleDateFormat("y###MMM##d");
        //将日期中字符串解析成日期输出:Wed Aug 10 00:00:00 CST 2016
        System.out.println(sdf2.parse(str));

从上面程序可以看出,使用SimpleDateFormat类可以通过日期格式化成形如“公元2014年中第101天”这样的字符串,也可以把形如“14###三月##21”这样的字符串解析成日期,功能非常强大。

SimpleDateFormat把日期格式化成怎样的字符串,以及能把怎样的字符串解析成Date,完全取决于创建该对象时指定的pattern参数:pattern是一个使用日期字段占位符的日期模板

六、Java 8新增的日期、时间格式器

Java 8新增的日期、时间API不仅包括了Instant、LocalDate、LocalDateTime、LocalTime等代表日期、时间的类,而且在java.time.format包下提供了一个DateTimeFormater格式器类,该类相当于前面介绍的DateFormat和SimpleDateFormat的合体,功能非常强大

为了使用DateTimeFormatter进行格式化或解析,必须先获取DateTimeFormattr对象,获取DateTimeFormatter对象有如下三种常见的方式。

①**直接使用静态常量来创建DateTimeFormatter格式器。**DateTimeFormatter类中包含了大量的形如ISO_LOCAL_DATE、ISO_LOCAL_TIME、ISO_LOCAL_DATE_TIME等静态常量,这些静态常量本身就是DateFormatter实例。

使用代表不同风格的枚举值来创建DateTimeFormatter格式器。在FormatStyle风格类中定义了FULL、LONG、MEDIUM、SHORT四个枚举值,它们代表日期、时间的不同风格。

根据模板字符串来创建DateFormat格式器。类似于SimpleDateFormat,可以采用模式字符串来创建DateFormat。

1.使用DateTimeFormatter完成格式化

使用DateTimeFormatter将日期、时间(LocalDate、LocalDateTime、LocalTime等实例)格式化为字符串。可通过如下两种方式。

调用DateTimeFormatter的format(TemporalAccessor temporal)方法执行格式化,其中LocalDate、LocalDateTime、LocalTime等都是TemporalAccessor接口的实现类。

调用LocalDate、LocalDateTime、LocalTime等日期、时间对象的format(DateTimeFormatter formatter)方法执行格式化

上面两种方式的功能相同,用法也类似。

public class DateFormatTest {
    public static void main(String[] args) throws ParseException {
        DateTimeFormatter[] formatters = new DateTimeFormatter[] {
            //直接使用  常量创建DateTimeFormatter格式器
            DateTimeFormatter.ISO_LOCAL_DATE,
            DateTimeFormatter.ISO_LOCAL_TIME,
            DateTimeFormatter.ISO_LOCAL_DATE_TIME,

            //使用本地化的不同风格来创建DateTimeFormatter格式器
            DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL,
            FormatStyle.MEDIUM),
            DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG),

            //根据模式字符串来创建DateFormatter格式器
            DateTimeFormatter.ofPattern("Gyyyy%%MMM%%dd  
            HH:mm:ss")
        };

        LocalDateTime date = LocalDateTime.now();

        //依次使用不同的格式器对LocalDateTime进行格式化
        for(int i = 0;i < formatters.length;i++ )
        {
            //下面两行代码的作用相同
            System.out.println(date.format(formatters[i]));
            System.out.println(formatters[i].format(date));
        }
    }
}

使用DateTimeFormatter进行格式化时
不仅可以按系统预置的格式对日期、时间进行格式化
也可以使用模式字符串对日期、时间进行自定义格式化
由此可见,DateTimeFormatter的功能完全覆盖了传统的DateFormatter、SimpleDateFormatter功能。

提示:DateTimeFormatter还提供了一个toFormat()方法,该方法可以获取DateTimeFormatter对于的Format读写。

2.使用DateTimeFormatter解析字符串

为了使用DateTimeFormatter将指定字符串解析成日期、时间对象(LocalDateTime、LocalTime等实例),可通过日期、时间对象提供的parse(CharSequence text,DateFormatter formatter)方法进行解析。

//定义一个任意格式的日期、时间字符串
        String str1 = "2016==08==10 01时17分10秒";
        //根据需要解析的日期、时间字符串定义解析所用的格式器
        DateTimeFormatter formatter1 = DateTimeFormatter
                .ofPattern("yyyy==MM==dd HH时mm分ss秒");
        //执行解析
        LocalDateTime dt1 = LocalDateTime.parse(str1,
            formatter1);
        System.out.println(dt1);//输出2016-08-10T01:17:10

        //下面代码再次解析另一个字符串
        String str2 = "2016$$$八月$$$10 20时";
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy$$$MMM$$$dd HH时");
        LocalDateTime dt2 = LocalDateTime.parse(str2,
            formatter2);
        System.out.println(dt2);//输出2016-08-10T20:00

上面程序中定义两个不同的格式日期、时间字符串。
为了解析它们,程序分别使用对于的格式化字符串创建了DateTimeFormatter对象,这样DateTimeFormatter即可按该格式字符串将日期、时间字符串解析成LocalDateTime对象

最后

以上就是仁爱大门为你收集整理的Java 8的日期、时间类一、Date类二、Calendar类三、Java 8新增的日期、时间包四、使用DateFormat格式化日期、时间五、使用SimpleDateFormat格式化日期六、Java 8新增的日期、时间格式器的全部内容,希望文章能够帮你解决Java 8的日期、时间类一、Date类二、Calendar类三、Java 8新增的日期、时间包四、使用DateFormat格式化日期、时间五、使用SimpleDateFormat格式化日期六、Java 8新增的日期、时间格式器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部