본문 바로가기
개념

[JAVA의 정석] Chapter10

by cook_code 2024. 9. 8.
반응형

교재 목차

Chapter10. 날짜와 시간 & 형식화 

Chapter10. 날짜와 시간 & 형식화 


 

1. Calendar 클래스와 Date 클래스 

1-1. 자바 날짜 관련 패키지

Java 시간/날짜 API 시대 계보도

  • JDK 1.0 : java.util.Date (java의 유일한 시간/날짜 API)
  • JDK 1.1 : java.util.Calendar (java.util.Date의 날짜간의 연산, 국제화 지원 등의 기능을 java.util.Calendar가 맡게 됨)
  • JDK 1.8 (JSR-310) : java.time (오픈소스 Joda-Time에서 많은 영향을 받아 만들어진 새로운 시간/날짜 관련 패키지)

 

Calendar

추상클래스이기 때문에 직접 객체를 생성할 수 없고, 메서드를 통해서 완전히 구현된 클래스의 인스턴스를 얻어야 한다.

Date

Calendar 클래스 등장이후 대부분의 메서드가 deprecated 되었다.

1-2. Date와 Calendar 간의 변환

//1. Calendar를 Date로 변환
    Calendar cal = Calendar.getInstance();
      ...
    Date d = new Date(cal.getTimeInMillis());

//2. Date를 Calendar로 변환
    Date d = new Date();
      ...
    Calendar cal = Calendar.getInstance();
    cal.setTime(d);

 

연, 월 정도의 계산이라면 굳이 Calendar를 사용하지 않고 간단히 처리해도 좋다.

public class CalendarEx9 {
    public static void main(String[] args) {
        System.out.println("2014. 5. 31 : " + getDayOfWeek(2014, 5, 31));
        System.out.println("2012. 6. 1 : " + getDayOfWeek(2012, 6, 1));
        System.out.println("2014. 5. 1 - 2014. 4. 28 : " + dayDiff(2014, 5, 1, 2014, 4, 28));
        System.out.println("2015. 6. 29 : " + convertDateToDay(2015, 6, 29));
        System.out.println("735778 : " + convertDateToDay(735778));
    }

    // 각 달의 마지막 일
    public static int[] endOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // 매개변수 year가 윤년이면 true를 그렇지 않으면 false를 반환한다.
    public static boolean isLeapYear(int year) {
        return ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0));
    }

    // 두 날짜간의 차이를 일단위로 반환한다.
    public static int dayDiff(int y1, int m1, int d1, int y2, int m2, int d2) {
        return convertDateToDay(y1, m1, d1) - convertDateToDay(y2, m2, d2);
    }

    // 지정한 날짜의 요일을 반환한다.(1~7, 1이 일요일)
    public static int getDayOfWeek(int year, int month, int day) {
        return convertDateToDay(year, month, day) % 7 + 1;
    }

    // 일단위의 값을 년월일의 형태의 문자열로 변환하여 반환한다.
    public static String convertDateToDay(int day) {
        int year = 1;
        int month = 0;

        while (true) {
            int aYear = isLeapYear(year) ? 366 : 365;
            if (day > aYear) {
                day -= aYear;
                year++;
            } else {
                break;
            }
        }

        while (true) {
            int endDay = endOfMonth[month];
            // 윤년이고 윤달이 포함되어 있으면, 1일을 더한다.
            if (isLeapYear(year) && month == 1) endDay++;

            if (day > endDay) {
                day -= endDay;
                month++;
            } else {
                break;
            }
        }

        return year + "-" + (month + 1) + "-" + day;
    }

    // 년월일을 입력받아서 일단위로 변환한다.
    public static int convertDateToDay(int year, int month, int day) {
        int numOfLeapYear = 0; // 윤년의 수

        // 전년도까지의 윤년의 수를 구한다.
        for (int i = 1; i < year; i++) {
            if (isLeapYear(i))
                numOfLeapYear++;
        }

        // 전년도까지의 일수를 구한다.
        int tolastYeardaySum = (year - 1) * 365 + numOfLeapYear;

        // 올해의 현재 월까지의 일수 계산
        int thisyearDaySum = 0;

        for (int i = 0; i < month - 1; i++)
            thisyearDaySum += endOfMonth[i];

        // 윤년이고, 2월이 포함되어 있으면 1일을 증가시킨다.
        if (month > 2 && isLeapYear(year))
            thisyearDaySum++;

        thisyearDaySum += day;

        return tolastYeardaySum + thisyearDaySum;
    }
}

 

Calendar 클래스를 활용해 특정 날짜가 올해의, 또 이달의 몇 번째 주인지 구하기

※ Calendar 클래스에서는 1월 = 0 이기 때문에 month - 1을 해줘야 원하는 월을 구할 수 있음

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.KOREA);
private int getWeekOfYear(String date) {    Calendar calendar = Calendar.getInstance();    String[] dates = date.split("-");    int year = Integer.parseInt(dates[0]);    int month = Integer.parseInt(dates[1]);    int day = Integer.parseInt(dates[2]);    calendar.set(year, month - 1, day);    return calendar.get(Calendar.WEEK_OF_YEAR);}
// 오늘 날짜 
int thisWeek = getWeekOfYear(sdf.format(new Date()));

출처: https://altongmon.tistory.com/836 [IOS를 Java:티스토리]

 


2. 형식화 

2-1. 형식화란?

데이터를 정의된 패턴에 맞춰 형식화하거나 역으로 형식화된 데이터에서 원래의 데이터를 얻을 수 있도록 하는것. 형식화 클래스들은 java.text 패키지에 속해있으며 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현하는 법을 객체지향적으로 설계하여 표준화하였다.

2-2. 형식화 클래스 종류

DecimalFormat : 숫자 형식화

Java 시간/날짜 API 시대 계보도

import java.text.DecimalFormat;import java.text.NumberFormat;import java.util.Locale; public class Main {    public static void main(String[] args) {        double n = 123.456;         // 0 패턴 : 빈자리는 0으로 채운다.        DecimalFormat df = new DecimalFormat("0");        System.out.println(df.format(n)); // 출력값 : 123         // ; 패턴 : 음수 양수 둘다 표시        df = new DecimalFormat("+0.0; -0.0");        System.out.println(df.format(n)); // 출력값 : +123.5         // + or - 패턴 : 음수 또는 양수 표시        df = new DecimalFormat("-000000.00000");        System.out.println(df.format(n)); // 출력값 : -000123.45600          // # 패턴 : 0과 달리 빈자리를 채우지 않는다.        df = new DecimalFormat("###########");        System.out.println(df.format(n)); // 출력값 : 123         // . 패턴 : 소수점 표시        df = new DecimalFormat("######.#####");        System.out.println(df.format(n)); // 출력값 : 123.456         // , 패턴 : 단위 구분 기호 표시 ( 천자리 구분 )        df = new DecimalFormat("#,###.00000");        System.out.println(df.format(n)); // 출력값 : 123.45600         // % 패턴 : 100을 곱한 후 문자에 %를 붙인다.        df = new DecimalFormat("#.##%");        System.out.println(df.format(n)); // 출력값 : 12345.6%                // \u00A4 패턴 : 통화표시 ₩을 붙인다.        df = new DecimalFormat("\u00A4####.##");        System.out.println(df.format(n)); // 출력값 : ₩123.46         /*         * NumberFormat을 이용하여 통화표시를 지정         * Locale을 사용하여 국가 지정시 해당 국가의 통화기호 및 자리수 구분까지 된다.         */        NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.KOREA);        // 소수점 2자리까지 지정        nf.setMaximumFractionDigits(2);        System.out.println(nf.format(n)); // 출력값 : ₩123.46    }}

출처: https://hstory0208.tistory.com/entry/Java자바-숫자-천자리-구분-소수점-표기-방법DecimalFormat [< Hyun / Log >:티스토리]

 

SimpleDateFormat : 날짜 형식화

MessageFormat : 데이터 형식화(양식)

import java.text.MessageFormat;

public class MessageFormatEx1 {
    public static void main(String[] args) {
        String msg = "Name: {0} \nTel: {1} \nAge: {2} \nBirthday: {3}";
		// arguments의 인덱스 0부터 msg의 {숫자} 안에 들어간다.
        
        Object[] arguments = {
                "자바의 정석", "010-0000-0000", "29", "08-06"
        };

        String result = MessageFormat.format(msg, arguments);

        System.out.println(result);
    }

 

3. java.time 패키지 

3-1. java.time 패키지

JDK8부터 날짜, 시간 계산 시 time 패키지 사용

3-2. 핵심 클래스

LocalDate(일) + LocalTime(시간) → LocalDateTime

LocalDateTime + 시간대 → ZonedDateTime

날짜 - 날짜 = Period

시간 - 시간 = Duration

 // 로컬 컴퓨터의 현재 날짜 정보를 저장한 LocalDate 객체를 리턴
LocalDate currentDate = LocalDate.now();
// result : 2019-11-13

// 파라미터로 주어진 날짜 정보를 저장한 LocalDate 객체를 리턴한다.
LocalDate targetDate = LocalDate.of(2019,11,12);
 //결과 : 2019-11-12

// 로컬 컴퓨터의 현재 시간 정보를 저장한 LocalDate 객체를 리턴. 
LocalTime currentTime = LocalTime.now();   
// 결과 : 18:34:22

// 파라미터로 주어진 시간 정보를 저장한 LocalTime 객체를 리턴.
LocalTime targetTime = LocalTime.of(12,33,35,22); 
// 끝에 4번째 매개변수는 nanoSecond 인데 선택 값이다 굳이 쓰지 않아도 된다.
// 결과 : 12:32:33.0000022

// 로컬 컴퓨터의 현재 날짜와 시간 정보
LocalDateTime currentDateTime = LocalDateTime.now();    
// 결과 : 2019-11-12T16:34:30.388

LocalDateTime targetDateTime = LocalDateTime.of(2019, 11, 12, 12, 32,22,3333);
// 여기도 second,nanoSecond 매개변수는 필수가 아닌 선택입니다.
// 결과 : 2019-11-12T12:32:22.000003333

LocalDateTime currentDateTime = LocalDateTime.now();
// 더 하기는 plus***() 빼기는 minus***()
// currentDateTime.plusYears(long) or minusYears(long)
currentDateTime.plusDays(2)
// 결과 : 2019-11-14T12:32:22.000003333

LocalDateTime startDateTime = LocalDateTime.now();  
// 결과 : 2019-11-12T12:32:22.000003332
LocalDateTime endDateTime = LocalDateTime.of(2019, 11, 12,12, 32,22,3333);
// 결과 : 2019-11-12T12:32:22.000003333

// startDateTime이 endDateTime 보다 이전 날짜 인지 비교
startDateTime.isBefore(endDateTime);    
// 결과 : true

// 동일 날짜인지 비교
startDateTime.isEqual(endDateTime);
// 결과 : false

// startDateTime이 endDateTime 보다 이후 날짜인지 비교
startDateTime.isAfter(endDateTime); 
// 결과 : false

LocalTime startTime = LocalTime.now();  
// 결과 : 23:52:35
LocalTime endTime = LocalTime.of(23, 59, 59);
// 결과 : 23:59:59

// startTime이 endTime 보다 이전 시간 인지 비교
startTime.isBefore(endTime);    
// 결과 : true

// startTime이 endTime 보다 이후 시간 인지 비교
startTime.isAfter(endTime); 
// 결과 : false

LocalDate startDate = LocalDate.now(); 
// 결과 : 2019-11-12
LocalDate endDate = LocalDate.of(2019,12,13);
// 결과 : 2019-12-13

Period period = Period.between(startDate, endDate);

period.getYears();      // 0년
period.getMonths();     // 1개월
period.getDays();       // 1일 차이

LocalDate startDate = LocalDate.now(); 
// 결과 : 2019-11-12
LocalDate endDate = LocalDate.of(2019,12,13);
// 결과 : 2019-12-13

ChronoUnit.DAYS.between(startDate, endDate); 
// 결과 : 31 (1개월 1일)

LocalTime startTime = LocalTime.now();  
// 결과 : 17:14:55
LocalTime endTime = LocalTime.of(18,17,35);
// 결과 : 18:17:35

Duration duration = Duration.between(startTime, endTime);
duration.getSeconds();      
// 결과 : 3742
duration.getNano();
// 결과 : 922000000

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일 a h시 m분");
String nowString = now.format(dateTimeFormatter);   
// 결과 : 2019년 11월 12일 오후 7시 2분

LocalDateTime now2 = LocalDateTime.now();  
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
// 결과 : 2019-11-12 07:26:12

// LocalDate -> String
LocalDate.of(2020, 12, 12).format(DateTimeFormatter.BASIC_ISO_DATE);

// LocalDateTime -> String
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

// LocalDate -> java.sql.Date
Date.valueOf(LocalDate.of(2019, 12, 27));

// LocalDate -> java.sql.Date
Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());

// LocalDateTime -> java.sql.Timestamp
Timestamp.valueOf(LocalDateTime.now());

// String -> LocalDate
LocalDate.parse("1995-05-09");
LocalDate.parse("20191224", DateTimeFormatter.BASIC_ISO_DATE); 

// String -> LocalDateTime
LocalDateTime.parse("2019-12-25T10:15:30");
LocalDateTime.parse("2019-12-25 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

// java.util.Date -> LocalDateTime
LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());

// LocalDateTime -> LocalDate
LocalDate.from(LocalDateTime.now());

// LocalDate -> LocalDateTime
LocalDate.now().atTime(2, 30);

https://java119.tistory.com/52

 

3-3. TemporalAdjusters

JDK 8부터 존재, 자주 쓰일만한 날짜 계산을 대신 해주는 메서드를 정의해놓은 클래스

클래스
메서드
설명
dayOfWeekInMonth​(int ordinal, DayOfWeek dayOfWeek)
월 기준의 요일 조정기를 사용하여 새 날짜를 반환하는 요일 조정기를 반환합니다.
현재 달의 첫째 날로 설정된 새 날짜를 반환하는 "매월 첫째 날" 조정기를 반환합니다.
다음 달의 첫째 날로 설정된 새 날짜를 반환하는 "다음 달의 첫째 날" 조정기를 반환합니다.
다음 해의 첫날로 설정된 새 날짜를 반환하는 "다음 해의 첫날" 조정기를 반환합니다.
현재 연도의 첫 날로 설정된 새 날짜를 반환하는 "연중 첫 날" 조정기를 반환합니다.
firstInMonth​(DayOfWeek dayOfWeek)
같은 달의 첫 번째 요일과 일치하는 새 날짜를 반환하는 첫 번째 월 조정기를 반환합니다.
현재 달의 마지막 날로 설정된 새 날짜를 반환하는 "월 마지막 날" 조정기를 반환합니다.
현재 연도의 마지막 날로 설정된 새 날짜를 반환하는 "연도의 마지막 날" 조정기를 반환합니다.
lastInMonth​(DayOfWeek dayOfWeek)
같은 달의 마지막 요일과 일치하는 새 날짜를 반환하는 마지막 달 조정기를 반환합니다.
next​(DayOfWeek dayOfWeek)
다음 요일 조정기를 반환합니다. 이 조정기는 조정되는 날짜 다음에 지정된 요일이 처음 나타나는 날로 날짜를 조정합니다.
nextOrSame​(DayOfWeek dayOfWeek)
다음 또는 같은 요일 조정기를 반환합니다. 이 조정기는 조정하려는 날짜 다음에 지정된 요일이 처음 나타나는 날로 날짜를 조정합니다. 해당 요일이 이미 해당 요일인 경우에는 동일한 객체가 반환됩니다.
ofDateAdjuster​(UnaryOperator<LocalDate> dateBasedAdjuster)
TemporalAdjuster날짜 조정기를 래핑하는 를 가져옵니다 .
previous​(DayOfWeek dayOfWeek)
이전 요일 조정기를 반환합니다. 이 조정기는 조정하려는 날짜의 지정된 요일이 처음 나타나는 날로 날짜를 조정합니다.
이전 또는 같은 요일 조정기를 반환합니다. 이 조정기는 조정하려는 날짜 전에 지정된 요일이 처음 나타나는 날로 날짜를 조정합니다. 해당 요일이 이미 해당 요일인 경우에는 동일한 객체가 반환됩니다.

3-4. 파싱과 포맷

DateTimeFormmater

  • 상수로 정의된 형식들

 

형식
설명
형식
설명
ISO_DATE_TIME
Date and time with Zoneld
ISO_INSTANT
Date and Time of an Instant
ISO_LOCAL_DATE
ISO Local Date
BASIC_ISO_DATE
Basic ISO date
ISO_LOCAL_TIME
time without offset
ISO_DATE
ISO Date with or without offset
ISO_LOCAL_DATE_TIME
ISO Local Date and Time
ISO_TIME
Time with of without offset
ISO_OFFSET_DATE
ISO Date with Offset
ISO_ORDINAL_DATE
Year and day of year
ISO_OFFSET_TIME
Time with offset
ISO_WEEK_DATE
Year and Week
ISO_OFFSET_DATE_TIME
Date Time with Offset
RFC_1123_DATE_TIME
RFC 1123 / RFC 822
ISO_ZONED_DATE_TIME
Zoned Date Time
  • 로케일에 종속된 형식화
FormatStyle
날짜
시간
FULL
2017년 6월 12일 월요일
N/A
LONG
2017년 6월 12일 (월)
오후 3시 20분 30초
MEDIUM
2017. 6. 12
오후 3:20:30
SHORT
12. 6. 12
오후 3:20
  • 출력형식 직접 정의하기

반응형

'개념' 카테고리의 다른 글

[JAVA의 정석] Chapter12  (1) 2024.09.08
[JAVA의 정석] Chapter11  (1) 2024.09.08
[JAVA의 정석] Chapter08 - 09  (0) 2024.09.08
[JAVA의 정석] Chapter07  (2) 2024.09.08
[JAVA의 정석] Chapter06  (2) 2024.09.07