grep

Backend

MySQL DATETIME, TIMESTAMP 데이터 타입에 대한 분석

cammile.jung, bella.jj카카오

2025년 10월 17일

원문에서 보기 ↗

개요

MySQL에서는 날짜를 저장하는 데이터 타입으로 다음과 같은 데이터 타입을 지원합니다.

여기에서는 가장 자주 사용하고 중요한 DATETIME, TIMESTAMP에 대해 자세히 알아보려고 합니다. 어떤 경우에 사용하면 좋은지도 알아보고, 현재 해당 데이터 타입이 가진 문제점들도 정리해 보고자 합니다.

1. 날짜 데이터 타입의 저장 방식

먼저 각 데이터 타입에 따라 날짜 정보를 어떻게 선언하여 사용하고 어떻게 저장하는지 알아보겠습니다.


1.1 DATETIME(n)

날짜와 시간 정보를 같이 저장하는 가장 많이 사용하는 데이터 타입입니다. 다음과 같은 문법으로 선언하여 사용합니다.

컬럼 선언 시 DATETIME(fsp)로 선언합니다. fsp는 Fraction Seconds Precision의 약자로 1초보다 작은 시간 정보를 넣고자 하는 경우에 사용합니다. 예제처럼 (6)으로 선언하면 마이크로초 단위의 저장이 가능합니다. Fraction Seconds 값의 범위는 0~6까지입니다. DATETIME 데이터 타입으로 선언할 때 Fraction Seconds를 선언하지 않으면 기본값인 0으로 지정하여 선언됩니다.

값을 입력할 때는 다음과 같은 포맷으로 입력합니다.

입력 예제는 다음과 같습니다.

DATETIME 데이터 타입의 저장 범위는 다음과 같습니다.

1.1.1 DATETIME 저장 방식


DATETIME 데이터 타입은 Faction Seconds 저장 방식을 도입하면서 DATETIME 저장 방식을 크게 바뀌었습니다. 크게 정수부 저장 영역과 소수부 저장 영역을 나누고, 각 영역에 따라 저장하는 로직을 다르게 가져가고 있습니다.

[정수부 저장 방식]

DATETIME 데이터 타입은 5 Bytes의 저장 공간에 Fraction Seconds를 제외한 년/월/일/시/분/초 정보를 저장합니다. 이 공간은 고정 공간으로 변화 없이 사용합니다.

다음과 같은 순서로 저장 작업이 진행됩니다.

  1. YYYY-MM-DD hh:mm:ss 공식에 따라 5 Bytes 바이너리로 변환

  2. (1)번 결과 값을 3 Bytes(24 Bits) 소수부와 합쳐 64 Bits Packed longlong으로 만듦

  3. (2)번 결과 값을 my_packed_time_get_int_part() 함수의 파라미터로 전달하여 상위 40 Bits만 추출

  4. (3)번 결과 값에 오프셋(0x8000000000LL)을 더하여 5 Bytes로 정수부를 저장함

[소수부 저장 방식]

DATETIME의 Fraction Seconds 부분은 소수 몇 째자리까지 입력할 것인가를 선언하여 사용합니다. Fraction Seconds는 마이크로초까지 저장이 가능하며, 선언하는 자릿수에 따라 저장하는 사이즈가 달라집니다.

단위저장공간저장 시간 단위
0소수부 없음초단위까지만 가능
1,21 Byte10⁻² 초
3,42 Bytes10⁻⁴ 초
5,63 Bytes10⁻⁶ 초 (마이크로초)

위 처리 방식을 그림으로 표현하면 다음과 같이 표현할 수 있습니다.

[DATETIME(n) 변환 예시]

