Dico

[Java] Class Calendar

날짜와 시간

날짜와 시간을 다룰 목적으로 제공되는 클래스들.

JDK1.0 - Class Date.

JDK1.1 - Class Calendar.

JDK1.8 - package java.time

Class Calendar

추상 클래스

최소한의 변경으로 프로그램이 동작할 수 있도록 하기 위해 메서드를 통해서 완전히 구현된 클래스의 인스턴스를 얻는다.

import java.util.Calendar;

Calendar cal = Calendar.getInstance();

static Calendar getInstance()

시스템의 국가와 지역 설정을 확인해서 태국이면 BuddhistCalendar, 그 외는 GregorianCalendar의 인스턴스를 반환한다.

생성된 인스턴스는 현재 시스템의 날짜와 시간에 대한 정보를 담고 있다.

  • GregorianCalendar :  Calendar를 상속받아 오늘날 전세계 공통으로 사용하고 있는 그레고리력에 맞게 구현한 클래스.
import java.util.GregorianCalendar;

Calendar cal = new GregorianCalendar();

특정 인스턴스를 생성하도록 작성할 경우,

다른 종류의 역법(calendar)을 사용하는 국가에서 실행하거나 새로운 역법이 추가되거나 할 때 추가 작업이 필요하다.

Date와 Calendar간의 변환

Date는 대부분의 메서드가 deprecated되어 잘 사용하지 않지만

여전히 Date를 필요로 하는 메서드들이 존재하여 Calendar를 Date로 또는 그 반대로 변환할 일이 생긴다.

  • Calendar → Date
Calendar cal = Calendar.getInstance();
Date d = new Date(cal.getTimeInMillis());
  • Date → Calendar
Date d = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(d);

int get(int field)

주어진 값(field)에 해당하는 상수 값을 반환한다.

get 메서드의 매개변수로 사용되는 int 값들은 Calendar에 정의된 static 상수다.

  • 주요 상수
    • YEAR :  현재 년도
    • MONTH :  현재 월 (0~11. 0:1월)
    • WEEK_OF_YEAR :  현재 년도의 몇 째 주
    • WEEK_OF_MONTH :  현재 월의 몇 째 주
    • DATE :  현재 월의 날짜
    • DAY_OF_MONTH :  현재 월의 날짜
    • DAY_OF_YEAR :  현재 년도
    • DAY_OF_WEEK :  현재 요일 (1~7. 1:일요일)
    • DAY_OF_WEEK_IN_MONTH :  현재 월의 몇 째 요일
    • AM_PM :  현재 시간 (오전 0, 오후 1)
    • HOUR :  현재 시간 (0~11)
    • HOUR_OF_DAY :  현재 시간 (0~23)
    • MINUTE :  현재 분(0~59)
    • SECOND :  현재 초(0~590
    • MILLISECOND :  1000분의 1초(0~999)
    • ZONE_OFFSET :  TimeZone(-12~+12
  • YEAR :  현재 년도
  • MONTH :  현재 월 (0~11. 0:1월)
  • WEEK_OF_YEAR :  현재 년도의 몇 째 주
  • WEEK_OF_MONTH :  현재 월의 몇 째 주
  • DATE :  현재 월의 날짜
  • DAY_OF_MONTH :  현재 월의 날짜
  • DAY_OF_YEAR :  현재 년도
  • DAY_OF_WEEK :  현재 요일 (1~7. 1:일요일)
  • DAY_OF_WEEK_IN_MONTH :  현재 월의 몇 째 요일
  • AM_PM :  현재 시간 (오전 0, 오후 1)
  • HOUR :  현재 시간 (0~11)
  • HOUR_OF_DAY :  현재 시간 (0~23)
  • MINUTE :  현재 분(0~59)
  • SECOND :  현재 초(0~590
  • MILLISECOND :  1000분의 1초(0~999)
  • ZONE_OFFSET :  TimeZone(-12~+12

get(Calendar.Month)로 얻을 수 있는 값의 범위는 0~11이다. ex) 1월 → 0월

int year, month, day;

Calendar cal = Calendar.getInstance();
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DAY_OF_MONTH);

System.out.println(year + "년 " + month + "월 " + day + "일");       // 2017년 8월 22일

void set()

날짜와 시간을 원하는 값으로 변경한다.

public void set(int field, int value)
public final void set(int year, int month, int date)
public final void set(int year, int month, int date, int hourOfDay, int minute)
public final void set(int year, int month, int date, int hourOfDay, int minute, int second)
cal.set(Calendar.DATE, 2);
day = cal.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "년 " + month + "월 " + day + "일");      // 2017년 8월 2일

cal.set(2017, 10, 17);
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "년 " + month + "월 " + day + "일");      // 2017년 11월 17일

