📚 Study/JAVA

[JAVA] 날짜와 시간 & 형식화

0_ch4n 2022. 5. 5. 21:53
반응형

✔️ 날짜와 시간

📌 java.util.Date 클래스

  • Date 클래스는 대부분의 메서드가 'deprecated'이므로 Calendar로 변환해가며 사용한다
//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);

 

📌 java.util.Calendar 클래스

  • 추상 클래스이므로 getInstance()를 통해 날짜와 시간에 대한 정보를 갖게끔 구현해야 한다
  • getInstance()는 태국은 BuddhistCalendar, 나머지는 GregorianCalendar를 반환한다
//Calendar 클래스 구현
Calendar cal = Calendar.getInstance(); //getInstance()를 통해 클래스 구현
Calendar cal2 = new GregorianCalendar(); //GregorianCalendar를 통해 클래스 구현

Date d = new Date();
cal.setTime(d); //getInstance()로 Date 클래스를 구현

//get 메서드
System.out.println(cal.get(Calendar.YEAR)); //1, 년도
System.out.println(cal.get(Calendar.MONTH)); //2, 월(0~11월)
System.out.println(cal.get(Calendar.WEEK_OF_YEAR)); //3, 이 해의 몇 째 주
System.out.println(cal.get(Calendar.WEEK_OF_MONTH)); //4, 이 달의 몇 째 주

System.out.println(cal.get(Calendar.DATE)); //5, 일
System.out.println(cal.get(Calendar.DAY_OF_MONTH)); //5, 일
System.out.println(cal.get(Calendar.DAY_OF_YEAR)); //6, 이 해의 몇 일
System.out.println(cal.get(Calendar.DAY_OF_WEEK)); //7, 요일(1:일요일)
System.out.println(cal.get(Calendar.DAY_OF_WEEK_IN_MONTH)); //8, 이 달의 몇 쨰 요일

System.out.println(cal.get(Calendar.AM_PM)); //9, 오전오후(0:오전)
System.out.println(cal.get(Calendar.HOUR)); //10, 시간(0~11시간)
System.out.println(cal.get(Calendar.HOUR_OF_DAY)); //11, 시간(0~23시간)
System.out.println(cal.get(Calendar.MINUTE)); //12, 분(0~59분)
System.out.println(cal.get(Calendar.SECOND)); //13, 초(0~59초)
System.out.println(cal.get(Calendar.MILLISECOND)); //14, 1000분의 1초(0~999)
System.out.println(cal.get(Calendar.ZONE_OFFSET)); //15, 타임존(-12~+12)

System.out.println(cal.getActualMaximum(Calendar.DATE)); //이 달의 마지막 일

//set 메서드
cal.set(Calendar.HOUR, 5); 5시로 설정
cal.set(2030, 5, 30); //2030년 5월 30일로 설정
cal.set(2030, 5, 30, 5, 30); //2030년 5월 30일 5시 30분으로 설정
cal.set(2030, 5, 30, 5, 30 ,10); //2030년 5월 30일 5시 30분 10초로 설정

//1000분의 1초로 시간 구하기
cal.getTimeInMillis();

//증가, 감소
cal.add(Calendar.MONTH, -6) //달을 6만큼 감소 (다른 필드에 영향 O)
cal.roll(Calendar.MONTH, -6) //달을 6만큼 감소 (다른 필드에 영향 X, 말일은 영향 O)

 

✔️ 형식화

  • java.text 패키지에 포함되어 있으며 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현하거나 역으로 데이터를 얻어낼 수 있다

 

📌 DecimalFormat 클래스

  • 숫자를 형식화하거나 텍스트 데이터를 숫자로 변환하는데 사용한다

