MariaDB 강좌 / 날짜 계산하기: 기간·날짜 차이·표시 형식
DATE_ADD는 날짜에 기간을 더하고 DATEDIFF·TIMESTAMPDIFF는 두 시점의 차이를 계산하며 DATE_FORMAT은 출력 문자열을 만듭니다. 달력상의 날짜 차이와 실제 단위 시간 차이를 구분하고, 기간 검색에는 시작 이상·다음 경계 미만 조건을 쓰면 끝날의 시각을 빠뜨리지 않을 수 있습니다.
날짜 계산과 화면 표시의 목적 나누기
한 달 뒤의 만료일, 자정을 지난 날짜 수, 경과한 온전한 시간 수는 같은 계산이 아닙니다. 기간의 단위와 업무 의미를 먼저 정한 뒤 함수를 선택합니다. 날짜를 문자열로 바꾼 결과를 다시 계산에 사용하면 형식과 지역 설정의 영향을 받기 쉬우므로 가능한 한 날짜 타입으로 계산합니다. 저장된 값의 타입과 시간대는 날짜와 시간 저장하기: DATE·DATETIME·TIMESTAMP에서 확인하며, 같은 월 경계를 매출 집계에 적용하는 예는 조회 종합 실습: 월별 매출·고객별 구매·미판매 상품에서 볼 수 있습니다.
| 함수 | 의미 | 예제 기준 |
|---|---|---|
| DATE_ADD | 기간 더하기 | INTERVAL 1 MONTH |
| DATEDIFF | 날짜 부분의 차이 | 첫 날짜 − 둘째 날짜 |
| TIMESTAMPDIFF | 지정 단위의 정수 차이 | 둘째 시점 − 첫째 시점 |
| DATE_FORMAT | 표시 문자열 | %Y-%m 월 표시 |
같은 연결에서 고정된 날짜로 비교하기
shopcourse에 접속해 SELECT VERSION(), DATABASE(), @@SESSION.time_zone;를 확인합니다. 현재 시각 함수 대신 고정된 입력을 사용하므로 실행 날짜에 따라 예상 결과가 달라지지 않습니다. DATE·DATETIME·TIMESTAMP와 시간대에서 저장 타입과 시간대 변환의 차이를 확인하세요. 날짜 리터럴에는 연-월-일 순서를 사용합니다.
SELECT DATE_ADD('2026-01-31',INTERVAL 1 MONTH);
SELECT DATE_ADD('2026-01-31',INTERVAL 30 DAY);
한 달 뒤는 2026-02-28이고 30일 뒤는 2026-03-02입니다. 한 달은 항상 30일이 아니며, 대상 월에 없는 날짜는 그 월의 유효한 마지막 날로 조정됩니다. 구독 만료일처럼 월말 처리 정책이 중요한 업무에서는 이 동작이 요구 사항과 일치하는지 따로 확인해야 합니다. DATE_ADD의 기간 단위를 참고하세요.
DATEDIFF와 TIMESTAMPDIFF의 인수 순서 비교하기
SELECT DATEDIFF('2026-02-02 01:00:00','2026-02-01 23:00:00'),
TIMESTAMPDIFF(HOUR,'2026-02-01 23:00:00','2026-02-02 01:00:00');
결과는 날짜 차이 1과 온전한 시간 차이 2입니다. DATEDIFF는 시간 부분을 제외하고 첫 날짜에서 둘째 날짜를 뺍니다. TIMESTAMPDIFF는 단위를 첫 인수로 받고, 시작 시점을 두 번째·끝 시점을 세 번째 인수로 받습니다. 두 함수의 인수 순서를 무심코 동일하게 바꾸면 부호가 뒤집힐 수 있습니다. DATEDIFF의 날짜 부분 처리를 확인하세요.
시간 차이는 지정한 단위로 정수화되므로 남은 분·초가 표현되지 않을 수 있습니다. 일광 절약 시간이나 지역 시간대가 관련된 경과 시간을 계산할 때는 저장한 값이 지역의 벽시계 시각인지 UTC 시점인지부터 정의합니다. DATETIME 두 개의 차이를 자동으로 모든 지역의 실제 경과 시간이라고 해석하지 않습니다.
DATE_FORMAT은 저장값을 바꾸지 않는 표시 함수
SELECT DATE_FORMAT('2026-02-05 12:34:56','%Y-%m'),
DATE_FORMAT('2026-02-05 12:34:56','%Y-%m-%d %H:%i:%s');
월 표시는 2026-02, 전체 표시는 2026-02-05 12:34:56입니다. 분은 %i이고 %m은 월이므로 혼동하지 않습니다. 문자열 결과는 날짜 타입의 원본과 별도로 사용합니다. 월 이름처럼 지역 언어가 적용되는 형식은 세션의 언어 설정에 따라 다를 수 있습니다. DATE_FORMAT 형식 지정자에서 각 기호의 의미를 확인합니다.
한 달 전체를 경계값으로 조회하기
이 글의 dates_21_lab 테이블이 없는지 확인한 뒤 생성·입력·조회 전체를 같은 DB에서 실행합니다. 이전 강좌의 상품 테이블은 사용하지 않습니다.
CREATE TABLE dates_21_lab (event_id INT PRIMARY KEY, occurred_at DATETIME NOT NULL) ENGINE=InnoDB; INSERT INTO dates_21_lab VALUES (1,'2026-02-01 00:00:00'),(2,'2026-02-28 23:59:59'),(3,'2026-03-01 00:00:00'); SELECT event_id FROM dates_21_lab WHERE occurred_at >= '2026-02-01' AND occurred_at < '2026-03-01' ORDER BY event_id;
결과는 1·2번이며 정확히 3월 1일 자정인 3번은 제외됩니다. 2월 28일 23:59:59를 포함하기 위해 끝 날짜에 시간을 붙이는 방식보다 다음 달 시작 미만이 소수 초 정밀도가 달라져도 의미가 명확합니다. WHERE에서 날짜 열 자체를 범위 비교하면 인덱스 설계를 검토하기도 쉽습니다.
잘못된 날짜·반복 실습 확인하기
결과가 NULL이거나 경고가 나면 날짜 형식·월말·윤년·SQL 모드를 확인합니다. 문법상 변환되었다는 이유로 0 날짜나 불완전한 날짜를 정상 데이터로 사용하지 않습니다. NULL 입력의 결과를 임의의 오늘 날짜로 바꾸기 전에는 미입력의 의미를 보존할지도 판단하세요.
반복하려면 shopcourse의 dates_21_lab 정의와 행을 확인하고 보관할 자료가 없는 이 실습용 테이블임을 확인한 뒤 아래처럼 정리합니다. 구조 삭제는 ROLLBACK으로 취소되지 않습니다.
DROP TABLE shopcourse.dates_21_lab;










