java 日期相關類的學習和多線程下的日期格式化使用

Date類

Date類 實現Serializable Cloneable Comparable 接口

他的子類有:Date(sql包下的) Time Timestamp  這三個子類其實都是sql包下的

Date的構造方法:

Date() 獲取當前的時間對象  
Date(long date) 將時間戳數字轉化爲Date類對象  

Date常用方法:

long getTime() 將時間以long類型返回

boolean after(Date when)

是否在指定時間之後
boolean before(Date when) 是否在指定時間之前

Calendar日曆類 實現Serializable Cloneable Comparable 接口 ,是一個抽象類,構造方法都被protected修飾

用法比Date複雜,但是功能是日曆,而不再需要我們進行long類型的加減操

常用方法:

Calendar getInstance() 獲取calendar的示例對象
int get(int field) 獲取calendar的成員日期或其他時間數據
set(int field, int value) 設置指定成員的數據內容
abstract void add(int field, int amount) 在指定的成員數據上進行加法運算
   
public static void main(String[] args) {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MONTH, 6); //計算半年後的日期
        instance.set(instance.get(Calendar.DAY_OF_MONTH), 3); // 設置這個月的第三天,即半年後的那個月的第三天
        System.out.println(String.format("日曆爲,%s,%s,%s %s:%s:%s", instance.get(Calendar.YEAR)
                , instance.get(Calendar.MONDAY)
                , instance.get(Calendar.DAY_OF_MONTH)
                , instance.get(Calendar.HOUR_OF_DAY)
                , instance.get(Calendar.MINUTE)
                , instance.get(Calendar.SECOND)
                ));
    }

SimpleDateFormat:格式化日期類,在java.text 包下面,這個包是國際化都放在這個裏面

這個類繼承了DateFormat 

format(Date date) 將日期格式化轉化爲字符串
parse(String source) 將字符串轉化爲日期
SimpleDateFormat(String pattern) 創建對象,設置匹配模式

如果想成功的對日期進行格式化或者將字符串轉化爲日早起,那麼 就必須存在有一個日期的匹配表達式,而這組表達式裏面最重要的幾個日期單位年(yyyy) 月(MM)日(dd)時(HH)分(mm)秒(ss)毫秒(SSS)

public static void main(String[] args) throws Exception{
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        System.out.println(dateFormat.format(date));
        String str = "2020-04-01 22:23:11.606";
        Date parse = dateFormat.parse(str);
        System.out.println(parse);
    }

java中常用的 數據類型和字符串相互轉換的常用方法

LocalDate類

在jdk1.8 之後的版本里,java追加了一個新的日期時間的處理包,java.time ,在這個包有三個類比較重要LocalDate

LocalTime ,LocalDateTime ,通用Calendar類相比更加簡單

 

public static void main(String[] args) throws Exception {
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = LocalDateTime.now();

        System.out.println("LocalDate 實例化輸出" + localDate);
        System.out.println("LocalTime 實例化輸出" + localTime);
        System.out.println("LocalDateTime 實例化輸出" + localDateTime);

        System.out.println(String.format("當前日期%s-%s-%s", localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth()));
        System.out.println("獲取一週的時間數" + localDate.getDayOfWeek().getValue());
        System.out.println("今天所處的一月的週數" + localDate.get(ChronoField.ALIGNED_WEEK_OF_MONTH));
        System.out.println("今天所處的一年的週數" + localDate.get(ChronoField.ALIGNED_WEEK_OF_YEAR));
        System.out.println("今天所處的一年的第幾天" + localDate.getDayOfYear());

        LocalDate localDate2 = LocalDate.parse("2020-04-02");
        System.out.println("是否是閏年" + localDate2.isLeapYear());
        System.out.println("所在月的第一天" + localDate.with(TemporalAdjusters.firstDayOfMonth()));
        System.out.println("所在月的第一天" + localDate.withDayOfMonth(1));
        System.out.println("所在月的最後一天" + localDate.with(TemporalAdjusters.lastDayOfMonth()));
        System.out.println("三百年後的日期" + localDate.plusYears(300));
        System.out.println("日期所處月的第一個週一" + localDate.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)));

    }

在多線程下的SimpleDateFormat類的操作:

首先說一下出現的原因:將字符串轉化爲日期,一定要使用SimpleDateFormat類,於是這個類成了所有項目開發中必然要採用的工具類,於是下面來針對這個工具類使用進行多線程環境下的分析:

單線程:

public static void main(String[] args) throws Exception{

        for (int i = 0; i < 10; i++)
        {
            new Thread(() -> {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId() + sdf.parse("1998-02-17 22:31:32"));
                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }, "SDF轉換線程" + i).start();
        }
    }

上述代代碼,雖然也是多線程,但是每一個線程都保留了一個各自的SimpleDateFormat 類的對象,所以整個的轉換是可以正常完成的,但是上述多個線程要將字符串轉化爲相同的類型的日期,所以沒有必要每個線程都定義一個單獨的SimpleDateFormat 類對象實例(這樣可以減少內存垃圾內存開銷)

所以我們可以修改代碼(注意下面這代碼是錯誤的,給大家演示現象,危險代碼請勿模仿,這個錯誤時:將字符串轉化爲日期會報錯,但是當日期轉化爲字符串時不會報錯

public static void main(String[] args) throws Exception{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        for (int i = 0; i < 10; i++)
        {
            new Thread(() -> {

                try {
                    System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId() + sdf.parse("1998-02-17 22:31:32"));
                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }, "SDF轉換線程" + i).start();
        }
    }

發現代碼不僅報錯,而且有的時間不對

爲什麼會報錯:

出現的異常中有 NumberFormatException這個異常,是因爲在設計SimpleDateFormat類的時候,它的轉化處理操作機制並沒有同步的處理,即線程A的日期時間傳遞過來之後,可能剛配置了一半數據之後,線程B又傳過來的數據,也進行了匹配內容的變更,這樣就會出現線程不同步的問題。

即多個線程不能併發的訪問

如何解決這個問題的方法

1:傳統方法,每個線程都有一個SimpleDateFormat 對象,就是我們最開始的那種方法,但是缺點就是造垃圾

2:我們利用jdk1.8 的LocalDate ,LocalDateTime LocalDateTime 類來完成

public static void main(String[] args) throws Exception{

        // 創建日期的格式化類對象,定義SimpleDateFormat 類中的匹配日期時間字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        ZoneId zoneId = ZoneId.systemDefault();

        for (int i = 0; i < 10; i++)
        {
            new Thread(() -> {
                try {
                    LocalDateTime localDateTime = LocalDateTime.parse("1998-02-17 22:31:32", formatter);
                    Instant instant = localDateTime.atZone(zoneId).toInstant();// 獲得一個當前時區的一個實例
                    Date date = Date.from(instant);
                    System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId()+ date);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }, "SDF轉換線程" + i).start();
        }

下面給出LocalDate 類

public static void main(String[] args) throws Exception{

        // 創建日期的格式化類對象,定義SimpleDateFormat 類中的匹配日期時間字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        ZoneId zoneId = ZoneId.systemDefault();

        for (int i = 0; i < 10; i++)
        {
            new Thread(() -> {
                try {
                    LocalDate localDate = LocalDate.parse("1998-02-17", formatter);
                    Instant instant = localDate.atStartOfDay().atZone(zoneId).toInstant();// 獲得一個當前時區的一個實例
                    Date date = Date.from(instant);
                    System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId()+ date);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }, "SDF轉換線程" + i).start();
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章