double number = 1234567.89;
String[] pattern = {
        "0", //1234568
        "#", //1234568
        "0.0", //1234567.9
        "#.#", //1234567.9
        "0000000000.0000", //0001234567.8900
        "##########.####", //1234567.89
        "#.#-", //1234567.9-
        "-#.#", //-1234567.9
        "#,###.##", //1,234,567.89
        "#,####.##", //123,4567.89
        "#E0", //.1E7
        "0E0", //1E6
        "##E0", //1.2E6
        "####E0", //123.5E4
        "0000E0", //1235E3
        "#.#E0", //1.2E6
        "0.0E0", //1.2E6
        "0.000000000E0", //1.234567890E6
        "00.00000000E0", //12.34567890E5
        "000.0000000E0", //123.4567890E4
        "#.#########E0", //1.23456789E6
        "##.########E0", //1.23456789E6
        "###.#######E0", //1.23456789E6
        "#,###.##+;#,###.##-", //1,234,567.89+
        "#.#%", //123456789%
        "#.#\u2030", //1234567890%
        "\u00A4 #,###", //₩ 1,234,568
        "'#'#,###", //#1,234,568
        "''#,###", //'1,234,568
};

for(int i = 0; i <pattern.length; i++) {
    DecimalFormat df = new DecimalFormat(pattern[i]);
    System.out.printf("%s : %s\n", pattern[i], df.format(number));
}

DecimalFormat df = new DecimalFormat("#,###.##");
DecimalFormat df2 = new DecimalFormat("#.###E0");
Number num = df.parse("1,234,567.89");

double d = num.doubleValue(); //Number 클래스를 통한 문자열 -> 숫자로의 변환
System.out.println(d);

System.out.println(df2.format(num)); //format 메서드를 통한 숫자 -> 문자열로의 변환

 

📌 SimpleDateFormat 클래스

  • Date나 Calendar를 통해 만든 인스턴스를 원하는 형태로 출력하기 위해 사용한다
  • Date 인스턴스만 format 메서드에 사용될 수 있기 때문에 Calendar는 Date로 변환하여 사용한다

//Calendar를 Date로 변환
Calendar cal = Calendar.getInstance();
cal.set(2005, 9, 3);
Date d = cal.getTime();

//Date 생성
Date d2 = new Date();

//parse()를 통한 Date 생성
SimpleDateFormat sdf = new SimpleDateFormat("yyyy년 MM월 dd일");

try {
    Date d3 = sdf.parse("2015년 11월 23일");
} catch (Exception e) {}

//SimpleFormat 생성
SimpleDateFormat sdf1, sdf2, sdf3, sdf4, sdf5, sdf6, sdf7, sdf8, sdf9;

sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf2 = new SimpleDateFormat("''yy년 MMM dd일 E요일");
sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sdf4 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");

sdf5 = new SimpleDateFormat("오늘은 올 해의 D번째 날입니다.");
sdf6 = new SimpleDateFormat("오늘은 이 달의 d번째 날입니다.");
sdf7 = new SimpleDateFormat("오늘은 올 해의 w번째 주입니다.");
sdf8 = new SimpleDateFormat("오늘은 이 달의 W번째 주입니다.");
sdf9 = new SimpleDateFormat("오늘은 이 달의 F번째 E요일입니다.");

 

📌 ChoiceFormat 클래스

  • 특정 범위에 속하는 값을 문자열로 변환할 때 사용한다
//경계값과 치환할 문자열의 개수는 같아야 한다
double[] limits = {60,70,80,90}; //범위의 경계값 (꼭 double형이고 오름차순이어야 함)
String[] value = {"D","C","B","A"}; //치환할 문자열

ChoiceFormat cf = new ChoiceFormat(limits, value);

//패턴을 이용한 치환
String pattern = "60#D|70#C|80<B|90#A"; //#은 범위에 포함, <은 범위에 미포함

ChoiceFormat cf2 = new ChoiceFormat(pattern);

//변환 대상
int[] score = {100,95,88,70,52,60,70};

//출력
for(int i = 0; i < score.length; i++) {
    System.out.println(cf.format(score[i]));
}

 

📌 MessageFormat 클래스

  • 데이터를 정해진 양식에 맞게 출력할 때 사용한다
