티스토리 뷰
주의 사항!
- 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
- 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
- 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.
자바 7 이전까지는 Date와 Calendar 클래스를 이용해서 날짜와 시간 정보를 얻을 수 있었습니다. Date 클래스의 대부분의 메서드는 Deprecated 되었고, Date의 용도는 단순히 특정 시점의 날짜 정보를 저장하는 역할만 합니다. Calendar 클래스는 날짜와 시간 정보를 얻기에는 충분하지만, 날짜와 시간을 조작하거나 비교하는 기능이 불충분합니다.
그래서 자바 8부터 날짜와 시간을 나타내는 여러 가지 API를 새롭게 추가했습니다. 이 API는 java.util 패키지에 없고 별도로 java.time 패키지와 하위 패키지로 제공됩니다.
패키지 | 설명 |
java.time | 날짜와 시간을 나타내는 핵심 API인 LocalDate, LocalTime, LocalDateTime, ZonedDateTime을 포함하고 있습니다. 이 클래스들은 ISO-8601에 정의된 달력 시스템에 기초합니다. |
java.time.chrono | ISO-8601에 정의된 달력 시스템 이외에 다른 달력 시스템이 필요할 때 사용할 수 있는 API들이 포함되어 있습니다. |
java.time.format | 날짜와 시간을 파싱하고 포맷팅하는 API들이 포함되어 있습니다. |
java.time.temporal | 날짜와 시간을 연산하기 위한 보조 API들이 포함되어 있습니다. |
java.time.zone | 타임존을 지원하는 API들이 포함되어 있습니다. |
1. 날짜와 시간 객체 생성
java.time 패키지에는 다음과 같이 날짜와 시간을 표현하는 5개의 클래스가 있습니다.
클래스명 | 설명 |
LocalDate | 로컬 날짜 클래스 |
LocalTime | 로컬 시간 클래스 |
LocalDateTime | 로컬 날짜 및 시간 클래스(LocalDate + LocalTime) |
ZonedDateTime | 특정 타임존의 날짜와 시간 클래스 |
Instant | 특정 시점의 Time-Stamp 클래스 |
1. 1. LocalDate
LocalDate는 로컬 날짜 클래스로 날짜 정보만을 저장할 수 있습니다. LocalDate 객체는 두 가지 정적 메서드로 얻을 수 있는데, now()는 컴퓨터의 현재 날짜 정보를 저장한 LocalDate 객체를 리턴하고 of()는 매개 값으로 주어진 날짜 정보를 저장한 LocalDate 객체를 리턴합니다.
//Main.java
package Example;
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate currDate = LocalDate.now();
LocalDate targetDate = LocalDate.of(2020, 12, 23);
System.out.println(currDate);
System.out.println(targetDate);
}
}
/*
실행결과
2021-04-21
2020-12-23
*/
1. 2. LocalTime
LocalTime은 로컬 시간 클래스로 시간 정보만을 저장할 수 있습니다. LocalTime 객체도 마찬가지로 두 가지 정적 메서드를 얻을 수 있는데, now() 메서드는 컴퓨터의 현재 시간 정보를 저장한 LocalTime 객체를 리턴하고, of() 메서드는 매개 값으로 주어진 시간 정보를 저장한 LocalTime 객체를 리턴합니다.
//Main.java
package Example;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalTime currTime = LocalTime.now();
LocalTime targetTime = LocalTime.of(5, 46, 28, 123456);
System.out.println(currTime);
System.out.println(targetTime);
}
}
/*
실행결과
18:06:27.718933
05:46:28.000123456
*/
1. 3. LocalDateTime
LocalDateTime은 LocalDate와 LocalTime을 결합한 클래스라고 보면 됩니다. 이 클래스는 날짜와 시간 정보를 모두 저장할 수 있습니다. LocalDateTime 객체도 마찬가지로 두 가지 정적 메서드로 얻을 수 있습니다. now() 메서드는 컴퓨터의 현재 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴하고, of() 메서드는 매개 값으로 주어진 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴합니다.
//Main.java
package Example;
import java.time.LocalDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime currDateTime = LocalDateTime.now();
LocalDateTime targetDateTime = LocalDateTime.of(2012, 6, 14, 14, 46);
System.out.println(currDateTime);
System.out.println(targetDateTime);
}
}
/*
실행결과
2021-04-21T18:11:53.618667100
2012-06-14T14:46
*/
1. 4. ZonedDateTime
ZonedDateTime은 ISO-8601 달력 시스템에서 정의하고 있는 타임존의 날짜와 시간을 저장하는 클래스입니다. 저장 형태는 2014-04-21T 07:50:24.017+09:00 [Asia/Seoul]과 같이 맨 뒤에 타임존에 대한 정보(+존 오프셋[존 아이디])가 추가적으로 붙습니다.
존 오프셋(ZoneOffset)은 협정 세계시(UTC)와 차이 나는 시간(시차)을 말합니다. ZonedDateTime은 now() 정적 메서드에 zoneId를 매개 값으로 주고 얻을 수 있습니다. ZoneId는 of() 메서드로 얻을 수 있는데, of()의 매개 값은 java.util.TimeZone의 getAvailableIDs() 메서드가 리턴하는 유효한 값 중 하나입니다.
//Main.java
package Example;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime londonDateTime = ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println(utcDateTime);
System.out.println(londonDateTime);
System.out.println(seoulDateTime);
}
}
/*
실행결과
2021-04-21T09:20:21.549290300Z[UTC]
2021-04-21T10:20:21.566293900+01:00[Europe/London]
2021-04-21T18:20:21.568293900+09:00[Asia/Seoul]
*/
1. 5. Instant
Instant 클래스는 날짜와 시간의 정보를 얻거나 조작하는 데 사용되지 않고, 특정 시점의 타임스탬프(Time-Stamp)로 사용됩니다. 주로 특정한 두 시점 간의 시간적 우선순위를 따질 때 사용합니다. java.util.Date와 가장 유사한 클래스이지만, 차이점은 Date는 로컬 컴퓨터의 현재 날짜와 시간 정보를 기준으로 하지만 Instant는 협정 세계시(UTC)를 기준으로 합니다.
//Main.java
package Example;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
Instant instant1 = Instant.now();
Instant instant2 = Instant.now();
if(instant1.isBefore(instant2)) {
System.out.println("instant1이 빠릅니다.");
} else if (instant1.isAfter(instant2)) {
System.out.println("instant2가 빠릅니다.");
} else {
System.out.println("동일한 시간입니다.");
}
System.out.println("차이(nanos) : " + instant1.until(instant2, ChronoUnit.NANOS));
}
}
/*
실행결과
동일한 시간입니다.
차이(nanos) : 0
*/
2. 날짜와 시간에 대한 정보 얻기
LocalDate와 LocalTime은 프로그램에서 날짜와 시간 정보를 이용할 수 있도록 다음과 같은 메서드를 제공하고 있습니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
LocalDate | int | getYear() | 년 |
Month | getMonth() | Month 열거값 | |
int | getMonthValue() | 월 | |
int | getDayOfYear() | 일년의 몇 번째 일 | |
int | getDayOfMonth() | 월의 몇 번째 일 | |
DayOfWeek | getDayOfWeek() | 요일 | |
boolean | isLeapYear() | 윤년 여부 | |
LocalTime | int | getHour() | 시간 |
int | getMinute() | 분 | |
int | getSecond() | 초 | |
int | getNano() | 나노초 |
LocalDateTime 클래스와 ZonedDateTime은 날짜와 시간 정보를 모두 갖고 있기 때문에 위 표에 나와 있는 대부분의 메서드를 가지고 있습니다. 단, isLeapYear() 메서드는 LocalDate 클래스에만 있기 때문에 toLocalDate() 메서드로 LocalDate로 변환한 후에 사용할 수 있습니다.
ZonedDateTime은 시간 존에 대한 정보를 제공하는 다음 메서드들을 추가로 가지고 있습니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
ZonedDateTime | Zoned | getZone() | 존아이디를 리턴 |
ZoneOffset | getOffset() | 존오프셋(시차)을 리턴 |
//Main.java
package Example;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
StringBuilder sb = new StringBuilder();
sb.append(now.getYear());
sb.append("년 ");
sb.append(now.getMonthValue());
sb.append("월 ");
sb.append(now.getDayOfMonth());
sb.append("일 ");
sb.append(now.getDayOfWeek());
sb.append(" ");
sb.append(now.getHour());
sb.append("시 ");
sb.append(now.getMinute());
sb.append("분 ");
sb.append(now.getSecond());
sb.append("초 ");
sb.append(now.getNano());
sb.append("나노초 ");
System.out.println(sb);
System.out.println();
LocalDate nowDate = now.toLocalDate();
if(nowDate.isLeapYear()) {
System.out.println("올해는 윤년 : 2월 29일까지 있습니다.\n");
} else {
System.out.println("올해는 평년 : 2월 28일까지 있습니다.\n");
}
ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
System.out.println("협정세계시 : " + utcDateTime);
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
System.out.println("서울 타임존 : " + seoulDateTime);
ZoneId seoulZoneId = seoulDateTime.getZone();
System.out.println("서울 존아이디 : " + seoulZoneId);
ZoneOffset seoulZoneOffset = seoulDateTime.getOffset();
System.out.println("서울 존오프셋 : " + seoulZoneOffset);
}
}
/*
실행결과
2021-04-21T18:53:40.845941500
2021년 4월 21일 WEDNESDAY 18시 53분 40초 845941500나노초
올해는 평년 : 2월 28일까지 있습니다.
협정세계시 : 2021-04-21T09:53:40.847942100Z[UTC]
서울 타임존 : 2021-04-21T18:53:40.847942100+09:00[Asia/Seoul]
서울 존아이디 : Asia/Seoul
서울 존오프셋 : +09:00
*/
3. 날짜와 시간을 조작하기
날짜와 시간 클래스들은 날짜와 시간을 조작하는 메서드와 상대 날짜를 리턴하는 메서드들을 가지고 있습니다.
3. 1. 빼기와 더하기
다음은 날짜를 빼거나 더하는 메서드들입니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
LocalDate LocalDateTime ZonedDateTime |
LocalDate LocalDateTime ZonedDateTime |
minusYears(long) | 년 빼기 |
minusMonths(long) | 달 빼기 | ||
minusDays(long) | 일 빼기 | ||
minusWeeks(long) | 주 빼기 | ||
plusYears(long) | 년 더하기 | ||
plusMonths(long) | 달 더하기 | ||
plusDays(long) | 일 더하기 | ||
plusWeeks(long) | 주 더하기 | ||
LocalTime LocalDateTime ZonedDateTime |
LocalTime LocalDateTime ZonedDateTime |
minusHours(long) | 시간 빼기 |
minusMinutes(long) | 분 빼기 | ||
minusSeconds(long) | 초 빼기 | ||
minusNanos(long) | 나노초 빼기 | ||
plusHours(long) | 시간 더하기 | ||
plusMinutes(long) | 분 더하기 | ||
plusSeconds(long) | 초 더하기 | ||
plusNanos(long) | 나노초 더하기 |
각 메서드들은 수정된 LocalDate, LocalTime, LocalDateTime, ZonedDateTime을 리턴하기 때문에 도트(.) 연산자로 연결해서 순차적으로 호출할 수 있습니다.
다음 예제는 현재 날짜와 시간을 얻어 1년을 더하고, 2달을 빼고, 3일을 더하고, 4시간을 더하고, 5분을 빼고, 6초를 더한 날짜와 시간을 얻습니다.
//Main.java
package Example;
import java.time.LocalDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("현재시 : " + now);
LocalDateTime targetDateTime = now.plusYears(1).minusMonths(2).plusDays(3).plusHours(4).minusMinutes(5).plusSeconds(6);
System.out.println("연산 후 : " + targetDateTime);
}
}
/*
실행결과
현재시 : 2021-04-22T12:33:30.274761
연산 후 : 2022-02-25T16:28:36.274761
*/
3. 2. 변경하기
다음은 날짜와 시간을 변경하는 메서드들입니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
LocalDate LocalDateTime ZonedDateTime |
LocalDate LocalDateTime ZonedDateTime |
withYear(int) | 년 변경 |
withMonth(int) | 월 변경 | ||
withDayOfMonth(int) | 한 달을 기준으로 표시되는 일 변경 | ||
withDayOfYear(int) | 일 년을 기준으로 표시되는 일 변경 | ||
with(TemporalAdjuster adjuster) | 상대 변경 | ||
LocalTime LocalDateTime ZonedDateTime |
LocalTime LocalDateTime ZonedDateTime |
withHour(int) | 시간 변경 |
withMinute(int) | 분 변경 | ||
withSecond(int) | 초 변경 | ||
withNano(int) | 나노초 변경 |
with(TemporalAdjuster adjuster) 메서드를 제외한 나머지 메서드는 메서드 이름만 보면 어떤 정보를 수정하는지 알 수 있습니다. with() 메서드는 상대 변경이라고 설명되어 있는데, 이것은 현재 날짜를 기준으로 해의 첫 번째 일 또는 마지막 일, 달의 첫 번째 일 또는 마지막 일, 달의 첫 번째 요일, 지난 요일 및 돌아오는 요일 등 상대적인 날짜를 리턴합니다. 매개 값은 TemporalAdjuster 타입으로 다음 표에 있는 TemporalAdjusters의 정적 메서드를 호출하면 얻을 수 있습니다.
리턴 타입 | 메서드(매개 변수) | 설명 |
TemporalAdjuster | firstDayOfYear() | 이번 해의 첫 번째 일 |
lastDayOfYear() | 이번 해의 마지막 일 | |
firstDayOfNextYear() | 다음 해의 첫 번째 일 | |
firstDayOfMonth() | 이번 달의 첫 번째 일 | |
lastDauOfMonth() | 이번 달의 마지막 일 | |
firstDayOfNextMonth() | 다음 달의 첫 번째 일 | |
firstInMonth(DayOfWeek dayOfWeek) | 이번 달의 첫 번째 요일 | |
lastInMonth(DayOfWeek dayOfWeek) | 이번 달의 마지막 요일 | |
next(DayOfWeek dayOfWeek) | 돌아오는 요일 | |
nextOrSame(DayOfWeek dayOfWeek) | 돌아오는 요일(오늘 포함) | |
privious(DayOfWeek dayOfWeek) | 지난 요일 | |
priviousOrSame(DayOfWeek dayOfWeek) | 지난 요일(오늘 포함) |
다음 예제는 날짜와 시간을 변경하는 예제입니다.
//Main.java
package Example;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("현재 : " + now);
LocalDateTime targetDateTime = null;
//직접 변경
targetDateTime = now.withYear(2024).withMonth(10).withDayOfMonth(15).withHour(13).withMinute(30).withSecond(20);
System.out.println("직접 변경 : " + targetDateTime);
//년도 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstDayOfYear());
System.out.println("이번 해의 첫 번째 일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.lastDayOfYear());
System.out.println("이번 해의 마지막 일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.firstDayOfNextYear());
System.out.println("다음 해의 첫 번째 일 : " + targetDateTime);
//월 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("이번 달의 첫 번째 일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("이번 달의 마지막 일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println("다음 달의 첫 번째 일 : " + targetDateTime);
//요일 상대 변경
targetDateTime = now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println("이번 달의 첫 번째 월요일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("돌아오는 월요일 : " + targetDateTime);
targetDateTime = now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
System.out.println("지난 월요일 : " + targetDateTime);
}
}
/*
실행결과
현재 : 2021-04-22T12:57:32.598674900
직접 변경 : 2024-10-15T13:30:20.598674900
이번 해의 첫 번째 일 : 2021-01-01T12:57:32.598674900
이번 해의 마지막 일 : 2021-12-31T12:57:32.598674900
다음 해의 첫 번째 일 : 2022-01-01T12:57:32.598674900
이번 달의 첫 번째 일 : 2021-04-01T12:57:32.598674900
이번 달의 마지막 일 : 2021-04-30T12:57:32.598674900
다음 달의 첫 번째 일 : 2021-05-01T12:57:32.598674900
이번 달의 첫 번째 월요일 : 2021-04-05T12:57:32.598674900
돌아오는 월요일 : 2021-04-26T12:57:32.598674900
지난 월요일 : 2021-04-19T12:57:32.598674900
*/
4. 날짜와 시간을 비교하기
날짜와 시간 클래스들은 다음과 같이 비교하거나 차이를 구하는 메서드들을 가지고 있습니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
LocalDate LocalDataTime |
boolean | isAfter(ChrocnoLocalDate other) | 이후 날짜인지 비교 |
isBefore(ChronoLocalDate other) | 이전 날짜인지 비교 | ||
isEqual(ChronoLocalDate other) | 동일 날짜인지 비교 | ||
LocalTime LocalDateTime |
boolean | isAfter(LocalTime other) | 이후 시간인지 비교 |
isBefore(LocalTime other) | 이전 시간인지 비교 | ||
LocalDate | Period | until(ChronoLocalDate endDateExclusive) | 날짜 차이 |
LocalDate LocalTime LocalDateTime |
long | until( Temporal endExclusive, TemporalUnit nuit ) |
시간 차이 |
Period | Period | between( LocalDate startDateInclusive, LocalDate endDateExclusive ) |
날짜 차이 |
Duration | Duration | between( Tempral startInclusive, Temporal endExclusive ) |
시간 차이 |
ChronoUnit.YEAR | long | between( Temporal temporal1Inclusive, Temporal temporal2Exclusive ) |
전체 년 차이 |
ChronoUnit.MONTH | 전체 달 차이 | ||
ChronoUnit.WEEKS | 전체 주 차이 | ||
ChronoUnit.DAYS | 전체 일 차이 | ||
ChronoUnit.HOURS | 전체 시간 차이 | ||
ChronoUnit.SECONDS | 전체 초 차이 | ||
ChronoUnit.MILLIS | 전체 밀리초 차이 | ||
ChronoUnit.NANOS | 전체 나노초 차이 |
Period와 Duration은 날짜와 시간의 양을 나타내는 클래스들입니다. Period는 년, 달, 일의 양을 나타내는 클래스이고, Duration은 시, 분, 초, 나노초의 양을 나타내는 클래스입니다. 이 클래스들은 D-day나 D-time을 구할 때 사용될 수 있습니다.
다음은 Period와 Duration에서 제공하는 메서드들입니다.
클래스 | 리턴 타입 | 메서드(매개 변수) | 설명 |
Period | int | getYears() | 년의 차이 |
int | getMonths() | 달의 차이 | |
int | getDays() | 일의 차이 | |
Duration | int | getSeconds() | 초의 차이 |
int | getNano() | 나노초의 차이 |
between() 메서드는 Period와 Duration 클래스, 그리고 ChronoUnit 열거 타입에도 있습니다. Period와 Duration의 between() 메서드는 년, 달, 일, 초의 단순 차이를 리턴하고, ChronoUnit 열거 탕비의 between() 메서드는 전체 시간을 기준으로 차이를 리턴합니다. 예를 들어 2023년 1월과 2024년 3월의 달의 차이를 구할 때 Period의 between()은 2가 되고 ChronoUnit.MONTHS.between()은 14가 됩니다.
//Main.java
package Example;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
LocalDateTime startDateTime = LocalDateTime.of(2023, 1, 1, 9, 0, 0);
System.out.println("시작일 : " + startDateTime);
LocalDateTime endDateTime = LocalDateTime.of(2024, 3, 31, 18, 0, 0);
System.out.println("종료일 : " + endDateTime + "\n");
if(startDateTime.isBefore(endDateTime)) {
System.out.println("진행 중입니다.\n");
} else if(startDateTime.isEqual(endDateTime)) {
System.out.println("종료합니다.\n");
} else if(startDateTime.isAfter(endDateTime)) {
System.out.println("종료했습니다.\n");
}
System.out.println("[종료까지 남은 기간]");
long remainYear = startDateTime.until(endDateTime, ChronoUnit.YEARS);
long remainMonth = startDateTime.until(endDateTime, ChronoUnit.MONTHS);
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);
System.out.println("남은 달 : " + remainMonth);
System.out.println("남은 일 : " + remainDay);
System.out.println("남은 시간 : " + remainHour);
System.out.println("남은 분 : " + remainMinute);
System.out.println("남은 초 : " + remainSecond);
System.out.println();
System.out.println("[종료까지 남은 기간]");
remainYear = ChronoUnit.YEARS.between(startDateTime, endDateTime);
remainYear = ChronoUnit.MONTHS.between(startDateTime, endDateTime);
remainYear = ChronoUnit.DAYS.between(startDateTime, endDateTime);
remainYear = ChronoUnit.HOURS.between(startDateTime, endDateTime);
remainYear = ChronoUnit.SECONDS.between(startDateTime, endDateTime);
System.out.println("남은 해 : " + remainYear);
System.out.println("남은 달 : " + remainMonth);
System.out.println("남은 일 : " + remainDay);
System.out.println("남은 시간 : " + remainHour);
System.out.println("남은 분 : " + remainMinute);
System.out.println("남은 초 : " + remainSecond);
System.out.println();
System.out.println("종료까지 남은 기간]");
Period period = Period.between(startDateTime.toLocalDate(), endDateTime.toLocalDate());
System.out.print("남은 기간 : " + period.getYears() + "년 ");
System.out.print(period.getMonths() + "달 ");
System.out.println(period.getDays() + "일\n");
Duration duration = Duration.between(startDateTime.toLocalTime(), endDateTime.toLocalTime());
System.out.println("남은 초 : " + duration.getSeconds() + "초");
}
}
/*
실행결과
시작일 : 2023-01-01T09:00
종료일 : 2024-03-31T18:00
진행 중입니다.
[종료까지 남은 기간]
남은 해 : 1
남은 달 : 14
남은 일 : 455
남은 시간 : 10929
남은 분 : 655740
남은 초 : 39344400
[종료까지 남은 기간]
남은 해 : 39344400
남은 달 : 14
남은 일 : 455
남은 시간 : 10929
남은 분 : 655740
남은 초 : 39344400
종료까지 남은 기간]
남은 기간 : 1년 2달 30일
남은 초 : 32400초
*/
(실행 결과를 보면 남은 해를 구한 결과에서 큰 차이를 보입니다. LocalDateTime 클래스의 until() 메서드를 사용했을 때는 정확히 나왔지만, ChronoUnit.YEARS.between() 메서드를 사용했을 때는 이상한 값이 나왔습니다. 이유는 저도 잘 모르겠습니다.)
5. 파싱과 포맷팅
날짜와 시간 클래스는 문자열을 파싱(Paring)해서 날짜와 시간을 생성하는 메서드와 이와 반대로 날짜와 시간을 포맷팅(Formatting)된 문자열로 변환하는 메서드를 제공하고 있습니다.
5. 1. 파싱(Parsing) 메서드
다음은 날짜와 시간 정보가 포함된 문자열을 파싱 해서 날짜와 시간을 생성하는 두 개의 parse() 정적 메서드입니다.
클래스 | 리턴 타입 | 메서드(매개 변수) |
LocalDate LocalTime LocalDateTime ZonedDateTime |
LocalDate LocalTime LocalDateTime ZonedDateTime |
parse(CharSequence) |
parse(CharSequence, DateTimeFormatter) |
LocalDate의 parse(CharSequence) 메서드는 기본적으로 ISO_LOCAL_DATE 포맷터를 사용해서 문자열을 파싱 합니다. ISO_LOCAL_DATE는 DateTimeFormatter의 상수로 정의되어 있는데, "2023-05-03"형식의 포맷터입니다.
LocalDate localDate = LocalDate.parse("2024-05-21");
만약 다른 포맷터를 이용해서 문자열을 파싱 하고 싶다면 parse(CharSequence, DateTimeFormatter) 메서드를 사용할 수 있습니다. DateTimeFormatter는 ofPattern() 메서드로 정의할 수도 있습니다. 다음 코드는 "2024년05월21일"형식의 DateTimeFormatter를 정의하고 문자열을 파싱 한 것입니다.
//Main.java
package Example;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
DateTimeFormatter fomatter = DateTimeFormatter.ofPattern("yyyy년MM월dd일");
LocalDate localDate = LocalDate.parse("2024년05월21일", fomatter);
System.out.println(localDate);
}
}
/*
실행결과
2024-05-21
*/
ofPattern() 메서드의 매개 값으로 사용되는 패턴 기호에 대한 설명은 API 도큐먼트의 java.time.format.DateTimeFormatter 클래스 설명 부분에 "Patterns for Formatting and Parsing"이란 제목으로 나와 있습니다. DateTimeFormatter에는 표준화된 포맷터들이 다음과 같이 상수로 미리 정의되어 있기 때문에 ofPattern() 메서드를 사용하지 않고 바로 이용할 수도 있습니다.
상수 | 설명 | 예 |
BASIC_ISO_DATE | Basic ISO date | "20111203" |
ISO_LOCAL_DATE | ISO Local Date | "2011-12-03" |
ISO_OFFSET_DATE | ISO Date with offset | "2011-12-03+01:00" |
ISO_DATE | ISO Date with or without offset | "2011-12-03+01:00" "2011-12-03" |
ISO_LOCAL_TIME | Time without offset | "10:15:30" |
ISO_OFFSET_TIME | Time with offset | "10:15:30+01:00" |
ISO_TIME | Time with or without offset | "10:15:30+01:00" "10:15:30" |
ISO_LOCAL_DATE_TIME | ISO Local Date and Time | "2011-12-03T 10:15:30" |
ISO_OFFSET_DATE_TIME | Date Time with offset | "2011-12-03T 10:15:30+01:00" |
ISO_ZONED_DATE_TIME | Zoned Date Time | "2011-12-03T 10:15:30+01:00[Europe/Paris]" |
ISO_DATE_TIME | Date and Time with ZoneId | "2011-12-03T 10:15:30+01:00[Europe/Paris]" |
ISO_ORDINAL_DATE | Year and day of year | "2012-337" |
ISO_WEEK_DATE | Year and Week | "2012-W48-6" |
ISO_INSTANT | Date and Time of an Instant | "2011-12-03T 10:15:30Z" |
RFC_1123_DATE_TIME | RFC 1123/ RFC 822 | "Tue. 3 Jun 2008 11:05:30 GMT" |
예를 들어 parse(CharSequence)와 동일하게 "2024-05-21"이라는 문자열을 파싱 해서 LocalDate 객체를 얻고 싶다면 다음과 같이 코드를 작성하면 됩니다.
//Main.java
package Example;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
DateTimeFormatter fomatter = DateTimeFormatter.ISO_LOCAL_DATE;
LocalDate localDate = LocalDate.parse("2024-05-21", fomatter);
System.out.println(localDate);
}
}
/*
실행결과
2024-05-21
*/
만약 포맷터의 형식과 다른 문자열을 파싱 하게 되면 DateTimeParseException이 발생합니다.
다음은 문자열을 파싱 하는 예제입니다.
//Main.java
package Example;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter;
LocalDate localDate;
localDate = LocalDate.parse("2024-05-21");
System.out.println(localDate);
formatter = DateTimeFormatter.ISO_LOCAL_DATE;
localDate = LocalDate.parse("2024-05-21", formatter);
System.out.println(localDate);
formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
localDate = LocalDate.parse("2024/05/21", formatter);
System.out.println(localDate);
formatter = DateTimeFormatter.ofPattern("yyyy년도일까연도일까MM월일까달일까dd일일까뭘까");
localDate = LocalDate.parse("2024년도일까연도일까05월일까달일까21일일까뭘까", formatter);
System.out.println(localDate);
}
}
/*
실행결과
2024-05-21
2024-05-21
2024-05-21
2024-05-21
*/
5. 2. 포맷팅(Formatting) 메서드
다음은 날짜와 시간을 포맷팅 된 문자열로 변환시키는 format() 메서드입니다.
클래스 | 리턴 타입 | 메서드(매개 변수) |
LocalDate LocalTime LocalDateTime ZonedDateTime |
String | format(DateTimeFormatter formatter) |
format()의 매개 값은 DateTimeFormatter인데 해당 형식대로 문자열을 리턴합니다.
다음 예제는 다양한 형식으로 날짜를 포맷팅 하는 예제입니다.
//Main.java
package Example;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter;
LocalDate localDate = LocalDate.now();
formatter = DateTimeFormatter.ISO_LOCAL_DATE;
System.out.println(localDate.format(formatter));
formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(localDate.format(formatter));
formatter = DateTimeFormatter.ofPattern("yyyy년도일까연도일까MM월일까달일까dd일일까뭘까");
System.out.println(localDate.format(formatter));
}
}
/*
실행결과
2021-04-22
2021/04/22
2021년도일까연도일까04월일까달일까22일일까뭘까
*/
'공부 일지 > JAVA 공부 일지' 카테고리의 다른 글
자바, 작업 스레드 생성과 실행 (0) | 2021.04.26 |
---|---|
자바, 멀티 스레드 개념 (0) | 2021.04.22 |
자바, Format 클래스 (0) | 2021.04.21 |
자바, Date, Calendar 클래스 (0) | 2021.04.21 |
자바, Math, Random 클래스 (0) | 2021.04.21 |