Java基础类库(二)————日期类

Java提供了Date和Calendar用于处理日期、时间的类,但是Date无法实现国际化,且对不同属性使用了前后矛盾的偏移量,比如月份与小时都是从0开始,月份中的天数却是从1开始的,年又是从1900年开始。而Calendar则显得过于复杂。因此Java 8 提供了一套全新的日期时间库。

一、Date类

  1. 通常使用的是java.util包下的
  2.  构造方法: Date date = new Date();该构造器会在底层调用System.currentTimeMillis()获得long整数作为日期参数。即这个方法获得的时间是系统当前时间
  3. 常用方法:
  •                   boolean before(Date when): date1.before(date2): 比较date1时间是否在date2之前
  •                   boolean after(Date when);测试该日期是否在指定日期之后
  •                   setTime(long time);设置Date对象的时间
  •                   long getTime();   返回该时间对应的long型整数

   4.设置Date类时间格式:DateFormat类

该类是抽象类,需要子类才能使用,所以通常使用其子类:SimpleDateFormat类来处理Date类的格式

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH-mm-ss”);

String v = sdf.format(new Date())//将当前日期以指定格式返回,并转化成字符串

或者

  Date d = sdf.parse("2019-10-11 11:57:00")

注意:在多线程下,SimpleDateFormate是非线程安全的。

二、Calendar类

Calendar类是一个抽象类,它用于表示日历。

  1. java.util包下
  2. 有构造方法,用protected修饰,通常访问不到。需要调用默认的getInstance()方法
  3. Calendar caledar = Calendar.getInstance();   //系统当前时间的对象
  4. void set(int year,int month,int date):设置Calendar对象的年、月、日三个字段的值。因为月份是从0开始的,所以要设置8月时,第二个参数应该用7;
  5. int year = calendar.get(Canlendar.YEAR);//其他同理,但是month这个参数是从0开始数的,所以当获取当前月份时,记得+1;
  6. 获取时区:calendar.getTimeZone();
  7. 获取明天的当前时间 :

                 

 //JDK1.8之前:

          Calendar calendar = Calendar.getInstance();//获取系统当前时间

          Calendar.add(Calendar.DATE,1);//对日期加1,add()方法第一个参数可以是YEAR、MONTH、DATE,第二个参数可正可负。正表示未来,负表示过去

          System.out.println(calendar.getTime())


//JDK1.8之后:

    //方法一:

           LocalDateTime today = LocalDateTime.now();

           LocalDateTime tomorrow = today.plusDays(1);//增加一天

           System.out.println(tomorrow);

    //方法二:

           LocalDateTime tomorrow = today.minusDays(-1);//minus是减去一天,参数是负数时,则表示加一天。


除了add()方法外,Calendar类还提供了一个方法,实现同样的效果:void roll(int field,int amount)
二者的区别在于:
(1)add()的功能更加强大,当被修改的字段超出他允许的范围时,他会自动向前进位。
    例:  Calendar call = Calendar.getInstance();
             call.set(2003,7,23,0,0,0);//2003-8-23
             call.add(MONTH,6);//2003-8-23 -->2004-2-23

 (2)如果下一级的字段也需要改变,该字段会在自动修正到变化最小的值

例:      Calendar call = Calendar.getInstance();
             call.set(2003,7,31,0,0,0);//2003-8-31

             //因为进位之后2月没有31号,所以自动修正到29号
             call.add(MONTH,6);//2003-8-31 -->2004-2-29

(3)    roll()则不会自动增大
 

三、Java 8中的时间操作

Java 8 中新增了三个类:

LocalDateTime:既包含时间也包含日期,不可变且线程安全

LocalDate:       只包含日期,不包含时间,不可变且线程安全

LocalTime:    只包含时间,不包含日期,不可变且线程安全

1、获取时间

LocalDate localDate = LocalDate.now();//获取当前日期
LocalTime localTime = LocalTime.mow();//获取当前时间
LocalDateTime ldt = LocalDateTime.now();//获取时间和日期

2、获取时间戳

时间戳是指格林威治时间1970-01-01 00:00:00(北京时间 1970-01-01 08:00:00)起到现在的总秒数

long milli = Instant.now().toEpochMilli();//获取当前时间戳,精确到毫秒
long second = Instant.now.getEpoSecond();//获取当前时间戳,精确到秒
 

3、时间格式化

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String timeFormat = dateTimeFormatter.format(LocalDateTime.now());
//LocalDateTime:该类是布带时区的日期、时间
System.out.println(timeFormat);//输出 2019-10-11 12:37:50