//양식 생성 ({}부분에 데이터가 들어간다)
String pattern = "Name: {0} \nTel: {1} \nAge: {2} \nBirthday: {3}";

//양식에 들어갈 데이터
Object[] data = {"이자바", "02-123-1234", "27", "07-09"};

//format 생성과 출력
String result = MessageFormat.format(pattern, data);
System.out.println(result);

 

📌 DateTimeFormatter

  • 형식화 클래스 중 날짜와 시간에 특화된 형식화 클래스이다

  • static 메서드 ofLocalizedDate(), ofLocalizedTime(), ofLocalizedDateTime()의 FormatStyle

  • ofPattern()로 기호를 이용해 출력형식을 직접 정의할 수도 있다
  • parse()로 문자열을 날짜 또는 시간으로 변환할 수 있다

 

✔️ java.time 패키지

  • jdk 8부터 Date와 Calendar의 단점을 보완하고 불변이므로 항상 새로운 객체를 반환하며 멀티스레드에 안전하다.

java.time 패키지와 서브 패키지들

 

📌 java.time 패키지의 클래스들

  • TemporalUnit(날짜와 시간의 단위를 정의)과 ChronoUnit(열거형)이 있다
    • Temporal, TemporalAccessor, TemporalAdjuster -> LocalDate, LocalTime, LocalDateTime, ZonedDateTime
    • TemporalAmount -> Period, Duration

 

LocalDate와 LocalTime 클래스

//now()를 통한 객체 생성
LocalDate date = LocalDate.now(); //날짜
LocalTime time = LocalTime.now(); //시간

//of()를 통한 객체 생성
LocalDate date2 = LocalDate.of(2015, 11, 23);
LocalTime time2 = LocalTime.of(23,59,59);

//parse를 통한 문자열 -> 날짜와 시간
LocalDate date3 = LocalDate.parse("1999-12-31");
LocalTime time3 = LocalTime.parse("23:59:59");

//get(), getXXX()을 통해 값 가져오기
date.getYear();
time.getHour();

//필드 값 변경
date.withYear(2022); //with()는 직접 지정
date.plusYears(2); //plus()는 더하기
date.minusYears(2); //minus()는 빼기

//날짜와 시간의 비교
date.isAfter(date2);
date.isBefore(date2);
date.isEqual(date2);

 

Instant 클래스

  • 에포크 타임(1970-01-01 00:00:00 UTC)부터 경과된 시간을 나노초 단위로 표현한다
  • 세계협정시 UTC(+00:00)는 한국 시간대(+09:00)와 9시간 차이난다
//Instant 생성
Instant now = Instant.now();
Instant now2 = Instant.ofEpochSecond(now.getEpochSecond());

//필드 값 가져오기
now.getEpochSecond(); //초 단위
now.getNano(); //나노초 단위
now.toEpochMilli(); //밀리초 단위

//Instant와 Date 변환
Instant.from(now); //Instant -> Date

Date d = new Date();
d.toInstant(); //Date -> Instant

 

LocalDateTime과 ZonedDateTime 클래스

  • LocalDateTime = LocalDate + LocalTime
  • ZonedDateTime = LocalDateTime + 시간대
//LocalDateTime 생성
LocalDateTime dt = LocalDateTime.now();
LocalDateTime dt1 = LocalDateTime.of(2015,12,31,12,34,56);
LocalDateTime dt2 = LocalDateTime.of(date,time);
LocalDateTime dt3 = date.atTime(time);
LocalDateTime dt4 = time.atDate(date);
LocalDateTime dt5 = date.atStartOfDay(); //0시 0분 0초

//ZonedDateTime 생성
ZonedDateTime zdt = ZonedDateTime.now();
ZonedDateTime zdt1 = ZonedDateTime.of(dt, ZoneId.of("Asia/Seoul"));
ZonedDateTime zdt2 = dt.atZone(ZoneId.of("Asia/Seoul"));
ZonedDateTime zdt3 = ZonedDateTime.now().withZoneSameInstant(ZoneId.of("America/NewYork"));

