天天看點

學習筆記:LocalDateTime

LocalDateTime

      • 1. 環境
      • 2. 代碼
        •      2.1 LocalDate: 擷取年月日
        •      2.2 LocalTime: 擷取時分秒
        •      2.3 LocalDateTime: 擷取年月日時分秒
        •      2.4 LocalDateTime 年月日時分秒的 操作.
        •      2.5 時間計算
        •      2.6 格式化時間
        •      2.7 解析時間:
        •      2.8 看得懂的時間輸出
        •      2.9 日期加減日期
        •          2.91 LocalDateTime.util()
        •          2.92 Duration.between()
        •      7.0 相關工具類

1. 環境

Since JDK8

LocalDateTime 的好處
  • 每一個時間對象,都是線程安全的
  • 每一個對象都沒有公開的構造器,如果需要一個對象你首先想的不是 new,而是靜态工廠方法: now、of、from
  • 如果你喜歡敲全類名,請在使用時間api時忘記java.util和java.text,記住java.time

2. 代碼

為什麼建議使用你 LocalDateTime ,而不是 Date?

根據這篇部落格學習,下面練習的代碼, 并附上了輸出結果.

JDK8新增的 java.time

JDK8 新增的 java.time 這篇講得好

JDK8 的新特性 這個不錯

     2.1 LocalDate: 擷取年月日

/** LocalDate: 擷取年月日 */
	@Test
	public void m1() {
		//擷取目前年月日
		LocalDate localDate = LocalDate.now();
		//構造指定的年月日
		LocalDate localDate1 = LocalDate.of(2019, 9, 10);
		System.out.println("localDate = " + localDate); // localDate = 2020-07-04
		System.out.println("localDate1 = " + localDate1); // localDate1 = 2019-09-10
		
		int year = localDate.getYear();
		System.out.println("year = " + year); // year = 2020
		int year1 = localDate.get(ChronoField.YEAR);
		System.out.println("year1= " + year1); // year1= 2020
		Month month = localDate.getMonth();
		System.out.println("month= " + month); // month= JULY
		int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);
		System.out.println("month1= " + month1); // month1= 7
		int day = localDate.getDayOfMonth();
		System.out.println("day= " + day); // day= 6
		int day1 = localDate.get(ChronoField.DAY_OF_MONTH);
		System.out.println("day1= " + day1); // day1= 6
		DayOfWeek dayOfWeek = localDate.getDayOfWeek();
		System.out.println("dayOfWeek= " + dayOfWeek); // dayOfWeek= MONDAY
		int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);
		System.out.println("dayOfWeek1= " + dayOfWeek1); // dayOfWeek1= 1
	}
           

     2.2 LocalTime: 擷取時分秒

/** LocalTime: 擷取時分秒 */
	@Test
	public void m2() {
		// 擷取目前時分秒
		LocalTime localTime = LocalTime.now();
		// 構造指定的時分秒
		LocalTime localTime1 = LocalTime.of(10, 30, 55);
		System.out.println("localTime= " + localTime); // localTime= 10:34:27.591553
		System.out.println("localTime1= " + localTime1); // localTime1= 10:30:55
		

		//擷取小時
		int hour = localTime.getHour(); 
		int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
		System.out.println("hour= " + hour); // hour= 10
		System.out.println("hour1= " + hour1); // hour1= 10
		//擷取分
		int minute = localTime.getMinute();
		int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
		System.out.println("minute = " + minute); // minute = 34
		System.out.println("minute1 = " + minute1); // minute1 = 34
		//擷取秒
		int second = localTime.getSecond();
		int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);
		System.out.println("second = " + second); // second = 27
		System.out.println("second1 = " + second1); // second1 = 27
	}
           

     2.3 LocalDateTime: 擷取年月日時分秒

