Format
클래스 ]자바에서는 숫자와 날짜를 원하는 형식의 문자열로 쉽게 변환하기 위해 형식 클래스를 제공한다.
형식 클래스는 java.text
패키지에 포함되어 있는데
DecimalFormat
,SimpleDateFormat
,MessageFormat
등을 제공한다.DecimalFormat
)
DecimalFormat
은 숫자 데이터를 원하는 형식을 표현하기 위해서 패턴을 사용한다.
DecimalFormat
패턴패턴 사용 방법은 다음과 같다.
DecimalFormat
생성자 매개값으로 지정해서 객체를 생성한다. format()
메소드를 호출해서 패턴이 적용된 문자열을 얻는다.DecimalFormat df = new DecimalFormat("#,###.0");
String result = df.format(1234567.89);
SimpleDateFormat
)Date
클래스의 toString()
메소드는 영문으로 된 날짜를 리턴하는데 만약 특정 문자열 포맷으로 얻고 싶다면 java.text.SimpleDateFormat
클래스를 이용하면 된다. SimpleDateFormat
클래스도 날짜를 원하는 형식으로 표현하기 위해서 패턴을 사용한다.
SimpleDateFormat
패턴패턴에는 자릿수에 맞게 기호를 반복하여 작성할 수 있다.
yyyy
는 년도를 4자리로 표현하라는 의미이다.MM
과 dd
는 각각 달과 일을 2자리로 표시하라는 의미이다.SimpleDateFormat df = new SimpleDateFormat("yyyy년 MM월 dd일");
String strDate = sdf.format(new Date());
MessageFormat
)데이터를 파일에 저장하거나, 네트워크로 전송할 때, 그리고 데이터베이스 SQL문을 작성할 때 등 많은 부분에서 일정한 형식의 문자열을 사용한다.
MessageFormat
클래스를 사용하면 문자열에 데이터가 들어갈 자리를 표시해 두고,
프로그램이 실행하면서 동적으로 데이터를 삽입해 문자열을 완성시킬 수 있다.
예를 들어 다음과 같이 회원 정보를 출력한다고 가정해보자.
회원 ID: blue
회원 이름: Java
회원 전화번호: 010-1234-5678
만약 id
, name
, tel
이라는 변수에 회원 정보가 저장되어 있을 경우,
연결 연산자 +
를 사용하거나, MessageForma
를 사용할 수 있다.
+
사용 다음과 같이 문자열 연결 연산자+
로 출력할 문자열을 생성할 수 있다.
String resut = "회원 ID: " + id + "\n회원 이름: " + name + "\n회원 전화번호: " + tel;
위의 방법은 +
연산자로 인해 복잡해 보이고, 전체 문자열을 파악하기 힘들다.
MessageFormat
사용MessageFormat
클래스를 사용하면 조금 더 깔끔하게 데이터를 삽입하고 전체 문자열을 쉽게 예측할 수 있다.
String message = "회원 ID: {0} \n회원 이름: {1} \n회원 전화번호: {2}";
String result = MessageFormat.format(message, id, name, tel):
MessageFormat
은 정적 format()
메소드를 호출해서 완성된 문자열을 리턴시킨다.
format()
의
값을 나열하는 대신, 다음과 같이 배열을 대입해도 된다.
String text = "회원 ID: {0} \n회원 이름: {1}\n 회원 전화번호: {2}";
Ojbect[] arguments = {id, name, tel};
String result = MessageFormat.format(text, arguments);
java.time
패키지 ]자바 7 이전까지는 Date
와 Calendar
클래스를 이용해서 날짜와 시간 정보를 얻을 수 있었다. 하지만 여러 요인들로 인해 자바 8부터는 java.time
패키지와 하위 패키지를 사용한다.
💡 참고 |
Date
와Calendar
클래스의 문제점
Date
클래스의 대부분의 메소드는Deprecated
되었고,Date
용도는 단순히 특정 시점의 날짜 정보를 저장하는 역할만 한다.Calendar
클래스는 날짜와 시간 정보를 얻기에는 충분하지만, 날짜와 시간을 조작하거나 비교하는 기능이 불충분하다.
java.time
패키지에는 다음과 같이 날짜와 시간을 표현하는 5개의 클래스가 있다.
LocalDate
LocalDate
는 로컬 날짜 클래스로, 날짜 정보만을 저장할 수 있다.
LocalDate
객체는 두 가지 정적 메소드로 얻을 수 있다.
now()
: 컴퓨터의 현재 날짜 정보를 저장한 LocalDate
객체를 리턴한다.of()
: 매개값으로 주어진 날짜 정보를 저장한 LocalDate
객체를 리턴한다.LocalDate currDate = LocalDate.now();
LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);
LocalTime
LocalTime
은 로컬 시간 클래스로, 시간 정보만을 저장할 수 있다.
LocalTime
객체도 마찬가지로 두 가지 정적 메소드로 얻을 수 있다.
now()
: 컴퓨터의 현재 시간 정보를 저장한 LocalTime
객체를 리턴한다.of()
: 매개값으로 주어진 시간 정보를 저장한 LocalTime
객체를 리턴한다.LocalTime currTime = LocalTime.now();
LocalTime targetTime = LocalTime.of(int hour, int minute, int second, int nanoOfSecond);
LocalDateTime
LocalDateTime
은LocalDate
와LocalTime
을 결합한클래스라고 보면 된다.
날짜와 시간 정보를 모두 저장할 수 있다.
LocalDateTime
객체도 마찬가지로 두 가지 정적 메소드로 얻을 수 있다.
now()
: 컴퓨터의 현재 날짜와 시간 정보를 저장한 LocalDateTime
객체를 리턴한다.of()
: 매개값으로 주어진 날짜와 시간 정보를 저장한 LocalDateTime
객체를 리턴한다.LocalDateTime currDateTime = LocalDateTime.now();
LocalDateTime targetTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);
ZonedDateTime
ZonedDateTime
은 ISO-8601 달력 시스템에서 정의하고 있는 타임존의 날짜와 시간을 저장하는 클래스이다.
2014-04-21T07:50:24.017+09:00[Asia/Seoul]
와 같이 맨 뒤에 타임존에 대한 정보(±존오프셋[존아이디]
)가 추가적으로 붙는다.ZoneOffset
): 협정세계시 (UTC: Universal Time Coordinated)와 차이 나는 시간(시차)을 말한다. ZonedDateTime
은 now()
정적 메소드에 ZoneId
를 매개값으로 주고 얻을 수 있다.ZoneId
는 of()
메소드로 얻을 수 있다. of()
의 매개값은 java.util.TimeZone
의 getAvailableIDs()
메소드가 리턴하는 유효한 값 중 하나이다.ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime londonDateTime = ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
Instant
Instant
클래스는 날짜와 시간의 정보를 얻거나 조작하는데 사용되지 않고, 특정 시점의 타임스탬프(Time-Stamp
)로 사용된다. 주로 특정한 두 시점 간의 시간적 우선순위를 따질 때 사용한다.
java.util.Date
와 가장 유사한 클래스이지만
Date
는 로컬 컴퓨터의 현재 날짜와 시간 정보를,Instant
는 협정세계시(UTC)를 기준으로 한다는 차이점이 있다.Instant instant1 = Instant.now();
Instant instant2 = Instant.now();
if(instant1.isBefore(instant2)) {
System.out.println("instant1이 빠릅니다.");
} else if (instant1.isAfter(instant2)) {
System.out.println("instant1이 늦습니다.");
} else {
System.out.println("동일한 시간입니다.");
}
System.out.println("차이(nanos): " + instant1.until(instant2,ChronoUnit.NANOS));
위 코드에서 isBefore()
와 isAfter()
는 시간의 앞뒤 여부를 확인하는 메소드이고,
until()
메소드는 두 시점 간의 차이를 리턴한다.
LocalDate
와 LocalTime
은 프로그램에서 날짜와 시간 정보를 이용할 수 있도록 다음과 같은 메소드를 제공하고 있다.
LocalDateTime
과 ZonedDateTime
은 날짜와 시간 정보를 모두 갖고 있기 때문에 위 표에 나와 있는 대부분의 메소드를 가지고 있다. 단, isLeapYear()
는 LocalDate
에만 있기 때문에 toLocalDate()
메소드로 LocalDate
로 변환한 후에 사용할 수 있다.
ZonedDateTime
은 시간존에 대한 정보를 제공하는 다음 메소드들을 추가적으로 가지고 있다.
날짜와 시간 클래스들은 날짜와 시간을 조작하는 메소드와 상대 날짜를 리턴하는 메소드들을 가지고 있다.
다음은 날짜와 시간을 빼거나 더하는 메소드들이다.
각 메소드들은 수정된 LocalDate
, LocalTime
, LocalDateTime
, ZonedDateTime
을 리턴하기 때문에 도트 .
연산자로 연결해서 순차적으로 호출할 수 있다.
다음은 날짜와 시간을 변경하는 메소드들이다.
with()
메소드는 현재 날짜를 기준으로 해의 첫 번째 일 또는 마지막 일, 달의 첫 번재 일 또는 마지막 일, 달의 첫 번째 요일, 지난 요일 및 돌아오는 요일 등 상대적인 날짜를 리턴한다. 매개값은 TemporalAdjuster
타입으로 다음 표에 있는 TemporalAdjusters
의 정적 메소드를 호출하면 얻을 수 있다.
날짜와 시간 클래스들은 다음과 같이 비교하거나 차이를 구하는 메소드들을 가지고 있다.
Period
나 Duration
은 날짜와 시간의 양을 나타내는 클래스들이다.
Period
는 년, 달, 일의 양을 나타내는 클래스이고,Duration
은 시, 분, 초, 나노초의 양을 나타내는 클래스이다.이 클래스는 D-day
나 D-time
을 구할 때 사용될 수 있다.
다음은 Period
와 Durataion
에서 제공하는 메소드들이다.
between()
메소드는 Period
와 Duration
클래스, 그리고 ChronoUnit
열거 타입에도 있다.
Period
와 Duration
의 between()
은 년, 달, 일의 단순 차이를 리턴하고,ChronoUnit
열거 타입의 between()
은 전체 시간을 기준으로 차이를 리턴한다.예를 들어 2023년 1월과 2024년 3월의 달의 차이를 구할 때
Period
의 between()
은 2가 되고,ChronoUnit.MONTHS.between()
은 14가 된다.날짜와 시간 클래스는 문자열을 파싱(parsing
)해서 날짜와 시간을 생성하는 메소드와 이와 반대로 날짜와 시간을 포맷팅(Formatting
)된 문자열로 변환하는 메소드를 제공하고 있다.
Parsing
) 포맷팅다음은 날짜와 시간 정보가 포함된 문자열을 파싱해서 날짜와 시간을 생성하는 두 개의 parse()
정적 메소드이다.
LocalDate
의 parse(CharSequence)
메소드는 기본적으로 ISO_LOCAL_DATE
포맷터를 사용해서 문자열을 파싱한다. ISO_LOCAL_DATE
는 DateTimeFormatter
의 상수로 정의되어 있는데, "2022-02-08"
형식의 포맷터이다.
LocalDate localDate = LocalDate.parse("2022-02-08");
만약 다른 포맷터를 이용해서 문자열을 파싱하고 싶다면 parse(CharSequence, DateTime Formatter)
메소드를 사용할 수 있다. DateTimeFormatter
는 ofPattern()
메소드로 정의할 수도 있는데, 다음 코드는 "2022.02.08"
형식의 DateTimeFormatter
를 정의하고 문자열을 파싱했다.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
LocalDate localDate = LocalDate.parse("2022.02.08", formatter);
DateTimeFormatter
에는 표준화된 포맷터들이 다음과 같이 상수로 미리 정의되어 있기 때문에 ofPattern()
메소드를 사용하지 않고 바로 이용할 수 있다.
만약 포맷터의 형식과 다른 문자열을 파싱하게 되면 DateTimeParseException
이 발생하게 된다.
Formatting
) 메소드format()
의 매개값은 DateTimeFormatter
로, 해당 형식대로 문자열을 리턴한다.
다음은 LocalDateTime
으로부터 "2022년 2월 8일 오후 5시 30분"
과 같은 문자열을 얻는 코드이다.
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일 a h시 m분");
String nowString = now.format(dateTimeFormatter);