위 그림에서 표현된 작업 내용은 다음과 같이 정리해 볼 수 있습니다.

  1. ‘2023-07-01 12:34:56.123456’ 날짜, 시간 정보를 DATETIME(6)으로 선언된 컬럼에 넣는다고 가정합니다.

  2. 우선 Fraction Seconds 부분을 제외한 ‘2023-07-01 12:34:56’ 부분을 5 Bytes 바이너리로 변환합니다.

    ⇒ 0x19b702c8b8

  3. (2)번 결과에 오프셋(0x8000000000) 정보를 더하여 정수부를 완성합니다.

    ⇒ 정수부: 0x19b702c8b8 (2번 결과값) + 0x8000000000 (오프셋) = 0x99b702c8b8

  4. 소수부를 3 Bytes 바이너리로 변환합니다.

    ⇒ 0x1e240

  5. (3)번 결과값과 (4)번 결과값을 합하여 8 Bytes로 변환합니다.

    ⇒ packed longlong = (0x99b702c8b8 << 24) + 0x1e240 = 0x99b702c8b801e240

  6. 정수부 앞자리부터 Little-Endian 방식으로 5 Bytes까지 저장합니다.

  1. 소수부를 저장합니다. 6자리까지 선언된 데이터 타입이기 때문에 3 Bytes를 할당하여 저장합니다.

⇒ 소수부: 123456 = 0x01e240 (16진수)

즉, '2023-07-01 12:34:56.123456’라는 DATETIME(6)의 값은 8 Bytes의 [0]:0x99, [1]:0xb7, [2]:0x02, [3]:0xc8, [4]:0xb8, [5]: 0x01, [6]: 0xe2, [7]: 0x40 바이너리로 변환되어 저장됩니다.

[ DATETIME(n) 저장 공간 크기 ]

DATETIME(n)은 소수부의 초 정보를 저장하는 특징 때문에 선언된 Fraction Seconds 선언 값에 따라 최소 5 Bytes에서 최대 8 Bytes까지 저장 공간이 차이가 발생합니다.

1.1.2 오프셋(0x8000000000) 저장 로직이 필요한 이유


DATETIME 데이터 타입에서 오프셋 정보를 추가로 저장하는 이유는 시간 순서에 따른 정렬을 보장하기 위함입니다. DATETIME(n) 타입의 정수부는 실제로는 부호 있는 40 Bits 정수(상위 5 Bytes)입니다. 하지만, 디스크에 저장할 때에는 부호 없는 5 Bytes 바이너리로 저장됩니다. 그래서, 오프셋을 저장하지 않고 음수 값으로 인지되는 바이너리를 그냥 저장하게 되면 바이너리 정렬 시 음수 값으로 인지되어 시간순으로 정렬되지 못하게 됩니다.

오프셋을 앞단에 저장하면 부호 있는 정수 범위(-2^39 ~ 2^39-1)에서 부호 없는 정수 범위(0 ~ 2^40-1)로 매핑되게 값이 변화합니다. 그래서 정렬 순서가 시간 순서와 일치하게 됩니다. 그래서, 인덱스를 생성 하거나, 정렬, 비교 연산 을 하는 경우에 시간 순을 정확히 인식하여 정확한 값이 도출되게 합니다. (MySQL은 정렬 및 비교 연산 시 바이너리 값을 기준으로 처리합니다.)


1.2 TIMESTAMP

TIMESTAMP 데이터 타입은 날짜/시간 정보 외에 시간대 정보도 같이 저장하는 데이터 타입입니다. 그래서, MySQL에 선언된 시간대 정보를 기반으로 하여 입력된 값을 UTC로 변환하여 저장하게 됩니다. 즉, DATETIME 데이터 타입과 다르게, 저장/추출 시 시간대 정보를 기반 으로 날짜/시간 정보의 변환이 발생합니다.

다음과 같은 문법으로 선언하여 사용합니다.

