Java에서 시간 다루기

Martin the dog·2023년 11월 1일

Date and LocalDate

Before LocalDate

기존 자바는 Date라는 클래스 하나로 날싸와 시간을 표현하였다. 이때 Date는 1900년 1월 1일 00시를 기준으로 얼마나 많은 ms가 흘러갔는지를 저장하여 시간을 표현한다. 그렇기 때문에 2023년 10월 31일을 담은 객체를 생성하는 코드는 다음과 같다

Date strangeDate = new Date(123,9,31);

뭔가 봤을 때 결과가 직관적이지 않다.
그렇기 때문에 이를 보완하고자 Java 8이후에는 LocalDate, LocalTime이 나왔다.

LocalDate & LocalTime

LocalDate는 기존 Date와 달리 보다 더 직관적이며 또 다양한 메써드들을 제공해준다.다음은 Date와 똑같이 2023년 10월 31일을 생성하는 코드이다.

LocalDate date = LocalDate.of(2023,10,31);<--of를 통해 LocalDate 생성
LocalDate date = LocalDate.parse("2023-10-31"); <-- parse를 통해 LocalDate 생성

보기만 해도 바로 설정한 날자가 언제인지 확인할 수 있다.
parse를 통해 값을 가져올 때는 DateTimeFormatter에서 그 형식을 설정할 수 있다.
저렇게 날을 직접 지정하는 방식 이외에도 LocalDate.now()를 통해 현재일로 세팅하는 방법도 있다.

설정한 값을 가져오는 메서드들도 다양하다.

date.getYear();<--2023 반환
date.getMonth();<--November 반환
date.getDayofMonth()<-- 31 설정된 일자 반환
date.getDayOfWeek()<-- Monday 반환
date.lengthOfMonth()<-- 31 설정된 달의 일수 반환
date.isLeapYear()<--윤년 여부 조사

시간을 나타내는 LocalTime도 별반 다르지 않다.

LocalTime time = LocalTime.of(22,10,15); <-- of를 이용한 방법
LocalTime time = LocalTime.parse("22:10:15") <-- parse를 이용한 방법

이는 22시 10분 15초를 의미한다.
LocalTime도 시,분,초를 반환하는 메소드를 제공한다.

time.getHour(); <-- 시간 반환
time.getMinute(); <-- 분 반환
time.getSecond(); <-- 초 반환

LocalDateTime

시간이 년원일, 시분초 두개로 언제나 나눠져 있는 것은 아니다. 년원일시분초가 전부 필요할 때가 있다.
그럴 때는 LocalDateTime을 사용하면 된다!
생LocalDate.time을 생성하는 법에는 위에서 나온 방법 처럼
1. of를 이용한 방법
2. atTime(time)/atTime(시,분,초) 를 통한 시간 설정
3. atDate(date)를 통한 년원일 설정
이 있다.

Instant

기계는 우리 처럼 시,분,초가 필요하지 않다! 좀더 정밀한 시간을 초단위로 표현하는데 Instant가 사용 된다. Instant는 1970년 1월 1일 0시0분0초를 기준으로 몇초의 시간이 흘렀는지를 초 단위로 기록하는 시간 표시 클래스이다.

Instant.ofEpochSecond를 통해 10억분의 1초 단위로 조절해 가며 초 값을 설정 해준다.

1970년 1월 1일 00시 00분 03초를 표현하는 방법들은 다음과 같다.

Instant.ofEpochSecond(3);
Instant.ofEpochSecond(3,0);
Instant.ofEpochSecond(2,1_000_000_000); 2초에서 1초뒤
Instant.ofEpochSecond(4,-1_000_000_000); 4초에서 1초전

Duration & Period

현실 세계에서는 두 시간 사이의 차이, 지속시간을 이용하여 validation을 하는 경우가 많다. Java에서도 이러한 조작을 하기 위해서 Duration이란 코드를 제공한다.

Duration

Duration d1 = Duration.between(시간1,시간2);

저 시간1과 시간2의 데이터 타입에는 time, LocalTime, LocalDateTime, Instant 등 이전에 배운 시간 요소들을 넣을 수 있다. 이때 Duration은 초단위로 계산하기 때문에 LocalDate는 Between에 입력하지 못한다.

Period

Period는 Duration과 달리 LocalDate를 입력받을 수 있다.

Period period = Period.between(LocalDate.of(2023,10,12),Localdate.of(2023,11,1);

Duration과 Period에서 제공하는 공통 메서드는 다음 링크에 나와 있는 내용을 참고하면 된다.
메써드 목록 링크

날짜 속성 변경 & 포맷팅

LocalDate에서는 withAttribute로 값을 바꿀수 있다. 물론 원본값은 수정되지 않고 수정된 값을 반환하는 방법이다.

date.withYear(2024); <- 2024년으로 바꿈
date.withDayOfMonth(25); <- 25일로 바꿈
date.withMonthOfYear(12); <- 12월로 바꿈

이렇게 직접 설정하는 방법 이외에도 plusWeek, minusYear와 같은 연산을 통해 값을 변경해줄 수 있다.

TemperalAdjuster

이렇게 단순히 값을 더하고 빼는 것 이외에도 다음주 일요일을 구한다거나 달의 마지막 날을 구하는 등 좀더 복잡한 일자 변경이 필요할 때가 있다. 이때는 TemporalAdjusters를 이용하여 해당 라이브러리에서 제공하는 복잡한 날짜 연산 메써드를 사용할 수 있다.

다음은 해당 메써드들중 중요하다 생각하는 것들의 목록이다.

메써드명설명
lastDayOfMonth월의 마지막 날을 구함
nextOrSame입력한 요일이 처음으로 나타나는 날짜를 반환함
firtInMonth현재 달의 첫 요일을 반환함

그 이외에도 다양한 메써드들을 제공한다. 그 이외에도 다양한 함수들을 제공하니 직접 찾아보기 바란다.

만약 원하는 메써드가 없다면 직접 만들 수 도 있다. 함수형 인터페이스 TemperalAdjuster를 implement하여 구현하면 된다!

@FunctionalInterface
public interface TemperalAdjuster{
	Temperal adjustInto(Temperal temperal);
}

이걸 직접 implement해도 되지만 우리는 람다 함수를 배웠으니 람다 함수를 이용해서 사용해보도록 하자.

포맷팅

날짜를 표시할때 한국에서만 해도 1998.02.27, 1998/02/27, 980227 처럼 날짜를 표기하는 방법이 다양하다. 이러한 데이터들의 형식을 지정해줘야 정상적으로 사용할 수 있을 것이다.

DateTimeFormatter.BASIC_ISO_DATE 와 DateTimeFormatter.ISO_LOCAL_DATE처럼 미리 정해진 형식도 있고 그 이외에도 우리가 직접 fomat을 지정하여 사용할 수 있다.

DateTimeFormatter format = DateTimeFormatter.ofPattern("YYYY.MM.dd");<= 포맷을 정의하여
localDateTime.format(format);<=사용한다
profile
Happy Developer

0개의 댓글