Java:简述Java中对时间和日期的操作

ゞ 浴缸里的玫瑰 2023-05-31 03:14 93阅读 0赞

一、Date

1. java.util.Date

(1)java.util.Date的构造方法如下:

  1. public Date() {
  2. this(System.currentTimeMillis());
  3. }
  4. public Date(long date) {
  5. fastTime = date;
  6. }

(2)java.util.Date的测试用例及输出结果如下:

  1. java.util.Date date_util_1=new java.util.Date();
  2. System.out.println(date_util_1);
  3. 输出:Tue Oct 22 17:37:10 CST 2019
  4. java.util.Date date_util_2=new java.util.Date(System.currentTimeMillis());
  5. System.out.println(date_util_2);
  6. 输出:Tue Oct 22 17:37:10 CST 2019
  7. java.util.Date date_util_3=new java.util.Date(System.currentTimeMillis());
  8. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  9. System.out.println(simpleDateFormat.format(date_util_3));
  10. 输出:2019-10-22 17:54:28

(3)总结
Date如果不格式化,打印出的日期可读性较差。使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的。SimpleDateFormat的format方法的源码如下。

源码中calendar是共享变量,并且这个共享变量没有做线程安全控制。当多个线程同时使用相同的SimpleDateFormat对象【如用static修饰的SimpleDateFormat】调用format方法时,多个线程会同时调用calendar.setTime方法,可能一个线程刚设置好time值另外的一个线程马上把设置的time值给修改了,导致返回的格式化时间可能是错误的。

  1. java.text.DateFormat
  2. protected Calendar calendar;
  3. java.text.SimpleDateFormat
  4. private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) {
  5. // Convert input date to time field list
  6. calendar.setTime(date);
  7. boolean useDateFormatSymbols = useDateFormatSymbols();
  8. for (int i = 0; i < compiledPattern.length; ) {
  9. int tag = compiledPattern[i] >>> 8;
  10. int count = compiledPattern[i++] & 0xff;
  11. if (count == 255) {
  12. count = compiledPattern[i++] << 16;
  13. count |= compiledPattern[i++];
  14. }
  15. switch (tag) {
  16. case TAG_QUOTE_ASCII_CHAR:
  17. toAppendTo.append((char)count);
  18. break;
  19. case TAG_QUOTE_CHARS:
  20. toAppendTo.append(compiledPattern, i, count);
  21. i += count;
  22. break;
  23. default:
  24. subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
  25. break;
  26. }
  27. }
  28. return toAppendTo;
  29. }

在多并发情况下使用SimpleDateFormat需格外注意:SimpleDateFormat除了format是线程不安全以外,parse方法也是线程不安全的。parse方法实际调用alb.establish(calendar).getTime()方法来解析,alb.establish(calendar)方法里主要完成了:
①重置日期对象cal的属性值;②使用calb中中属性设置cal;③返回设置好的cal对象。

但是这三步不是原子操作。多线程并发为了保证线程安全

  • 避免线程之间共享一个SimpleDateFormat对象,每个线程使用时都创建一次SimpleDateFormat对象 => 创建和销毁对象的开销大;
  • 对使用format和parse方法的地方进行加锁 => 线程阻塞性能差;
  • 使用ThreadLocal保证每个线程最多只创建一次SimpleDateFormat对象 => 较好的方法。

Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及n天以后的时间,如果用Date来处理的话真是太难了,虽然Date类有getYear、getMonth这些方法,获取年月日很Easy,但都被弃用了。

2. java.sql.Date

(1)java.sql.Date的构造方法如下:

  1. public Date(long date) {
  2. super(date);
  3. }

(2)java.util.Date的测试用例及输出结果如下:

  1. java.sql.Date date_sql=new java.sql.Date(System.currentTimeMillis());
  2. System.out.println(date_sql);
  3. 输出:2019-10-22

(3)总结
java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分,一般在读写数据库的时候用,PreparedStament的setDate()的参数和ResultSet的getDate()方法的都是java.sql.Date。java.util.Date 是 java.sql.Date 的父类,即:继承关系:java.lang.Object —》 java.util.Date —》 java.sql.Date。