/** LocalDateTime: 擷取年月日時分秒 */
	@Test
	public void m3() {
		
		//擷取目前年月日
		LocalDate localDate = LocalDate.now();
		// 擷取目前時分秒
		LocalTime localTime = LocalTime.now();
		
		LocalDateTime localDateTime = LocalDateTime.now();
		LocalDateTime localDateTime1 = LocalDateTime.of(LocalDate.of(2020, 7, 3), LocalTime.of(10, 38, 55));
		LocalDateTime localDateTime2 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
		LocalDateTime localDateTime3 = localDate.atTime(localTime); // 相當于 localDate + localTime = LocalDateTime
		LocalDateTime localDateTime4 = localTime.atDate(localDate); // 相當于 localDate + localTime = LocalDateTime
		
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 2020-07-06T10:40:10.128524
		System.out.println("localDateTime1 = " + localDateTime1); // localDateTime1 = 2020-07-03T10:38:55
		System.out.println("localDateTime2 = " + localDateTime2); // localDateTime2 = 2019-09-10T14:46:56
		System.out.println("localDateTime3 = " + localDateTime3); // localDateTime3 = 2020-07-08T14:58:20.685306
		System.out.println("localDateTime4 = " + localDateTime4); // localDateTime4 = 2020-07-08T14:58:20.685306
		
		
		// 擷取LocalDate
		LocalDate localDate2 = localDateTime.toLocalDate();
		// 擷取LocalTime
		LocalTime localTime2 = localDateTime.toLocalTime();
		System.out.println("localDate2 = " + localDate2); // localDate2 = 2020-07-08;  localDateTime = 2020-07-08T15:05:34.630987
		System.out.println("localTime2 = " + localTime2); // localTime2 = 15:05:34.630987;  localDateTime = 2020-07-08T15:05:34.630987
		
		
		// 擷取秒數. ( 用 System.currentTimeMills()更友善 )
		Instant instant = Instant.now();
		long currentSecond = instant.getEpochSecond();
		long timeStamp1 = instant.toEpochMilli();
		long timeStamp2 = System.currentTimeMillis();
		System.out.println("currentSecond = " + currentSecond); // currentSecond = 1594192226
		System.out.println("timeStamp1 = " + timeStamp1); // timeStamp1 = 1594192226826
		System.out.println("timeStamp2 = " + timeStamp2); // timeStamp2 = 1594192226826
	}
           

     2.4 LocalDateTime 年月日時分秒的 操作.

/** 
	 * LocalDateTime 年月日時分秒的 操作.
	 * 
	 * LocalDate、LocalTime、LocalDateTime、Instant為不可變對象,修改這些對象對象會傳回一個副本
	 * 
	 * plusXX(): 在原來的基礎上加
	 * withXX(): 直接設定值
	 */
	@Test
	public void m4() {
		LocalDateTime localDateTime = LocalDateTime.of(1997, Month.FEBRUARY, 2, 9, 13, 14);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1997-02-02T09:13:14

		//增加一年 plusYears()
		localDateTime = localDateTime.plusYears(1);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1998-02-02T09:13:14
		localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1999-02-02T09:13:14
		// 減少一年 minusYears()
		localDateTime = localDateTime.minusYears(1);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1998-02-02T09:13:14
		
		//減少一個月 minusMonths(); 同理增加一月 就是 plusMonths(); 還可以修改 日、時分秒、周等等.
		localDateTime = localDateTime.minusMonths(1);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1998-01-02T09:13:14
		localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1997-12-02T09:13:14
		
		/* with: 設定值 */
		//修改年為2020
		localDateTime = localDateTime.withYear(2020);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 2020-12-02T09:13:14
		//修改為2022
		localDateTime = localDateTime.with(ChronoField.YEAR, 2022);
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 2022-12-02T09:13:14
	}
           

     2.5 時間計算

/**
	 * 時間計算
	 * 
	 * 比如有些時候想知道這個月的最後一天是幾号、下個周末是幾号,通過提供的時間和日期API可以很快得到答案
	 */
	@Test
	public void m5() {
		LocalDate localDate = LocalDate.now();
		System.out.println("localDate = " + localDate); // localDate = 2020-07-08
		
		// 年的第一天
		LocalDate localDate1 = localDate.with(TemporalAdjusters.firstDayOfYear());
		System.out.println("localDate1 = " + localDate1); // localDate1 = 2020-01-01
		
		// 月的第一天; 還有很多其他的, 點進去看吧.
		localDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
		System.out.println("localDate = " + localDate); // localDate = 2020-07-01
	}
           

     2.6 格式化時間

LocalDateTime -> String