Fraction Seconds 관련 내용은 DATETIME 데이터 타입과 동일합니다. DATETIME 데이터 타입처럼 (6)으로 선언하면 마이크로초 단위의 저장이 가능합니다. Fraction Seconds 값의 범위는 0~6까지입니다. TIMESTAMP 데이터 타입으로 선언할 때 Fraction Seconds를 선언하지 않으면 기본값인 0으로 지정하여 선언됩니다.

값을 입력할 때는 다음과 같은 포맷으로 입력합니다.

입력 예제는 다음과 같습니다.

TIMESTAMP 데이터 타입의 저장 범위는 다음과 같습니다.

DATETIME과 다르게 TIMESTAMP 데이터 타입의 최대 입력값은 13년 정도 남았습니다. 이 문제를 Y2K38 문제라고 합니다.

1.2.1 TIMESTAMP 저장 방식


MySQL은 TIMESTAMP 데이터 타입에 저장하는 날짜/시간/시간대 정보를 구조체를 선언하여 저장합니다. 사용자가 입력한 입력값을 먼저 String으로 가져온 후 str_to_datetime()함수를 사용하여 아래의 구조체에 그 정보를 입력하게 됩니다.

/*
	Structure which is used to represent datetime values inside MySQL.

	We assume that values in this structure are normalized, i.e. year <= 9999,
	month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions
	in server such as my_system_gmt_sec() or make_time() family of functions
	rely on this (actually now usage of make_*() family relies on a bit weaker
	restriction). Also functions that produce MYSQL_TIME as result ensure this.
	There is one exception to this rule though if this structure holds time
	value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold
	bigger values.

*/

  

typedef struct MYSQL_TIME {
	unsigned int year, month, day, hour, minute, second;
	unsigned long second_part; /**< microseconds */
	bool neg;
	enum enum_mysql_timestamp_type time_type;
	/// The time zone displacement, specified in seconds.
	int time_zone_displacement;
} MYSQL_TIME;

변환 시 사용하는 함수는 다음과 같습니다. (상세 함수 로직은 실제 소스 코드를 확인하시기 바랍니다.)

/**

	Convert a timestamp string to a MYSQL_TIME value.
	
	DESCRIPTION
		At least the following formats are recognized (based on number of digits)
		YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
		YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
		YYYYMMDDTHHMMSS where T is a the character T (ISO8601)
		Also dates where all parts are zero are allowed

		The second part may have an optional .###### fraction part.
		The datetime value may be followed by a time zone displacement +/-HH:MM.

(생략)
*/

bool  str_to_datetime  (const  char  *const  str_arg,  std::size_t  length,
						MYSQL_TIME  *l_time,  my_time_flags_t  flags,
						MYSQL_TIME_STATUS  *status)  {

//(생략)
		l_time->year  =  date[static_cast(0)];
		l_time->month  =  date[static_cast(1)];
		l_time->day  =  date[static_cast(2)];
		l_time->hour  =  date[static_cast(3)];
		l_time->minute  =  date[static_cast(4)];
		l_time->second  =  date[static_cast(5)];
		l_time->time_zone_displacement  =  displacement;

		frac_pos  =  static_cast(6);
		frac_len  =  date_len[frac_pos];
		status->fractional_digits  =  frac_len;
		if  (frac_len  <  6)
			date[frac_pos]  *=
				static_cast(log_10_int[DATETIME_MAX_DECIMALS  -  frac_len]);
		l_time->second_part  =  date[frac_pos];

//(생략)

}

Fraction Seconds 정보는 구조체를 따로 정의하여 저장합니다.

/**
	Replacement of system's struct timeval to ensure we can carry 64 bit values
	even on a platform which has 64 bits time, but only 32 bits tv_sec member,
	notably Windows. We do use the system timeval when interfacing the C API
	calls, though, so in a few cases, e.g. by THD::{start_time, user_time},
	we need to convert between representations but mostly the struct is only used
	internally by MySQL so we can use our own.
*/

  

struct  my_timeval  {
	int64_t  m_tv_sec;
	int64_t  m_tv_usec;
};