3. java.util.Date 与 java.sql.Date的互相转化

  1. java.sql.Date转为java.util.Date
  2. java.sql.Date date=new java.sql.Date();
  3. java.util.Date d=new java.util.Date (date.getTime());
  4. java.util.Date转为java.sql.Date
  5. java.util.Date utilDate=new Date();
  6. java.sql.Date sqlDate=new java.sql.Date(utilDate.getTime());
  7. java.util.Date utilDate=new Date();
  8. java.sql.Date sqlDate=new java.sql.Date(utilDate.getTime());
  9. java.sql.Time sTime=new java.sql.Time(utilDate.getTime());
  10. java.sql.Timestamp stp=new java.sql.Timestamp(utilDate.getTime());
  11. 这里所有时间日期都可以被SimpleDateFormat格式化format()
  12. SimpleDateFormat f=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  13. f.format(stp);
  14. f.format(sTime);
  15. f.format(sqlDate);
  16. f.format(utilDate)
  17. java.sql.Date sqlDate=java.sql.Date.valueOf(" 2005-12-12");
  18. utilDate=new java.util.Date(sqlDate.getTime());
  19. 另类取得年月日的方法:
  20. import java.text.SimpleDateFormat;
  21. import java.util.*;
  22. java.util.Date date = new java.util.Date();
  23. 如果希望得到YYYYMMDD的格式SimpleDateFormat
  24. sy1=new SimpleDateFormat("yyyyMMDD");
  25. String dateFormat=sy1.format(date);
  26. 如果希望分开得到年,月,日SimpleDateFormat
  27. sy=new SimpleDateFormat("yyyy");
  28. SimpleDateFormat sm=new SimpleDateFormat("MM");
  29. SimpleDateFormat sd=new SimpleDateFormat("dd");
  30. String syear=sy.format(date);
  31. String smon=sm.format(date);
  32. String sday=sd.format(date);

二、java8全新的日期和时间API

1. LocalDate

(1)作用
只会获取年月日星期。

(2)创建LocalDate

  1. //获取当前年月日
  2. LocalDate localDate = LocalDate.now();
  3. System.out.println(localDate.toString());
  4. 输出:2019-10-22
  5. //构造指定的年月日
  6. LocalDate localDate1 = LocalDate.of(2019, 10, 22);
  7. System.out.println(localDate1.toString());
  8. 输出:2019-10-22

(3)获取年、月、日、星期

  1. int year = localDate.getYear();
  2. int year1 = localDate.get(ChronoField.YEAR);
  3. System.out.println(year + "--" + year1);
  4. 输出:2019--2019
  5. Month month = localDate.getMonth();
  6. int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);
  7. System.out.println(month + "--" + month1);
  8. 输出:OCTOBER--10
  9. int day = localDate.getDayOfMonth();
  10. int day1 = localDate.get(ChronoField.DAY_OF_MONTH);
  11. System.out.println(day + "--" + day1);
  12. 输出:22--22
  13. DayOfWeek dayOfWeek = localDate.getDayOfWeek();
  14. int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);
  15. System.out.println(dayOfWeek + "--" + dayOfWeek1);
  16. 输出:TUESDAY--2

2. LocalTime

(1)作用
只会获取时分秒毫秒。

(2)创建LocalDate

  1. LocalTime localTime = LocalTime.of(20, 10, 10,10);
  2. System.out.println(localTime.toString());
  3. 输出:20:10:10.000000010
  4. LocalTime localTime1 = LocalTime.now();
  5. System.out.println(localTime1.toString());
  6. 输出:20:20:43.105
  1. 获取时、分、秒

    //获取小时
    int hour = localTime.getHour();
    int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
    System.out.println(hour + “—“ + hour1);
    输出:20—20

    //获取分
    int minute = localTime.getMinute();
    int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
    System.out.println(minute + “—“ + minute1);
    输出:10—10

    //获取秒
    int second = localTime.getSecond();
    int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);
    System.out.println(second + “—“ + second1);
    输出:10—10