/** 
	 * 格式化時間 
	 * 
	 * DateTimeFormatter預設提供了多種格式化方式,如果預設提供的不能滿足要求,可以通過DateTimeFormatter的ofPattern方法建立自定義格式化方式
	 */
	@Test
	public void m6() {
		LocalDate localDate = LocalDate.of(2019, 9, 10);
		String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
		String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
		//自定義格式化
		DateTimeFormatter dateTimeFormatter =   DateTimeFormatter.ofPattern("dd/MM/yyyy");
		String s3 = localDate.format(dateTimeFormatter);
		System.out.println("localDate = " + localDate); // localDate = 2019-09-10
		System.out.println("s1 = " + s1); // s1 = 20190910
		System.out.println("s2 = " + s2); // s2 = 2019-09-10
		System.out.println("s3 = " + s3); // s3 = 10/09/2019
		
		// LocalDateTime 轉換成 特定格式的 字元串
		LocalDateTime now = LocalDateTime.now();
		String nowStr1 = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
		String nowStr2 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
		System.out.println("now = " + now); // now = 2020-07-08T16:41:12.647672
		System.out.println("nowStr1 = " + nowStr1); // nowStr1 = 2020/07/08 16:41:12
		System.out.println("nowStr2 = " + nowStr2); // nowStr2 = 2020-07-08 16:42
		
		// format 是線程不安全的.  用 parse() 方法時候 需要特定格式的, 并且還要 try-catch
		String dateStr = "";
		Date date = new Date();
		if (date != null) {
			dateStr = new SimpleDateFormat("yyyy MM dd HH:mm").format(date);
		}
		System.out.println("dateStr = " + dateStr); // dateStr = 2020 07 08 16:43
	}
           

     2.7 解析時間:

String -> LocalDateTime

