java.util.Date -> java.util.Calendar -> java.time.(LocalDate, LocalTime, LocalDateTIme)
Java 초기에는 Date 와 Calendar 를 사용해서 날짜와 시간을 표현했지만 Java 8 부터는 java.time API 가 제공되어 보다 개선된 방법으로 날짜와 시간을 표현할 수 있습니다.
불변 객체가 아니다.
Calendar 와 Date 클래스에 set() 메서드를 호출해서 날짜를 지정하여 세팅하면 연산 결과는 같은 인스턴스에 저장됩니다. 이러한 이유로 Calendar 객체나 Date 객체가 여러 곳에서 공유되면 한 곳에서 바꾼 값이 다른 곳에 영향을 미치는 부작용이 발생할 수 있습니다.
int 상수 필드의 남용
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.JULY, 1);
System.out.println(calendar.getTime());
}
}
첫 번째 매개변수 자리(년, 월, 일 등 의 필드의 자리)에 Calendar.JULY 와 같이 전혀 전혀 어울리지 않는 상수가 들어가도 컴파일 시점에서 확인할 방법이 없습니다. 이 뿐만 아니라 Calendar 클래스에는 많은 int 상수가 쓰였는데 이러한 요인이 많은 혼란을 유발합니다.
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(2000, 10, 10); //10 월 세팅
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String format = df.format(calendar.getTime());
System.out.println(format);
//2000-11-10
}
}
LocalTime, LocalDate, LocalDateTime 클래스는 객체를 생성하기 위해 now(), of() 메서드를 제공합니다.
now() 는 현재의 날짜나 시간을 이용하여 새로운 객체를 만들어 반환합니다.
of() 는 날짜나 시간을 매개변수로 세팅값을 지정하여 지정된 값으로 생성하여 반환합니다.
public class Main {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.now();
LocalDate ld = LocalDate.now();
LocalTime lt = LocalTime.now();
Calendar calendar = Calendar.getInstance();
calendar.set(2000, 13, 10);
//Sat Feb 10 02:22:16 KST 2001
System.out.println(calendar.getTime());
LocalDate ldOf = LocalDate.of(2000, 13, 10);
//Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 13
//Calendar 는 존재하지 않는 월(13) 을 세팅해도 별다른 오류가 없는 반면 LocalDate 는 컴파일 에서 오류를 잡아줍니다.
}
}
새로운 날짜/시간 API 의 특징
Calendar 와 Date 를 사용할 때는 날짜 차이를 구하기 위해서 밀리세컨드 단위로 바꾸고 빼고 다시 곱하고 하는 복잡한 과정을 통해서 계산하였지만 java.time 에서 제공하는 Period, Duration 등 을 이용하여 쉽게 계산할 수 있습니다.
public class Main {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldtOf = LocalDateTime.of(2020, 1, 26, 2, 40);
//시간 크기 비교
System.out.println(ldt.isBefore(ldtOf)); //ldt 가 ldtOf 보다 전 시간인지 false
System.out.println(ldt.isAfter(ldtOf)); //ldt 가 ldtOf 보다 후의 시간인지 true
//날짜/시간 차이 계산
Period between = Period.between(ldtOf.toLocalDate(), ldt.toLocalDate());
System.out.println(between.getYears() + " 년 " + between.getMonths() + " 개월 " + (between.getDays() == 0 ? "" : between.getDays() + "일 ") + "차이가 납니다.");
//1 년 8 개월 차이가 납니다.
LocalDate localDate = LocalDate.now();
LocalDate localDateOf = LocalDate.of(2020, 1, 1);
System.out.println(Math.abs(ChronoUnit.DAYS.between(localDate, localDateOf)) + " 일 차이가 납니다.");
//634 일 차이가 납니다.
LocalTime lt = LocalTime.now();
LocalTime ltOf = LocalTime.of(00, 00);
Duration duration = Duration.between(lt, ltOf);
System.out.println(duration.abs().toSeconds()+ "s");
//10293s
}
}
public class Main {
public static void main(String[] args) {
//해당 날짜에 해당하는 월의 일 수 & 날짜
YearMonth from = YearMonth.from(LocalDate.now());
System.out.println(from.lengthOfMonth());
//30
System.out.println(from.atEndOfMonth());
//2021-09-30
//해당 주차 요일의 날짜 구하기
LocalDate localDate = LocalDate.now()
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 4)//올 해의 4주 차
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));//월요일
System.out.println(localDate);
//2021-01-25
}
}