이렇게 DATETIME과 다르게 구조체에 정보를 저장하여 처리하기 때문에 이후 처리 로직은 복잡하지 않습니다.

TIMESTAMP 저장 처리 로직을 정리하면 다음과 같이 그림으로 표현해 볼 수 있습니다.

[TIMESTAMP(n) 변환 예시]

위 그림에서 표현된 작업 내용은 다음과 같이 정리해 볼 수 있습니다.

  1. ‘2023-07-01 12:34:56.123456’ 값을 시간대가 UTC+9인 상황에서 입력한다고 가정해 봅니다.

  2. 먼저 ‘2023-07-01 12:34:56’ 부분을 변환하여 MYSQL_TIME 구조체에 저장합니다.

  3. Fractional Seconds 영역을 변환하여 my_timeval 구조체에 저장합니다.

  4. MYSQL_TIME 구조체에 저장된 값을 timezone에 따른 차이 값을 계산하여 UTC 시간대 값으로 변경합니다.

  5. (4)번 결과 값을 16 진수로 변환하여 4 Bytes로 저장합니다.

  6. (3)번 결과 값도 16 진수로 변환하여 3 Bytes로 저장합니다.

예제에서는 마이크로초로 선언되어 저장하여 3 Bytes를 저장하여 총 7 Bytes로 데이터가 저장됨을 확인할 수 있습니다.

[ TIMESTAMP(n) 저장 공간 크기 ]

TIMESTAMP(n)도 DATETIME(n)과 마찬가지로 소수부의 초 정보를 저장하는 특징 때문에 선언된 Fraction Seconds 선언 값에 따라 최소 4 Bytes에서 최대 7 Bytes까지 저장 공간이 차이가 발생합니다.

2. DATETIME, TIMESTAMP 기능 분석

이제 DATETIME와 TIMESTAMP 데이터 타입을 사용할 때 어떤 기능이 있는지 정리해 보도록 하겠습니다.


2.1 초기화 및 자동 업데이트 기능

DATETIME, TIMESTAMP 모두 컬럼 선언 시 다음과 같이 선언하면 현재 시간으로 초기화하거나 업데이트되게 할 수 있습니다.

ts  TIMESTAMP  DEFAULT  CURRENT_TIMESTAMP  [ON  UPDATE  CURRENT_TIMESTAMP]
dt  DATETIME  DEFAULT  CURRENT_TIMESTAMP  [ON  UPDATE  CURRENT_TIMESTAMP]

만약, Fraction Seconds 값으로 입력되게 하고 싶다면 다음과 같이 선언해야 합니다.

ts  TIMESTAMP(6)  DEFAULT  CURRENT_TIMESTAMP(6)  [ON  UPDATE  CURRENT_TIMESTAMP(6)]
dt  DATETIME(6)  DEFAULT  CURRENT_TIMESTAMP(6)  [ON  UPDATE  CURRENT_TIMESTAMP(6)]

2.2 explicit_defaults_for_timestamp 시스템 변수

explicit_defaults_for_timestamp 시스템 변수는 TIMESTAMP 데이터 타입에만 적용되는 시스템 변수입니다. 레퍼런스를 보면 굉장히 복잡하게 설명되어서 복잡하게 느껴지기도 합니다. 하지만, 이 시스템 변수는 간단하게 설명하면 다음과 같이 정리할 수 있습니다.

Explicit_defaults_for_timestamp 시스템 변수는 TIMESTAMP 데이터 타입 선언 시 기본값이 설정되어 있지 않은 경우에 동작 방식을 정의한 시스템 변수이다.

기본값이 선언되지 않은 상황에서 explicit_defaults_for_timestamp 시스템 변수 값에 따라 달라지는 동작 방식은 다음과 같이 정리할 수 있습니다.

