[Java] 기본 API 클래스 ⑦

kiteB·2022년 2월 8일

Java

목록 보기
35/35
post-thumbnail

[ Format 클래스 ]

자바에서는 숫자와 날짜를 원하는 형식의 문자열로 쉽게 변환하기 위해 형식 클래스를 제공한다.

형식 클래스는 java.text 패키지에 포함되어 있는데

  • 숫자 형식을 위해 DecimalFormat,
  • 날짜 형식을 위해 SimpleDateFormat,
  • 매개 변수화된 문자열 형식을 위해 MessageFormat 등을 제공한다.

1. 숫자 형식 클래스 ( DecimalFormat )

DecimalFormat은 숫자 데이터를 원하는 형식을 표현하기 위해서 패턴을 사용한다.

📌 DecimalFormat 패턴

패턴 사용 방법은 다음과 같다.

  • 적용할 패턴을 DecimalFormat 생성자 매개값으로 지정해서 객체를 생성한다.
  • format() 메소드를 호출해서 패턴이 적용된 문자열을 얻는다.
DecimalFormat df = new DecimalFormat("#,###.0");
String result = df.format(1234567.89);

2. 날짜 형식 클래스 ( 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());

3. 문자열 형식 클래스 ( 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 클래스는 날짜와 시간 정보를 얻기에는 충분하지만, 날짜와 시간을 조작하거나 비교하는 기능이 불충분하다.

1. 날짜와 시간 객체 생성

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() 메소드는 두 시점 간의 차이를 리턴한다.


2. 날짜와 시간에 대한 정보 얻기

LocalDate와 LocalTime은 프로그램에서 날짜와 시간 정보를 이용할 수 있도록 다음과 같은 메소드를 제공하고 있다.

LocalDateTime과 ZonedDateTime은 날짜와 시간 정보를 모두 갖고 있기 때문에 위 표에 나와 있는 대부분의 메소드를 가지고 있다. 단, isLeapYear()는 LocalDate에만 있기 때문에 toLocalDate() 메소드로 LocalDate로 변환한 후에 사용할 수 있다.

ZonedDateTime은 시간존에 대한 정보를 제공하는 다음 메소드들을 추가적으로 가지고 있다.


3. 날짜와 시간 조작하기

날짜와 시간 클래스들은 날짜와 시간을 조작하는 메소드와 상대 날짜를 리턴하는 메소드들을 가지고 있다.

✅ 빼기와 더하기

다음은 날짜와 시간을 빼거나 더하는 메소드들이다.

각 메소드들은 수정된 LocalDate, LocalTime, LocalDateTime, ZonedDateTime을 리턴하기 때문에 도트 . 연산자로 연결해서 순차적으로 호출할 수 있다.


✅ 변경하기

다음은 날짜와 시간을 변경하는 메소드들이다.

with() 메소드는 현재 날짜를 기준으로 해의 첫 번째 일 또는 마지막 일, 달의 첫 번재 일 또는 마지막 일, 달의 첫 번째 요일, 지난 요일 및 돌아오는 요일 등 상대적인 날짜를 리턴한다. 매개값은 TemporalAdjuster 타입으로 다음 표에 있는 TemporalAdjusters의 정적 메소드를 호출하면 얻을 수 있다.


4. 날짜와 시간을 비교하기

날짜와 시간 클래스들은 다음과 같이 비교하거나 차이를 구하는 메소드들을 가지고 있다.

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가 된다.

5. 파싱과 포맷팅

날짜와 시간 클래스는 문자열을 파싱(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);
profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글