[자바의 정석 기초편] 날짜와 시간 & 형식화

JEREGIM·2023년 3월 4일
0

자바의 정석 기초편

목록 보기
13/23

📌날짜와 시간

java.util.Date : 날짜와 시간을 다룰 목적으로 만들어진 클래스

java.util.Calendar : Date 클래스를 개선한 새로운 클래스

java.time 패키지 : Date와 Calendar는 날짜와 시간을 함께 다룰 수 밖에 없는 단점이 있는데 이것을 개선한 새로운 클래스들을 제공한다.(JDK 1.8 이후 부터)

  • 날짜 : LocalDate, 시간 : LocalTime, 날짜 + 시간 : LocalDateTime

📌Calendar 클래스

추상 클래스이므로 getInstance()를 통해 구현된 객체를 얻어야 한다.

Calendar cal = Calendar.getInstance(); // Calendar 객체 생성
int thisYear = cal.get(Calendar.YEAR);
int lastDayOfMonth = cal.getActualMaximum(Calendar.DATE);
  • Calendar cal = Calendar.getInstance(); : 현재 날짜와 시간으로 세팅
  • int thisYear = cal.get(Calendar.YEAR); : 올해가 몇년인지
  • int lastDayOfMonth = cal.getActualMaximum(Calendar.DATE); : 이 달의 마지막 날

Calendar에 정의된 필드

필드명설명
YEAR
MONTH월(0부터 시작)
DATE
WEEK_OF_YEAR그 해의 몇 번째 주
WEEK_OF_MONTH그 달의 몇 번째 주
DAY_OF_MONTH그 달의 몇 번째 일
DAY_OF_YEAR그 해의 몇 번째 일
DAY_OF_WEEK요일(1~7) 1 : 일요일
DAY_OF_WEEK_IN_MONTH그 달의 몇 번째 요일
HOUR시간(0~11)
HOUR_OF_DAY시간(0~23)
MINUTE
SECOND
MILLISECOND천분의 일 초
ZONE_OFFSETGMT 기준 시차(천분의 일 초 단위)
AM_PM오전/오후

set()으로 날짜와 시간 지정

날짜 지정

Calendar date = Calendar.getInstance();
date.set(2022, 1, 22); // 2022년 2월 22일
  • date.set(2022, 1, 22); : 월은 0부터 시작한다.

시간 지정

Calendar time = Calendar.getInstance();
time.set(Calendar.HOUR_OF_DAY, 10);
time.set(Calendar.MINUTE, 20);
time.set(Calendar.SECOND, 30);
  • 시간 지정은 날짜처럼 한번에 시,분,초 설정하는 방법이 없기 때문에 하나씩 설정해줘야 한다.

두 날짜 간의 차이를 얻는 방법

두 날짜를 천 분의 일 초 단위로 바꾸고 계산한다.

Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();

long difference = (date2.getTimeInMillis() - date1.getTimeInMillis()) / 1000;
int differenceDay = difference / (24*60*60);
  • getTimeInMillis() 메서드를 통해 ms 단위로 변경 후 차이를 계산하고 1000을 나눠서 초 단위로 바꿔준다.
  • 두 날짜 간의 차이를 일 단위로 바꿔주기 위해서 (24*60*60) 을 나눠준다.

두 시간의 차이를 얻는 방법

두 시간을 천 분의 일 초 단위로 바꾸고 계산한다.

import java.util.Calendar;

public class Ex10_3 {
    public static void main(String[] args) {
        final int[] TIME_UNIT = {3600, 60, 1}; // 큰 단위를 앞에 놓는다.
        final String[] TIME_UNIT_NAME = {"시간 ", "분 ", "초 "};

        Calendar time1 = Calendar.getInstance();
        Calendar time2 = Calendar.getInstance();

        time1.set(Calendar.HOUR_OF_DAY, 10);
        time1.set(Calendar.MINUTE, 20);
        time1.set(Calendar.SECOND, 30); // 10시 20분 30초로 설정

        time2.set(Calendar.HOUR_OF_DAY, 20);
        time2.set(Calendar.MINUTE, 30);
        time2.set(Calendar.SECOND, 10); // 20시 30분 10초로 설정

        System.out.printf("time1 : %d시 %d분 %d초%n",
                time1.get(Calendar.HOUR_OF_DAY), time1.get(Calendar.MINUTE), time1.get(Calendar.SECOND));
        System.out.printf("time2 : %d시 %d분 %d초%n",
                time2.get(Calendar.HOUR_OF_DAY), time2.get(Calendar.MINUTE), time2.get(Calendar.SECOND));


        long difference = Math.abs(time2.getTimeInMillis() - time1.getTimeInMillis()) / 1000;
        System.out.printf("두 시간의 차이는 %d초%n", difference);

        String tmp = "";
        for(int i = 0; i < TIME_UNIT.length; i++) {
            tmp += difference/TIME_UNIT[i] + TIME_UNIT_NAME[i];
            difference %= TIME_UNIT[i];
        }
        System.out.printf("두 시간의 차이는 %s입니다.", tmp);
    }
}