/** 
	 * 解析時間: 感覺還是 SimpleDateTime好用, 即使它線程不安全, 但是在開辟一個線程處理 好了.
	 * 
	 * 注意: 
	 * 1. 要解析的字元串, 格式必須要和 設定的pattern是一緻的, 不然就報錯。 
	 * 2. 使用 解析必須要 try-catch,  SimpleDateFormate的parse還會提示要處理異常, LocalDateTime居然不提示...
	 */
	@Test
	public void m7() {
		String dateStr = "1997-02-02 17:13:14";
		LocalDateTime localDateTime = null;
		try {
			localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("localDateTime = " + localDateTime); // localDateTime = 1997-02-02T17:13:14
		
		/*
		 * 自我感覺 沒 SimpleDateTime好用啊... 雖然 SimpleDateTime是線程不安全的
		 * 
		 * 1. LocatDateTime的parse() 使用 LocalDateTime 那字元串必須要 年月日 時分秒, 如果隻寫年月日, 就算 ofPattern("yyyy-MM-dd") 也不行. 需要用 LocalDate.parse()
		 * 2. 而SimpleDateFormat.parse() 就算隻寫了 "yyyy-MM-dd" 隻需要保證 年月日是此格式即可, 後面的時分秒無所謂.
		 */
		
		Date date = null;
		try {
			date = new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println("date = " + date); // date = Sun Feb 02 00:00:00 CST 1997
		
		
		// LocalDate, 這樣是不會報錯的, 字元串隻寫了年月日 就必須用 LocalDate來解析.
		String dateStr2 = "1997-02-02";
		LocalDate localDate = null;
		try {
			localDate = LocalDate.parse(dateStr2, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("localDate = " + localDate); // localDate = 1997-02-02
	}
           

     2.8 看得懂的時間輸出

挺好用的東西… JDK 14 會報錯, JDK8沒問題

/** 挺好用的東西.. JDK 14 會報錯, JDK8沒問題 */
	@Test
	public void m8() {
		LocalDateTime d1=LocalDateTime.now();
		FormatStyle dateTimeStyle=FormatStyle.LONG;
		 
		Locale.setDefault(Locale.CHINA);
		DateTimeFormatter formater=DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
		String format = d1.format(formater);
		System.out.println(format);//2017年11月30日 下午04時10分32秒
		 
		dateTimeStyle=FormatStyle.MEDIUM;
		 
		Locale.setDefault(Locale.CHINA);
		formater=DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
		format = d1.format(formater);
		System.out.println(format);//2017-11-30 16:10:32
		 
		Locale.setDefault(Locale.UK);
		format = d1.format(formater);
		System.out.println(formater);//2017-11-30 16:10:32
		
		// Locale.setDefault 和 DateTimeFormatter.ofLocalizedDateTime 必須重新設定一次, 否則像上面這樣的輸出結果和 第2個一樣
		Locale.setDefault(Locale.UK);
		formater=DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
		format = d1.format(formater);
		System.out.println(format);//30-Nov-2017 16:10:32
	}
           

     2.9 日期加減日期

         2.91 LocalDateTime.util()

         2.92 Duration.between()

public class Test02_LocalDateTime {

	public static void main(String[] args) {
		
		ZoneId zoneId = ZoneId.systemDefault();
		System.out.println("zoneId = " + zoneId); // zoneId = Asia/Shanghai
		
		LocalDateTime now = LocalDateTime.now();
		String dateStr1 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("dateStr1 = " + dateStr1);
		LocalDateTime loc = LocalDateTime.of(1997, 07, 13, 14, 55, 59);
		String dateStr2 = loc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("locStr = " + dateStr2); // dateStr2 = 1997-07-13 14:55:00

/// JDK14 報錯, JDK8 可以.		
//		FormatStyle formatStyle = FormatStyle.LONG;
//		Locale.setDefault(Locale.CHINA);
//		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(formatStyle);
//		String f1 = now.format(dateTimeFormatter);
//		System.out.println("f1 = " + f1);
		
		/* 
		 * 日期加減日期
		 * 
		 * 1. minusXX/plusXX: 隻能單獨加減年月日 or 時分秒的.
		 *    TemporalAmount 實作類之一是: Duration
		 * 3. LocalDateTime.until(): 第二個參數 - 第一個參數 的出來的正負天數.
		 * 4. Duration.between(): 第二個參數 - 第一個參數 的出來的正負天數.   
		 */
		Duration duration = Duration.between(now, loc);
		System.out.println("duration = " + duration); // duration = PT-201690H-36M-19.603835S .
		
		now = LocalDateTime.of(2020, 7, 16, 10, 13, 14);
		dateStr1 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("dateStr1 = " + dateStr1); // dateStr1 = 2020-07-16 10:13:14
		
		// locStr = 1997-07-13 14:55:59
		now = now.minusYears(loc.getYear()); // 1997
		dateStr1 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("dateStr1 = " + dateStr1); // dateStr1 = 0023-07-16 10:13:14
		
		now = now.minusDays(loc.getDayOfMonth()); // 13
		dateStr1 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("dateStr1 = " + dateStr1); // dateStr1 = 0023-07-03 10:13:14
		now = now.plusDays(13);
		
		TemporalAmount amountToSubtract = Duration.ofDays(13);
		now = now.minus(amountToSubtract);
		dateStr1 = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		System.out.println("dateStr1 = " + dateStr1); // dateStr1 = 0023-07-03 10:13:14
		
		
		/*
		 * 時間與時間的計算
		 * 
		 * 兩個時間之間的計算,結果為一個量。如,計算兩個時間相隔多少天。
		 * 舉例,計算2016年元旦到五一勞動節相隔多少天?
		 */
		LocalDateTime d1=LocalDateTime.of(2020, 07, 16, 11, 04);
		LocalDateTime d2=LocalDateTime.of(1997, 01, 03, 13, 14);
		System.err.println("d1 = " + d1.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // d1 = 2020-07-16 11:04:00
		System.err.println("d2 = " + d2.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // d2 = 1997-01-03 13:14:00
		
		long interval = d2.until(d1, ChronoUnit.DAYS);
		System.out.println(interval); // 8594

		// 也可以使用時間量的計算:
		Duration d = Duration.between(d1, d2);
		System.out.println(d.toDays()); // -8594
		System.out.println(d.toHours()); // -206277
		
		long age = d2.until(d1, ChronoUnit.YEARS);
		System.out.println("age = " + age); // age = 23, 這個算年齡...  但是不算天數, 自己寫的 age計算的工具類 會把天算上.
	}
}
           

     7.0 相關工具類

/** 聽說是 解決 SImpleDateFormat線程不安全問題 */
	private static final ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
	private static SimpleDateFormat getTime() {
		SimpleDateFormat sdf = local.get();
		if (sdf == null) {
			sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			local.set(sdf);
		}
		return sdf;
	}
	
    /** LocalDate轉Date */
    public static Date localDateToDate(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /** Date轉LocalDate */
    public static LocalDate dateToLocalDate(java.util.Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /** Date轉換為LocalDateTime */
    public static LocalDateTime dateToLocalDateTime(Date date){
        if (null == date) {
            return null;
        }
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    /** LocalDateTime轉換為Date */
    public static Date localDateTimeToDate( LocalDateTime localDateTime){
    	if (localDateTime == null) {
    		return null;
    	}
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }