ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바] 날짜와 시간 & 형식화
    자바 2022. 7. 21. 00:28
    728x90

    1. Calendar 와 Date

    Calendar 

    추상클래스 이므로 직접 객체 생성이 불가능하여, 메서드를 통해서 완전히 구현된 클래스의 인스턴스를 얻어야 한다.

    예시 ) GregorianCalendar, BuddhistCalendar

     

    메서드를 통해서 인스턴스를 반환받게 하는 예시

    Calendar cal = new Calendar(); // error 추상클래스는 인스턴스를 생성할 수 없다.
    
    // OK. getInstance()는 Calendar클래스를 구현한 클래스의 인스턴스를 반환한다
    Calendar cal = Calendar.getInstance();
    
    // 예시
    class MyApplication {
        public static void main(String[] args) {
            Calendar cal = Calendar.getInstance();
            ...
        }
    }

    다른 종류의 인스턴스를 가져오기 위해서는 getInstance()의 내용만 달라지면 된다. ( getInstance는 static 메서드 이다. )

     

    Date & Calendar 사이의 형변환

    // 1. Calendar -> Date
    Calendar cal = Calendar.getInstace();
    ...
    Date d = new Date(cal.getTimeInMills());
    
    // 2. Date -> Calendar
    Date d = new Date();
    ...
    Calendar cal = Calendar.getInstace();
    cal.setTime(d)

     

    getInstance로 얻은 인스턴스는 기본적으로 현재 시스템의 날짜와 시간에 대한 정보를 담고 있는데, 원하는 날짜와 시간으로 설정하려면 set( ) 을 원하는 필드의 값을 얻으려면 get( ) 을 사용하면 된다

     

    get( ) 

    import java.util.*;
    
    class CalendarEx {
        public static void main(String[] args) {
            Calendar today = Calendar.getInstance();
            
            System.out.println("이 해의 년도: " + today.get(Calendar.YEAR));
            System.out.println("월(0~11), 0:1월 ): " + today.get(Calendar.MONTH));
            // 주의, 달의 범위는 1 ~ 12가 아닌 0 ~ 11이다.
            System.out.println("이 해의 몇 째 주: " + today.get(Calendar.WEEK_OF_YEAR));
        }
    }
    // get 메서드의 매개변수로 사용되는 int값들은 Calendar에 정의된 static 상수이다

     

    set( )

    import java.util.*;
    
    class CalendarEx {
        public static void main(String[] args) {
            Calendar date1 = Calendar.getInstance();
            Calendar date2 = Calendar.getInstance();
            
            date1.set(2022.6,2) // 2022년 7월 2일
            date1.set(2022.Calendar.JULY,2) // 2022년 7월 2일
            
            // 두 날짜간의 차이 -> getTiemInMillis( ) 사용( 천분의 일초 단위로 변환 )
            long difference = (date2.getTimeInMills() - date1.getTimeInMills()) / 1000;
            // difference 는 몇초가 지났다
            // difference / ( 24 * 60 * 60 ) 는 며칠이 지났다 
        }
    }

    시간상의 전후를 알고 싶을 때는 두 날짜간의 차이가 양수인지 음수인지를 판단하면 될거같다. ( 또는 boolean after(object when) , boolean before(object when) ) 을 사용하면 된다

     

    add( ) - 필드의 값을 원하는 만큼 증가 또는 감소 

    import java.util.*;
    
    class CalendarEx {
        public static void main(String[] args) {
            Calendar date = Calendar.getInstance();
            
            date.set(2015,0,31); // 2015년 1월 31일
            System.out.println(toString(date); // 2015년 1월 31일
            
            // 1일 후
            date.add(Calendar.DATE, 1); // 2016년 2월 1일
            System.out.println(toString(date); // 2016년 2월 1일
        }
    }

     

    boolean isLeapYear(int year) : 매개변수 year가 윤년이면 true 아니면 false
    int dayDiff(int y1, int m1, int d1, int y2, int m2, int d2 ) : 두 날짜간의 차이를 일단위로 표현
    int getDayOfWeek(int year, int month, int day) : 지정한 날짜의 요일을 반환한다( 1~7, 1이 일요일 )
    String convertDayToDate(int day) : 일 단위의 값을 년월일의 형태의 문자열을 변환하여 반환한다.
    int convertDateToDay(int year, int month, int day) : 년월일을 입력받아서 일단위로 변환

    두 날짜간의 차이를 구하려면, 일단위로 변환한 다음 두 값을 서로 빼기만 하면 된다.

     

    2. 형식화 클래스

    숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현할 수 있는 방법을 객체지향적으로 설계하여 표준화한다.

     

    DecimalFormat ( 텍스트 데이터 <-> 숫자 )

    기호 의미 패턴 결과(1234567.89)
    0 10진수(값이 없을 때는 0) 0
    0.0
    0000000000.0000
    1234568
    1234567.9(9에서 반올림)
    0001234567.8900
    # 10진수 #
    #.#
    ##########.####
    1234568
    1234567.9(9에서 반올림)
    0001234567.8900
    . 소수점 #.# 1234567.9 (9에서 반올림)
    - 음수부호 #.#-
    -#.#
    1234567.9-(9에서 반올림)
    -1234567.9(9에서 반올림)
    , 단위 구분자 #.###.## 1,234,567.89
    E 지수 기호 (너무 많음)
    #E0
    0E0
    ##E0
    00E0
    .1E7 ( E7 -> 10^7)
    1E6
    1.2E6
    12E5
    ; 패턴 구분자 #,###.##+; #,###.##- 1,234,567.89+(양수일 때)
    1,234,567.89-(음수일 때)
    % 퍼센트 #.#% 123456789%
    \u2030 퍼밀( 퍼센트 * 10 ) #.#\u2030 1234567890 %(퍼센트 밑에 동그라미 하나더 있음 )
    \u00A4 통화 \u00A4 #,### ₩1,234,568
    ' escape 문자 '#'#,###
    ''#,###
    #1,234,568
    '1,234,568

     

    사용하는 방법은 원하는 출력형식의 패턴을 작성하고, DecimalFormat 인스턴스를 생성한 다음, 출력하고자 하는 문자열로 format 메서드를 호출하면 된다.

    double number = 1234567.89;
    DecimalFormat df = new DecimalFormat("#.#E0");
    String res = df.format(number);

     

    parse메서드를 이용하면 기호와 문자가 포함된 무자열을 숫자로 쉽게 바꿀수있다.

    import java.text.*;
    
    class DecimalFormatEx2 {
        public static void main(String[] args) {
            DecimalFormat df = new DecimalFormat("#,###.##");
            DecimalFormat df2 = new DecimalFormat("#.###E0");
            
            try {
                Number num = df.parse("1,234,567.89");
                // "1,234,567.89" -> 1,234,567.89 로 변환
                System.out.println("1,234,567.89" + " -> ");
                
                // doubleValue -> number에 지정된 값을 double 형식으로 변환
                double d = num.doubleValue();
                System.out.println(d + " -> ");
                
                // doubleValue, intValue, floatValue 등도 있다.
                // Number에 저장된 값을 특정 타입으로 변경해준다.
                
                System.out.println(df2.format(num); // 1.235E6
            }
            catch( Exception e) { }
        }
    }

     

    SimpleFormat ( 날짜를 출력 )

    Date 인스턴스만 format메서드에 사용될 수 있기에 Calendar 인스턴스를 Date 인스턴스로 변환해야 한다.

    -> pares(String source)는 문자열 source을 날짜 Date인스턴스로 변환해준다.

    // Calendar -> Date로 변경하는 방법
    Calendar cal = Calendar.getInstance();
    
    Date day = cal.getTime(); // 변경하는 부분

     

    import java.util.*;
    import java.text.*;
    
    class DateFormatEx {
        public static void main(String[] args) {
            DateFormat df = new SimpleDateFormat("yyyy년 mm월 dd일");
            DateFormat df2 = new SimpleDateFormat("yyyy/mm/dd");
            
            try {
                Date d = df.parse("2015년 7월 2일");
                System.out.println(df2.format(d));
            } catch(Exception e) { }
        }
    }

     

     

    ChoiceFormat ( 특정 범위에 속하는 값을 문자열로 변환 )

    경계값은 double형으로 반드시 모두 오름차순으로 정렬되어 있어야하며, 치환 될 문자열의 개수는 경계값에 의해 정의된 범위의 개수와 일치해야 한다. 그렇지 않으면 IllegalArgumentException 발생

     

    연속적인 데이터들은 if나 swtich 문으로도 많은 해결을 보지만, 불연속적인 데이터의 경우들은 ChoiceFormat을 사용하기

     

    '#', '<'는 'limit#value' 의 형태로 사용되며, #는 경계값을 포함, <는 포함시키지 않는다

    import java.text.*;
    
    class ChoiceFormatEx {
        public static void main(String[] args) {
            String pattern = "60#D|70#C|80<B|90#A"; // 80 경계 체크 안함
            int[] scores = {91, 90, 80, 88, 73, 67 };
            	
            ChoiceFormat form = new ChoiceFormat(pattern);
            
            for(int i = 0; i < scores.length; i++) {
                System.out.println(scores[i] + " : " + form.format(scores[i]));
            }
        }
    }

     

    MessageFormat ( 데이터를 정해진 양식에 맞게 출력 )

    '{숫자}' 로 표시된 부분이 데이터가 출력될 자리이며, 이 자리는 순차적일 필요가 없고 여러번 반복 가능하다.

    import java.text.*;
    
    class MessageFormatEx1 {
        public static void main(String[] args) {
            String msg = "Name: {0} , Tel: {1} , Age: {2} , BirthDay: {3} " ;
            
            Object[] arguments = { "정수영", "010-0000-0000", "24", "07-02" };
            
            String res = MessageFormat.format(msg, arguments);
            System.out.println(res);
        }
    }
    // Name : 정수영 , Tel : 010-0000-0000 , Age : 24 , Birthday : 07-02

     

    홑따옴표(')는 MessageFormat의 양식에 escape문자로 사용되기 때문에 문자열 msg내에서 홑따옴표르르 사용하려면 연속 2번 사용해야함.

    import java.text.*;
    
    class MessageFormatEx1 {
        public static void main(String[] args) {
            String msg = "Name: ''{0}'' , Tel: ''{1}'' , Age: ''{2}'' , BirthDay: ''{3}'' " ;
            
            Object[] arguments = { "정수영", "010-0000-0000", "24", "07-02" };
            
            String res = MessageFormat.format(msg, arguments);
            System.out.println(res);
        }
    }
    // Name : '정수영' , Tel : '010-0000-0000' , Age : '24' , Birthday : '07-02'

     

    parse(String source)를 이용해서 필요한 데이터만을 뽑아낼 수 있다.

     

    3. Java.time 패키지

    java.time 패키지의 핵심 클래스

    시간 - LocalTime 클래스
    날짜 - LocalDate 클래스
    LocalTime + LocalDate -> LocalDateTime ( 날짜 & 시간 )
    LocalDateTime + 시간대 -> ZonedDateTime ( 시간대 & 날짜 & 시간  = ( Calendar와 같다 ) ) 
    Date와 유사한 클래스로는 Instant 가 있다. ( 날짜와 시간을 초단위로 표현하여 타임스탬프와 같은 역할 )

     

    Period, Duration 

    날짜 - 날짜 = Period
    시간 - 시간 = Duration

     

    객체 생성 - now(), of() ( 둘다 static 메서드 )

    now( ) - 현재 날짜와 시간을 저장
    of( ) - 해당 필드의 값을 순서대로 지정
    // now
    LocalDate date = LocalDate.now(); // 2020-07-15
    LocalTime time = LocalTime.now(); // 21:54:01.875
    LocalDateTime dateTime = LocalDateTime.now(); // 2020-07-15T21:54:01.875
    ZonedDateTime dateTimeInKr = ZonedDateTime.now(); // 2020-07-15T21:54:01.875+09:00[Asia/Seoul]
    
    
    // of
    LocalDate date = LocalDate.of(2020,07,15); 
    LocalTime time = LocalTime.of(21,54,01);
    LocalDateTime dateTime = LocalDateTime.of(date,time);
    ZonedDateTime dateTimeInKr = ZonedDateTime.of(dateTime, ZoneId.of("Asia/Seoul"));

     

    Temporal, TemporalAmount

    TemporalAmount 인지 아닌 지만 구분하면 된다.

    Temporal - LocalDate, LocalTime, LocalDateTime, ZonedDateTime

    TemporalAmount - period, duration

     

    LocalDate, LocalTime

    Parse( ) 를 이용하면 문자열을 날짜와 시간으로 바꿀 수 있다.

    LocalDate birthDate = LocalDate.parse("1999-12-22"); // 1999년 12월 22일
    LocalTime birthTime = LocalTime.parse("23:59:59"); // 23시 59분 59초

     

    특정 필드의 값 가져오기 - get( ), getXXX( )

     

    필드의 값 변경하기 - with( ), plus( ), minus( )

    날짝와 시간에서 특정 필드 값을 변경하려면 with로 시작하는 메서드를 사용하면 된다. ( with( ) 사용시 원하는 필드를 직접 지정 가능 )

    date = date.withYear(2000); // 년도를 2000년으로 변경
    time = time.withHour(12); // 시간을 12시로 변경

     

    plus( ), minus( ) 는 특정 필드에 값을 더하거나 빼면 된다.

    LocalDate plusYears(long yearsToAdd)
    LocalDate plusMonths(long MonthsToAdd)
    LocalDate plusDays(long DaysToAdd)
    LocalDate plusWeeks(long WeeksToAdd)
    
    
    LocalTime plusHours(long HoursToAdd)
    LocalTime plusMinutes(long MinutesToAdd)
    LocalTime plusSeconds(long SecondsToAdd)
    LocalTime plusNanos(long NanosToAdd)

     

    날짜와 시간 비교 - isAfter( ), isBefore( ), isEqual( )

    LocalTime, LocalDate도 compareTo( ) 가 오버라이딩 되어 있어서 이것으로 비교 가능

    int res = date1.compareTo(date2); 
    // 같으면 0, date1 이전이면 -1, 이후면 1

     

    isAfter( ), isBefore( ), isEqual( )은 LocalDate 에만 있다.

    isEqual은 equals() 와 다르게 오직 날짜만 비교한다

     

    Instant

    에포크 타임부터 경과된 시간을 나노초 단위로 표현한다.

     

    Instant를 생성할 때에에는 now(), ofEpochSecond( )를 같이 사용한다.

    Instant now = Instant.now();
    Instant now2 = Instant.ofEpochSecond(now.getEpochSecond() );
    Instant now3 = Instant.ofEpochSecond(now.getEpochSecond(), now.getNano() );

     

    LocalDateTime, ZonedDateTime

    localDate + localTime -> localDateTime 변환

    LocalDate date = LocalDate.of(2015, 12, 31 );
    LocalTime time = LocalTime.of(12, 23, 34 );
    
    LocalDateTime dt = LocalDateTime.of(date,time);
    
    // LocalDateTime 날짜와 시간 직접 지정
    LocalDateTime dateTime = LocalDateTime.of(2015,12,31,12,23,34);
    LocalDateTime today = LocalDateTime.now()

     

    localDateTime -> localDate + localTime  변환

    LocalDateTime dt = LocalDateTime.of(2015,12,31,12,23,34);
    
    LocalDate date = dt.toLocalDate();
    LocalTime time = dt.toLocalTime();

     

    localDateTime -> ZonedDateTime 변환 ( ZoneId 클래스 사용 )

    LocalDate에  시간 정보를 추가하는 atTime( )을 쓰면 LocalDateTime( )이 되듯,
    LocalDateTime에  시간대 정보를 추가하는 atZone( )을 쓰면 ZonedDateTime( )이 된다.

     

    TemporalAdjusters

    메서드 설명
    firstDayOfNextYear() 다음 해의 첫날
    firstDayOfNextMonth() 다음 달의 첫날
    firstDayOfYear() 올 해의 첫날
    firstDayOfMonth() 이번 의 첫날
    lastDayOfYear() 올 해의 마지막 날
    lastDayOfMonth() 이번 달의 마지막날
    firstInMonth (DayOfWeek dayOfWeek) 이번 달의 첫번째 ?요일
    lastInMonth (DayOfWeek dayOfWeek) 이번 달의 마지막 ?요일
    previous (DayOfWeek dayOfWeek) 지난 ?요일( 당일 미포함)
    previousOrSame (DayOfWeek dayOfWeek) 지난 ?요일( 당일 포함)
    next (DayOfWeek dayOfWeek) 다음 ?요일( 당일 미포함)
    nextOrSame (DayOfWeek dayOfWeek) 다음 ?요일( 당일 포함)
    dayOfWeekInMonth (int ordinal, DayOfWeek dayOfWeek) 이번 달의 n번째 ? 요일

     

    Period, Duration

    두 날짜 차이를 나타내는 Period는 between( ) 으로 얻을 수 있다.

    LocalDate date1 = LocalDate.of(2014, 1, 1);
    LocalDate date2 = LocalDate.of(2015, 12, 31);
    
    Period pe = Period.between(date1, date2);
    // date1이 date2 보다 날짜 상으로 이전이면 양수, 이후면 음수

     

    Period, Duration 모두 특정 필드의 값을 얻을 때는 get( ) 사용

    of( ), with( ) 도 있다

    plus( ), minus( ) 이외에 multipliedBy( ), dividedBy( ) 가 있다.

    pe = pe.minusYears(1).multipliedBy(2); // 1년 빼고 2배 곱하기
    pe = pe.plusHours(1).dividedBy(60); // 1시간 더하고 60으로 나누기

     

    Period에 normalized 함수

    pe = Period.of(1,13,32).normalized();
    // 1년 13개월 32일 -> 2년 1개월 32일

     

    isNegative( ) - 음수인지 확인 하기

    isZero( ) - 0인지 확인 하기

    negate( ) - 부호 변경하기

    abs( ) - 부호 없애기

     

    다른 단위로 변환

    'to' 로 시작하는 메서드들은 period, duration을 다른 단위값을 변환 시켜준다

    클래스 메서드 설명
    Period long toTotalMonths() 년월일을 월단위로 변환해서 반환( 일 단위 무시 )
    Duration long toDays( ) 일단위로 변환해서 반환
      long toHours( ) 시간단위로 변환해서 반환
      long toMinutes( ) 분단위로 변환해서 반환
      long toMills( ) 천분의 일초 단위로 변환해서 반환
      long toNanos( ) 나노초 단위로 변환해서 반환

     

    문자열을 날짜와 시간으로 파싱하기 - parse()

    static LocalDateTime parse(CharSequence text)
    static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter)
    
    LocalDate newDate = LocalDate.parse("2001-01-02");
    LocalTime newTime = LocalTime.parse("23:59:59");

     

    ofPattern()을 이용해 파싱하기

    DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-mm-dd HH:mm:ss");
    
    LocalDateTime endOfYear = LocalDateTime.parse("2015-21-31 23:59:59", pattern);

    '자바' 카테고리의 다른 글

    [자바] 제네릭스  (0) 2022.07.22
    [자바] 컬렉션 프레임웍  (0) 2022.07.21
    [자바] 정규형 패턴  (0) 2022.07.15
    [자바] JAVA.LANG패키지와 유용한 클래스  (0) 2022.07.15
    [자바] 예외처리  (0) 2022.07.13
Designed by Tistory.