TL;DR
- Java
- Date는 immutable하지 않고, 레거시
- LocalDate = 날짜, LocalTime = 시간, LocalDateTime = LocalDate + LocalTime
- ZoneId: 지역 정보(Asia/Seoul), ZoneOffset: 시간대 정보(+09:00)
- OffsetDateTime = LocalDateTime + ZoneOffset 로 시간대 정보가 포함됨
- ZoneDateTime = LocalDateTime + ZoneOffset + ZoneId 로 지역 정보가 포함되어 써머타임등 관리 가능
- Instant: 1970-01-01T00:00:00Z 를 기준으로 지난 시간을 측정. OffsetDateTime과 비슷하다
- SQL
- DATE: 날짜만 저장하며 시간 정보는 포함되지 않습니다.
- DATETIME: 날짜와 시간을 저장하며 시간대 정보를 포함하지 않습니다.
- TIMESTAMP: 날짜와 시간을 저장하며, UTC 기반으로 저장되고 타임존 변환을 지원합니다.
자바의 시간
로컬 시간
java.util.Date
- 레거시
java.sql.TimeStamp
- 레거시
java.time.LocalDate
java.time.LocalTime
java.time.LocalDateTime
- LocalDate + LocalTime
Timezone-aware을 다루기 전에
ZoneId
val timeZone = ZoneId.of("America/Guatemala")
ZoneOffset
val zoneOffset = ZoneOffset.of("-06:00")
Timezone-aware
java.time.Instant
- 유닉스 타임스탬프 시작 시간인 1970-01-01T00:00:00Z 를 기준으로 지난 시간을 저장한다
private Instant(long epochSecond, int nanos) {
this.seconds = epochSecond; // 1970-01-01T00:00:00Z 이후 지난 시간(초)
this.nanos = nanos; // 소수점 시간, 음수일 수 없다
}
java.time.OffsetTime
- LocalTime + ZoneOffset
java.time.OffsetDateTime
- LocalDateTime + ZoneOffset
- LocalDateTime에 시간대(-12h ~ UTC ~ +12h)를 포함한 것
- Instant와 사용 측면에서 유사
java.time.ZoneDateTime
- LocalDateTime + ZoneOffset + ZoneId
- OffsetDateTime과 달리 ZoneId가 들어간다
- 즉, +09:00 만이 아닌, Asia/Seoul 정보도 저장한다
- DST(Daylight Saving Time)와 같은 써머타임의 정보도 들어가 있는 것
- Instant와 달리 시간대(ZoneId) 정보를 포함함
ZoneDateTime 생성자, of 구조
private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
this.dateTime = dateTime;
this.offset = offset;
this.zone = zone;
}
public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
return ofLocal(localDateTime, zone, null);
}
public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
if (zone instanceof ZoneOffset) {
return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
}
ZoneRules rules = zone.getRules();
List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);
ZoneOffset offset;
if (validOffsets.size() == 1) {
offset = validOffsets.get(0);
} else if (validOffsets.size() == 0) {
ZoneOffsetTransition trans = rules.getTransition(localDateTime);
localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
offset = trans.getOffsetAfter();
} else {
if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
offset = preferredOffset;
} else {
offset = Objects.requireNonNull(validOffsets.get(0), "offset"); // protect against bad ZoneRules
}
}
return new ZonedDateTime(localDateTime, offset, zone);
}
ZoneDateTime.now() 호출 구조
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
public static ZonedDateTime now(ZoneId zone) {
return now(Clock.system(zone));
}
public static ZonedDateTime now(Clock clock) {
Objects.requireNonNull(clock, "clock");
final Instant now = clock.instant(); // called once
return ofInstant(now, clock.getZone());
}
SQL
DATE
- 형식: YYYY-MM-DD
- 범위: 1000-01-01 ~ 9999-12-31
날짜만 저장할 때 사용합니다. 시간 정보는 포함되지 않습니다.
DATETIME
- 형식: YYYY-MM-DD HH:MM:SS
- 범위: 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
날짜와 시간을 함께 저장할 때 사용합니다. 시간대 정보는 포함되지 않습니다.
TIMESTAMP
- 형식: YYYY-MM-DD HH:MM:SS
- 범위: 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC (범위는 MySQL 기준으로 다를 수 있습니다)
저장 시 서버의 타임존 설정에 따라 UTC로 변환되어 저장되고, 읽을 때는 다시 로컬 타임존으로 변환됩니다.
자동으로 **CURRENT_TIMESTAMP**로 초기화되거나 업데이트되는 특성을 가질 수 있습니다.
References
Java 타임존, 날짜 그리고 시간객체 뽀개기
항상 헷갈리는 타임존과 관련된 용어를 정리고, 데이터베이스에 어떻게 저장되고, 어플리케이션에선 어떻게 보여지는지 알아봅니다.
medium.com
When should I use OffsetDateTime, ZonedDateTime and Instant in database applications?
When should I use OffsetDateTime, ZonedDateTime and Instant in database applications?
The documentation of the java.time package says: Many applications can be written only using LocalDate, LocalTime and Instant, with the time-zone added at the user interface (UI) layer. The offset...
stackoverflow.com
TL;DR
- Java
- Date는 immutable하지 않고, 레거시
- LocalDate = 날짜, LocalTime = 시간, LocalDateTime = LocalDate + LocalTime
- ZoneId: 지역 정보(Asia/Seoul), ZoneOffset: 시간대 정보(+09:00)
- OffsetDateTime = LocalDateTime + ZoneOffset 로 시간대 정보가 포함됨
- ZoneDateTime = LocalDateTime + ZoneOffset + ZoneId 로 지역 정보가 포함되어 써머타임등 관리 가능
- Instant: 1970-01-01T00:00:00Z 를 기준으로 지난 시간을 측정. OffsetDateTime과 비슷하다
- SQL
- DATE: 날짜만 저장하며 시간 정보는 포함되지 않습니다.
- DATETIME: 날짜와 시간을 저장하며 시간대 정보를 포함하지 않습니다.
- TIMESTAMP: 날짜와 시간을 저장하며, UTC 기반으로 저장되고 타임존 변환을 지원합니다.
자바의 시간
로컬 시간
java.util.Date
- 레거시
java.sql.TimeStamp
- 레거시
java.time.LocalDate
java.time.LocalTime
java.time.LocalDateTime
- LocalDate + LocalTime
Timezone-aware을 다루기 전에
ZoneId
val timeZone = ZoneId.of("America/Guatemala")
ZoneOffset
val zoneOffset = ZoneOffset.of("-06:00")
Timezone-aware
java.time.Instant
- 유닉스 타임스탬프 시작 시간인 1970-01-01T00:00:00Z 를 기준으로 지난 시간을 저장한다
private Instant(long epochSecond, int nanos) {
this.seconds = epochSecond; // 1970-01-01T00:00:00Z 이후 지난 시간(초)
this.nanos = nanos; // 소수점 시간, 음수일 수 없다
}
java.time.OffsetTime
- LocalTime + ZoneOffset
java.time.OffsetDateTime
- LocalDateTime + ZoneOffset
- LocalDateTime에 시간대(-12h ~ UTC ~ +12h)를 포함한 것
- Instant와 사용 측면에서 유사
java.time.ZoneDateTime
- LocalDateTime + ZoneOffset + ZoneId
- OffsetDateTime과 달리 ZoneId가 들어간다
- 즉, +09:00 만이 아닌, Asia/Seoul 정보도 저장한다
- DST(Daylight Saving Time)와 같은 써머타임의 정보도 들어가 있는 것
- Instant와 달리 시간대(ZoneId) 정보를 포함함
ZoneDateTime 생성자, of 구조
private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
this.dateTime = dateTime;
this.offset = offset;
this.zone = zone;
}
public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
return ofLocal(localDateTime, zone, null);
}
public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
if (zone instanceof ZoneOffset) {
return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
}
ZoneRules rules = zone.getRules();
List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);
ZoneOffset offset;
if (validOffsets.size() == 1) {
offset = validOffsets.get(0);
} else if (validOffsets.size() == 0) {
ZoneOffsetTransition trans = rules.getTransition(localDateTime);
localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
offset = trans.getOffsetAfter();
} else {
if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
offset = preferredOffset;
} else {
offset = Objects.requireNonNull(validOffsets.get(0), "offset"); // protect against bad ZoneRules
}
}
return new ZonedDateTime(localDateTime, offset, zone);
}
ZoneDateTime.now() 호출 구조
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
public static ZonedDateTime now(ZoneId zone) {
return now(Clock.system(zone));
}
public static ZonedDateTime now(Clock clock) {
Objects.requireNonNull(clock, "clock");
final Instant now = clock.instant(); // called once
return ofInstant(now, clock.getZone());
}
SQL
DATE
- 형식: YYYY-MM-DD
- 범위: 1000-01-01 ~ 9999-12-31
날짜만 저장할 때 사용합니다. 시간 정보는 포함되지 않습니다.
DATETIME
- 형식: YYYY-MM-DD HH:MM:SS
- 범위: 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
날짜와 시간을 함께 저장할 때 사용합니다. 시간대 정보는 포함되지 않습니다.
TIMESTAMP
- 형식: YYYY-MM-DD HH:MM:SS
- 범위: 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC (범위는 MySQL 기준으로 다를 수 있습니다)
저장 시 서버의 타임존 설정에 따라 UTC로 변환되어 저장되고, 읽을 때는 다시 로컬 타임존으로 변환됩니다.
자동으로 **CURRENT_TIMESTAMP**로 초기화되거나 업데이트되는 특성을 가질 수 있습니다.
References
Java 타임존, 날짜 그리고 시간객체 뽀개기
항상 헷갈리는 타임존과 관련된 용어를 정리고, 데이터베이스에 어떻게 저장되고, 어플리케이션에선 어떻게 보여지는지 알아봅니다.
medium.com
When should I use OffsetDateTime, ZonedDateTime and Instant in database applications?
When should I use OffsetDateTime, ZonedDateTime and Instant in database applications?
The documentation of the java.time package says: Many applications can be written only using LocalDate, LocalTime and Instant, with the time-zone added at the user interface (UI) layer. The offset...
stackoverflow.com