Date와 Calendar를 사용하지 않는 이유?
Java에서 날짜와 시간을 다룰 때, Calendar와 Date 대신 LocalDateTime을 사용합니다. LocalDateTime은 Java 8에서 도입된 java.time 패키지에 포함된 클래스로, Java 8 이전의 Date와 Calendar 클래스는 몇 가지 단점이 있었습니다.
- 불변성 부족:
Date와 Calendar는 setter가 존재하여 mutable(변경 가능) 하기 때문에, 날짜 객체를 공유할 때 상태가 변할 수 있어 멀티스레드 환경에서 오류가 발생할 가능성이 큽니다. - 복잡한 API, 가독성 문제:
Date와 Calendar 클래스에서 1월을 0부터 표기하고, 요일을 지정할 때도 일관성이 없습니다. 또한 Date와 Calendar의 API는 복잡하고 역할 분담이 하여, 많은 메서드들이 일관성이 부족해 개발자가 사용하기 어렵습니다. - 타입 안전성 부족:
Date는 시간이 포함된 날짜와 시간을 구분하지 않고, 타임존 개념이 약하여 정확한 시간대 처리가 어렵습니다.
Java 8의 java.time 패키지는 불변성과 명확한 API를 제공하여 안전하고 사용하기 쉬운 날짜/시간 처리를 가능하게 합니다.
클래스 | 설명 | 타임존 포함 여부 | 주로 사용하는 경우 |
LocalDateTime | 타임존 없이 로컬 시스템의 날짜와 시간을 표현 | X | 일정 관리, 로컬 시간 다루기 |
Instant | UTC 기준의 정확한 시점(타임스탬프) 표현 | X | 서버 로그 기록, 이벤트 타임스탬프 처리 |
OffsetDateTime | UTC와의 오프셋(±시간)를 포함한 날짜와 시간 표현 | 오프셋 포함 | 특정 오프셋을 기준으로 시간을 다뤄야 할 때 |
ZonedDateTime | 타임존을 포함한 날짜와 시간 표현 | 타임존 포함 | 여러 시간대 간 시간 변환, 글로벌 애플리케이션 시간 관리 |
LocalDateTime
LocalDateTime은 타임존 없이 로컬 시스템의 날짜와 시간을 표현하는 클래스입니다. 타임존이 없기 때문에 시스템의 로컬 타임에 의존합니다. 따라서 타임존을 고려하지 않고 로컬 시스템의 날짜와 시간이 필요한 경우 사용됩니다. LocalDateTime은 불변성을 띄고 있어 객체는 한 번 생성되면 변경되지 않습니다. 일정 관리, 로컬 서버에서 작동하는 로컬 이벤트 처리 등 시간대에 무관한 시간을 다룰 때 사용합니다.
// 현재 로컬 날짜와 시간
LocalDateTime now = LocalDateTime.now();
System.out.println("현재 날짜와 시간: " + now);
// 특정 날짜와 시간
LocalDateTime specificDateTime = LocalDateTime.of(2024, 9, 10, 20, 30);
System.out.println("특정 날짜와 시간: " + specificDateTime);
// 현재 날짜
LocalDate today = LocalDate.now();
System.out.println("오늘 날짜: " + today);
// 특정 날짜
LocalDate specificDate = LocalDate.of(2024, 9, 19);
System.out.println("특정 날짜: " + specificDate);
now() 메서드는 현재 로컬 컴퓨터의 날짜/시간을 저장한 객체를 리턴하고, of() 메서드는 매개값으로 주어진 날짜/시간 정보를 저장한 객체를 리턴합니다. LocalDate는 날짜를 LocalTime은 시간을 LocalDateTime은 날짜와 시간을 표현하는 데 사용합니다.
LocalDateTiem 메서드
- now(): 현재 날짜와 시간을 반환
- of(): 특정 날짜와 시간을 지정하여 LocalDateTime 객체 생성
- plusDays(), plusMonths(), plusYears(): 날짜를 더할 때 사용
- minusDays(), minusMonths(), minusYears(): 날짜를 뺄 때 사용
- plusHours(), plusMinutes(), plusSeconds(): 시간을 더할 때 사용
- minusHours(), minusMinutes(), minusSeconds(): 시간을 뺄 때 사용
- withYear(), withMonth(), withDayOfMonth(): 특정 연도, 월, 일로 날짜를 변경
- getYear(), getMonth(), getDayOfMonth(): 날짜 정보를 반환
- isBefore(), isAfter(): 날짜와 시간을 비교하여 이전인지, 이후인지를 확인
- toLocalDate(), toLocalTime(): 날짜 또는 시간 부분만 추출
LocalDateTime now = LocalDateTime.now();
LocalDateTime dateTime = LocalDateTime.of(2024, 9, 19, 14, 30);
LocalDateTime futureDate = dateTime.plusDays(10);
LocalDateTime pastDate = dateTime.minusMonths(2);
LocalDateTime laterTime = dateTime.plusHours(5);
LocalDateTime earlierTime = dateTime.minusMinutes(30);
LocalDateTime newDate = dateTime.withYear(2025).withMonth(5);
int year = dateTime.getYear();
boolean isBefore = dateTime.isBefore(LocalDateTime.now());
LocalDate date = dateTime.toLocalDate();
Instant
Instant는 기본적으로 UTC(협정세계시) 기준으로 시간을 다룰 때 사용합니다. 시간대 정보는 없고, 절대적인 시간을 나타냅니다. 서버 로그 기록, 이벤트 타임스태프 등 정확한 시점을 다루거나, 시간 차이 계산 사용에 적합합니다.
💁 UTC란?
국제적인 표준 시간의 기준으로 쓰이는 시각입니다. 1970년 1월 1일 00:00:00을 0밀리 초로 설정하여 그 후로 시간의 흐름을 나노초로 계산한 것입니다. 참고로 한국은 UTC+9입니다.
// 현재 UTC 시간
Instant now = Instant.now();
System.out.println("현재 UTC 시간: " + now);
// 1시간 뒤의 시간
Instant oneHourLater = now.plusSeconds(3600);
System.out.println("1시간 뒤의 시간: " + oneHourLater);
Duration timeElapsed = Duration.between(now, oneHourLater);
System.out.println("경과 시간: " + timeElapsed.getSeconds() + "초");
Instant객체로 현재 시간과 1시간 뒤 시간을 기록하고, Duration.between()을 사용해 두 시점 간 경과한 시간을 계산합니다.
Instant의 메서드
- now(): 현재 시간을 UTC 기준으로 반환
- ofEpochSecond(): 1970년 1월 1일 00:00:00 UTC부터 지정된 초만큼 지난 시점의 Instant 객체를 반환합니다.
- plusSeconds(), minusSeconds(): 초 단위로 시간을 더하거나 뺍니다.
- plusMillis(), minusMillis(): 밀리초 단위로 시간을 더하거나 뺍니다.
- isBefore(), isAfter(): 다른 Instant와 비교하여 이전 또는 이후 시점을 확인합니다.
- toEpochMilli(): 1970년 1월 1일 UTC 기준으로 밀리초 단위의 타임스탬프를 반환합니다.
- toString(): Instant 객체를 ISO-8601 형식의 문자열로 변환합니다.
Instant now = Instant.now();
Instant instant = Instant.ofEpochSecond(1620000000L);
Instant futureInstant = now.plusSeconds(3600);
Instant pastInstant = now.minusMillis(1000);
boolean isBefore = now.isBefore(Instant.now());
long epochMilli = now.toEpochMilli();
String instantString = now.toString();
OffsetDateTime
OffsetDateTime은 특정 UTC 오프셋(±시간)을 기준으로 시간을 다룰 때 사용합니다. +9:00 또는 -5:00과 같은 오프셋이 있는 시간대를 명확히 해야 할 때 유용합니다. 예를 들어, 글로벌 이벤트 예약처럼 해당 서비스는 UTC+2 시간대에서 오후 3시에 시작된다."와 같은 상황일 때 OffsetDateTime을 사용하면 적합합니다.
타임존 변환이 필요할 때는 ZonedDateTime을 사용하는 것이 더 적합합니다.
// UTC+02:00 시간
OffsetDateTime timeInParis = OffsetDateTime.now(ZoneOffset.of("+02:00"));
System.out.println("파리 시간 (UTC+2): " + timeInParis);
// UTC+09:00 시간
OffsetDateTime timeInSeoul = OffsetDateTime.now(ZoneOffset.of("+09:00"));
System.out.println("서울 시간 (UTC+9): " + timeInSeoul);
ZoneOffset은 UTC 기준으로 시간 차이(±)를 나타내는 클래스입니다. 위 예제는 ZoneOffset.of() 메서드를 사용하여 특정 오프셋을 지정한 후 OffsetDateTime 객체를 생성하는 코드입니다. 시간대가 다르더라도 고정된 오프셋을 기준으로 시간 관리가 가능합니다.
OffSetDateTime 메서드
- now(): 현재 날짜와 시간을 UTC 오프셋과 함께 반환합니다.
- of(): 특정 날짜, 시간, 오프셋을 지정하여 OffsetDateTime 객체를 생성합니다.
- withOffsetSameInstant(ZoneOffset): 다른 오프셋으로 변환하지만 UTC 기준의 시간을 유지합니다.
- withOffsetSameLocal(ZoneOffset): 로컬 시간을 유지하며 다른 오프셋으로 변경합니다.
- getOffset(): 현재 UTC 오프셋을 반환합니다.
- toZonedDateTime(): ZonedDateTime으로 변환합니다.
OffsetDateTime now = OffsetDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.of(2024, 9, 19, 14, 30, 0, 0, ZoneOffset.of("+09:00"));
OffsetDateTime newOffset = offsetDateTime.withOffsetSameInstant(ZoneOffset.of("-05:00"));
OffsetDateTime localOffset = offsetDateTime.withOffsetSameLocal(ZoneOffset.of("-05:00"));
ZoneOffset offset = offsetDateTime.getOffset();
ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();
ZonedDateTime
ZonedDateTime은 타임존 기반하여 날짜와 시간을 저장합니다. 세계 각국의 시간대를 관리할 수 있으며, 서로 다른 시간대 간의 시간 변환을 쉽게 할 수 있습니다.
// 서울 시간
ZonedDateTime seoulTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println("서울 시간: " + seoulTime);
// 도쿄 시간
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println("도쿄 시간: " + tokyoTime);
// 뉴욕 시간
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("뉴욕 시간: " + newYorkTime);
ZoneId는 전 세계 타임존을 정의한 클래스입니다. 예를 들어, "Asia/Seoul", "America/New_York"와 같은 문자열로 타임존을 나타냅니다. 위 예제는 ZoneId.of()를 사용해 각 도시의 타임존을 지정한 후, 해당 도시의 현재 시간을 가져오는 코드입니다. 이는 다른 시간대 간의 시간 비교 또는 시간 변환에 유용합니다.
타임존 간 시간 변환
// 서울 시간 기준으로 현재 시간
ZonedDateTime seoulTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println("서울 시간: " + seoulTime);
// 뉴욕 시간으로 변환
ZonedDateTime newYorkTime = seoulTime.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println("뉴욕 시간: " + newYorkTime);
withZoneSameInstant() 메서드를 사용해 서울 시간을 뉴욕 시간으로 변환한 예제 코드입니다. 국제적인 시간을 관리할 때 유용한 방법입니다.
ZonedDateTime 메서드
- now(): 현재 시스템의 타임존을 기준으로 날짜와 시간을 반환합니다.
- of(): 특정 날짜, 시간, 타임존을 지정하여 ZonedDateTime 객체를 생성합니다.
- withZoneSameInstant(ZoneId): 타임존을 변경하지만 동일한 UTC 시간을 유지합니다.
- withZoneSameLocal(ZoneId): 로컬 시간을 유지하면서 타임존을 변경합니다.
- toLocalDateTime(): 타임존을 제거하고 LocalDateTime 객체를 반환합니다.
- getZone(): 현재 타임존을 반환합니다.
- plusDays(), minusDays(): 날짜를 더하거나 뺄 수 있습니다.
- toOffsetDateTime(): OffsetDateTime 객체로 변환합니다.
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(2024, 9, 19, 14, 30, 0, 0, ZoneId.of("Asia/Seoul"));
ZonedDateTime newYorkTime = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New_York"));
ZonedDateTime newZoneTime = zonedDateTime.withZoneSameLocal(ZoneId.of("America/New_York"));
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
ZoneId zone = zonedDateTime.getZone();
ZonedDateTime futureTime = zonedDateTime.plusDays(5);
OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime();
두 시간 또는 날짜 간의 차이: Duration, Period
Duration
- 두 시간 간격을 시, 분, 초, 나노초 단위로 나타냅니다.
- 두 Instant 사이의 시간 차이를 구할 때 유용합니다.
Instant start = Instant.now();
Instant end = start.plusSeconds(120); // 2분 뒤
Duration duration = Duration.between(start, end);
System.out.println("Seconds: " + duration.getSeconds() + "초");
LocalTime startTime = LocalTime.of(10, 0, 0);
LocalTime endTime = LocalTime.of(15, 30, 0);
Duration duration = Duration.between(startTime, endTime);
System.out.println("Hours: " + duration.toHours() + ", Minutes: " + duration.toMinutesPart());
// 5시간을 나타내는 Duration 객체 생성
Duration fiveHours = Duration.ofHours(5);
System.out.println(fiveHours);
주요 메서드
- ofHours(), ofMinutes(), ofSeconds(), ofMillis(): 시간 단위의 Duration 객체를 생성합니다.
- between(): 두 Instant나 LocalTime 간의 차이를 Duration으로 반환합니다.
- plusHours(), plusMinutes(), plusSeconds(): 시간을 더합니다.
- minusHours(), minusMinutes(), minusSeconds(): 시간을 뺍니다.
- toHours(), toMinutes(), toMillis(): 특정 단위로 변환된 값을 반환합니다.
Period
- 두 날짜 간의 차이를 년, 월, 일 단위로 나타냅니다.
LocalDate startDate = LocalDate.of(2024, 1, 1);
LocalDate endDate = LocalDate.of(2024, 12, 31);
Period period = Period.between(startDate, endDate);
System.out.println("남은 기간: " + period.getMonths() + "개월 " + period.getDays() + "일");
주요 메서드
- ofYears(), ofMonths(), ofDays(): 연도, 월, 일 단위의 Period 객체를 생성합니다.
- between(): 두 날짜 간의 차이를 Period로 반환합니다.
- plusYears(), plusMonths(), plusDays(): 기간을 더합니다.
- minusYears(), minusMonths(), minusDays(): 기간을 뺍니다.
- getYears(), getMonths(), getDays(): 각각의 연도, 월, 일 값을 반환합니다.
'Java' 카테고리의 다른 글
Java 컬렉션 프레임워크 완벽 이해하기 (0) | 2024.09.26 |
---|---|
Java 날짜 및 시간 포맷 다루기. SimpleDateFormat, DateTimeFormatter, FastDateFormat (1) | 2024.09.24 |
Java 예외 처리 완벽 이해하기 (0) | 2024.09.19 |
Java JVM 메모리 구조와 메모리 저장 방식 (1) | 2024.09.18 |
Java 상속(Inheritance), 인터페이스(Interface), 추상 클래스(Abstract Class) 차이점 (0) | 2024.09.18 |