[강의] 인프런 : 더 자바, Java8 섹션 5

haeny-dev·2021년 7월 27일
0
post-thumbnail

📌 섹션 5 : Date와 Time

🙋🏻‍♂️ Date와 Time 소개

➕ 배경

1. 기존 API는 mutable하여 Thread safe 하지 않다.

2. 클래스 이름이 명확하지 않다.

public static void main(String[] args) throws InterruptedExceptio
    /**
     * 기존에 사용하고 있던 Date 객체는 mutable한 객체이다.
     * mutable 한 객체는 멀티스레드 환경에서 스레드 safe 하지 않다.
     *
     * thread safe 하게 접근할 수 있도록 개발하지 않는 이상
     * 여러 객체에서 동시에 접근하여 해당 객체에 변화를 줄 수 있기 때문에 thread safe 하지않다.
     *
     * 예를 들어, A, B 두 객체가 Date 객체에 접근하려고 하고 있고,
     * A 객체에서 Date 객체에 접근하여 1일을 늘려주는 작업을 진행하고 있고,
     * A 작업이 끝나기도 전에 B 객체에서 1일을 줄여주는 작업을 진행하여 끝냈을 경우
     * A 작업이 끝났음에도 불구하고 Date 객체는 1일이 늘어나지 않는 상태가 됩니다.
     */
    Date date = new Date();
    long time = date.getTime(); // Date 지만 시간을 가져올 수 있고, 그 시간의 타입이 long이다...??
   
    System.out.println("date : " + date);
    System.out.println("time : " + time);
    
    Thread.sleep(1000 * 3);
    
    Date after3Seconds = new Date();
    System.out.println("after3Seconds date : " + after3Seconds);
    
    after3Seconds.setTime(time); // 변화를 줄 수 있음.
    System.out.println("after3Seconds setTime!");
    System.out.println("after3Seconds date : " + after3Seconds);
}

3. 버그가 발생할 여지가 많다.

/**
 * 생일 10월 4일에 대한 Calendar객체 생성할 경우에 month에 10을 넣으면 인텔리제이가 주의를 준다.
 * java.util.Calendar.NOVEMBER 를 사용하라고 알려주지만, 이 경우 11월이다.
 * month의 시작인 1월이의 int값이 0부터 시작하기 때문에 서로 맞지 않는 현상이 발생한다.
 *
 * 또한 해당 메서드의 매개변수의 타입이 모두 int타입으로 선언되어 있는데, 이 경우 타입 safety 하지 않다고 한다.
 * year나 month의 자리에 -1, -10 을 넣을 수 있기 때문이다.
 * 이런 경우 Year 나 Month 객체를 만들어서 해당 객체만 넣을 수 있도록 해야한다.
 */
Calendar haenyBirthDay = new GregorianCalendar(1992, Calendar.NOVEMBER, 4);

4. Joda Time 라이브러리

/**
 * 그래서 예전부터 날짜 시간 처리가 복잡한 애플리케이션에서는 Joda Time 이라는 라이브러리를 사용하곤 했다.
 * Java8 로 버전이 올라가면서 Joda Time의 다양한 기능들을 표준화하여 JSR-310 이라는 스펙으로 표준화하면서
 * 4가지의 원칙이 생김
 * - Clear
 * - Fluent
 * - Immutable
 * - Extensible
 */

➕ 주요 API

  • 크게 인류용 시간 과 기계용 시간으로 2가지로 나눌 수 있다.
  • 기계용 시간은 EPOCK time으로부터 현재까지의 타임스탬프를 표현한다.
  • 인류용 시간은 연, 월, 일, 시, 분, 초 등을 표현한다.
  • 타임스탬프는 Instant 를 사용한다.
  • 특정 날짜(LocalDate), 시간(LocalTime), 일시(LocalDateTime) 를 사용할 수 있다.
  • 기간을 표현할 때는 Duration(시간) 과 Period(날짜) 를 사용할 수 있다.
  • DateTimeFormatter 를 사용해서 일시를 특정한 문자열로 변경할 수 있다.

📚 Date와 Time API

➕ 기계용 시간 Instant

public static void main(String[] args) {

    // 현재 시간을 기계용 시간으로 가져온다.
    Instant instant = Instant.now();
    System.out.println(instant);
    System.out.println(instant.atZone(ZoneId.of("UTC")));
    /*
    * <출력 결과>
    * 2021-07-27T05:57:47.015Z
    *
    * 현재 나의 시간
    * 2021-07-27 14:58 인데, 왜 저렇게 나오는 것인가??
    * 기준시가 UTC, GMT 로 설정되어 있기 때문이다.
    *
    * 내 시간 기준으로 보기 위해서는 Zone을 설정해 주어야 한다.
    * */
    ZoneId zone = ZoneId.systemDefault();
    ZonedDateTime zonedDateTime = instant.atZone(zone);
    System.out.println(zone);
    System.out.println(zonedDateTime);
}

➕ 인류용 시간 LocalDateTime

public static void main(String[] args) {

    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    
    LocalDateTime birthDay = LocalDateTime.of(1992, Month.OCTOBER, 4, 0, 0, 0);
    
    ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
    System.out.println(nowInKorea);
    
    Instant nowInstant = Instant.now();
    ZonedDateTime zonedDateTime1 = nowInstant.atZone(ZoneId.of("Asia/Seoul"));
    System.out.println(zonedDateTime1);
}

➕ 기간 Period, Duration

public static void main(String[] args) {

    // Period (인류용)
    LocalDate today = LocalDate.now();
    LocalDate thisYearBirthday = LocalDate.of(2021, Month.OCTOBER, 4);
    
    Period period = Period.between(today, thisYearBirthday);
    
    Period until = today.until(thisYearBirthday);
    System.out.println(until.get(ChronoUnit.DAYS));
    
    // Duration (기계용)
    Instant now1 = Instant.now();
    Instant plus = now1.plus(10, ChronoUnit.SECONDS);
    Duration between = Duration.between(now1, plus);
    System.out.println(between);
}

➕ 포매팅 DateTimeFormmater

public static void main(String[] args) {
    now = LocalDateTime.now();
    
    DateTimeFormatter MMddyyyy = DateTimeFormatter.ofPattern("MM/dd/yyyy");
    System.out.println(now.format(MMddyyyy));
    
    LocalDate parse = LocalDate.parse("04/10/1992", MMddyyyy);
    System.out.println(parse);
}

➕ 레거시 API와의 호환

public static void main(String[] args) {
    Date date = new Date();
    Instant instant1 = date.toInstant();
    Date newDate = Date.from(instant1);
    
    GregorianCalendar gregorianCalendar = new GregorianCalendar();
    ZonedDateTime dateTime = gregorianCalendar.toInstant().atZone(ZoneId.systemDefault());
    GregorianCalendar from = GregorianCalendar.from(dateTime);
    
    ZoneId zoneId = TimeZone.getTimeZone("PST").toZoneId();
    TimeZone.getTimeZone(zoneId);
}

📖 REFERENCE

ALL ABOUT JAVA.UTIL.DATE (https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/)
Lesson: Date-Time Overview (https://docs.oracle.com/javase/tutorial/datetime/overview/index.html)
The Java™ Tutorials > Standard Calendar (https://docs.oracle.com/javase/tutorial/datetime/iso/overview.html)
DateTimeFormatter (https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#predefined)

0개의 댓글