| | 1 | [[PageOutline]] |
| | 2 | = MariaDB TIMESTAMP = |
| | 3 | |
| | 4 | == TIMESTAMP와 DATETIME 비교 == |
| | 5 | === 1. time_zone === |
| | 6 | DATETIME은 항상 입력한 값 그대로 일정하지만 TIMESTAMP는 time_zone 변수에 따라 값을 자동 변환하여 처리한다. |
| | 7 | {{{ |
| | 8 | MariaDB> CREATE OR REPLACE TABLE timezone_test ( dt DATETIME, ts TIMESTAMP ); |
| | 9 | |
| | 10 | MariaDB> SET time_zone = 'Asia/Seoul'; |
| | 11 | MariaDB> INSERT INTO timezone_test VALUES ((NOW()),(NOW())); |
| | 12 | MariaDB> SELECT * FROM timezone_test; |
| | 13 | +---------------------+---------------------+ |
| | 14 | | dt | ts | |
| | 15 | +---------------------+---------------------+ |
| | 16 | | 2022-11-01 12:40:23 | 2022-11-01 12:40:23 | |
| | 17 | +---------------------+---------------------+ |
| | 18 | |
| | 19 | MariaDB> SET time_zone = 'America/New_York'; |
| | 20 | MariaDB> SELECT * FROM timezone_test; |
| | 21 | +---------------------+---------------------+ |
| | 22 | | dt | ts | |
| | 23 | +---------------------+---------------------+ |
| | 24 | | 2022-11-01 12:40:23 | 2022-10-31 23:40:23 | |
| | 25 | +---------------------+---------------------+ |
| | 26 | }}} |
| | 27 | |
| | 28 | 따라서 글로벌 환경을 감안해서 개발할 때는 DATETIME보다 TIMESTAMP를 사용해야 한다. 그러나, 글로벌 환경이 아닌 경우에는 굳이 복잡하게 TIMESTAMP를 사용하는 것보다는 DATETIME을 사용하는 것이 간단하다. |
| | 29 | |
| | 30 | '''주의''' 글로벌 환경이 아니더라도 일광절약 시간제를 사용한다면 TIMESTAMP를 고려한다. |
| | 31 | |
| | 32 | === 2. 디폴트 값 === |
| | 33 | TIMESTAMP는 time_zone 변수에 따라 값을 자동 변환하여 처리하는 특성 외에 다른 여러 특징이 있다. |
| | 34 | |
| | 35 | TIMESTAMP는 레코드를 삽입하거나 업데이트할 때 명시적으로 값을 지정하지 않거나 Null을 지정하면 디폴트로 현재 시각을 자동으로 저장한다. 따라서, '''데이터를 입력하거나 수정한 시간을 저장'''하기 편하다. |
| | 36 | |
| | 37 | 자동으로 저장하는 속성은 레코드의 첫 번째 TIMESTAMP 컬럼에만 적용된다. 두번째 TIMESTAMP 컬럼부터는 변경되지 않는다. |
| | 38 | {{{ |
| | 39 | MariaDB> CREATE OR REPLACE TABLE timestamp_test (id INT, ts1 TIMESTAMP, ts2 TIMESTAMP); |
| | 40 | MariaDB> INSERT INTO timestamp_test (id) VALUES (1); |
| | 41 | MariaDB> SELECT * FROM timestamp_test; |
| | 42 | +------+---------------------+---------------------+ |
| | 43 | | id | ts1 | ts2 | |
| | 44 | +------+---------------------+---------------------+ |
| | 45 | | 1 | 2022-11-01 00:01:45 | 0000-00-00 00:00:00 | |
| | 46 | +------+---------------------+---------------------+ |
| | 47 | |
| | 48 | MariaDB> UPDATE timestamp_test SET id = 2 WHERE id = 1; |
| | 49 | MariaDB> SELECT * FROM timestamp_test; |
| | 50 | +------+---------------------+---------------------+ |
| | 51 | | id | ts1 | ts2 | |
| | 52 | +------+---------------------+---------------------+ |
| | 53 | | 2 | 2022-11-01 00:02:38 | 0000-00-00 00:00:00 | |
| | 54 | +------+---------------------+---------------------+ |
| | 55 | }}} |
| | 56 | |
| | 57 | ==== 2.1. TIMESTAMP의 디폴트 값을 없애려면 ==== |
| | 58 | 현재 시각이 자동 저장되는 특성을 없애려면 DEFAULT 값을 Null이 아닌 다른 값으로 지정하면 된다. |
| | 59 | {{{ |
| | 60 | MariaDB> CREATE OR REPLACE TABLE timestamp_test1 (id INT, ts TIMESTAMP DEFAULT 0); |
| | 61 | MariaDB> INSERT INTO timestamp_test1 (id) VALUES (1); |
| | 62 | MariaDB> SELECT * FROM timestamp_test1; |
| | 63 | +------+---------------------+ |
| | 64 | | id | ts | |
| | 65 | +------+---------------------+ |
| | 66 | | 1 | 0000-00-00 00:00:00 | |
| | 67 | +------+---------------------+ |
| | 68 | |
| | 69 | MariaDB> UPDATE timestamp_test1 SET id = 2 WHERE id = 1; |
| | 70 | MariaDB> SELECT * FROM timestamp_test1; |
| | 71 | +------+---------------------+ |
| | 72 | | id | ts1 | |
| | 73 | +------+---------------------+ |
| | 74 | | 2 | 0000-00-00 00:00:00 | |
| | 75 | +------+---------------------+ |
| | 76 | }}} |
| | 77 | |
| | 78 | ==== 2.2. DATETIME에도 디폴트 값을 지정하려면 ==== |
| | 79 | DATETIME 컬럼에도 TIMESTAMP처럼 레코드를 삽입하거나 업데이트할 때 디폴트로 현재 시각을 자동으로 저장하려면 DEFAULT CURRENT_TIMESTAMP 와 ON UPDATE CURRENT_TIMESTAMP를 지정해주면 된다. |
| | 80 | {{{ |
| | 81 | MariaDB> CREATE OR REPLACE TABLE datetime_test ( id INT, dt1 DATETIME DEFAULT CURRENT_TIMESTAMP, dt2 DATETIME ON UPDATE CURRENT_TIMESTAMP, dt3 DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); |
| | 82 | MariaDB> DESC datetime_test; |
| | 83 | +-------+----------+------+-----+---------------------+-------------------------------+ |
| | 84 | | Field | Type | Null | Key | Default | Extra | |
| | 85 | +-------+----------+------+-----+---------------------+-------------------------------+ |
| | 86 | | id | int(11) | YES | | NULL | | |
| | 87 | | dt1 | datetime | YES | | current_timestamp() | | |
| | 88 | | dt2 | datetime | YES | | NULL | on update current_timestamp() | |
| | 89 | | dt3 | datetime | YES | | current_timestamp() | on update current_timestamp() | |
| | 90 | +-------+----------+------+-----+---------------------+-------------------------------+ |
| | 91 | |
| | 92 | MariaDB> INSERT INTO datetime_test (id) VALUES (1); |
| | 93 | MariaDB> SELECT * FROM datetime_test; |
| | 94 | +------+---------------------+------+---------------------+ |
| | 95 | | id | dt1 | dt2 | dt3 | |
| | 96 | +------+---------------------+------+---------------------+ |
| | 97 | | 1 | 2022-11-01 00:34:48 | NULL | 2022-11-01 00:34:48 | |
| | 98 | +------+---------------------+------+---------------------+ |
| | 99 | |
| | 100 | MariaDB> UPDATE datetime_test SET id = 2 WHERE id = 1; |
| | 101 | MariaDB> SELECT * FROM datetime_test; |
| | 102 | +------+---------------------+---------------------+---------------------+ |
| | 103 | | id | dt1 | dt2 | dt3 | |
| | 104 | +------+---------------------+---------------------+---------------------+ |
| | 105 | | 2 | 2022-11-01 00:34:48 | 2022-11-01 00:41:16 | 2022-11-01 00:41:16 | |
| | 106 | +------+---------------------+---------------------+---------------------+ |
| | 107 | }}} |
| | 108 | |
| | 109 | |
| | 110 | === 3. 저장 범위 === |
| | 111 | TIMESTAMP의 저장 가능한 시각은 UTC 기준 '1970-01-01 00:00:01' 부터 '2038-01-19 03:14:07' 까지다. 반면에 DATETIME은 '1000-01-01 00:00:00' 부터 '9999-12-31 23:59:59'까지 입력할 수 있다. |
| | 112 | |
| | 113 | DATETIME이 저장 가능한 값의 범위가 넓은 만큼 8바이트를 차지하는데 반해 TIMESTAMP는 4바이트를 차지한다. |
| | 114 | == Time Zone 설정 == |
| | 115 | |
| | 116 | === mysql 데이터베이스의 Time Zone 테이블 === |
| | 117 | mysql 데이터베이스에는 다음과 같은 Time Zone 테이블이 있다. |
| | 118 | |
| | 119 | - time_zone |
| | 120 | - time_zone_leap_second |
| | 121 | - time_zone_name |
| | 122 | - time_zone_transition |
| | 123 | - time_zone_transition_type |
| | 124 | |
| | 125 | 위 Time Zone 테이블은 생성은 되지만 실제 데이터는 입력되어 있지 않다. 여기에 데이터가 입력되어 있어야 {{{'Asia/Seoul'}}} 같은 시간대를 설정할 수 있다. |
| | 126 | |
| | 127 | 데이터를 입력하지 않았을 때는 다음과 같은 오류가 발생한다. |
| | 128 | {{{ |
| | 129 | MariaDB> set time_zone='Asia/Seoul'; |
| | 130 | ERROR 1298 (HY000): Unknown or incorrect time zone: 'Asia/Seoul' |
| | 131 | }}} |
| | 132 | |
| | 133 | 데이터를 입력하려면 다음과 같이 mysql_tzinfo_to_sql 명령을 이용한다. |
| | 134 | {{{ |
| | 135 | # /usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql |
| | 136 | }}} |
| | 137 | |
| | 138 | 단 윈도우를 사용할 때는 mysql_tzinfo_to_sql 명령을 사용할 수 없기 때문에 다른 서버에서 데이터를 백업받아와서 복원해야 한다. |
| | 139 | |
| | 140 | |
| | 141 | === 디폴트 시간대 설정 === |
| | 142 | time_zone 시스템 변수로 시간대를 설정한다. |
| | 143 | |
| | 144 | 시간대는 다음과 같은 형식으로 지정할 수 있다. |
| | 145 | |
| | 146 | - UTC로부터의 오프셋. 예를 들어 '+9:00' |
| | 147 | - mysql 데이터베이스의 Time Zone 테이블에 데이터가 있을 때는 {{{'Asia/Seoul'}}}과 같은 형식으로 time_zone 변수를 지정할 수 있다. |
| | 148 | |
| | 149 | |
| | 150 | 글로벌 time_zone 변수를 지정하는 방법은 다음과 같다. mysql.time_zone_name 테이블을 참조하면 지정할 수 있는 time_zone 이름을 알 수 있다. |
| | 151 | {{{ |
| | 152 | [mariadb] |
| | 153 | ... |
| | 154 | default_time_zone = 'Asia/Seoul' |
| | 155 | }}} |
| | 156 | |
| | 157 | mysql 데이터베이스의 Time Zone 테이블에 데이터가 없어도 다음과 같이 지정할 수는 있다. |
| | 158 | {{{ |
| | 159 | [mariadb] |
| | 160 | ... |
| | 161 | default_time_zone = '+9:00' |
| | 162 | }}} |
| | 163 | |
| | 164 | systemd에서 쓰지 않는 리눅스 시스템에서는 mysqld_safe로 MariaDB를 구동하므로 [mysqld_safe] 항목에 지정해주면 된다. |
| | 165 | {{{ |
| | 166 | [mysqld_safe] |
| | 167 | timezone = 'Asia/Seoul' |
| | 168 | }}} |
| | 169 | |
| | 170 | 글로벌 time_zone 변수를 조회하려면 다음과 같이 한다. |
| | 171 | {{{ |
| | 172 | MariaDB> SHOW GLOBAL VARIABLES LIKE 'time_zone'; |
| | 173 | +---------------+--------+ |
| | 174 | | Variable_name | Value | |
| | 175 | +---------------+--------+ |
| | 176 | | time_zone | SYSTEM | |
| | 177 | +---------------+--------+ |
| | 178 | }}} |
| | 179 | |
| | 180 | 글로벌 time_zone 변수가 SYSTEM인 경우 system_time_zone 시스템 변수에 정의된 시간대를 대신 사용한다는 뜻이므로 다음과 같이 system_time_zone 시스템 변수를 찾아봐야 한다. |
| | 181 | {{{ |
| | 182 | MariaDB> SHOW GLOBAL VARIABLES LIKE 'system_time_zone'; |
| | 183 | +------------------+-------+ |
| | 184 | | Variable_name | Value | |
| | 185 | +------------------+-------+ |
| | 186 | | system_time_zone | KST | |
| | 187 | +------------------+-------+ |
| | 188 | }}} |
| | 189 | 위 예에서는 시간대 설정으로 'KST'를 사용한다는 것인데 MariaDB는 'KST'라는 시간대를 이해하지 못한다. |
| | 190 | |
| | 191 | === 세션의 시간대 설정 === |
| | 192 | 따로 지정하지 않으면 세션의 시간대는 글로벌 time_zone 시스템 변수 값을 상속한다. 그러나 time_zone 시스템 변수를 바꿔 세션마다 시간대를 다르게 지정할 수 있다. |
| | 193 | |
| | 194 | 다음과 같이 바꾸면 된다. |
| | 195 | {{{ |
| | 196 | MariaDB> SET time_zone = 'Asia/Seoul'; |
| | 197 | }}} |
| | 198 | |
| | 199 | 현재 세션의 시간대는 다음과 같이 확인할 수 있다. |
| | 200 | {{{ |
| | 201 | MariaDB> SHOW VARIABLES LIKE 'time_zone'; |
| | 202 | +---------------+------------+ |
| | 203 | | Variable_name | Value | |
| | 204 | +---------------+------------+ |
| | 205 | | time_zone | Asia/Seoul | |
| | 206 | +---------------+------------+ |
| | 207 | }}} |
| | 208 | |
| | 209 | |
| | 210 | === JDBC 시간대 오류 === |
| | 211 | JDBC로 MariaDB에 접속하면 다음과 같은 오류가 나온다. KST라는 시간대를 인식하지 못한다는 뜻이다. |
| | 212 | {{{ |
| | 213 | ### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: |
| | 214 | Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: |
| | 215 | Cannot create PoolableConnectionFactory (The server time zone value KST is unrecognized or represents more than one time zone. |
| | 216 | You must configure either the server or JDBC driver (via the serverTimezone configuration property) |
| | 217 | to use a more specifc time zone value if you want to utilize time zone support.) |
| | 218 | }}} |
| | 219 | |
| | 220 | |
| | 221 | 이 때는 위와 같이 설정하면 된다. |
| | 222 | |
| | 223 | ---- |
| | 224 | [WikiStart 처음으로] |