4、时间转化

String timeStr = "2019-10-11 12:40:23";
LocalDateTime dateTime = LocalDateTime.parse(timeStr,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

相关面试题


1. 获取当前时间有几种方式?

答:获取当前时间常见的方式有以下三种:

new Date()
Calendar.getInstance().getTime()
LocalDateTime.now()


2. 如何获取昨天此刻的时间?


答:以下为获取昨天此刻时间的两种方式:

// 获取昨天此刻的时间(JDK 8 以前)
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE,-1);
System.out.println(c.getTime());
// 获取昨天此刻的时间(JDK 8)
LocalDateTime todayTime = LocalDateTime.now();
System.out.println(todayTime.plusDays(-1));


3. 如何获取本月的最后一天?


答:以下为获取本月最后一天的两种方式:

// 获取本月的最后一天(JDK 8 以前)
Calendar ca = Calendar.getInstance();
ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
System.out.println(ca.getTime());
// 获取本月的最后一天(JDK 8)
LocalDate today = LocalDate.now();
System.out.println(today.with(TemporalAdjusters.lastDayOfMonth()));


4. 获取当前时间的时间戳有几种方式?


答:以下为获取当前时间戳的几种方式:

System.currentTimeMillis()
new Date().getTime()
Calendar.getInstance()

Instant.now().toEpochMilli()
LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()
其中,第四种和第五种方式是 JDK 8 才新加的。



5. 如何优雅地计算两个时间的相隔时间?


答:JDK 8 中可以使用 Duration 类来优雅地计算两个时间的相隔时间,代码如下:

LocalDateTime dt1 = LocalDateTime.now();
LocalDateTime dt2 = dt1.plusSeconds(60);
Duration duration = Duration.between(dt1, dt2);
System.out.println(duration.getSeconds());  // output:60


6. 如何优雅地计算两个日期的相隔日期?


答:JDK 8 中可以使用 Period 类来优雅地计算两个日期的相隔日期,代码如下:

LocalDate d1 = LocalDate.now();
LocalDate d2 = d1.plusDays(2);
Period period = Period.between(d1, d2);
System.out.println(period.getDays());   //output:2


7. SimpleDateFormat 是线程安全的吗?为什么?


答:SimpleDateFormat 是非线程安全的。因为查看 SimpleDateFormat 的源码可以得知,所有的格式化和解析,都需要通过一个中间对象进行转换,这个中间对象就是 Calendar,这样的话就造成非线程安全。试想一下当我们有多个线程操作同一个 Calendar 的时候后来的线程会覆盖先来线程的数据,那最后其实返回的是后来线程的数据,因此 SimpleDateFormat 就成为了非线程的了。



8. 怎么保证 SimpleDateFormat 的线程安全?


答:保证 SimpleDateFormat 线程安全的方式如下:

使用 Synchronized,在需要时间格式化的操作使用 Synchronized 关键字进行包装,保证线程堵塞格式化;
手动加锁,把需要格式化时间的代码,写到加锁部分,相对 Synchronized 来说,编码效率更低,性能略好,代码风险较大(风险在于不要忘记在操作的最后,手动释放锁);
使用 JDK 8 的 DateTimeFormatter 替代  SimpleDateFormat。


9. JDK 8 中新增的时间类都有哪些优点?

答:JDK 8 中的优点具体有以下几个优点,如下:

线程安全性
使用的便利性(如获取当前时间戳的便利性、增减日期的便利性等)
编写代码更简单优雅,如当前时间的格式化:LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));


10. 如何比较两个时间(Date)的大小?

答:时间比较有以下三种方式:

获取两个时间的时间戳,得到两个 long 类型的变量,两个变量相减,通过结果的正负值来判断大小;
通过 Date 自带的 before()、after()、equals() 等方法比较,代码示例 date1.before(date2);
通过 compareTo() 方法比较,代码示例:date1.compareTo(date2),返回值 -1 表示前一个时间比后一个时间小,0 表示两个时间相等,1 表示前一个时间大于后一个时间。


总结


JDK 8 之前使用 java.util.Date 和 java.util.Calendar 来操作时间,它们有两个很明显的缺点,第一,非线程安全;第二,API 调用不方便。JDK 8 新增了几个时间操作类 java.time 包下的 LocalDateTime、LocalDate、LocalTime、Duration(计算相隔时间)、Period(计算相隔日期)和 DateTimeFormatter,提供了多线程下的线程安全和易用性,让我们可以更好的操作时间。
 

发布了47 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/monologuezjp/article/details/102498414