long getTimeInMillis()

시간을 1/1000초 단위로 값을 반환한다.

1초 단위로 값을 얻으려면 1000으로 나눠 주어야 한다.

Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.HOUR_OF_DAY, 5);
cal1.set(Calendar.MINUTE, 10);
cal1.set(Calendar.SECOND, 40);

Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.HOUR_OF_DAY, 15);
cal2.set(Calendar.MINUTE, 20);
cal2.set(Calendar.SECOND, 10);

long dif = (cal2.getTimeInMillis() - cal1.getTimeInMillis()) / 1000;

System.out.println(dif);      // 36570
  • 두 개의 시간간의 차이

     두 개의 시간 데이터로부터 초 단위로 차이를 구한 후,

     가장 큰 단위인 시간 단위(3600s)로 나누고 → 시간

     남은 나머지를 분 단위(60s)로 다시 나누면 → 분

     그 나머지는 초 단위의 값이 된다. → 초

final int[] UNIT = {3600, 60, 1};
final String[] NAME = {"시 ", "분 ", "초"};

String temp = "";
for (int i = 0; i < UNIT.length; i++) {
    temp += (dif / UNIT[i]) + NAME[i];
    dif %= UNIT[i];
}
System.out.println(temp);          // 10시 9분 30초

시간상의 전후를 알고 싶을 때는 두 날짜간의 차이가 양수인지 음수인지 판단하면 된다.

  • boolean after(Object when) :  when과 비교하여 현재 날짜 이후이면 true, 아니면 false
  • boolean before(Object when) :  when과 비교하여 현재 날짜 이전이면 true, 아니면 false

void add(int field, int amount)

지정한 필드의 값을 원하는 만큼 증가/감소 시킨다.

특정 날짜/시간을 기점으로 해서 일정 기간 전후의 날짜와 시간을 알아낼 수 있다.

int year, month, day;

Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 15);

year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DATE);
System.out.println(year + "년 " + month + "월 " + day + "일");         // 2017년 9월 6일

void roll(int field, int amount)

지정한 필드의 값을 원하는 만큼 증가/감소 시킨다.

다른 필드에 영향을 미치지 않는다.

int year, month, day;

Calendar cal = Calendar.getInstance();
cal.roll(Calendar.DAY_OF_MONTH, 15);

year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DATE);
System.out.println(year + "년 " + month + "월 " + day + "일");         // 2017년 8월 6일

단, 일 필드가 말일(end of month)일 때 월 필드를 변경하면 일 필드에 영향을 미칠 수 있다. (add()도 동일)

int year, month, day;

Calendar cal = Calendar.getInstance();
cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));           // 2017년 8월 31일
cal.roll(Calendar.MONTH, 1);

year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1;
day = cal.get(Calendar.DATE);
System.out.println(year + "년 " + month + "월 " + day + "일");         // 2017년 9월 30일
  • int getActualMaximum(int field) :  해당 월의 마지막 날을 반환한다.
  • int getActualMinimum(int field) :  해당 월의 첫 날을 반환한다.

쓰레드에 안전하지 않다.

멀티 쓰레드 환경에서는 동시에 여러 쓰레드가 같은 객체에 접근할 수 있기 때문에, 변경 가능한 객체는 데이터가 잘못될 가능성이 있다.

날짜나 시간을 변경하는 메서드들이 기존의 객체를 변경할 수 있어서 멀티 쓰레드 환경에서 안전하지 못하다.

Calendar API

참고 서적: 자바의 정석 3판 2