1. DateTimeFormatter: 무엇이며 왜 필요한가
실제 프로그램에서 날짜는 코드 내부에만 존재하지 않습니다. 보통 다음이 필요합니다:
- 문자열로 변환해 콘솔, 화면, 파일 등에 출력하기(예: "01.06.2025 14:30").
- 문자열을 파싱해, 사용자 입력이나 파일에서 온 문자열을 다시 날짜/시간 객체로 되돌리기.
이를 위해 Java에는 강력하고 편리한 도구 — java.time.format.DateTimeFormatter 클래스가 있습니다.
DateTimeFormatter는 시간 객체(LocalDate, LocalDateTime, ZonedDateTime, Instant 등)와 문자열 사이를 이어 주는 “번역기”라고 할 수 있습니다. 할 수 있는 일은 다음과 같습니다:
- 날짜/시간 객체를 원하는 형식의 문자열로 변환(format — 포매팅).
- 문자열을 날짜/시간 객체로 변환(parse — 파싱).
2. 표준 포매터: 빠르고 간편하게
Java는 가장 대중적인 ISO 형식(날짜와 시간에 대한 국제 표준)을 다루는 표준 포매터들을 이미 준비해 두었습니다.
그중 일부는 다음과 같습니다:
| 포매터 | 문자열 예 | 설명 |
|---|---|---|
|
2025-06-01 | 날짜만 (년-월-일) |
|
14:30:00 | 시간만 (시:분:초) |
|
2025-06-01T14:30:00 | 시간대 없는 날짜와 시간 |
|
2025-06-01T14:30:00+03:00[Europe/Minsk] | 날짜, 시간 및 시간대 |
표준 포매터 사용 예
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormatterDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
// 날짜를 문자열로 포매팅
String text = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(text); // 예: 2025-06-01
// 문자열을 다시 날짜로 파싱
LocalDate parsed = LocalDate.parse("2025-06-01", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(parsed); // 2025-06-01
}
}
비유
만약 Java가 커피숍이라면, 표준 포매터는 “아메리카노”, “라떼”, “에스프레소”와 같습니다. 빠르고 표준적이지만, 때로는 특별한 무언가가 필요하죠!
3. 사용자 지정 패턴: DateTimeFormatter.ofPattern
가끔 표준 형식만으로는 부족합니다. 예를 들어 "01.06.2025 14:30"처럼 출력해야 할 때가 있고, "2025-06-01T14:30:00"은 원치 않을 수 있습니다. 이럴 때 DateTimeFormatter.ofPattern(String pattern) 메서드로 원하는 패턴을 만들 수 있습니다.
패턴 문법
패턴에는 다음과 같은 특수 문자를 사용합니다:
- y — 연도 (yyyy — 2025)
- M — 월 (MM — 06)
- d — 일 (dd — 01)
- H — 시 (24시간제, HH — 14)
- m — 분 (mm — 30)
- s — 초 (ss — 00)
패턴 예시
| 패턴 | 결과 예 |
|---|---|
|
01.06.2025 |
|
2025/06/01 |
|
01.06.2025 14:30 |
|
2025-06-01 14:30:00 |
|
1 iyunya 2025 (ru 로케일에서) |
예: 날짜와 시간 포매팅
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class CustomFormatDemo {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 6, 1, 14, 30);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
String text = dt.format(formatter);
System.out.println(text); // 01.06.2025 14:30
}
}
예: 문자열을 날짜로 파싱
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dt = LocalDateTime.parse(input, formatter);
System.out.println(dt); // 2025-06-01T14:30
}
}
주의: 패턴은 문자열과 정확히 일치해야 합니다! 문자열에 초가 있다면 패턴에 :ss를 추가하세요.
4. 포매팅: 날짜/시간을 문자열로 변환
일반 절차
- LocalDate, LocalDateTime, ZonedDateTime 등 필요한 객체를 만든다.
- 필요한 포매터를 만들거나 선택한다.
- 객체의 format(DateTimeFormatter) 메서드를 호출해 문자열을 얻는다.
예: 여러 형식으로 날짜 출력
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class MultiFormatDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
// 표준 ISO
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 2025-06-01
// 사용자 지정 형식
DateTimeFormatter rusFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(date.format(rusFormat)); // 01.06.2025
// 영어 스타일
DateTimeFormatter usFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy");
System.out.println(date.format(usFormat)); // 06/01/2025
}
}
시간 포매팅
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class TimeFormatDemo {
public static void main(String[] args) {
LocalTime time = LocalTime.of(14, 30, 5);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(formatter)); // 14:30:05
}
}
5. 파싱: 문자열을 날짜/시간으로 변환
일반 절차
- 문자열을 받는다(예: 사용자 입력).
- 문자열과 동일한 패턴의 포매터를 생성한다.
- 정적 메서드 parse() 또는 포매터 객체의 parse() 메서드를 호출한다.
예: 날짜 파싱
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class ParseDateDemo {
public static void main(String[] args) {
String input = "01.06.2025";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date); // 2025-06-01
}
}
예: 날짜와 시간 파싱
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDateTimeDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(input, formatter);
System.out.println(dateTime); // 2025-06-01T14:30
}
}
6. 파싱 오류 처리
파싱은 까다로울 수 있습니다. 문자열이 패턴과 맞지 않으면 Java는 DateTimeParseException 예외를 던집니다. 이는 사용자가 잘못된 날짜를 입력한 경우처럼 흔한 상황입니다.
예: 파싱 시 오류 처리
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public class ParseErrorDemo {
public static void main(String[] args) {
String input = "32.13.2025"; // 잘못된 날짜
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
try {
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date);
} catch (DateTimeParseException ex) {
System.out.println("파싱 오류: " + ex.getMessage());
}
}
}
중요: 사용자 입력을 다룰 때에는 반드시 이러한 오류를 처리하세요!
7. 실습: 사용자용 날짜 변환
예를 들어, 학습용 애플리케이션에서 다음과 같은 작업이 있다고 합시다. 사용자가 "dd.MM.yyyy" 형식으로 생년월일을 입력하면, 프로그램은 이를 "yyyy/MM/dd" 형식으로 출력하고 요일까지 보여줘야 합니다.
예
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Scanner;
public class BirthdayFormatDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("생년월일을 입력하세요 (dd.MM.yyyy): ");
String input = scanner.nextLine();
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd");
try {
LocalDate birthday = LocalDate.parse(input, inputFormat);
String formatted = birthday.format(outputFormat);
System.out.println("새 형식의 날짜: " + formatted);
System.out.println("요일: " + birthday.getDayOfWeek()); // 예: SATURDAY
} catch (DateTimeParseException ex) {
System.out.println("오류: 잘못된 날짜 형식입니다!");
}
}
}
8. 현지화: 언어가 포매팅에 미치는 영향
DateTimeFormatter를 사용하면 숫자 순서만 바꾸는 것이 아니라 월 이름, 요일 등도 단어로 출력할 수 있습니다. 이때 로케일(언어와 지역 설정)이 반영됩니다.
예: 러시아어로 월을 글자로 출력
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", new Locale("ru"));
System.out.println(date.format(formatter)); // 1 iyunya 2025
}
}
예: 영어 로케일
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleEnDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH);
System.out.println(date.format(formatter)); // 1 June 2025
}
}
팁: 월이나 요일을 원하는 언어로 출력하려면 로케일을 명시적으로 지정하세요!
9. 날짜 포매팅/파싱에서 흔한 실수
실수 № 1: 패턴과 문자열이 일치하지 않음.
문자열이 "01.06.2025 14:30"인데 패턴이 "dd.MM.yyyy"라면 파싱은 실패합니다. 패턴은 문자열과 정확히 일치해야 합니다.
실수 № 2: 패턴 문자를 혼동함.
MM은 월, mm은 분입니다. "dd.mm.yyyy"처럼 작성하면 Java는 분을 의미한다고 판단해 오류가 발생합니다. 월에는 항상 대문자 M을 사용하세요.
실수 № 3: 파싱 예외를 처리하지 않음.
DateTimeParseException을 잡지 않으면, 잘못된 사용자 입력으로 프로그램이 갑자기 종료될 수 있습니다. 반드시 이런 예외를 처리하세요.
실수 № 4: 단어를 사용할 때 로케일을 지정하지 않음.
월을 글자로 출력하는 패턴(MMMM)을 쓰면서 로케일을 지정하지 않으면, Java는 기본 언어(예: 영어)를 사용할 수 있습니다. 항상 필요한 로케일을 명시적으로 지정하세요.
실수 № 5: 구식 클래스(SimpleDateFormat, Date)를 새 프로젝트에서 사용함.
기억하세요: 현대 코드에서는 java.time과 DateTimeFormatter만 사용하세요.
GO TO FULL VERSION