Java8 ,LocalDate,LocalDateTime处理日期和时间工具类,
Java8 ,LocalDate,LocalDateTime處理日期和時間工具類
- 日期格式化
- 1、獲取今天的日期
- 2、在Java 8 中獲取年、月、日信息
- 3、在Java 8 中處理特定日期
- 4、在Java 8 中判斷兩個日期是否相等
- 5、在 Java 8 中檢查像生日這種周期性事件
- 6、在 Java 8 中獲取當前時間
- 7、在現有的時間上增加小時
- 8、計算一周后的日期
- 9、計算一年前或一年后的日期
- 10、使用 Java 8 的 Clock 時鐘類
- 11、如何用 Java 判斷日期是早于還是晚于另一個日期
- 12、在 Java 8 中處理時區
- 13、如何表示信用卡到期這類固定日期,答案就在 YearMonth
- 14、如何在 Java 8 中檢查閏年
- 15、計算兩個日期之間的天數和月數
- 16、包含時差信息的日期和時間
- 17、在 Java 8 中獲取當前的時間戳
- 18、在 Java 8 中如何使用預定義的格式化工具去解析或格式化日期
- 19、如何在 Java 中使用自定義格式化工具解析日期
- 20、在 Java 8 中如何把日期轉換成字符串
- 21Java 8 日期時間API
- 22.LocalDateTime與字符串互轉/Date互轉/LocalDate互轉/指定日期/時間比較
- 與字符串互轉
- 與Date互轉
- 與LocalDate互轉
- 調整時間
- 時間比較
- 間隔計算
- 判斷是否是今天或昨天
- 23.獲取當天的開始和結束時間
- 24.本周開始、結束時間
- 25.本月第一天、最后一天
- 26.LocalDateTime指定時間,生成指定時間段的隨機時間
- 日期處理
- 1.1 用Calendar設置時間的坑
- 1.2 Java日期格式化YYYY的坑
- 1.3 Java日期格式化hh的坑。
- 1.4 Calendar獲取的月份比實際數字少1即(0-11)
- 1.5 Java日期格式化DD的坑
- 1.6 SimleDateFormat的format初始化問題
- 1.7 日期本地化問題
- 1.8 SimpleDateFormat 解析的時間精度問題
- 1.9 SimpleDateFormat 的線性安全問題
- 1.10Java日期的夏令時問題
titile 1 to 21 from:
zhisheng
日期格式化
import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter;public static final String DATE_TIME_FORMATTER_PATTERN = "yyyy-MM-dd HH:mm:ss"; public static final String DATE_FORMATTER_PATTERN = "yyyy-MM-dd"; public static final String TIME_FORMATTER_PATTERN = "HH:mm:ss"; public static final SimpleDateFormat S_DATE_TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static final SimpleDateFormat S_DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); public static final SimpleDateFormat S_TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss"); public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");1、獲取今天的日期
Java 8 中的 LocalDate 用于表示當天日期。和 java.util.Date 不同,它只有日期,不包含時間。當你僅需要表示日期時就用這個類。
LocalDate now = LocalDate.now(); System.out.println(now);結果是:
2018-9-10上面的代碼創建了當天的日期,不含時間信息。打印出的日期格式非常友好,不像老的 Date 類打印出一堆沒有格式化的信息。
2、在Java 8 中獲取年、月、日信息
LocalDate 類提供了獲取年、月、日的快捷方法,其實例還包含很多其它的日期屬性。通過調用這些方法就可以很方便的得到需要的日期信息,不用像以前一樣需要依賴 java.util.Calendar 類了。
LocalDate now = LocalDate.now(); int year = now.getYear(); int monthValue = now.getMonthValue(); int dayOfMonth = now.getDayOfMonth(); System.out.printf("year = %d, month = %d, day = %d", year, monthValue, dayOfMonth);結果是:
year = 2018, month = 6, day = 203、在Java 8 中處理特定日期
在第一個例子里,我們通過靜態工廠方法 now() 非常容易地創建了當天日期,你還可以調用另一個有用的工廠方法LocalDate.of() 創建任意日期, 該方法需要傳入年、月、日做參數,返回對應的 LocalDate 實例。這個方法的好處是沒再犯老 API 的設計錯誤,比如年度起始于 1900,月份是從 0 開始等等。日期所見即所得,就像下面這個例子表示了 6 月 20 日,沒有任何隱藏機關。
LocalDate date = LocalDate.of(2018, 06, 20); System.out.println(date);4、在Java 8 中判斷兩個日期是否相等
LocalDate 重載了 equal 方法:
LocalDate now = LocalDate.now(); LocalDate date = LocalDate.of(2018, 06, 20); if (date.equals(now)) {System.out.println("同一天"); }如果比較的日期是字符型的,需要先解析成日期對象再作判斷。
5、在 Java 8 中檢查像生日這種周期性事件
Java 中另一個日期時間的處理就是檢查類似每月賬單、結婚紀念日、EMI日或保險繳費日這些周期性事件。如果你在電子商務網站工作,那么一定會有一個模塊用來在圣誕節、感恩節這種節日時向客戶發送問候郵件。Java 中如何檢查這些節日或其它周期性事件呢?答案就是 MonthDay 類。這個類組合了月份和日,去掉了年,這意味著你可以用它判斷每年都會發生事件。和這個類相似的還有一個 YearMonth 類。這些類也都是不可變并且線程安全的值類型。下面我們通過 MonthDay 來檢查周期性事件:
LocalDate now = LocalDate.now(); LocalDate dateOfBirth = LocalDate.of(2018, 06, 20); MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth()); MonthDay currentMonthDay = MonthDay.from(now); if (currentMonthDay.equals(birthday)) {System.out.println("Happy Birthday"); } else {System.out.println("Sorry, today is not your birthday"); }結果:(注意:獲取當前時間可能與你看的時候不對,所以這個結果可能和你看的時候運行結果不一樣)
只要當天的日期和生日匹配,無論是哪一年都會打印出祝賀信息。
6、在 Java 8 中獲取當前時間
與 Java 8 獲取日期的例子很像,獲取時間使用的是 LocalTime 類,一個只有時間沒有日期的 LocalDate 近親。可以調用靜態工廠方法 now() 來獲取當前時間。默認的格式是 hh:mm:ss:nnn。
LocalTime localTime = LocalTime.now(); System.out.println(localTime);結果:
13:35:56.1557、在現有的時間上增加小時
通過增加小時、分、秒來計算將來的時間很常見。Java 8 除了不變類型和線程安全的好處之外,還提供了更好的plusHours() 方法替換 add(),并且是兼容的。注意,這些方法返回一個全新的 LocalTime 實例,由于其不可變性,返回后一定要用變量賦值。
LocalTime localTime = LocalTime.now(); System.out.println(localTime); LocalTime localTime1 = localTime.plusHours(2);//增加2小時 System.out.println(localTime1);8、計算一周后的日期
LocalDate 日期不包含時間信息,它的 plus()方法用來增加天、周、月,ChronoUnit 類聲明了這些時間單位。由于 LocalDate 也是不變類型,返回后一定要用變量賦值。
LocalDate now = LocalDate.now(); LocalDate plusDate = now.plus(1, ChronoUnit.WEEKS); System.out.println(now); System.out.println(plusDate);結果:
2018-06-20 2018-06-27可以看到新日期離當天日期是 7 天,也就是一周。你可以用同樣的方法增加 1 個月、1 年、1 小時、1 分鐘甚至一個世紀,更多選項可以查看 Java 8 API 中的 ChronoUnit 類
9、計算一年前或一年后的日期
利用 minus() 方法計算一年前的日期。
LocalDate now = LocalDate.now(); LocalDate minusDate = now.minus(1, ChronoUnit.YEARS); LocalDate plusDate1 = now.plus(1, ChronoUnit.YEARS); System.out.println(minusDate); System.out.println(plusDate1);10、使用 Java 8 的 Clock 時鐘類
Java 8 增加了一個 Clock 時鐘類用于獲取當時的時間戳,或當前時區下的日期時間信息。以前用到System.currentTimeInMillis() 和 TimeZone.getDefault() 的地方都可用 Clock 替換。
Clock clock = Clock.systemUTC(); Clock clock1 = Clock.systemDefaultZone(); System.out.println(clock); System.out.println(clock1);結果:
SystemClock[Z] SystemClock[Asia/Shanghai]11、如何用 Java 判斷日期是早于還是晚于另一個日期
LocalDate 類有兩類方法 isBefore() 和 isAfter() 用于比較日期。調用 isBefore() 方法時,如果給定日期小于當前日期則返回 true。
LocalDate tomorrow = LocalDate.of(2018,6,20); if(tomorrow.isAfter(now)){System.out.println("Tomorrow comes after today"); } LocalDate yesterday = now.minus(1, ChronoUnit.DAYS); if(yesterday.isBefore(now)){System.out.println("Yesterday is day before today"); }12、在 Java 8 中處理時區
Java 8 不僅分離了日期和時間,也把時區分離出來了。現在有一系列單獨的類如 ZoneId 來處理特定時區,ZoneDateTime 類來表示某時區下的時間。這在 Java 8 以前都是 GregorianCalendar 類來做的。
ZoneId america = ZoneId.of("America/New_York"); LocalDateTime localtDateAndTime = LocalDateTime.now(); ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america ); System.out.println(dateAndTimeInNewYork);13、如何表示信用卡到期這類固定日期,答案就在 YearMonth
YearMonth 是另一個組合類,用于表示信用卡到期日、FD 到期日、期貨期權到期日等。還可以用這個類得到 當月共有多少天,YearMonth 實例的 lengthOfMonth() 方法可以返回當月的天數,在判斷 2 月有 28 天還是 29 天時非常有用。
YearMonth currentYearMonth = YearMonth.now(); System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth()); YearMonth creditCardExpiry = YearMonth.of(2018, Month.FEBRUARY); System.out.printf("Your credit card expires on %s %n", creditCardExpiry);結果:
Days in month year 2018-06: 30 Your credit card expires on 2018-0214、如何在 Java 8 中檢查閏年
LocalDate 類有一個很實用的方法 isLeapYear() 判斷該實例是否是一個閏年。
15、計算兩個日期之間的天數和月數
有一個常見日期操作是計算兩個日期之間的天數、周數或月數。在 Java 8 中可以用 java.time.Period 類來做計算。下面這個例子中,我們計算了當天和將來某一天之間的月數。
LocalDate date = LocalDate.of(2019, Month.MARCH, 20); Period period = Period.between(now, date); System.out.println("離下個時間還有" + period.getMonths() + " 個月");16、包含時差信息的日期和時間
在 Java 8 中,ZoneOffset 類用來表示時區,舉例來說印度與 GMT 或 UTC 標準時區相差 +05:30,可以通過ZoneOffset.of() 靜態方法來獲取對應的時區。一旦得到了時差就可以通過傳入 LocalDateTime 和 ZoneOffset 來創建一個 OffSetDateTime 對象。
LocalDateTime datetime = LocalDateTime.of(2014, Month.JANUARY, 14,19,30); ZoneOffset offset = ZoneOffset.of("+05:30"); OffsetDateTime date = OffsetDateTime.of(datetime, offset); System.out.println("Date and Time with timezone offset in Java : " + date);17、在 Java 8 中獲取當前的時間戳
Instant 類有一個靜態工廠方法 now() 會返回當前的時間戳,如下所示:
Instant timestamp = Instant.now(); System.out.println(timestamp);結果:
2018-06-20T06:35:24.881Z時間戳信息里同時包含了日期和時間,這和 java.util.Date 很像。實際上 Instant 類確實等同于 Java 8 之前的 Date類,你可以使用 Date 類和 Instant 類各自的轉換方法互相轉換,例如:Date.from(Instant) 將 Instant 轉換成java.util.Date,Date.toInstant() 則是將 Date 類轉換成 Instant 類。
18、在 Java 8 中如何使用預定義的格式化工具去解析或格式化日期
在 Java 8 以前的世界里,日期和時間的格式化非常詭異,唯一的幫助類 SimpleDateFormat 也是非線程安全的,而且用作局部變量解析和格式化日期時顯得很笨重。幸好線程局部變量能使它在多線程環境中變得可用,不過這都是過去時了。Java 8 引入了全新的日期時間格式工具,線程安全而且使用方便。它自帶了一些常用的內置格式化工具。
19、如何在 Java 中使用自定義格式化工具解析日期
盡管內置格式化工具很好用,有時還是需要定義特定的日期格式。可以調用 DateTimeFormatter 的 ofPattern() 靜態方法并傳入任意格式返回其實例,格式中的字符和以前代表的一樣,M 代表月,m 代表分。如果格式不規范會拋出 DateTimeParseException 異常,不過如果只是把 M 寫成 m 這種邏輯錯誤是不會拋異常的。
20、在 Java 8 中如何把日期轉換成字符串
這是迄今為止 Java 日期轉字符串最為簡單的方式了。下面的例子將返回一個代表日期的格式化字符串。和前面類似,還是需要創建 DateTimeFormatter 實例并傳入格式,但這回調用的是 format() 方法,而非 parse() 方法。這個方法會把傳入的日期轉化成指定格式的字符串。
LocalDateTime arrivalDate = LocalDateTime.now(); try {DateTimeFormatter format = DateTimeFormatter.ofPattern("MMMdd yyyy hh:mm a");String landing = arrivalDate.format(format);System.out.printf("Arriving at : %s %n", landing); }catch (DateTimeException ex) {System.out.printf("%s can't be formatted!%n", arrivalDate);ex.printStackTrace(); }21Java 8 日期時間API
22.LocalDateTime與字符串互轉/Date互轉/LocalDate互轉/指定日期/時間比較
與字符串互轉
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime time = LocalDateTime.now();String localTime = df.format(time);LocalDateTime ldt = LocalDateTime.parse("2018-06-01 10:12:05",df);System.out.println("LocalDateTime轉成String類型的時間:"+localTime);System.out.println("String類型的時間轉成LocalDateTime:"+ldt);與Date互轉
java.util.Date date = new java.util.Date();Instant instant = date.toInstant();ZoneId zone = ZoneId.systemDefault();LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone); LocalDateTime localDateTime = LocalDateTime.now();ZoneId zone = ZoneId.systemDefault();Instant instant = localDateTime.atZone(zone).toInstant();java.util.Date date = Date.from(instant);與LocalDate互轉
LocalDateTime now = LocalDateTime.now();LocalDate localDate = now.toLocalDate(); LocalDate localDate = LocalDate.now();ZoneId zone = ZoneId.systemDefault();Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();java.util.Date date = Date.from(instant);調整時間
LocalDateTime now = LocalDateTime.now();//明天LocalDateTime plusDays = now.plusDays(1);//昨天LocalDateTime plusDays2 = now.plusDays(-1);//還有時分等同理時間比較
LocalDateTime now = LocalDateTime.now();Long epochMilli = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();間隔計算
使用Duration進行 day,hour,minute,second等的計算
使用Period進行Year,Month的計算
Duration duration = Duration.between(localDateTime,localDateTime4); duration.toDays(); duration.toHours(); duration.toMinutes(); Period period2 = Period.between(localDateTime.toLocalDate(),localDateTime4.toLocalDate()); period2.getYears(); period2.getMonths(); period2.toTotalMonths();判斷是否是今天或昨天
String time = "2018-08-09 11:20:45";DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");LocalDateTime localTime = LocalDateTime.parse(time, dtf);LocalDateTime startTime = LocalDate.now().atTime(0, 0, 0);LocalDateTime endTime = LocalDate.now().atTime(23, 59, 59);LocalDateTime startYesterday = LocalDate.now().plusDays(-1).atTime(0, 0, 0);LocalDateTime endYesterday = LocalDate.now().plusDays(-1).atTime(23, 59, 59);//如果小于昨天的開始日期if (localTime.isBefore(startYesterday)) {System.out.println("時間是過去");}//時間是昨天if (localTime.isAfter(startYesterday) && localTime.isBefore(endYesterday)) {System.out.println("時間是昨天");}//如果大于今天的開始日期,小于今天的結束日期if (localTime.isAfter(startTime) && localTime.isBefore(endTime)) {System.out.println("時間是今天");}//如果大于今天的結束日期if (localTime.isAfter(endTime)) {System.out.println("時間是未來");}}23.獲取當天的開始和結束時間
private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");public static void main(String[] args) {//獲取當前時間LocalDateTime nowTime = LocalDateTime.now();//獲取當前日期LocalDate nowDate = LocalDate.now();//設置零點LocalDateTime beginTime = LocalDateTime.of(nowDate,LocalTime.MIN);//將時間進行格式化String time1= beginTime.format(dtf);//設置當天的結束時間LocalDateTime endTime = LocalDateTime.of(nowDate,LocalTime.MAX);//將時間進行格式化String time2 =dtf.format(endTime);System.out.println("今天開始的時間beginTime:"+time1);System.out.println("今天結束的時間endTime:"+time2); }輸出的結果是:今天開始的時間beginTime:2019-05-26 00:00:00今天結束的時間endTime: 2019-05-26 23:59:5924.本周開始、結束時間
//本周開始時間 TemporalAdjuster FIRST_OF_WEEK =TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue()- DayOfWeek.MONDAY.getValue())); String weekStart = df.format(inputDate.with(FIRST_OF_WEEK)); //本周結束時間 TemporalAdjuster LAST_OF_WEEK =TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue())); String weekEnd = df.format(inputDate.with(LAST_OF_WEEK));25.本月第一天、最后一天
//TODO 本月的第一天 String monthStart = df.format(LocalDate.of(inputDate.getYear(),inputDate.getMonth(),1)); //TODO 本月的最后一天 String monthEnd = df.format(inputDate.with(TemporalAdjusters.lastDayOfMonth()));26.LocalDateTime指定時間,生成指定時間段的隨機時間
/*** 取范圍日期的隨機日期時間,不含邊界* @param startDay* @param endDay* @return*/public static LocalDateTime randomLocalDateTime(int startDay, int endDay) {int plusMinus = 1;if (startDay < 0 && endDay > 0) {plusMinus = Math.random() > 0.5 ? 1 : -1;if (plusMinus > 0) {startDay = 0;} else {endDay = Math.abs(startDay);startDay = 0;}} else if (startDay < 0 && endDay < 0) {plusMinus = -1;//兩個數交換startDay = startDay + endDay;endDay = startDay - endDay;startDay = startDay - endDay;//取絕對值startDay = Math.abs(startDay);endDay = Math.abs(endDay);}//指定時間LocalDate day = LocalDate.now().plusDays(plusMinus * RandomUtils.nextInt(startDay, endDay));int hour = RandomUtils.nextInt(1, 24);int minute = RandomUtils.nextInt(0, 60);int second = RandomUtils.nextInt(0, 60);LocalTime time = LocalTime.of(hour, minute, second);return LocalDateTime.of(day, time);}調用方法:
//生成指定時間段的隨機LocalDateTime時間 randomLocalDateTime(-3, 3).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));或:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime ldt = randomLocalDateTime(-7, 1); String odMapStartTime = ldt.format(dtf); String odMapEndTime = ldt.plusMinutes(r.nextInt(5)).format(dtf);日期處理
1.1 用Calendar設置時間的坑
反例:
Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR, 10); System.out.println(c.getTime());運行結果:
Thu Mar 26 22:28:05 GMT+08:00 2020解析:
我們設置了10小時,但運行結果是22點,而不是10點。因為Calendar.HOUR默認是按12小時制處理的,需要使用Calendar.HOUR_OF_DAY,因為它才是按24小時處理的。
正例:
1.2 Java日期格式化YYYY的坑
反例:
Calendar calendar = Calendar.getInstance(); calendar.set(2019, Calendar.DECEMBER, 31);Date testDate = calendar.getTime();SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd"); System.out.println("2019-12-31 轉 YYYY-MM-dd 格式后 " + dtf.format(testDate));運行結果:
2019-12-31 轉 YYYY-MM-dd 格式后 2020-12-31解析:
為什么明明是2019年12月31號,就轉了一下格式,就變成了2020年12月31號了?因為YYYY是基于周來計算年的,它指向當天所在周屬于的年份,一周從周日開始算起,周六結束,只要本周跨年,那么這一周就算下一年的了。正確姿勢是使用yyyy格式。
正例:
Calendar calendar = Calendar.getInstance(); calendar.set(2019, Calendar.DECEMBER, 31);Date testDate = calendar.getTime();SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd"); System.out.println("2019-12-31 轉 yyyy-MM-dd 格式后 " + dtf.format(testDate));1.3 Java日期格式化hh的坑。
反例:
String str = "2020-03-18 12:00"; SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd hh:mm"); Date newDate = dtf.parse(str); System.out.println(newDate);運行結果:
Wed Mar 18 00:00:00 GMT+08:00 2020解析:
設置的時間是12點,為什么運行結果是0點呢?因為hh是12制的日期格式,當時間為12點,會處理為0點。正確姿勢是使用HH,它才是24小時制。
正例:
1.4 Calendar獲取的月份比實際數字少1即(0-11)
反例:
//獲取當前月,當前是3月 Calendar calendar = Calendar.getInstance(); System.out.println("當前"+calendar.get(Calendar.MONTH)+"月份");運行結果:
當前2月份
解析:
The first month of the year in the Gregorian and Julian calendars is <code>JANUARY</code> which is 0;也就是1月對應的是下標 0,依次類推。因此獲取正確月份需要加 1.
復制代碼正例:
1.5 Java日期格式化DD的坑
反例:
Calendar calendar = Calendar.getInstance(); calendar.set(2019, Calendar.DECEMBER, 31);Date testDate = calendar.getTime();SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-DD"); System.out.println("2019-12-31 轉 yyyy-MM-DD 格式后 " + dtf.format(testDate));運行結果:
2019-12-31 轉 yyyy-MM-DD 格式后 2019-12-365解析:
DD和dd表示的不一樣,DD表示的是一年中的第幾天,而dd表示的是一月中的第幾天,所以應該用的是dd。
正例:
1.6 SimleDateFormat的format初始化問題
反例:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); System.out.println(sdf.format(20200323));運行結果:
1970-01-01
解析:
用format格式化日期是,要輸入的是一個Date類型的日期,而不是一個整型或者字符串。
正例:
1.7 日期本地化問題
反例:
String dateStr = "Wed Mar 18 10:00:00 2020"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy"); LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter); System.out.println(dateTime);運行結果:
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Wed Mar 18 10:00:00 2020' could not be parsed at index 0at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)at java.time.LocalDateTime.parse(LocalDateTime.java:492)at com.example.demo.SynchronizedTest.main(SynchronizedTest.java:19)解析:
DateTimeFormatter 這個類默認進行本地化設置,如果默認是中文,解析英文字符串就會報異常。可以傳入一個本地化參數(Locale.US)解決這個問題
正例:
1.8 SimpleDateFormat 解析的時間精度問題
反例:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String time = "2020-03"; System.out.println(sdf.parse(time));運行結果:
Exception in thread "main" java.text.ParseException: Unparseable date: "2020-03"at java.text.DateFormat.parse(DateFormat.java:366)at com.example.demo.SynchronizedTest.main(SynchronizedTest.java:19)解析:
SimpleDateFormat 可以解析長于/等于它定義的時間精度,但是不能解析小于它定義的時間精度。
正例:
1.9 SimpleDateFormat 的線性安全問題
反例:
public class SimpleDateFormatTest {private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000));while (true) {threadPoolExecutor.execute(() -> {String dateString = sdf.format(new Date());try {Date parseDate = sdf.parse(dateString);String dateString2 = sdf.format(parseDate);System.out.println(dateString.equals(dateString2));} catch (ParseException e) {e.printStackTrace();}});}}運行結果:
Exception in thread "pool-1-thread-49" java.lang.NumberFormatException: For input string: "5151."at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)at java.lang.Long.parseLong(Long.java:589)at java.lang.Long.parseLong(Long.java:631)at java.text.DigitList.getLong(DigitList.java:195)at java.text.DecimalFormat.parse(DecimalFormat.java:2051)at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)at java.text.DateFormat.parse(DateFormat.java:364)at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748) Exception in thread "pool-1-thread-47" java.lang.NumberFormatException: For input string: "5151."at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)at java.lang.Long.parseLong(Long.java:589)at java.lang.Long.parseLong(Long.java:631)at java.text.DigitList.getLong(DigitList.java:195)at java.text.DecimalFormat.parse(DecimalFormat.java:2051)at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)at java.text.DateFormat.parse(DateFormat.java:364)at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)解析:
全局變量的SimpleDateFormat,在并發情況下,存在安全性問題。
- SimpleDateFormat繼承了 DateFormat
- DateFormat類中維護了一個全局的Calendar變量
- sdf.parse(dateStr)和sdf.format(date),都是由Calendar引用來儲存的。
- 如果SimpleDateFormat是static全局共享的,Calendar引用也會被共享。
- 又因為Calendar內部并沒有線程安全機制,所以全局共享的SimpleDateFormat不是線性安全的。
解決SimpleDateFormat線性不安全問題,有三種方式:
- 將SimpleDateFormat定義為局部變量
- 使用ThreadLocal。
- 方法加同步鎖synchronized。
正例:
public class SimpleDateFormatTest {private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>();public static DateFormat getDateFormat() {DateFormat df = threadLocal.get();if(df == null){df = new SimpleDateFormat(DATE_FORMAT);threadLocal.set(df);}return df;}public static String formatDate(Date date) throws ParseException {return getDateFormat().format(date);}public static Date parse(String strDate) throws ParseException {return getDateFormat().parse(strDate);}public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000));while (true) {threadPoolExecutor.execute(() -> {try {String dateString = formatDate(new Date());Date parseDate = parse(dateString);String dateString2 = formatDate(parseDate);System.out.println(dateString.equals(dateString2));} catch (ParseException e) {e.printStackTrace();}});}} }1.10Java日期的夏令時問題
反例:
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.parse("1986-05-04 00:30:00"));運行結果:
Sun May 04 01:30:00 CDT 1986
解析:
先了解一下夏令時
- 夏令時,表示為了節約能源,人為規定時間的意思。
- 一般在天亮早的夏季人為將時間調快一小時,可以使人早起早睡,減少照明量,以充分利用光照資源,從而節約照明用電。
- 各個采納夏時制的國家具體規定不同。目前全世界有近110個國家每年要實行夏令時。
- 1986年4月,中國中央有關部門發出“在全國范圍內實行夏時制的通知”,具體作法是:每年從四月中旬第一個星期日的凌晨2時整(北京時間),將時鐘撥快一小時。(1992年起,夏令時暫停實行。)
- 夏時令這幾個時間可以注意一下哈,1986-05-04, 1987-04-12, 1988-04-10, 1989-04-16, 1990-04-15, 1991-04-14.
結合demo代碼,中國在1986-05-04當天還在使用夏令時,時間被撥快了1個小時。所以0點30分打印成了1點30分。如果要打印正確的時間,可以考慮修改時區為東8區。
正例:
總結
以上是生活随笔為你收集整理的Java8 ,LocalDate,LocalDateTime处理日期和时间工具类,的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 慎独,是自律的最高层次
- 下一篇: java美元兑换,(Java实现) 美元