Java 날짜 연산

내 이 세상 도처에서 쉴 곳을 찾아보았으나, 마침내 찾아낸, 컴퓨터가 있는 구석방보다 나은 곳은 없더라.

Java 날짜 연산

Java 8에 추가된 날짜/시간 관련 클래스 중 LocalDate를 사용한 간단한 날짜 연산 방법을 정리한다. LocalDate에는 시간 정보가 포함되어 있지 않다. 날짜와 시간을 함께 다루려면 LocalDateTime을 사용해야 한다. UTC 오프셋이나 시간대도 함께 필요한 경우는 OffsetDateTime 또는 ZonedDateTime을 사용해야 한다.

간단한 날짜 관련 연산

// 오늘, 어제, 내일
var today = LocalDate.now();
var yesterday = today.minus(1, ChronoUnit.DAYS);
var tomorrow  = today.plus(1, ChronoUnit.DAYS);

// day of week
var dayOfWeek = today.getDayOfWeek();

// day of year
var dayOfYear = today.getDayOfYear();

// week of year
var weekOfYear = today.get(ChronoField.ALIGNED_WEEK_OF_YEAR)

// 한 주 전/후
var oneWeekBefore = today.minusWeeks(1);
var oneWeekAfter = today.plusWeeks(1);

// 한 달 전/후
var oneMonthBefore = today.minusMonths(1);
var oneMonthAfter = today.plusMonths(1);

// 두 날짜 사이의 날 수
var d1 = LocalDate.of(2020, 3, 1);
var d2 = LocalDate.of(2020, 6, 1);
vat numDays = ChronoUnit.DAYS.between(d1, d2);

한 주의 첫날, 마지막 날 구하기

// 이번 주 첫 날과 마지막 날 (월요일을 한 주의 시작인 경우)
var startOfWeek = today.with(DayOfWeek.MONDAY);
var endOfWeek = today.with(DayOfWeek.SUNDAY);

우리나라나 미국 같은 일부 나라는 일요일을 한 주의 시작으로 생각한다.

// 이번 주 첫 날과 마지막 날 (일요일을 한 주의 시작인 경우)
var startOfWeek = today.with(WeekFields.of(Locale.KOREA).dayOfWeek(), 1);
var endOfWeek = today.with(WeekFields.of(Locale.KOREA).dayOfWeek(), 7);

지난주, 다음주의 첫날과 마지막 날은 today에 plusWeeksminusWeeks로 한주 전/후 날짜를 구한 다음 위 방법을 사용하면 된다.

한 달의 첫날, 마지막 날 구하기

달의 첫 날은 1일이니 구하기 쉽지만, 달의 마지막 날은 28, 29, 30, 31이 될 수 있으므로 다음과 같이 구한다.

var start = today.withDayOfMonth(1);
var end   = today.with(TemporalAdjusters.lastDayOfMonth());

YearMonth 클래스를 사용하면 좀더 코드가 단순해진다.

var start = YearMonth.now().atDay(1);
var end   = YearMonth.now().atEndOfMonth();

날짜 스트림

LocalDate에 있는 datesUntil메서드를 사용하면 두 날짜 사이의 날짜 스트림을 구할 수 있다. datesUntil은 현재 인스턴스의 날부터 인자로 주어진 날 까지(인자 날짜는 제외) 스트림을 리턴한다.

따라서 한 주의 모든 날짜를 구하려면 그 주의 첫 날과 그 다음 주의 첫 날을 구해 datesUntil을 호출하면 된다.

var start = today.with(DayOfWeek.MONDAY);
var dates = start.datesUntil(start.plusWeeks(1)).collect(Collectors.toList());

같은 원리로, 한 달의 모든 날짜를 구하는 것은 다음과 같이 할 수 있다.

var start = YearMonth.now().atDay(1);
var dates = start.datesUntil(start.plusMonths(1)).collect(Collectors.toList());

스트림을 리스트로 모은 것은 예시일 뿐이다. 스트림을 필요에 맞게 사용하면 된다. 예를 들어, 2020년의 모든 일요일을 구하려면 다음과 같이 할 수 있다.

var sundays = Year.of(2020).atDay(1).datesUntil(Year.of(2021).atDay(1))
    .filter(d -> d.getDayOfWeek() == DayOfWeek.SUNDAY)
    .collect(Collectors.toList());