//LocalDateTime -> LocalDate or LocalTime or ZonedDateTime 변환
LocalDate date = dt.toLocalDate();
LocalTime time = dt.toLocalTime();
ZonedDateTime zdt = dt.atZone(ZoneId.of("Asia/Seoul"));

//UTC로부터 얼만큼 떨어져있는지 확인
ZoneOffset zo = ZonedDateTime.now().getOffset();
int offset = zo.get(ChronoField.OFFSET_SECONDS);

//ZonedDateTime -> OffsetDateTime
OffsetDateTime odt = zdt.toOffsetDateTime();
OffsetDateTime odt1 = OffsetDateTime.of(date, time, zo);

//ZonedDateTime과 GregorianCalendar 변환
GregorianCalendar gc = GregorianCalendar.from(zdt); //ZonedDateTime -> GregorianCalendar
gc.toZonedDateTime(); //GregorianCalendar -> ZonedDateTime

 

TemporalAdjusters 클래스

  • 자주 쓰이는 날짜 계산을 메서드로 정의해놓은 것이다
LocalDate date = LocalDate.now();

TemporalAdjusters.firstDayOfNextMonth(); //다음 해의 첫 날
TemporalAdjusters.firstDayOfNextYear(); //다음 달의 첫 날
TemporalAdjusters.firstDayOfYear(); //올 해의 첫 날
TemporalAdjusters.firstDayOfMonth(); //이번 달의 첫 날
TemporalAdjusters.lastDayOfYear(); //올 해의 마지막 날
TemporalAdjusters.lastDayOfMonth(); //이번 달의 마지막 날
TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY); //이번 달의 첫 번째 ?요일
TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY); //이번 달의 마지막 ?요일
TemporalAdjusters.previous(DayOfWeek.MONDAY); //지난 ?요일(당일 미포함)
TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY); //지난 ?요일(당일 포함)
TemporalAdjusters.next(DayOfWeek.MONDAY); //다음 ?요일(당일 미포함)
TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY); //다음 ?요일(당일 포함)
TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.MONDAY); //이번 달의 n번째 ?요일

//with()를 통한 활용
date.with(TemporalAdjusters.firstDayOfNextMonth());

 

Period와 Duration 클래스

  • Period는 날짜 간의 차이, Duration은 시간 간의 차이를 계산한다
//Period를 통해 날짜 간의 간격 구하기
Period period = Period.between(date, date2);

//Duration을 통해 시간 간의 간격 구하기
Duration duration = Duration.between(time, time2);

//get()을 통해 필드 값 구하기
period.get(ChronoUnit.YEARS); //int getYears()
period.get(ChronoUnit.MONTHS); //int getMonths()
period.get(ChronoUnit.DAYS); //int getDays()
duration.get(ChronoUnit.SECONDS); //long getSeconds()
duration.get(ChronoUnit.NANOS); //int getNano();

//between()과 until()
Period period1 = Period.between(date, date2); //static 메서드
Period period2 = date.until(date2); //instance 메서드

//기타 연산
period = period.minusYears(1).multipliedBy(2); //1년 빼고 2 곱함
duration = duration.plusHours(1).dividedBy(60); //1시간 더하고 60으로 나눔
boolean sameDate = Period.between(date, date2).isZero(); //0인지 확인
boolean isBefore = Duration.between(time, time2).isNegative(); //음수인지 확인
duration = duration.negated(); //부호를 반대로 변경
period = Period.of(1,13,32).normalized(); //1년 13개월 32일 -> 2년 1개월 32일

//toXXX()로 다른 단위로 변환하기
period.toTotalMonths(); //년월일을 월단위로 변환
duration.toDays(); //일단위로 변환
duration.toHours(); //시간단위로 변환
duration.toMinutes(); //분단위로 변환
duration.toMillis(); //천분의 일초 단위로 변환
duration.toNanos(); //나노초 단위로 변환

 

📄 참고

자바의 정석 3rd Edition

반응형