time1 : 10시 20분 30초
time2 : 20시 30분 10초
두 시간의 차이는 36580초
두 시간의 차이는 10시간 9분 40초 입니다.

  • 두 시간의 차이를 초 단위로 구한 값(difference) : 36580

  • difference를 시분초 단위로 바꾸는 법은 1시간은 3600초기 때문에 3600으로 나눈 몫이 시간, 3600으로 나눈 나머지를 또 60으로 나눈 몫이 분, 60으로 나눈 나머지가 초가 된다.

    • 36580 / 3600 = 10(시간), 나머지 580
    • 580 / 60 = 9(분), 나머지 40(초)

clear()

: Calendar 객체의 모든 필드를 초기화

Calendar dt = Calendar.getInstance(); // 현재 시간
System.out.println(new Date(dt.getTimeInMillis())); // 현재 시간 출력

dt.clear();
System.out.println(new Date(dt.getTimeInMillis())); // EPOCH Time으로 초기화 : 1970년 1월 1일 00:00:00

Sun Mar 05 17:08:49 KST 2023
Thu Jan 01 00:00:00 KST 1970

clear(int field) : Calendar 객체의 특정 필드를 초기화

Calendar dt = Calendar.getInstance(); // 현재 시간
System.out.println(new Date(dt.getTimeInMillis()));

dt.clear(Calendar.SECOND); // 초를 초기화
dt.clear(Calendar.MINUTE); // 분을 초기화
dt.clear(Calendar.HOUR_OF_DAY); // 시간을 초기화
dt.clear(Calendar.HOUR); // 시간을 초기화

getInstance()로 객체 생성을 한 다음 set() 메서드를 쓰기 전에 clear()로 초기화 해줘야 한다.

Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
System.out.println(date1);
System.out.println(date2);

  • clear()를 해주지 않으면 두 객체를 생성하는 사이의 ms초 차이가 발생한다.
  • 날짜와 시간을 계산할 때 set() 메서드로 지정해주기 전에 clear() 메서드로 초기화 해줘야 한다.

add()

: 특정 필드의 값을 증가 또는 감소(다른 필드에 영향 O)

Calendar dt = Calendar.getInstance();
dt.clear();
dt.set(2023, 7, 31); // 2023년 8월 31일

dt.add(Calendar.DATE, 1); // + 1일 -> 2023년 9월 1일
dt.add(Calendar.MONTH, -8); // - 8개월 -> 2023년 1월 1일

roll()

: 특정 필드의 값을 증가 또는 감소(다른 필드에 영향 X)

Calendar dt = Calendar.getInstance();
dt.clear();
dt.set(2023, 7, 31); // 2023년 8월 31일

dt.roll(Calendar.DATE, 1); // + 1일 -> 2023년 8월 1일
dt.roll(Calendar.MONTH, -8); // - 8개월 -> 2023년 12월 1일
  • 31일에서 1일을 더해도 월이 변하지 않는다.
  • 2023년 8월에서 8월을 빼도 년도가 변하지 않는다.

달력 출력하는 예제

import java.util.*;

