도메인 모델과 Entity를 만들다가 Birthday와 같은 날짜를 String이 아닌 날짜 형식으로 맞춰주는 게 좋다는 피드백을 들었다.
String으로 하면 데이터의 타입이나 형식이 잘못 들어왔을 경우를 막기 어렵다. 물론, 검증 로직을 추가하면 되지만 그럴 바에는 처음부터 타입을 명시해두는 편이 실수를 줄일 수 있다.
따라서, java의 날짜 타입을 찾아보다가 글을 정리하게 되었다.
내가 알고 있고 배웠던 Java 날짜 타입은 Date
나 Calendar
와 같은 타입이었다. 그런데 찾아보니, 이 두 타입은 문제가 있어 사용하지 않는 것이 좋다고 한다.
따라서 기존의 날짜 API와 대체하여 나온 새로운 날짜 API를 정리해봤다.
Java 8 이전에 사용하던 Date 관련 클래스로는, 대표적으로 다음 세 가지가 있다.
java.util
패키지에 있는 객체로, Java 8부터 deprecated 되었다.import java.util.Date;
public class DateExample {
public static void main(String[] args) {
// 현재 날짜와 시간을 가져오기
Date currentDate = new Date();
System.out.println("현재 날짜와 시간: " + currentDate);
// 특정 날짜와 시간을 생성하기 (2022년 1월 24일)
// 연도는 1900년이 기준이며, 상대적인 값으로 넣어야 한다.
Date specificDate = new Date(122, 0, 24);
System.out.println("특정 날짜와 시간: " + specificDate);
// 시간을 밀리초로 가져오기
long currentTimeInMillis = currentDate.getTime();
System.out.println("현재 시간(밀리초): " + currentTimeInMillis);
// 특정 날짜와 시간으로 설정하기 (현재 시간 + 1일)
Date newDate = new Date();
newDate.setTime(currentTimeInMillis + 86400000);
System.out.println("하루 뒤의 날짜와 시간: " + newDate);
}
}
java.util
패키지에 있는 객체로, Java 8부터 deprecated 되었다.import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
// 현재 날짜와 시간 정보 가져오기
Calendar calendar = Calendar.getInstance();
System.out.println("현재 날짜와 시간: " + calendar.getTime());
// 특정 날짜와 시간 설정
calendar.set(2022, Calendar.JANUARY, 24, 14, 30, 0);
System.out.println("지정된 날짜와 시간: " + calendar.getTime());
// 특정 필드 값 변경
calendar.set(Calendar.YEAR, 2023);
System.out.println("연도 변경 후: " + calendar.getTime());
// 특정 필드 값 추가
calendar.add(Calendar.MONTH, 3);
System.out.println("3개월 후: " + calendar.getTime());
// 특정 필드 값 롤백
calendar.roll(Calendar.DAY_OF_MONTH, -5);
System.out.println("5일 전으로 롤백 후: " + calendar.getTime());
}
}
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
public static void main(String[] args) {
// 현재 날짜와 시간을 얻어옵니다.
Date currentDate = new Date();
System.out.println("현재 날짜와 시간: " + currentDate);
// SimpleDateFormat 객체를 생성하고 원하는 패턴을 지정합니다.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 날짜를 문자열로 형식화합니다.
String formattedDate = sdf.format(currentDate);
System.out.println("형식화된 날짜: " + formattedDate);
// 문자열을 날짜로 파싱합니다.
String dateString = "2022-01-24 15:30:00";
try {
Date parsedDate = sdf.parse(dateString);
System.out.println("파싱된 날짜: " + parsedDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Java SE 8 버전부터 추가되었다.
Instant cur = Instant.now();
System.out.println(cur); // 2022-10-09T12:45:11.825755Z
System.out.println(cur.getEpochSecond()); // 1665319511
System.out.println(cur.getNano()); // 825755000
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class LocalDateExample {
public static void main(String[] args) {
// LocalDate
// 현재 날짜 가져오기
LocalDate currentDate = LocalDate.now();
System.out.println("현재 날짜: " + currentDate);
// 특정 날짜 생성
LocalDate specificDate = LocalDate.of(2022, 1, 24);
System.out.println("특정 날짜: " + specificDate);
// LocalTime
// 현재 시간 가져오기
LocalTime currentTime = LocalTime.now();
System.out.println("현재 시간: " + currentTime);
// 특정 시간 생성
LocalTime specificTime = LocalTime.of(14, 30, 0);
System.out.println("특정 시간: " + specificTime);
// LocalDateTime
// 현재 날짜와 시간 가져오기
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("현재 날짜와 시간: " + currentDateTime);
// 특정 날짜와 시간 생성
LocalDateTime specificDateTime = LocalDateTime.of(2022, 1, 24, 14, 30, 0);
System.out.println("특정 날짜와 시간: " + specificDateTime);
}
}
시간대(時間帶,time zone)는 영국의 그리니치 천문대(본초 자오선, 경도 0도)를 기준으로 지역에 따른 시간의 차이, 다시 말해 지구의 자전에 따른 지역 사이에 생기는 낮과 밤의 차이를 인위적으로 조정하기 위해 고안된 시간의 구분선을 일컫는다.
출처: 위키백과 - https://ko.wikipedia.org/wiki/시간대
TimeZone은 특정 지역에서 사용되는 표준 시간을 말한다. 지구는 24개의 시간대로 나뉘어져 있으며, 각 시간대는 특정 경도를 기준으로 정해진다.
시간대는 UTC를 기준으로 일정한 시간 차이를 가지며, 이를 통해 전 세계의 시간을 일관성 있게 표시할 수 있다.
UTC 기준 (+, -) 시, 분
으로 표현한다.UTC + 9
라면 UTC 보다 9시간이 빠르다는 의미이다.나는 MySQL을 DB로 고려 중이었고, 생성 일시와 같은 날짜+시간을 Timestamp로 저장하기로 결정했다.
따라서 Timestamp와 LocalDateTime을 매핑하는 방법에 대해 찾아봤는데 JPA 2.2 에서도 지원하고 있었다.
@Column(name = "local_time", columnDefinition = "TIME")
private LocalTime localTime;
@Column(name = "local_date", columnDefinition = "DATE")
private LocalDate localDate;
@Column(name = "local_date_time", columnDefinition = "TIMESTAMP")
private LocalDateTime localDateTime;
만약, JPA 2.2 버전을 사용한다면 Converter를 사용해서 매핑시켜줘야 한다.
대한민국 내에서라면 TimeZone이 없는 객체(Local로 시작하는 객체들)를 선택하면 되지만, 글로벌한 환경을 고려한다면 TimeZone이 있는 객체를 선택하는 것이 좋다.
처음에는 Entity에 Timestamp로 선언을 했다가, 나중에 LocalDate를 적용하면서 이것도 수정해야 하나 고민에 빠졌다.
LocalDateTime을 사용하면 Timezone 정보가 없어서 DB와 시간이 엇나갈 수 있겠다는 생각이 들었기 때문이다.
그래서 TimeZone부터 해서 다시 찾아봤는데, LocalDateTime과 Timestamp를 매핑해주는 기술을 지원하고 있었다.
TimeZone 관련해서는 예전에도 지나가듯 관련 글을 읽어본 적이 있었는데, 일단 이렇게 정리해두고 나중에 개발하다 문제가 생기면 깊게 분석해봐야겠다.
자바의 정석 - 날짜와 시간(Calendar와 Date, java.time패키지) | Integerous DevLog
Java 프로젝트에서 Default Time Zone은 어떻게 설정되는가?