MariaDB / 함수 / YEAR, MONTH, DAY / 날짜 데이터에서 년, 월, 일을 반환하는 함수
MariaDB의 YEAR(), MONTH(), DAY()는 날짜 값에서 연도·월·월 안의 일을 각각 숫자로 반환합니다. DAY()는 DAYOFMONTH()와 같은 함수이며 요일을 뜻하지 않습니다. 날짜와 시간이 함께 있는 값에서도 날짜 부분을 추출할 수 있지만, TIMESTAMP 열은 조회 시간대에 따라 그 날짜가 달라질 수 있습니다.
기본 사용법과 반환값
MariaDB 서버에 접속할 수 있는 SQL 클라이언트에서 다음 SELECT를 실행합니다. 이 첫 예제는 테이블 없이 실행할 수 있으며 날짜는 연-월-일 순서로 명확하게 적었습니다.
SELECT YEAR('2024-02-29') AS year_part,
MONTH('2024-02-29 08:10:20') AS month_part,
DAY('2024-02-29') AS day_part,
DAYOFMONTH('2024-02-29') AS same_day;
결과는 2024·2·29·29입니다. MONTH()는 02가 아닌 숫자 2를 반환합니다. 표시용으로 두 자리가 필요하다는 요구와 월을 숫자로 추출하는 요구를 구분하세요.
| 함수 | 반환하는 부분 | 일반적인 유효 날짜의 예 |
|---|---|---|
| YEAR(date) | 연도 | 2024 |
| MONTH(date) | 월, 1~12 | 2 |
| DAY(date), DAYOFMONTH(date) | 월 안의 일, 1~31 | 29 |
각 함수의 정의는 YEAR, MONTH, DAYOFMONTH 문서를 참고하세요. DAY()를 DATE()와 혼동하지 마세요. DATE()는 전체 날짜 부분을 얻는 용도이고, DAY()는 그중 월 안의 일을 숫자로 얻는 용도입니다.
테이블의 DATETIME 열에서 연·월·일 추출
다음은 learning 실습 DB와 테이블 생성·입력·조회 권한이 있는 환경에서 한 번 실행합니다. 같은 이름의 테이블이 있다면 기존 것을 지우지 말고 새 실습 DB를 사용합니다. 서로 다른 연도의 2월과 월 경계, NULL을 함께 넣어 뒤의 조건을 비교합니다.
USE learning;
CREATE TABLE date_parts_demo (
id INT PRIMARY KEY,
created_at DATETIME NULL,
KEY idx_created_at (created_at)
);
INSERT INTO date_parts_demo (id, created_at) VALUES
(1, '2024-01-31 23:59:59'),
(2, '2024-02-01 00:00:00'),
(3, '2024-02-29 23:59:59'),
(4, '2024-03-01 00:00:00'),
(5, '2023-02-28 12:00:00'),
(6, NULL);
SELECT id, created_at,
YEAR(created_at) AS y,
MONTH(created_at) AS m,
DAY(created_at) AS d
FROM date_parts_demo ORDER BY id;
id 1은 2024·1·31, id 2는 2024·2·1, id 3은 2024·2·29, id 4는 2024·3·1, id 5는 2023·2·28입니다. 시·분·초가 있어도 여기서는 날짜 구성 요소만 추출합니다. id 6의 세 결과는 모두 NULL입니다. DATETIME 자료형의 저장 값과 함수로 추출한 숫자를 구분하세요.
특정 연월의 데이터를 찾는 조건
SELECT id FROM date_parts_demo
WHERE MONTH(created_at) = 2
ORDER BY id;
SELECT id FROM date_parts_demo
WHERE YEAR(created_at) = 2024 AND MONTH(created_at) = 2
ORDER BY id;
SELECT id FROM date_parts_demo
WHERE created_at >= '2024-02-01'
AND created_at < '2024-03-01'
ORDER BY id;
첫 조회는 id 2·3·5를 반환합니다. 월만 검사했기 때문에 2023년 2월도 포함됩니다. 두 번째와 세 번째 조회는 모두 id 2·3을 반환하므로 “2024년 2월”처럼 연도가 있는 검색에서는 그 범위를 명확하게 지정해야 합니다.
시각이 있는 열에서 마지막 날짜를 = '2024-02-29'로 비교하면 그 날의 모든 시각을 뜻하지 않습니다. 시작 이상·다음 달 시작 미만의 범위는 월 길이나 소수 초 정밀도를 일일이 마지막 시각으로 계산하지 않고 해당 월을 지정할 수 있습니다. 이 실습에서는 DATETIME의 달력 값에 대한 조건입니다. TIMESTAMP라면 아래 시간대 조건도 함께 고려하세요.
성능을 이유로 “날짜 함수가 있으면 인덱스를 절대 못 쓴다”고 단정하지는 마세요. MariaDB 11.1부터는 조건을 충족하는 인덱스 날짜 열의 YEAR·DATE 비교를 범위로 바꾸는 최적화가 있습니다. 지원 조건은 DATE·YEAR 조건 최적화 문서를 참고하세요. 실제 쿼리 앞에 EXPLAIN을 붙여 버전·인덱스·데이터 분포에 맞는 실행 계획을 확인해야 하며, 위의 작은 실습 결과로 운영 성능까지 판단할 수는 없습니다.
NULL과 0 날짜는 서로 다른 값
SELECT YEAR(NULL) AS y, MONTH(NULL) AS m, DAY(NULL) AS d;
SELECT YEAR('0000-00-00') AS y,
MONTH('0000-00-00') AS m,
DAY('0000-00-00') AS d;
첫 조회의 결과는 NULL·NULL·NULL이고, 두 번째는 0·0·0입니다. 0 날짜는 실제 달력의 유효한 날짜가 아니며 데이터가 없다는 NULL과도 다릅니다. 기존 자료에서 0을 발견했다면 자동으로 1월·1일이나 특정 연도로 바꾸지 말고 저장 과정과 데이터 의미를 확인해야 합니다.
이 SELECT 예제는 0 날짜에서 함수가 반환하는 값을 살펴보기 위한 것입니다. 0 날짜나 잘못된 날짜를 테이블에 저장해도 된다는 뜻은 아닙니다. 입력 허용·경고·오류는 자료형과 SQL 모드 등에 영향을 받으므로, 입력 단계에서 유효 날짜 정책을 정하고 서버 경고도 확인하세요.
TIMESTAMP는 조회 시간대에 따라 날짜가 달라질 수 있음
아래는 같은 접속에서 한 블록으로 실행합니다. 연결의 기존 시간대를 기억한 뒤 +00:00에서 값을 넣고 +09:00으로 바꾸어 비교한 다음 원래 설정으로 되돌립니다. 서버 전체의 시간대는 바꾸지 않습니다. named time zone 테이블 없이도 비교할 수 있도록 숫자 오프셋을 사용했습니다.
SET @previous_time_zone = @@session.time_zone;
SET SESSION time_zone = '+00:00';
CREATE TABLE date_parts_zone_demo (
ts TIMESTAMP NULL,
dt DATETIME NULL
);
INSERT INTO date_parts_zone_demo (ts, dt) VALUES
('2024-02-29 15:30:00', '2024-02-29 15:30:00');
SELECT ts, YEAR(ts), MONTH(ts), DAY(ts),
dt, YEAR(dt), MONTH(dt), DAY(dt)
FROM date_parts_zone_demo;
SET SESSION time_zone = '+09:00';
SELECT ts, YEAR(ts), MONTH(ts), DAY(ts),
dt, YEAR(dt), MONTH(dt), DAY(dt)
FROM date_parts_zone_demo;
SET SESSION time_zone = @previous_time_zone;
+00:00에서 ts와 dt는 모두 2024-02-29 15:30:00이며 추출 값은 2024·2·29입니다. +09:00에서는 ts가 2024-03-01 00:30:00, 추출 값은 2024·3·1로 바뀝니다. 반면 dt는 저장한 2024-02-29 15:30:00과 2024·2·29를 그대로 유지합니다.
TIMESTAMP는 세션 시간대에 맞춰 변환되는 시각 값이므로 월말·자정 부근에서 추출 날짜가 달라질 수 있습니다. 보고서를 어느 시간대의 날짜 기준으로 만들지 먼저 정하고, 데이터 저장·조회 연결의 시간대와 비교 조건을 함께 맞추세요. 숫자 +09:00 오프셋이 모든 지역의 서머타임 규칙을 표현하는 것은 아닙니다.