[explicit_defaults_for_timestamp=OFF(0)인 경우]

  1. 선언 시 NULL 여부를 선언하지 않은 경우 NOT NULL 속성으로 생성됩니다.
  2. 기본값 선언이 되어 있지 않거나, ON UPDATE 구문이 추가되어 선언되어 있지 않다면 다음과 같은 규칙에 따라 값이 저장되게 선언됩니다. a. 첫번째 TIMESTAMP 컬럼: DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 속성이 자동으로 추가됩니다. b. 그 외 TIMESTAMP 컬럼: 자동으로 '0000-00-00 00:00:00’으로 선언됩니다.

[참고]

‘0000-00-00 00:00:00’ 선언은 SQL_MODE 로 STRICT_TRANS_TABLES,

STRICT_ALL_TABLES, NO_ZERO_DATE 옵션 중 하나라도 추가되어 있다면, 충돌이 발생할 수도 있습니다.

[explicit_defaults_for_timestamp=ON(1)인 경우]

  1. 선언 시 NULL 여부를 선언하지 않은 경우 NULL 속성으로 생성됩니다.
  2. NOT NULL 속성으로 선언하는 경우에 DEFAULT CURRENT_TIMESTAMP, ON UPDATE CURRENT_TIMESTAMP 같은 기본 날짜 정보를 입력하는 속성이 추가 선언되지 않습니다.

[참고]

explicit_default_for_timestamp 시스템 변수는 예전부터 Deprecated가 예정되어 있지만, 아직 Deprecated가 되지는 않았습니다. 하지만, 언제든 다음 버전에서 Deprecated될 수 있고, Deprecated된다면 ON으로 고정되기 때문에 영향을 받지 않게 테이블의 컬럼을 선언하여 사용하는 습관을 들이는 것이 좋습니다.


2.3 Zero-Date 및 비표준 날짜 입력 처리

MySQL Ver. 5.7이 되면서 실제 존재하지 않는 날짜는 입력할 수 없도록 하기 위한 기능들이 추가되었습니다. 이전 버전에서 만들어진 Application에 영향을 줄 수는 없기 때문에 비표준 날짜 입력을 무조건적으로 막지는 않았습니다. 하지만, 이런 내용들을 인지시키기 위해 SQL_MODE에서 비표준 날짜 데이터에 대한 컨트롤이 가능하게 모드 추가를 하였습니다. 예를 들어, ‘0000-00-00’, '9999-99-99’와 같은 값을 입력하는 경우가 많았습니다. 실제 존재하지 않는 날짜로 DATETIME 데이터 타입에 대해 해당 값을 Default 값으로 선언하여 사용자가 실제 값을 입력하지 않았다는 것을 명시하는 용도로 사용하였습니다.

[ALLOW_INVALID_DATES]

날짜 정보에 대한 Validation 체크를 단순화하는 SQL_MODE입니다. 월이 1~12 사이 값인지, 일이 1~31 사이 값인지만 확인합니다. DATETIME에만 적용됩니다. TIMESTAMP에는 적용되지 않습니다.

[NO_ZERO_IN_DATE]

년/월/일 중에 월/일 부분에 대한 0값 입력을 허용하지 않는다는 SQL_MODE입니다. 만약 해당 SQL_MODE가 활성화되어 있다면, ‘2010-11-00’, '2011-00-21’과 같은 값을 INSERT할 때 ‘0000-00-00’ 값으로 변환한 뒤 경고문을 출력하게 됩니다. 하지만, 해당 SQL_MODE는 언젠가 Deprecated될 것이라고 경고하니, 가능하면 사용하지 않는 것이 좋습니다.

[NO_ZERO_DATE]

년/월/일 모두 0인 날짜 값, 즉 ‘0000-00-00’ 값에 대한 SQL_MODE입니다. 활성화 여부와 상관없이 ‘0000-00-00’ 값을 허용하지만, 활성화 시 경고문을 출력하게 됩니다. NO_ZERO_DATE SQL_MODE도 마찬가지로 Deprecated될 것이라고 경고하고 있습니다. 하지만, 언제 될 것인지는 아직 결정되지 않았습니다.