class Ex10_5 {
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Usage : java Ex10_5 2019 9");
            return;
        }

        int year = Integer.parseInt(args[0]);
        int month = Integer.parseInt(args[1]);
        int START_DAY_OF_WEEK = 0; // 1일의 요일
        int END_DAY = 0;

        Calendar sDay = Calendar.getInstance(); // 시작일
        Calendar eDay = Calendar.getInstance(); // 끝일

        // 월은 0이 1월, 11이 12월이기 때문에 -1을 해준다.
        sDay.set(year, month - 1, 1);
        eDay.set(year, month, 1);

        // 끝일은 다음달 1일에서 -1을 해준다.
        eDay.add(Calendar.DATE, -1);

        // 1일이 무슨 요일인지 알아낸다.
        START_DAY_OF_WEEK = sDay.get(Calendar.DAY_OF_WEEK);

        END_DAY = eDay.get(Calendar.DATE);

        System.out.println("      " + year + "년 " + month + "월");
        System.out.println(" SU MO TU WE TH FR SA");

        for (int i = 1; i < START_DAY_OF_WEEK; i++)
            System.out.print("   ");

        for (int i = 1, n = START_DAY_OF_WEEK; i <= END_DAY; i++, n++) {
            System.out.print((i < 10) ? "  " + i : " " + i);
            // 토요일이 될 때 마다 줄바꿈
            if (n % 7 == 0) System.out.println();
        }
    }
}

Date와 Calendar 간의 변환

Date의 메서드는 대부분 deprecated(사용하지 않을 것을 권장) 되었지만 여전히 사용

  • 하위호환성 때문에 Date의 메서드를 없애지 않는다.
  1. Calendar -> Date
Calendar cal = Calendar.getInstance();
Date d = new Date(cal.getTimeInMillis());
  1. Date -> Calendar
Date d = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(d);

📌형식화 클래스

: 숫자와 날짜를 형식화하여 출력하는 클래스(숫자, 날짜 -> 형식 문자열), 그 반대도 가능

java.text 패키지의 DecimalFormat, SimpleDateFormat

DecimalFormat

: 숫자를 형식화할 때 사용(숫자 -> 형식 문자열), 그 반대도 가능

기호의미패턴결과(777.77)
010진수(값이 없을 때는 0)0778
0.0777.77
0000.0000777.770
#10진수#778
#.#777.77
####.###777.77

숫자를 형식 문자열로 바꿀 때 사용(숫자 -> 형식 문자열)

double num = 1234567.89;
DecimalFormat df = new DecimalFormat("#.#E0"); // 지수 표현
String result = df.format(num);

result = "1.2E6"

형식 문자열에서 숫자로 변환(형식 문자열 -> 숫자)

DecimalFormat df = new DecimalFormat("#,###.##");
Number num = df.parse("1,234,567.89");
double d = num.doubleValue();

d = 1234567.89

[참고] Integer.parseInt()는 콤마(,)가 포함된 문자열을 숫자로 변환 못시킨다.

SimpleDateFormat

: 날짜와 시간을 다양한 형식으로 출력할 수 있게 해준다.

Date today = new Date(); // 현재 날짜
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

String result = sdf.format(today);

result = "2023-03-05"

날짜와 관련된 기호들

기호의미예시
G연대(BC, AD)AD
Y연도2023
M10, 10월, OCT
w년의 몇 번째 주(1~53)52
W월의 몇 번째 주(1~5)4
D년의 몇 번째 일(1~365)300
d월의 몇 번째 일(1~31)15
F월의 몇 번째 요일(1~5)1
E요일

특정 형식으로 되어 있는 문자열에서 날짜와 시간을 뽑아낼 수 있다.

DateFormat df = new SimpleDateFormat("yyyy년 MM월 dd일");
DateFormat df2 = new SimpleDateFormat("yyyy/MM/dd");

Date d = df.parse("2022년 2월 2일");
String result = df.format(d);
String result2 = df2.format(d);

System.out.println("result = " + result);
System.out.println("result2 = " + result2);

result = 2022년 02월 02일
result2 = 2022/02/02

  • Date d = df.parse("2022년 2월 2일"); : 문자열을 Date 형으로 변환
  • String result = df.format(d); : Date 형식을 원하는 형식 문자열로 변환

시간과 관련된 기호들

기호의미예시
a오전/오후(AM, PM)PM
H시간(0~23)21
k시간(1~24)24
K시간(0~11)11
h시간(1~12)12
m분(0~59)55
s초(0~59)33
S천분의 일초(0~999)235
zTime zone(General time zone)GMT+9:00
ZTime zone(RFC 822 time zone)+0900

0개의 댓글