3. LocalDateTime

(1)作用
获取年月日时分秒,等于LocalDate+LocalTime 。

(2)创建LocalDateTime

  1. LocalDateTime localDateTime = LocalDateTime.now();
  2. LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.OCTOBER, 10, 14, 46, 56);
  3. LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
  4. LocalDateTime localDateTime3 = localDate.atTime(localTime);
  5. LocalDateTime localDateTime4 = localTime.atDate(localDate);

(3)获取LocalDate、LocalTime

  1. LocalDate localDate = localDateTime.toLocalDate();
  2. LocalTime localTime = localDateTime.toLocalTime();

4. Instant

(1)作用
获取秒数 。如果只是为了获取秒数或者毫秒数,使用System.currentTimeMillis()来得更为方便。

(2)创建创建Instant对象

  1. Instant instant = Instant.now();

(3)获取秒数、毫秒数

  1. long currentSecond = instant.getEpochSecond();
  2. System.out.println(currentSecond);
  3. 输出:1571747741
  4. long currentMilli = instant.toEpochMilli();
  5. System.out.println(currentMilli);
  6. 输出:1571747741372

5. LocalDate、LocalTime、LocalDateTime、Instant的计算

LocalDate、LocalTime、LocalDateTime、Instant为不可变对象,修改这些对象对象会返回一个副本。
(1)增加、减少年数、月数、天数等,以LocalDateTime为例

  1. LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,14, 46, 56);
  2. //增加一年
  3. localDateTime = localDateTime.plusYears(1);
  4. localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
  5. //减少一个月
  6. localDateTime = localDateTime.minusMonths(1);
  7. localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
  8. //修改年为2019
  9. localDateTime = localDateTime.withYear(2020);
  10. //修改年为2022
  11. localDateTime = localDateTime.with(ChronoField.YEAR, 2022);

(2)时间计算
比如有些时候想知道这个月的最后一天是几号、下个周末是几号,通过提供的时间和日期API可以很快得到答案。比如通过firstDayOfYear()返回了当前日期的第一天日期,还有很多方法这里不在举例说明。

  1. LocalDate localDate = LocalDate.now();
  2. LocalDate localDate1 = localDate.with(firstDayOfYear());

(3)格式化时间
DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过DateTimeFormatter的ofPattern方法创建自定义格式化方式。

  1. LocalDate localDate = LocalDate.of(2019, 9, 10);
  2. String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
  3. String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
  4. //自定义格式化
  5. DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
  6. String s3 = localDate.format(dateTimeFormatter);

(4)解析时间
和SimpleDateFormat相比,DateTimeFormatter是线程安全的。

  1. LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
  2. LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);

三、SpringBoot中应用LocalDateTime

1. 将LocalDateTime字段以时间戳的方式返回给前端

(1)添加日期转化类

  1. public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {
  2. @Override
  3. public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
  4. gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());
  5. }
  6. }

(2)在LocalDateTime字段上添加@JsonSerialize(using = LocalDateTimeConverter.class)注解

  1. @JsonSerialize(using = LocalDateTimeConverter.class)
  2. protected LocalDateTime gmtModified;

2. 将LocalDateTime字段以指定格式化日期的方式返回给前端

在LocalDateTime字段上添加@JsonFormat(shape=JsonFormat.Shape.STRING, pattern=“yyyy-MM-dd HH:mm:ss”)注解即可

  1. @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
  2. protected LocalDateTime gmtModified;

3. 对前端传入的日期进行格式化

在LocalDateTime字段上添加@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”)注解即可。

  1. @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  2. protected LocalDateTime gmtModified;

参考:

  1. https://mp.weixin.qq.com/s/IMAGF5Nmh3amHi78B7DCMQ

发表评论

表情:
评论列表 (有 0 条评论,93人围观)

还没有评论,来说两句吧...

相关阅读