2.4 Y2K38 문제

Y2K38문제는 2038년 1월 19일 03시 14분 07초(UTC)가 지나면 시간이 제대로 표시되지 않아 오작동을 일으킬 수 있는 버그를 말합니다. OS부터 각종 소프트웨어에서 32 Bits로 저장하는 Timestamp 값으로 인해 발생하게 되는데요, 현재 사용하는 OS들은 64 Bits로 전환하여 문제가 되지는 않지만, 각종 소프트웨어에서는 아직도 다 해결되지 않은 상황입니다.

MySQL도 마찬가지로 해당 문제를 가지고 있습니다. MySQL Ver. 8.0.28 버전에서 unix_timestamp()와 같이 OS에서 시간 정보를 가져오는 함수들은 소스 코드를 변경하여 대응하였으나, 아직 TIMESTAMP 데이터 타입은 해당 버그를 잠재적으로 가지고 있습니다.

MySQL Ver. 9.4 코드까지 전부 확인했을 때 해당 문제를 수정하지 않은 것을 확인할 수 있었습니다.

2.4.1 Y2K38 재현 테스트


먼저 Y2K38 현상을 재현하기에 앞서, 테스트를 진행한 환경은 다음과 같습니다.

-- 현재 os의 64bit 여부를 확인합니다.

mysql> system uname -m;
x86_64

-- 현재 세션의 time_zone은 'UTC'입니다.
mysql> show variables like 'time_zone';
+---------------+------------+
| Variable_name | Value |
+---------------+------------+
| time_zone | UTC |
+---------------+------------+

-- 현재 MySQL의 version은 8.4.5-5입니다.
mysql>  select  @@version;
+-----------+
|  @@version  |
+-----------+
|  8.4.5-5  |
+-----------+

unix_timestamp() 함수를 이용해 32 Bits 정수형에서 허용 가능한 날짜/시간과, 허용 범위를 초과한 날짜/시간을 조회하면 다음과 같습니다.

mysql>  select  unix_timestamp('2038-01-19 03:14:07')  as  '32bit허용가능한날짜시간';
+----------------------------------+
|  32bit허용가능한날짜시간  |
+----------------------------------+
|  2147483647  |
+----------------------------------+
1  row  in  set  (0.00  sec)

mysql>  select  unix_timestamp('2038-01-19 03:14:08')  as  '32bit초과한날짜시간';
+----------------------------+
|  32bit초과한날짜시간  |
+----------------------------+
|  2147483648  |
+----------------------------+
1  row  in  set  (0.00  sec)

위와 같이, unix_timestamp() 함수를 사용한 경우에는 반환값을 64 Bits 정수로 반환하기 때문에, 32 Bits를 초과하는 시간에 대해서도 문제 없이 변환되는 것을 알 수 있습니다.

이제 MySQL Ver. 8.4.5 에서 다음과 같이 테이블을 생성한 뒤, 데이터를 INSERT해 보겠습니다.


mysql> CREATE  TABLE  `y2k38_test`  (
	`id`  int  NOT  NULL  AUTO_INCREMENT,
	`dt_col`  datetime  DEFAULT  NULL,
	`ts_col`  timestamp  NOT  NULL  DEFAULT  CURRENT_TIMESTAMP  ON  UPDATE  
CURRENT_TIMESTAMP,
	PRIMARY  KEY  (`id`)
);

