CodeGym /행동 /JAVA 25 SELF /날짜 계산과 비교, Duration, Period

날짜 계산과 비교, Duration, Period

JAVA 25 SELF
레벨 13 , 레슨 5
사용 가능

1. 날짜와 시간 더하기/빼기

프로그래밍에서 날짜와 시간을 다루는 일은 단순히 “화면에 날짜를 예쁘게 출력”하는 것만이 아닙니다. 매우 자주 이런 작업이 필요합니다:

  • 중요한 이벤트까지 며칠이 남았는지 확인하기;
  • 사용자의 나이를 계산하기;
  • 두 이벤트 사이에 얼마나 시간이 흘렀는지 구하기;
  • 마감일이 이미 지났는지 확인하기;
  • 특정 일수, 주, 개월 또는 시간을 날짜에 더하기.

예를 들어, 우리 앱에서 작업 마감까지 3일 남았다고 사용자에게 알림을 보내고 싶을 수 있습니다. 또는 생일이 이미 지났다면 축하 메시지를 보내고 싶을 수 있습니다.

이를 위해 java.time에는 이런 계산을 간단하고 안전하게 만들어 주는 전용 클래스와 메서드가 있습니다.

덧셈 및 뺄셈을 위한 기본 메서드

다음의 날짜/시간 클래스들(LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant)에는 공통적으로 다음 메서드가 있습니다:

  • plusXxx() — 더하기(일, 월, 년, 시, 분 등)
  • minusXxx() — 빼기(동일)
import java.time.LocalDate;

LocalDate today = LocalDate.now(); // 오늘 날짜
LocalDate tomorrow = today.plusDays(1); // 내일
LocalDate nextMonth = today.plusMonths(1); // 한 달 후
LocalDate lastWeek = today.minusWeeks(1); // 일주일 전

System.out.println("오늘: " + today);
System.out.println("내일: " + tomorrow);
System.out.println("한 달 후: " + nextMonth);
System.out.println("일주일 전: " + lastWeek);

이 메서드들은 모두 원본을 변경하지 않고 새로운 객체를 반환합니다. 불변성은 매우 중요합니다!

import java.time.LocalTime;

LocalTime now = LocalTime.now();
LocalTime inTwoHours = now.plusHours(2);
LocalTime tenMinutesAgo = now.minusMinutes(10);

System.out.println("지금: " + now);
System.out.println("2시간 후: " + inTwoHours);
System.out.println("10분 전: " + tenMinutesAgo);

조합 메서드

LocalDate vacation = today.plusMonths(2).plusDays(10);
System.out.println("휴가: " + vacation);

2. 날짜 간 차이 구하기: Period와 Duration

두 날짜나 시점 사이에 얼마나 시간이 지났는지 알아야 할 때 두 주인공이 등장합니다 — PeriodDuration. 자세히 살펴보겠습니다.

Period와 Duration의 차이점은?

  • Period — 날짜 단위(년, 월, 일)에 사용. 예: “3년 2개월 5일”.
  • Duration — 시간 단위(시, 분, 초, 나노초)에 사용. 예: “5시간 30분”.
클래스 용도 사용 예
Period
날짜 간 차이 두 날짜 사이의 년/개월/일
Duration
시점 간 차이 두 사건 사이의 시간/분/초

예: 사용자 나이 계산

import java.time.LocalDate;
import java.time.Period;

LocalDate birthday = LocalDate.of(2000, 1, 15); // 생일
LocalDate today = LocalDate.now();

Period age = Period.between(birthday, today);

System.out.println("나이: " + age.getYears() + "년, " +
                   age.getMonths() + "개월, " +
                   age.getDays() + "일");

비유하자면: Period는 두 날짜 사이의 “사람이 이해하기 쉬운” 차이입니다(“나는 24년 5개월 12일이다” 같은 표현).

예: 마감까지 남은 시간

import java.time.LocalDate;

LocalDate deadline = LocalDate.of(2025, 7, 1);
LocalDate today = LocalDate.now();

if (today.isBefore(deadline)) {
    Period left = Period.between(today, deadline);
    System.out.println("마감까지 남은 기간: " +
        left.getMonths() + "개월과 " +
        left.getDays() + "일");
} else {
    System.out.println("마감이 이미 지났습니다!");
}

