zoukankan      html  css  js  c++  java
  • Java

    一、获取当前时间的时间戳

    1)时间进制

    1秒 = 1000毫秒

    1秒 = 1000000微秒(1毫秒=1000微秒)

    1秒 = 1000000000纳秒(1微秒=1000纳秒)( 1毫秒=1000000纳秒)

    要获得秒级时间戳,可以使用毫秒级时间戳除以1000即可

    2)获取毫秒时间戳(13位) - 单位是毫秒

    获取毫秒时间戳的方式比较多,一般都是用System.currentTimeMillis()

    // 方式1
    long timeStamp1 = System.currentTimeMillis();
    
    // 方式2
    Date date = new Date();
    long timeStamp2 = date.getTime();
    
    // 方式3
    Calendar calendar = Calendar.getInstance();
    long timeStamp3 = calendar.getTimeInMillis();
    
    // 方法4
    Clock clock = Clock.systemUTC();
    long timeStamp4 = clock.millis();
    
    // 打印时间戳示例
    System.out.println(timeStamp1 + " - " + timeStamp2 + " - " + timeStamp3 + " - " + timeStamp4);

    3)获取纳秒时间戳

    纳秒时间戳,好像用的不是特别多

    System.out.println(System.nanoTime());

    二、java.util包

    1)Date - 不建议使用

    之所以使用java.util.Date指明Date类的包为java.util,是因为java.sql包中也有一个Date类。

    Date类的输出格式:Sun Sep 08 17:49:50 CST 2019

    Date类有很多方法都被废弃了,包括构造方法,所以常用的使用方法如下:

    // 利用当前时间戳创建的Date实例,底层调用System.currentTimeMillis()
    Date date1 = new Date();
    
    // 利用一个时间戳来创建Date对象(时间戳转Date对象)
    Date date2 = new Date(System.currentTimeMillis());
    
    // Date的compareTo,用于比较两个时间的先后
    int flag = date1.compareTo(date2);
    // date1.compareTo(date2)返回值分三种情况
    // flag = 0, 两个时间相同(时间戳相同)
    // flag = 1, date1 要晚于 date2(date1的时间戳大于date2的时间戳)
    // flag = -1,date1 要早于 date2(date1的时间戳小于于date2的时间戳)
    
    // 判断date1是否晚于date2
    boolean after = date1.after(date2);
    
    // 判断date1是否早于date2
    boolean before = date1.before(date2);
    
    // 获取date对象的时间戳(13位),毫秒
    long timeStamp = date1.getTime();
    
    // 设置date对象的时间戳
    date1.setTime(timeStamp);

    建议不要使用Date类的废弃的API,有一个Date.getMonth()获取月份,是从0开始计数,也就是说,3月份,getMonth()的值是2。

    2)Calendar

    Calendar是一个抽象类,所以不能实例化,但是可以调用getInstance()静态方法获得Calendar实例。

    // 调用静态方法获取Calendar实例(使用默认的TimeZone和Locale)
    Calendar calendar1 = Calendar.getInstance();
    
    // 获取时间戳(13位),毫秒
    long timeStamp = calendar1.getTimeInMillis();
    
    // 获取Date对象
    Date date1 = calendar1.getTime();
    
    // 设置时间
    Date date2 = new Date(System.currentTimeMillis() - 100);
    calendar1.setTime(date2);
    
    // 获取Calendar的字段值(比如YEAR、MONTH....)
    final int month = calendar1.get(Calendar.MONTH);
    System.out.println(month); // 注意,month索引为0 - 11
    
    // 修改时间(为指定字段进行计算)
    calendar1.add(Calendar.YEAR, -1); // 当前是2020年,这里将年份减1
    System.out.println(calendar1.get(Calendar.YEAR)); // 2019
    // 其他字段,比如月、天、时分秒的计算都是一样的做法
    
    // 获取某个字段的最大值(同样可以有对应的接口获取最小值)
    int maxDay = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH);
    System.out.println(maxDay); // 2019年3月,最多有31天
    
    Calendar calendar2 = Calendar.getInstance();
    
    // 设置指定字段值,注意,月份是从0开始计数
    calendar2.set(Calendar.YEAR, 2030);
    System.out.println(calendar2.getTime());// Wed Mar 20 10:27:37 CST 2030
    
    // 设置年月日
    calendar2.set(2029, 11, 5);
    System.out.println(calendar2.getTime());// Wed Dec 05 10:27:53 CST 2029
    
    // 设置年月日时分秒
    calendar2.set(2030, 10, 4, 12, 58, 59);
    System.out.println(calendar2.getTime());// Mon Nov 04 12:58:59 CST 2030

    三、java.time - 推荐使用

    java8新的时间API的使用方式,包括创建、格式化、解析、计算、修改。

    Java的Date,Calendar类型使用起来并不是很方便,而且Date类有着线程不安全等诸多弊端。同时若不进行封装,会在每次使用时特别麻烦。

    于是Java8推出了线程安全、简易、高可靠的时间包。并且数据库中也支持LocalDateTime类型,在数据存储时候使时间变得简单。

    java.time包括三个相关的时间类型:LocalDateTime - 年月日时分秒;LocalDate - 日期;LocalTime - 时间;

    1)LocalDate

    LocalDate可以说使用的比较多了,因为可以比较方便的获取、设置、修改日期,需要注意的是,LocalDate,从名称上就能看出,这是获取“本地”日期。

    // 创建LocalDate对象
    LocalDate localDate = LocalDate.now();
    System.out.println(localDate); // 2020-03-20
    
    final LocalDate localDate2 = localDate.minusDays(5);
    System.out.println(localDate); // 2020-03-20 注意,并不会直接修改LocalDate对象
    System.out.println(localDate2); // 2020-03-15
    
    // getXxxx获取年月日信息
    final int dayOfMonth = localDate.getDayOfMonth();
    System.out.println(dayOfMonth);// getDayOfMonth = 20日
    
    // 设置时间为2019-11-20,月份从1开始
    LocalDate localDate3 = LocalDate.of(2019, 9, 14);
    System.out.println(localDate3); // 2019-09-14
    
    // 2019年的第100天
    LocalDate localDate4 = LocalDate.ofYearDay(2020, 100);
    System.out.println(localDate4); // 2020-04-09
    
    // 可以调用LocalData的minusXxx、plusXxx进行日期的计算,getXxx获取某项值
    System.out.println(localDate3.plusYears(1));

    2)LocalTime

    LocalTime,主要是对Time,也就是对时间的操作,并且是本地的时间

    // 利用当前时间,创建LocalTime对象
    LocalTime localTime1 = LocalTime.now();
    System.out.println(localTime1); // 10:44:43.379
    
    // 指定时-分,创建LocalTime对象,注意,小时范围为0-23
    LocalTime localTime2 = LocalTime.of(23, 59);
    System.out.println(localTime2); // 23:59 注意,输出没有秒数
    
    // 指定时-分-秒,创建LocalTime对象
    LocalTime localTime3 = LocalTime.of(12, 35, 40);
    System.out.println(localTime3); // 12:35:40
    
    // 额外指定纳秒
    LocalTime localTime4 = LocalTime.of(13, 20, 55, 1000);
    System.out.println(localTime4);
    
    // 指定一天中的第1000秒来创建LocalTime对象
    LocalTime localTime5 = LocalTime.ofSecondOfDay(1000);
    System.out.println(localTime5); // 00:16:40
    
    // 利用一天中的纳秒数来创建LocalTime对象
    LocalTime localTime6 = LocalTime.ofNanoOfDay(100000000);
    System.out.println(localTime6); // 00:00:00.100
    
    // 可以调用LocalTime的plusXxx,minusXxx进行时间计算,getXxx获取某项值
    System.out.println(localTime2.plusMinutes(10));// 23:59+10分钟 = 00:09

    3)LocalDateTime

    LocalDateTime其实就是LocalDate和LocalTime加在一起的类了,使用方式也是一样的:

    LocalDateTime now = LocalDateTime.now();
    System.out.println(now); // 2020-03-20T10:40:33.204
    
    // 利用LocalDate和LocalTime创建LocalDateTime实例
    LocalDateTime localDateTime1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());
    System.out.println(localDateTime1); // 2020-03-20T10:40:33.205
    
    // of用法和LocalDate和LocalTime的of用法一样,综合在一起了而已
    LocalDateTime localDateTime2 = LocalDateTime.of(2019, 9, 14, 16, 30, 45);
    System.out.println(localDateTime2); // 2019-09-14T16:30:45
    
    // 可以调用LocalDateTime的minusXxx和plusXxx来进行日期和时间的操作,使用getXxx获取某个项的值
    LocalDateTime localDateTime3 = localDateTime2.plusYears(1);// Year+1
    System.out.println(localDateTime3);// 2020-09-14T16:30:45

    4)Clock

    Clock - 时钟,用法如下:

    Clock clock = Clock.systemUTC();
    
    // 获取时区
    final ZoneId zone = clock.getZone();
    System.out.println(zone); // Z
    
    // 获取时间戳(13位),毫秒
    long timeStamp = clock.millis();
    System.out.println(timeStamp); // 1584671920052

    四、日期时间格式

    1)SimpleDateFormat

    Date date = new Date();
    System.out.println(date); // Fri Mar 20 11:03:41 CST 2020
    
    // 创建想要显示的格式
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    final String dateStr = formatter.format(date);
    System.out.println(dateStr); // 2020-03-20 11:03:41

    使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的 SimpleDateFormat的format方法最终调用代码:

    private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) {
        // Convert input date to time field list
        calendar.setTime(date);
    
        boolean useDateFormatSymbols = useDateFormatSymbols();
    
        for (int i = 0; i < compiledPattern.length;) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            }
    
            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char) count);
                break;
    
            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;
    
            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }
    View Code

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

    在多并发情况下使用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)DateTimeFormatter ★推荐

    LocalDate localDate = LocalDate.of(2019, 9, 14);
    
    // 20190914
    String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
    
    // 2019-09-14
    String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
    
    // 自定义格式化 - 14/09/2019
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    String s3 = localDate.format(dateTimeFormatter);

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

    解析时间

    LocalDate localDate1 = LocalDate.parse("20190914", DateTimeFormatter.BASIC_ISO_DATE);
    System.out.println(localDate1);// 2019-09-14
    
    LocalDate localDate2 = LocalDate.parse("2019-09-14", DateTimeFormatter.ISO_LOCAL_DATE);
    System.out.println(localDate2);// 2019-09-14

    和SimpleDateFormat相比,DateTimeFormatter是线程安全的

  • 相关阅读:
    基于Spring的集群会话共享方案-spring session
    Tensorflow 模型线上部署
    Dijkstra算法
    BFS和DFS
    图的基本概念
    排序5
    排序4
    排序3
    排序2
    排序1
  • 原文地址:https://www.cnblogs.com/Dm920/p/12530441.html
Copyright © 2011-2022 走看看