-- 32 bit 허용 가능한 날짜/시간을 입력
mysql> INSERT  INTO y2k38_test(dt_col,ts_col) values ('2038-01-19 
03:14:07','2038-01-19 03:14:07');

-- 32 bit 초과한 날짜/시간을 입력
mysql> INSERT  INTO y2k38_test(dt_col,ts_col) values ('2038-01-19 
03:14:08','2038-01-19 03:14:08');

위와 같이 날짜/시간 정보를 입력 후 조회해 보면, 입력 가능한 날짜를 초과하는 경우에 OverFlow가 발생하여 초기화되는 것을 확인할 수 있으며, 또한 TIMESTAMP 데이터 타입에서만 발생하는 것도 확인할 수 있었습니다.

mysql>  select  id,dt_col,ts_col,unix_timestamp(ts_col)  from  y2k38_test;
+----+---------------------+---------------------+------------------------+
|  id  |  dt_col  |  ts_col  |  unix_timestamp(ts_col)  |
+----+---------------------+---------------------+------------------------+
|  1  |  2038-01-19  03:14:07  |  2038-01-19  03:14:07  |  2147483647  |
|  2  |  2038-01-19  03:14:08  |  0000-00-00  00:00:00  |  0  |
+----+---------------------+---------------------+------------------------+

결과적으로, MySQL 8.0.28 버전 이상에서 Y2K38이슈 관련된 개선점은 "unix_timestamp(), from_timestamp() 함수에 대한 반환값을 64 Bits 정수로 반환한 것"으로, 즉, TIMESTAMP 컬럼 타입은 여전히 32 Bits 정수로 시간을 저장하며, 최대 2,147,483,647까지만 저장한다는 것을 확인했습니다.

해당 이슈에 대해서는 Oracle에 대응 계획을 문의했으나, 아직 미정이라는 답변만 전달 받았습니다.

3. DATETIME, TIMESTAMP 선택 가이드

여기에서는 날짜/시간 정보를 입력하는 DATETIME/TIMESTAMP 데이터 타입에 대해 상세히 알아 보았습니다. 또한, 각 데이터 타입에 영향을 주는 변수 및 설정들에 대해서도 간단히 알아보았습니다. 두 데이터 타입의 차이점을 정리하면 다음과 같이 정리해 볼 수 있습니다.

DATETIME/TIMESTAMP 데이터 타입은 같은 날짜/시간 정보를 입력할 수 있지만, 범위가 다르고 TIMEZONE 반영 여부에 차이가 있음을 확인할 수 있습니다. 그래서 그 차이를 기준으로 선택 기준을 잡아볼 수 있습니다.

즉, 다음과 같이 고려해 보고 결정하는 것이 좋습니다.

4. 마무리

DATETIME과 TIMESTAMP 데이터 타입은, 이전에는 저장 범위 및 기본값 설정 등 지금보다 더 큰 차이를 가졌습니다. 하지만, 이제는 사용성 부분에서 큰 차이가 없게 되었습니다. Y2K38 문제를 해결하고 나면, 저장 영역도 크게 차이가 나지 않을 가능성이 높습니다. 그러면, TIMEZONE 반영 여부만 달라지게 되지 않을까 생각합니다. 그러면 더더욱 어떤 데이터 타입을 사용하는 것이 맞는지 고민이 될 것으로 보입니다. MySQL을 계속 분석하며 공부하는 엔지니어로서 향후 어떻게 변화할지 예측하는 것도 재미있는 부분이 아닌가 싶습니다. 이후에도 계속 리서치하면서 재미있는 변화 사항이 있으면 공부하고 공유해 보겠습니다.


참고

https://medium.com/finda-tech/mysql-timestamp-%EC%99%80-y2k38-problem-d43b8f119ce5

https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html

https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp

https://dev.mysql.com/doc/refman/8.0/en/datetime.html

https://dev.mysql.com/doc/refman/8.0/en/time.html

https://dev.mysql.com/doc/refman/8.0/en/year.html

https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html

https://dev.mysql.com/doc/refman/8.0/en/fractional-seconds.html

https://dev.mysql.com/doc/refman/8.0/en/two-digit-years.html

https://github.com/mysql/mysql-server/tree/8.0