<1> Date와 Time API 소개
- 자바 8에 새로운 날짜와 시간 API가 생긴 이유
- 그전까지 사용하던 java.util.Date 클래스는 mutable해서 thread safe하지 않다.
- 클래스 이름이 명확하지 않다. Date인데 시간까지 다룬다.
- 버그 발생할 여지가 많다. (타입 안정성이 없고, 월이 0부터 시작한다거나..)
- 날짜 시간 처리가 복잡한 애플리케이션에서는 보통 Joda Time을 쓰곤했다.
출력:
똑같은 인스턴스(after3Seconds) 안의 데이터가 바뀐다. = mutable
mutable한 객체들은 멀티 쓰레드 환경에서 안전하게 쓰기가 어렵다.
- 자바 8에서 제공하는 Date-Time API
- JSR-310 스팩의 구현체를 제공한다.
- Date-Time 디자인 철학
- Clear
- 명확하다.
- 기존의 java.util.Date 클래스처럼 time을 꺼냈는데 기계 time이고 이런 일 없음.
- Fluent
- null을 받는 게 없기 때문에 점(.) 찍어서 계속 이어갈 수 있다.
- Immutable
- 새로운 인스턴스가 나오는 것이지 기존의 인스턴스가 바뀐 게 아니다.
- Extensible
- 확장성
- 그레고리안 캘린더 말고도..
- Clear
// 예시
// Fluent
LocalDate today = LocalDate.now();
LocalDate payday = today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
// Immutable
LocalDate dateOfBirth = LocalDate.of(2012, Month.MAY, 14);
LocalDate firstBirthday = dateOfBirth.plusYears(1);
- 주요 API
- 기계용 시간 (machine time)과 인류용 시간(human time)으로 나눌 수 있다.
- 기계용 시간 : EPOCK (1970년 1월 1일 0시 0분 0초)부터 현재까지의 타임스탬프를 표현한다.
- 인류용 시간 : 우리가 흔히 사용하는 연,월,일,시,분,초 등을 표현한다.
- 타임스탬프는 Instant를 사용한다.
- 특정 날짜(LocalDate), 시간(LocalTime), 일시(LocalDateTime)를 사용할 수 있다.
- 기간을 표현할 때는 Duration (시간 기반)과 Period (날짜 기반)를 사용할 수 있다.
- DateTimeFormatter를 사용해서 일시를 특정한 문자열로 포매팅할 수 있다.
- 기계용 시간 (machine time)과 인류용 시간(human time)으로 나눌 수 있다.
<2> Date와 Time API
- 지금 이 순간을 기계 시간으로 표현하는 방법
- Instant.now() : 현재 UTC (GMT)를 리턴한다.
- Universal Time Coordinated == Greenwich Mean Time
Instant now = Instant.now();
System.out.println(now); // 기준 시 UTC(GMT) 출력
System.out.println(now.atZone(ZoneId.of("UTC"))); // now가 UTC 맞는지
// 내 위치의 시간 출력하기
ZoneId zone = ZoneId.systemDefault();
System.out.println(zone); // 내 위치 출력
ZonedDateTime zonedDateTime = now.atZone(zone);
System.out.println(zonedDateTime); // 내 위치의 시간 출력
출력:
- 인류용 일시를 표현하는 방법
- LocalDateTime.now() : 현재 시스템 Zone에 해당하는(로컬) 일시를 리턴한다.
- LocalDateTime.of(int, Month, int, int, int, int) : 로컬의 특정 일시를 리턴한다.
- ZonedDateTime.of(int, Month, int, int, int, int, ZoneId) : 특정 Zone의 특정 일시를 리턴한다.
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
LocalDateTime birthday =
LocalDateTime.of(1982, Month.JULY, 15, 0, 0, 0);
System.out.println(birthday);
ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
// Instant에서 ZonedDateTime으로 바꾸기 가능
Instant nowInstant = Instant.now();
ZonedDateTime zonedDateTime = nowInstant.atZone(ZoneId.of("Asia/Seoul"));
// 같은 결과 출력됨
System.out.println(nowInKorea);
System.out.println(zonedDateTime);
Instant <-> ZonedDateTime 왔다갔다 바꾸기 가능
- 기간을 표현하는 방법
- 인류용 기간 비교
- Period.between()
- until
- 기계용 기간 비교 (Instant 사용)
- Duration.between()
- 인류용 기간 비교
// 인간 시간 비교
LocalDate today = LocalDate.now();
LocalDate thisYearBirthday = LocalDate.of(2022, Month.JULY, 15);
// Period.between()
Period period = Period.between(today, thisYearBirthday);
System.out.println(period.getDays()); // 올해 생일까지 남은 날 출력
// until
Period until = today.until(thisYearBirthday));
System.out.println(until.get(ChronoUnit.DAYS)); // 같은 결과 출력
// 기계 시간 비교
Instant now = Instant.now();
Instant plus = now.plus(10, ChronoUnit.SECONDS);
Duration between = Duration.between(now, plus);
System.out.println(between.getSeconds()); // 10 출력
- 파싱 또는 포매팅
- 문자열을 입력 받거나 LocalDateTime을 문자열로 출력 할 때 주로 쓴다.
- 미리 정의해둔 포맷 참고 https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#predefined
- LocalDateTime.parse(String, DateTimeFormatter);
- Datetime
LocalDateTime now = LocalDateTime.now();
// 포매팅
DateTimeFormatter MMddyyyy = DateTimeFormatter.ofPattern("MM/dd/yyyy");
System.out.println(now.format(MMddyyyy)); // 11/11/2022 출력
// 파싱
LocalDate parse = LocalDate.parse("01/01/2022", MMddyyyy);
System.out.println(parse); // 01/01/2022 출력
- 레거시 API 지원
- GregorianCalendar와 Date 타입의 인스턴스를 Instant나 ZonedDateTime으로 변환 가능.
- java.util.TimeZone에서 java.time.ZoneId로 상호 변환 가능.
- Instant로 바꿀 수 있으면 다 최신 API로 바꿀 수 있다.
GregorianCalendar gregorianCalendar = new GregorianCalendar();
ZonedDateTime dateTime = gregorianCalendar.toInstant()
.atZone(ZoneId.systemDefault()); // GregorianCalendar -> ZonedDateTime
GregorianCalendar from = GregorianCalendar.from(dateTime); // ZonedDateTime -> GregorianCalendar
Date date = new Date();
Instant instant = date.toInstant(); // Date -> Instant
Date newDate = Date.from(instant); // Instant -> Date
ZoneId zoneId = TimeZone.getTimeZone("PST").toZoneId(); // TimeZone -> ZoneId
TimeZone timeZone = TimeZone.getTimeZone(zoneId); // ZoneId -> TimeZone
* 백기선 님의 인프런 강의 <더 자바, Java 8>을 듣고 정리한 내용입니다.
강의 정보: https://www.inflearn.com/course/the-java-java8/
참고
https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/
https://docs.oracle.com/javase/tutorial/datetime/overview/index.html
https://docs.oracle.com/javase/tutorial/datetime/iso/overview.html
'온라인 학습 > 더 자바, Java 8 강의' 카테고리의 다른 글
7. 애노테이션의 변화, 배열 병렬 정렬, Metaspace (1) | 2022.11.14 |
---|---|
4. Optional (0) | 2022.11.11 |
3. Stream (0) | 2022.11.10 |
2. 인터페이스의 변화 - default method, static method (0) | 2022.11.10 |
6. CompletableFuture - Concurrent 프로그래밍, Executors, Callable, Future, CompletableFuture (0) | 2022.11.06 |