반응형
☕️ java.time 패키지
java.time 패키지는 자바8 버전에서 공개된 패키지로 날짜와 시간을 표현하는 클래스를 제공한다.
☕️ java.time 패키지 사용 이유
기존 날짜와 시간을 위해 사용하던 클래스인 Calendar와 Date 클래스 다양한 문제점이 존재하였다.
- 불변객체가 아니다
- 변하기 쉬운(mutable) 클래스이기 때문에 스레드 안전( thread safe ) 하지 않다. - 헷갈리는 월 지정
- Calendar 월의 상수값은 0부터 시작이기 때문에 2023.09.01로 셋팅을 하고 싶다면, 'cal.set(2023, 8, 1);' 과 같은 형태로 사용해야 한다. - 일관성 없는 요일 상수
- Calendar의 일요일은 상수값 1을, Date의 일요일은 상수값 0을 가진다. - 오류에 둔감한 TimeZone
- 존재하지 않는 TimeZone ID를 적어도 컴파일 시점에 오류를 잡지 못한다.
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/* Calendar / Date 단점 */
public class TimeEx {
public static void main(String[] args) {
// 헷갈리는 월 지정 : 월은 0부터 시작되어 2023.09.01을 설정하기 위해서는 9가 아닌 8을 입력해야한다.
Calendar cal = Calendar.getInstance();
cal.set(2023, 8, 1);
System.out.println(cal.getTime()); // Fri Sep 01 12:35:21 KST 2023
// 일관성 없는 요일 상수 (Calendar의 일요일은 상수값 1을, Date의 일요일은 상수값 0을 가진다.)
System.out.println(cal.get(Calendar.DAY_OF_WEEK)); // 1
Date date = cal.getTime();
System.out.println(date.getDay()); // 0
// 오류에 둔감한 TimeZone (존재하지 않는 TimeZone ID를 적어도 컴파일 시점에 오류를 잡지 못한다.)
TimeZone zone1 = TimeZone.getTimeZone("Asia/Seoul");
System.out.println(zone1.getID()); // Asia/Seoul
TimeZone zone2 = TimeZone.getTimeZone("Seoul/Asia");
System.out.println(zone2.getID()); // GMT
}
}
☕️ java.time 패키지의 주요 클래스
- LocalDate
- 날짜 정보만 저장할 수 있으며, 두 가지 정적 메서드가 정의되어 있다. now()는 컴퓨터의 현재 날짜 정보를 저장한 LocalDate 객체를 리턴하고, of()는 매개값으로 주어진 날짜 정보를 저장한 LocalDate 객체를 리턴한다. - LocalTime
- 시간 정보만 저장할 수 있으며, 두 가지 정적 메서드가 정의되어 있다. now()는 컴퓨터의 현재 시간 정보를 저장한 LocalTime 객체를 리턴한다. of()는 매개 값으로 주어진 시간 정보를 저장한 LocalTime 객체를 리턴한다. - LocalDateTime
- LocalDate와 LocalTime을 결합한 클래스라고 할 수 있으며, 날짜와 시간 정보를 모두 저장한다. 위에 설명한 클래스들처럼 두 가지 정적 메서드가 정의되어 있다. now()는 컴퓨터의 현재 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴하고, of()는 매개값으로 주어진 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴한다. - ZonedDateTime
- ISO-8601 달력 시스템에서 정의하고 있는 타임존(time-zone)의 날짜와 시간을 저장하는 클래스이다. - Instant
- 특정 시간의 타임스탬프로 사용된다. 주로 특정한 두 시점 간의 시간적 우선순위를 따질 때 사용한다. java.util.Date와 유사하지만, Date는 로컬 컴퓨터의 현재 날짜와 시간을 기준으로, Instant는 협정세계시(UTC)를 기준으로 한다는 차이점이 있다.
반응형
☕️ 사용 예제 - 객체 생성
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.TimeZone;
public class TimeEx {
public static void main(String[] args) throws InterruptedException {
/* LocalDate */
LocalDate curDate = LocalDate.now(); // 2023-09-09
System.out.println(curDate);
LocalDate targetDate = LocalDate.of(2023, 8, 1); // 2023-08-01. 캘린더와 다르게 month의 값이 직관적이다.
System.out.println(targetDate);
/* LocalTime */
LocalTime curTime = LocalTime.now();
System.out.println(curTime); // 13:19:06.503453
LocalTime targetTime = LocalTime.of(8, 10, 2, 3);
System.out.println(targetTime); // 08:10:02.000000003
/* LocalDateTime */
LocalDateTime curDateTime = LocalDateTime.now();
System.out.println(curDateTime); // 2023-09-09T13:20:31.646277
LocalDateTime targetDateTime = LocalDateTime.of(2023, 9, 1, 10, 30, 59, 1);
System.out.println(targetDateTime); // 2023-09-01T10:30:59.000000001
/* ZonedDateTime */
ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
System.out.println(utcDateTime); // 2023-09-09T04:21:07.926983Z[UTC]
ZonedDateTime londonDateTime = ZonedDateTime.now(ZoneId.of("Europe/London"));
System.out.println(londonDateTime); // 2023-09-09T05:21:07.927609+01:00[Europe/London]
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println(seoulDateTime); // 2023-09-09T13:21:07.928687+09:00[Asia/Seoul]
/* Instant */
Instant instant1 = Instant.now();
Thread.sleep(1000);
Instant instant2 = Instant.now();
if (instant1.isBefore(instant2)) {
System.out.println("instant1이 빠르다.");
} else if (instant2.isAfter(instant1)) {
System.out.println("instant1이 느리다.");
} else {
System.out.println("동일한 시간이다.");
}
System.out.println("차이(nanos): " + instant1.until(instant2, ChronoUnit.NANOS));
/* 실행결과
instant1이 빠르다.
차이(nanos): 1005076000
*/
}
}
☕️ 사용 예제 - 날짜 및 시간 조작
import java.time.*;
import java.time.temporal.ChronoUnit;
public class TimeEx {
public static void main(String[] args) throws InterruptedException {
/* 날짜와 시간 조작하기 */
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 현재. 2023-09-09T13:30:33.210107
System.out.println(now.minusYears(1L)); // 년 뺴기. 2022-09-09T13:30:33.210107
System.out.println(now.minusMonths(1L)); // 달 뺴기. 2023-08-09T13:30:33.210107
System.out.println(now.minusDays(1L)); // 일 빼기. 2023-09-08T13:30:33.210107
System.out.println(now.minusWeeks(1L)); // 주 빼기. 2023-09-02T13:30:33.210107
System.out.println(now.plusYears(1L)); // 년 더하기. 2024-09-09T13:30:33.210107
System.out.println(now.plusMonths(1L)); // 달 더하기. 2023-10-09T13:30:33.210107
System.out.println(now.plusWeeks(1L)); // 주 더하기. 2023-09-16T13:30:33.210107
System.out.println(now.plusDays(1L)); // 일 더하기. 2023-09-10T13:30:33.210107
System.out.println(now.minusHours(1L)); // 시간 뺴기. 2023-09-09T12:30:33.210107
System.out.println(now.minusMinutes(1L)); // 분 빼기. 2023-09-09T13:29:33.210107
System.out.println(now.minusSeconds(1L)); // 초 빼기. 2023-09-09T13:30:32.210107
System.out.println(now.minusNanos(1L)); // 나노초 빼기. 2023-09-09T13:30:33.210106999
System.out.println(now.plusHours(1L)); // 시간 더하기. 2023-09-09T14:30:33.210107
System.out.println(now.plusMinutes(1L)); // 분 더하기. 2023-09-09T13:31:33.210107
System.out.println(now.plusSeconds(1L)); // 초 더하기. 2023-09-09T13:30:34.210107
System.out.println(now.plusNanos(1L)); // 나노초 더하기. 2023-09-09T13:30:33.210107001
// 년도 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstDayOfYear());
System.out.println("이번 해의 첫 번째 일 : " + targetDateTime); // 2023-01-01T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.lastDayOfYear());
System.out.println("이번 해의 마지막 일 : " + targetDateTime); // 2023-12-31T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.firstDayOfNextYear());
System.out.println("다음 해의 첫 번째 일 : " + targetDateTime); // 2024-01-01T13:35:30.096807
// 월 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("이번 달의 첫 번째 일 : " + targetDateTime); // 2023-09-01T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("이번 달의 마지막 일 : " + targetDateTime); // 2023-09-30T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println("다음 달의 첫 번째 일 : " + targetDateTime); // 2023-10-01T13:35:30.096807
// 요일 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println("이번 달의 첫 번째 월요일 : " + targetDateTime); // 2023-09-04T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("돌아오는 월요일 : " + targetDateTime); // 2023-09-11T13:35:30.096807
targetDateTime = now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
System.out.println("지난 월요일 : " + targetDateTime); // 2023-09-04T13:35:30.096807
}
}
☕️ 사용 예제 - 날짜 및 시간 비교
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
public class TimeEx {
public static void main(String[] args) throws InterruptedException {
/* 날짜와 시간 비교 */
LocalDateTime startDateTime = LocalDateTime.of(2023, 9, 1, 9, 0, 0);
System.out.println(startDateTime); // 2023-09-01T09:00
LocalDateTime endDateTime = LocalDateTime.of(2023, 12, 31, 23, 59, 59);
System.out.println(endDateTime); // 2023-12-31T23:59:59
// 종료까지 남은 기간을 until()과 between()을 사용해서 구할 수 있다.
long remainYear = startDateTime.until(endDateTime, ChronoUnit.YEARS); // 남은 연도 차이
long remainMonth = startDateTime.until(endDateTime, ChronoUnit.MONTHS); // 남은 달 차이
long remainWeek = startDateTime.until(endDateTime, ChronoUnit.WEEKS); // 남은 주 차이
long remainDay = startDateTime.until(endDateTime, ChronoUnit.DAYS); // 남은 일 차이
long remainHour = startDateTime.until(endDateTime, ChronoUnit.HOURS); // 남은 시간 차이
long remainMinute = startDateTime.until(endDateTime, ChronoUnit.MINUTES); // 남은 분 차이
long remainSecond = startDateTime.until(endDateTime, ChronoUnit.SECONDS); // 남은 초 차이
System.out.println("연 : " + remainYear); // 0
System.out.println("월 : " + remainMonth); // 3
System.out.println("주 : " + remainWeek); // 17
System.out.println("일 : " + remainDay); // 121
System.out.println("시간 : " + remainHour); // 2918
System.out.println("분 : " + remainMinute); // 175139
System.out.println("초 : " + remainSecond); // 10508399
remainYear = ChronoUnit.YEARS.between(startDateTime, endDateTime);
remainMonth = ChronoUnit.MONTHS.between(startDateTime, endDateTime);
remainWeek = ChronoUnit.WEEKS.between(startDateTime, endDateTime);
remainDay = ChronoUnit.DAYS.between(startDateTime, endDateTime);
remainHour = ChronoUnit.HOURS.between(startDateTime, endDateTime);
remainMinute = ChronoUnit.MINUTES.between(startDateTime, endDateTime);
remainSecond = ChronoUnit.SECONDS.between(startDateTime, endDateTime);
System.out.println("연 : " + remainYear); // 0
System.out.println("월 : " + remainMonth); // 3
System.out.println("주 : " + remainWeek); // 17
System.out.println("일 : " + remainDay); // 121
System.out.println("시간 : " + remainHour); // 2918
System.out.println("분 : " + remainMinute); // 175139
System.out.println("초 : " + remainSecond); // 10508399
// Priod 클래스로 날짜 차이를 구할 수 있다.
Period period = Period.between(startDateTime.toLocalDate(), endDateTime.toLocalDate());
System.out.println("종료까지 남은 기간: " + period.getYears() + "년 " + period.getMonths() + "월 " + period.getDays() + "일"); // 종료까지 남은 기간: 0년 3월 30일
// Duration 클래스로 시간 차이를 구할 수 있다.
Duration duration = Duration.between(startDateTime.toLocalTime(), endDateTime.toLocalTime());
System.out.println("종료까지 남은 기간: " + duration.getSeconds() + "초 " + duration.getNano() + "나노 초"); // 종료까지 남은 기간: 53999초 0나노 초
}
}
☕️ 사용 예제 - 날짜 포맷
import java.time.*;
import java.time.format.DateTimeFormatter;
public class TimeEx {
public static void main(String[] args) throws InterruptedException {
/* 날짜 포맷 */
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
String formattedString = LocalDateTime.now().format(formatter);
System.out.println(formattedString); // 2023년 09월 09일
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
formattedString = LocalDateTime.now().format(formatter);
System.out.println(formattedString); // 2023-09-09
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd a hh:mm:ss");
formattedString = LocalDateTime.now().format(formatter);
System.out.println(formattedString); // 2023-09-09 오후 01:50:33
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
formattedString = LocalDateTime.now().format(formatter);
System.out.println(formattedString); // 2023-09-09 13:51:11
formatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일 HH시 mm분 ss초");
formattedString = LocalDateTime.of(2023, 7, 31, 23, 58, 59).format(formatter);
System.out.println(formattedString); // 2023년 07월 31일 23시 58분 59초
}
}
References.
1. 방구의 개발냄새 - [Java] 시간과 날짜 Class - 정리
2. 기계공학과졸업하고게임만들기 - 자바, java.time 패키지
3. 책 읽는 개발자 테드 - [Java] 자바8의 새로운 날짜 관련 클래스들 - java.time 패키지 (LocalDate, LocalTime, LocalDateTime, ZonedDateTime)
4. kkatal_chai.velog - [Java8 Time API] LocalTime 정리
반응형
'IT' 카테고리의 다른 글
[Spring] @Transactional (1) | 2025.01.24 |
---|---|
[Java] Checked Exception과 Unchecked Exception (3) | 2025.01.22 |
[Java] Optional (1) | 2025.01.22 |
[Java] 스트림 API(Stream API) (1) | 2025.01.22 |
[Java] 진법 변환(10진수 <-> N진수) (1) | 2025.01.22 |