Duration: 시간 차이

import java.time.LocalDateTime;
import java.time.Duration;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 10, 0, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 1, 15, 30, 0);

Duration duration = Duration.between(start, end);

System.out.println("지속 시간: " + duration.toHours() + "시간 " +
                   (duration.toMinutes() % 60) + "분");

Duration은 차이를 초, 분, 시, 일 단위로 측정합니다(단, ‘일’은 항상 24시간으로 간주하며 달력 특성은 고려하지 않습니다).

비교: Period는 언제, Duration은 언제?

  • 날짜만 있다면(LocalDate) — Period를 사용하세요.
  • 시간 정보가 있다면(예: LocalDateTime, Instant) — Duration을 사용하세요.

3. 날짜와 시간 비교: isBefore, isAfter, equals

가끔은 단지 이렇게 알고 싶을 때가 있습니다: 날짜가 이미 지났는가, 아직 아닌가? 사건이 과거인가 미래인가? 이를 위해 모든 날짜/시간 클래스에는 다음 메서드들이 있습니다:

  • isBefore(otherDate)
  • isAfter(otherDate)
  • isEqual(otherDate) (또는 equals)
import java.time.LocalDate;

LocalDate today = LocalDate.now();
LocalDate deadline = LocalDate.of(2025, 7, 1);

if (today.isBefore(deadline)) {
    System.out.println("아직 시간이 있습니다!");
} else if (today.isEqual(deadline)) {
    System.out.println("오늘이 마감일입니다!");
} else {
    System.out.println("마감이 이미 지났습니다 :(");
}
import java.time.LocalTime;

LocalTime now = LocalTime.now();
LocalTime lunch = LocalTime.of(13, 0);

if (now.isAfter(lunch)) {
    System.out.println("점심시간이 이미 지났습니다!");
} else {
    System.out.println("점심까지 아직 시간이 있습니다.");
}

중요: 같은 타입의 객체끼리만 비교할 수 있습니다(LocalDateLocalDate와, LocalDateTimeLocalDateTime과 비교).

4. 실습: 차이 계산과 마감 확인

예: 작업 마감까지 며칠 남았는지

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

LocalDate today = LocalDate.now();
LocalDate deadline = LocalDate.of(2025, 7, 1);

long daysLeft = ChronoUnit.DAYS.between(today, deadline);

if (daysLeft > 0) {
    System.out.println("마감까지 " + daysLeft + "일 남았습니다");
} else if (daysLeft == 0) {
    System.out.println("오늘이 마감일입니다!");
} else {
    System.out.println("마감이 " + Math.abs(daysLeft) + "일 전에 지났습니다");
}

ChronoUnit.DAYS.between()은 두 날짜 사이의 정확한 ‘일’ 수를 구하는 편리한 방법입니다(월/년 단위 계산 없이).

예: 두 이벤트 사이의 초 수

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 10, 0, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 1, 15, 30, 0);

long seconds = ChronoUnit.SECONDS.between(start, end);

System.out.println("두 이벤트 사이에 " + seconds + "초가 지났습니다");

예: 작업의 경과 기간 계산

import java.time.LocalDate;
import java.time.Period;

LocalDate created = LocalDate.of(2025, 5, 20);
LocalDate today = LocalDate.now();

Period period = Period.between(created, today);

System.out.println("작업이 생성된 지 " +
    period.getDays() + "일, " +
    period.getMonths() + "개월 및 " +
    period.getYears() + "년 지났습니다.");

예: 두 Instant 사이의 지속 시간

import java.time.Instant;
import java.time.Duration;

Instant start = Instant.now();
// ... 무언가를 수행 ...
Instant end = Instant.now();

Duration duration = Duration.between(start, end);

System.out.println("실행에는 " + duration.toMillis() + "밀리초가 걸렸습니다");

5. Period와 Duration 사용 시 유의점

Period의 특징

  • Period는 달력 기준으로 계산합니다: 2월 28일과 3월 1일 사이는 서로 다른 달이라도 1일입니다.
  • 년, 월, 일을 개별적으로 얻을 수 있습니다: getYears(), getMonths(), getDays().
  • 두 날짜 사이의 ‘총 일수’가 필요하다면 ChronoUnit.DAYS.between()을 사용하세요.

Duration의 특징

  • Duration은 정확한 시간 단위(시, 분, 초)를 다룹니다.
  • LocalTime, LocalDateTime, Instant와 함께 사용할 수 있습니다.
  • 시간이 없는 날짜(LocalDate)에는 사용할 수 없습니다 — 예외가 발생합니다.

예: Period와 Duration의 차이

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.Period;

LocalDate date1 = LocalDate.of(2025, 2, 28);
LocalDate date2 = LocalDate.of(2025, 3, 1);

Period period = Period.between(date1, date2); // 2일(윤년)
long days = java.time.temporal.ChronoUnit.DAYS.between(date1, date2); // 2일

System.out.println("Period: " + period.getDays() + " 일");
System.out.println("ChronoUnit: " + days + " 일");

LocalDateTime dt1 = LocalDateTime.of(2025, 6, 1, 23, 0);
LocalDateTime dt2 = LocalDateTime.of(2025, 6, 2, 1, 0);

Duration duration = Duration.between(dt1, dt2); // 2시간
System.out.println("Duration: " + duration.toHours() + " 시간");

6. Duration과 Period로 읽기 쉬운 형태로 출력하기

사용자에게 날짜/시간 차이를 보여줄 때 종종 “123456초”처럼 보이는 값은 불편합니다. 보통 “2일 3시간 15분”처럼 표시하길 원합니다.

예: 날짜와 시간 차이 출력

import java.time.LocalDateTime;
import java.time.Duration;

LocalDateTime start = LocalDateTime.of(2025, 6, 1, 14, 0);
LocalDateTime end = LocalDateTime.of(2025, 6, 3, 16, 30);

Duration duration = Duration.between(start, end);

long days = duration.toDays();
long hours = duration.minusDays(days).toHours();
long minutes = duration.minusDays(days).minusHours(hours).toMinutes();

System.out.println("차이: " + days + "일 " +
    hours + "시간 " + minutes + "분");

7. ZonedDateTime과 Instant를 사용할 때의 특징

  • 서로 다른 타임존의 ZonedDateTime 두 개를 비교하면 각 로컬 시간의 “체감 시간”이 아니라 절대 시간 기준으로 차이가 계산됩니다.
  • 서머타임(일광 절약 시간제) 전환은 날짜 사이의 시간 차이에 영향을 줄 수 있습니다.

예: ZonedDateTime 간 차이

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.Duration;

ZonedDateTime MinskTime = ZonedDateTime.of(2025, 6, 1, 12, 0, 0, 0, ZoneId.of("Europe/Minsk"));
ZonedDateTime nyTime = ZonedDateTime.of(2025, 6, 1, 5, 0, 0, 0, ZoneId.of("America/New_York"));

Duration diff = Duration.between(nyTime, MinskTime);
System.out.println("차이: " + diff.toHours() + " 시간");

8. 날짜/시간 계산에서 흔한 실수

오류 №1: Period와 Duration을 혼동.
DurationLocalDate에 사용하려 하면 예외가 발생합니다. 날짜에는 Period, 시간에는 Duration을 사용하세요.

오류 №2: 시간대를 고려하지 않음.
서로 다른 시간대의 날짜/시간을 비교하면 예상치 못한 결과가 나올 수 있습니다. 하나의 시간대로 통일하거나 Instant를 사용하는 것이 좋습니다.

오류 №3: plus/minus 메서드가 객체를 변경한다고 기대.
java.time의 모든 객체는 불변입니다! 결과를 새로운 변수에 할당하는 것을 잊지 마세요(예: today = today.plusDays(1)).

오류 №4: Period의 getDays()가 총 일수라고 착각.
실제로 이는 년과 월을 뺀 “나머지 일수”만 의미합니다. 총 일수는 ChronoUnit.DAYS.between()을 사용하세요.

오류 №5: 서로 다른 타입의 객체를 비교.
isBefore, isAfter, isEqual 메서드는 동일한 타입의 객체에 대해서만 동작합니다(예: LocalDateLocalDate).

1
설문조사/퀴즈
날짜와 시간, 레벨 13, 레슨 5
사용 불가능
날짜와 시간
날짜, 시간 그리고 타임존
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION