1. MySQL 기본 날짜 함수

MySQL에서 날짜와 시간을 다루는 기본 함수들부터 알아봅시다.

현재 날짜 및 시간 구하기

-- 현재 날짜만 가져오기
SELECT CURDATE();  -- 2025-03-19

-- 다른 형식으로 현재 날짜 가져오기
SELECT CURRENT_DATE();  -- 2025-03-19

-- 현재 시간만 가져오기
SELECT CURTIME();  -- 14:30:25

-- 현재 날짜와 시간 가져오기
SELECT NOW();  -- 2025-03-19 14:30:25

-- 다른 형식으로 현재 날짜와 시간 가져오기
SELECT CURRENT_TIMESTAMP();  -- 2025-03-19 14:30:25

활용 팁: NOW()는 쿼리 실행 시점의 시간을 반환하지만, SYSDATE()는 함수가 실행되는 정확한 시점의 시간을 반환합니다. 대부분의 경우 NOW()를 사용하는 것이 좋습니다.

NOW()와 SYSDATE() 차이

-- 동일한 쿼리에서 비교
SELECT NOW(), SLEEP(2), NOW();  -- 모든 NOW() 값이 동일함
SELECT SYSDATE(), SLEEP(2), SYSDATE();  -- SLEEP 이후의 SYSDATE() 값이 2초 차이남

언제 사용할까? 일반적으로 NOW()를 사용하는 것이 안전합니다. 로그 기록이나 정확한 시간 측정이 필요한 경우에만 SYSDATE()를 사용하시길 추천합니다.

 

2. MySQL 날짜 추출 및 변환

날짜 구성 요소 추출하기

-- 현재 날짜로부터 연, 월, 일 추출
SELECT 
    YEAR(NOW()) AS '연도',      -- 2025
    MONTH(NOW()) AS '월',       -- 3
    DAY(NOW()) AS '일',         -- 19
    HOUR(NOW()) AS '시',        -- 14
    MINUTE(NOW()) AS '분',      -- 30
    SECOND(NOW()) AS '초';      -- 25

실무 활용: 데이터 그룹화나 필터링 시 자주 사용됩니다. 월별 통계 계산, 특정 연도의 데이터만 추출할 때 유용합니다.

날짜 부분 추출 함수 (EXTRACT)

-- EXTRACT 함수로 날짜 부분 추출
SELECT 
    EXTRACT(YEAR FROM NOW()) AS '연도',         -- 2025
    EXTRACT(MONTH FROM NOW()) AS '월',          -- 3
    EXTRACT(DAY FROM NOW()) AS '일',            -- 19
    EXTRACT(HOUR FROM NOW()) AS '시',           -- 14
    EXTRACT(MINUTE FROM NOW()) AS '분',         -- 30
    EXTRACT(SECOND FROM NOW()) AS '초',         -- 25
    EXTRACT(YEAR_MONTH FROM NOW()) AS '연월',   -- 202503
    EXTRACT(DAY_HOUR FROM NOW()) AS '일시',     -- 1914
    EXTRACT(HOUR_MINUTE FROM NOW()) AS '시분',  -- 1430
    EXTRACT(MINUTE_SECOND FROM NOW()) AS '분초'; -- 3025

특별 기능: MySQL의 EXTRACT 함수는 연월(YEAR_MONTH), 일시(DAY_HOUR) 등 복합 단위 추출도 지원합니다.

요일 및 주차 정보 추출

-- 요일 정보 가져오기
SELECT 
    DAYNAME(NOW()) AS '요일이름',           -- Wednesday
    DAYOFWEEK(NOW()) AS '요일숫자1',        -- 4 (일요일=1, 수요일=4)
    WEEKDAY(NOW()) AS '요일숫자2';          -- 2 (월요일=0, 수요일=2)

-- 주차 및 연중 일수 정보
SELECT 
    WEEK(NOW()) AS '연중주차',              -- 12
    WEEK(NOW(), 1) AS '월요일시작주차',      -- 12
    DAYOFYEAR(NOW()) AS '연중일수',         -- 78
    QUARTER(NOW()) AS '분기';               -- 1

DAYOFWEEK vs WEEKDAY: DAYOFWEEK는 일요일을 1로, WEEKDAY는 월요일을 0으로 시작합니다. 주간 보고서 생성 시 유의할 필요가 있습니다.

문자열을 날짜로 변환하기

-- 문자열을 날짜로 변환
SELECT STR_TO_DATE('2025-03-19', '%Y-%m-%d');  -- 2025-03-19

-- 다양한 형식의 문자열을 날짜로 변환
SELECT 
    STR_TO_DATE('19/03/2025', '%d/%m/%Y') AS '영국식날짜',      -- 2025-03-19
    STR_TO_DATE('03/19/2025', '%m/%d/%Y') AS '미국식날짜',      -- 2025-03-19
    STR_TO_DATE('2025년 3월 19일', '%Y년 %c월 %e일') AS '한글날짜';  -- 2025-03-19

활용 사례: 사용자 입력이나 CSV 파일 등에서 가져온 문자열 데이터를 MySQL의 DATE/DATETIME 타입으로 변환할 때 사용 가능합니다.

 

3. MySQL 날짜 연산

날짜 더하기/빼기 (DATE_ADD/DATE_SUB)

-- DATE_ADD 사용
SELECT 
    NOW() AS '현재',                                        -- 2025-03-19 14:30:25
    DATE_ADD(NOW(), INTERVAL 1 DAY) AS '내일',              -- 2025-03-20 14:30:25
    DATE_ADD(NOW(), INTERVAL -1 DAY) AS '어제',             -- 2025-03-18 14:30:25
    DATE_ADD(NOW(), INTERVAL 1 MONTH) AS '한달후',          -- 2025-04-19 14:30:25
    DATE_ADD(NOW(), INTERVAL 1 YEAR) AS '일년후';           -- 2026-03-19 14:30:25

-- DATE_SUB 사용
SELECT 
    NOW() AS '현재',                                        -- 2025-03-19 14:30:25
    DATE_SUB(NOW(), INTERVAL 1 DAY) AS '어제',              -- 2025-03-18 14:30:25
    DATE_SUB(NOW(), INTERVAL 1 MONTH) AS '한달전',          -- 2025-02-19 14:30:25
    DATE_SUB(NOW(), INTERVAL 1 YEAR) AS '일년전';           -- 2024-03-19 14:30:25

실무 활용: 만료일 계산(30일 후), 결제 예정일(다음 달), 프로모션 기간(7일 후까지) 등 다양한 업무에 활용될 수 있습니다.

날짜 간 차이 계산 (DATEDIFF/TIMEDIFF)

-- 날짜 간의 일수 차이 계산
SELECT DATEDIFF('2025-12-31', NOW()) AS '올해남은일수';  -- 287 (예시)

-- 시간 간의 차이 계산 (시:분:초 형식)
SELECT TIMEDIFF('17:30:00', '09:00:00') AS '근무시간';  -- 08:30:00

-- 두 날짜/시간 간의 차이를 초 단위로 계산
SELECT TIMESTAMPDIFF(SECOND, '2025-03-19 09:00:00', '2025-03-19 17:30:00') AS '근무시간(초)';  -- 30600

-- 다양한 단위로 차이 계산
SELECT 
    TIMESTAMPDIFF(YEAR, '1990-05-15', NOW()) AS '만나이(년)',        -- 34
    TIMESTAMPDIFF(MONTH, '1990-05-15', NOW()) AS '월수',           -- 418
    TIMESTAMPDIFF(DAY, '2025-01-01', NOW()) AS '일수',             -- 78
    TIMESTAMPDIFF(HOUR, '2025-03-19 09:00:00', NOW()) AS '시간수';  -- 5 (예시)

DATEDIFF vs TIMESTAMPDIFF: DATEDIFF는 일수 차이만 반환하지만, TIMESTAMPDIFF는 다양한 단위(YEAR, MONTH, DAY, HOUR, MINUTE, SECOND)로 차이를 계산할 수 있습니다.

나이 계산하기

-- 생년월일로 정확한 나이 계산
SELECT TIMESTAMPDIFF(YEAR, '1990-05-15', CURDATE()) AS '만나이';  -- 34

-- 생일 지남 여부를 고려한 정확한 나이 계산
SELECT 
    TIMESTAMPDIFF(YEAR, '1990-05-15', CURDATE()) - 
    IF(DATE_FORMAT(CURDATE(), '%m%d') < DATE_FORMAT('1990-05-15', '%m%d'), 1, 0) 
    AS '정확한만나이';  -- 생일 지남 여부에 따라 34 또는 33

한국식 나이: 한국식 나이(세는 나이)는 위 계산결과에 1을 더하면 됩니다.

 

4. MySQL 날짜 형식 지정

DATE_FORMAT으로 날짜 형식 지정

-- 다양한 날짜 형식
SELECT 
    DATE_FORMAT(NOW(), '%Y-%m-%d') AS 'ISO형식',                  -- 2025-03-19
    DATE_FORMAT(NOW(), '%d/%m/%Y') AS '영국식',                   -- 19/03/2025
    DATE_FORMAT(NOW(), '%m/%d/%Y') AS '미국식',                   -- 03/19/2025
    DATE_FORMAT(NOW(), '%Y년 %m월 %d일') AS '한글식',             -- 2025년 03월 19일
    DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS 'ISO날짜시간';     -- 2025-03-19 14:30:25

활용 사례: 리포트, 웹 페이지 출력, CSV 내보내기 등에서 원하는 형식으로 날짜를 표시할 때 사용됩니다.

자주 사용되는 날짜 형식 지정자

-- 날짜 형식 지정자 예제
SELECT 
    DATE_FORMAT(NOW(), '%Y') AS '4자리연도',         -- 2025
    DATE_FORMAT(NOW(), '%y') AS '2자리연도',         -- 25
    DATE_FORMAT(NOW(), '%m') AS '월(숫자-0포함)',    -- 03
    DATE_FORMAT(NOW(), '%c') AS '월(숫자-0제외)',    -- 3
    DATE_FORMAT(NOW(), '%M') AS '월(영문-전체)',     -- March
    DATE_FORMAT(NOW(), '%b') AS '월(영문-약자)',     -- Mar
    DATE_FORMAT(NOW(), '%d') AS '일(0포함)',         -- 19
    DATE_FORMAT(NOW(), '%e') AS '일(0제외)',         -- 19
    DATE_FORMAT(NOW(), '%W') AS '요일(전체)',        -- Wednesday
    DATE_FORMAT(NOW(), '%a') AS '요일(약자)';        -- Wed

-- 시간 형식 지정자 예제
SELECT 
    DATE_FORMAT(NOW(), '%H') AS '24시간',           -- 14
    DATE_FORMAT(NOW(), '%h') AS '12시간',           -- 02
    DATE_FORMAT(NOW(), '%i') AS '분',               -- 30
    DATE_FORMAT(NOW(), '%s') AS '초',               -- 25
    DATE_FORMAT(NOW(), '%p') AS '오전/오후',         -- PM
    DATE_FORMAT(NOW(), '%r') AS '12시간형식';        -- 02:30:25 PM

알아두세요: MySQL의 날짜 형식 지정자는 %Y, %m 등으로 사용하며, Oracle의 ‘YYYY’, ‘MM’이나 MS-SQL의 ‘yyyy’, ‘mm’과 다릅니다.

 

5. MySQL 날짜 범위 다루기

월의 첫날/마지막날 구하기

-- 해당 월의 첫날
SELECT DATE_FORMAT(NOW(), '%Y-%m-01') AS '월의첫날';  -- 2025-03-01

-- 해당 월의 마지막날
SELECT LAST_DAY(NOW()) AS '월의마지막날';  -- 2025-03-31

-- 다음 달의 첫날
SELECT DATE_ADD(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 1 MONTH) AS '다음달첫날';  -- 2025-04-01

-- 이전 달의 마지막날
SELECT DATE_SUB(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 1 DAY) AS '이전달마지막날';  -- 2025-02-28

실무 활용: 월별 보고서 기간 설정, 월 단위 결제 주기 계산 등에 활용됩니다.

연도 및 분기의 시작/끝 구하기

-- 해당 연도의 첫날/마지막날
SELECT 
    DATE_FORMAT(NOW(), '%Y-01-01') AS '연도첫날',                 -- 2025-01-01
    DATE_FORMAT(NOW(), '%Y-12-31') AS '연도마지막날';              -- 2025-12-31

-- 해당 분기의 첫날
SELECT 
    DATE_FORMAT(
        DATE_SUB(NOW(), INTERVAL (MONTH(NOW())-1) % 3 MONTH), 
        '%Y-%m-01'
    ) AS '분기첫날';  -- 2025-01-01 (1분기)

-- 해당 분기의 마지막날
SELECT 
    LAST_DAY(
        DATE_ADD(
            DATE_FORMAT(
                DATE_SUB(NOW(), INTERVAL (MONTH(NOW())-1) % 3 MONTH), 
                '%Y-%m-01'
            ), 
            INTERVAL 2 MONTH
        )
    ) AS '분기마지막날';  -- 2025-03-31 (1분기)

분기별 계산: 회계 보고서나 분기별 목표 달성 보고서 작성 시 유용합니다.

일주일의 시작/끝 구하기

-- 현재 주의 월요일(한 주의 시작)
SELECT 
    DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY) AS '이번주월요일';  -- 2025-03-17 (월요일)

-- 현재 주의 일요일(한 주의 끝)
SELECT 
    DATE_ADD(DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY), INTERVAL 6 DAY) AS '이번주일요일';  -- 2025-03-23 (일요일)

주별 보고서: 주간 매출 보고서나 주간 활동 요약 작성 시 활용할 수 있습니다.

 

6. MySQL 실무 사례: 자주 사용되는 쿼리

오늘/어제/이번주/이번달 데이터 조회

-- 오늘 데이터 조회
SELECT * FROM orders
WHERE DATE(order_date) = CURDATE();

-- 어제 데이터 조회
SELECT * FROM orders
WHERE DATE(order_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY);

-- 이번 달 데이터 조회
SELECT * FROM orders
WHERE YEAR(order_date) = YEAR(CURDATE()) 
  AND MONTH(order_date) = MONTH(CURDATE());

-- 지난 7일간 데이터 조회
SELECT * FROM orders
WHERE order_date >= DATE_SUB(NOW(), INTERVAL 7 DAY);

: DATE()를 사용하여 시간 부분을 제거하면 날짜 비교가 더 정확해집니다.

일별 트렌드 분석 (간결한 버전)

-- 최근 7일간 일별 주문 집계
SELECT 
    DATE(order_date) AS order_day,
    COUNT(*) AS order_count,
    SUM(total_amount) AS daily_sales
FROM 
    orders
WHERE 
    order_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY 
    DATE(order_date)
ORDER BY 
    order_day;

: 이 쿼리로 요일별 주문 패턴을 파악할 수 있습니다. 주말에 주문이 늘어나는지, 특정 요일에 매출이 집중되는지 확인 가능합니다.

월별 매출 비교 (작년 vs 올해)

-- 월별 매출 비교 (작년 vs 올해)
SELECT 
    MONTH(order_date) AS order_month,
    SUM(CASE WHEN YEAR(order_date) = YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR)) 
        THEN total_amount ELSE 0 END) AS last_year_sales,
    SUM(CASE WHEN YEAR(order_date) = YEAR(CURDATE()) 
        THEN total_amount ELSE 0 END) AS this_year_sales
FROM 
    orders
WHERE 
    order_date >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 YEAR), '%Y-01-01')
GROUP BY 
    MONTH(order_date)
ORDER BY 
    order_month;

성장률 분석: 이 쿼리로 작년 대비 올해 매출 성장을 쉽게 비교할 수 있습니다.

 

7. MySQL 시간 관련 함수

MySQL에서는 시간 관련 작업을 위한 다양한 함수들을 제공합니다.

시간 데이터 다루기

-- TIME 데이터 타입 사용
SELECT CURTIME() AS '현재시간';  -- 14:30:25

-- 시간 추출
SELECT 
    HOUR(CURTIME()) AS '시',      -- 14
    MINUTE(CURTIME()) AS '분',    -- 30
    SECOND(CURTIME()) AS '초';    -- 25

-- 초를 시:분:초 형식으로 변환
SELECT SEC_TO_TIME(3665) AS '시간변환';  -- 01:01:05 (3665초 = 1시간 1분 5초)

-- 시:분:초를 초로 변환
SELECT TIME_TO_SEC('01:01:05') AS '초변환';  -- 3665

활용 팁: SEC_TO_TIME과 TIME_TO_SEC는 작업 시간이나 처리 시간을 계산할 때 유용합니다.

시간 계산

-- 시간 더하기/빼기
SELECT 
    CURTIME() AS '현재',                                      -- 14:30:25
    ADDTIME(CURTIME(), '01:00:00') AS '1시간후',              -- 15:30:25
    SUBTIME(CURTIME(), '01:00:00') AS '1시간전';              -- 13:30:25

-- 시간 간격 더하기
SELECT 
    NOW() AS '현재',                                           -- 2025-03-19 14:30:25
    DATE_ADD(NOW(), INTERVAL '1:30' HOUR_MINUTE) AS '1시간30분후';  -- 2025-03-19 16:00:25

업무 활용: 업무 시간 계산, 예상 완료 시간 계산 등에 활용할 수 있습니다.

실무 사례: 시간 활용

-- 시간대별 주문 분석
SELECT 
    HOUR(order_time) AS hour_of_day,
    CONCAT(LPAD(HOUR(order_time), 2, '0'), ':00-', LPAD(HOUR(order_time)+1, 2, '0'), ':00') AS time_slot,
    COUNT(*) AS order_count
FROM 
    orders
WHERE 
    DATE(order_date) = CURDATE()  -- 오늘 주문만
GROUP BY 
    HOUR(order_time)
ORDER BY 
    hour_of_day;

: 이 쿼리로 하루 중 주문이 가장 많은 시간대를 파악할 수 있습니다.

 

8. MySQL 날짜 관련 문제 해결

날짜 비교 주의사항

-- 시간 부분 포함된 날짜 비교 시 주의
SELECT 
    CASE 
        WHEN '2025-03-19 15:30:00' = '2025-03-19' 
        THEN '일치' 
        ELSE '불일치' 
    END AS result;  -- '불일치' 반환 (시간 부분이 다름)

-- 올바른 방식 (날짜 부분만 비교)
SELECT 
    CASE 
        WHEN DATE('2025-03-19 15:30:00') = '2025-03-19' 
        THEN '일치' 
        ELSE '불일치' 
    END AS result;  -- '일치' 반환

흔한 실수: 시간이 포함된 DATETIME과 날짜만 있는 문자열을 비교할 때 발생하는 가장 흔한 오류입니다. DATE() 함수를 사용하여 시간 부분을 제거한 후 비교해야 합니다.

월말 처리 문제

-- 월말 날짜 이슈
SELECT 
    '2025-01-31' AS "1월말",
    DATE_ADD('2025-01-31', INTERVAL 1 MONTH) AS "1개월후";  -- 2025-02-28 (2월은 28일까지)

-- LAST_DAY 함수 활용
SELECT 
    LAST_DAY('2025-01-31') AS "1월마지막날",  -- 2025-01-31
    LAST_DAY('2025-02-01') AS "2월마지막날";  -- 2025-02-28

날짜 계산 주의: 월마다 일수가 다르기 때문에 월 단위 계산 시 예상과 다른 결과가 나올 수 있습니다. 월말 결제일 계산 시 LAST_DAY 함수를 활용할 수 있습니다.

윤년 처리

-- 윤년 여부 확인
CREATE FUNCTION is_leap_year(p_year INT) 
RETURNS VARCHAR(1)
DETERMINISTIC
BEGIN
    IF (p_year % 400 = 0) OR (p_year % 4 = 0 AND p_year % 100 <> 0) THEN
        RETURN 'Y';
    ELSE
        RETURN 'N';
    END IF;
END;

-- 사용 예
SELECT 
    is_leap_year(2024) AS "2024년",  -- Y (윤년)
    is_leap_year(2025) AS "2025년";  -- N (평년)

-- 2월 마지막 날 확인으로 윤년 확인
SELECT 
    DAY(LAST_DAY('2024-02-01')) AS "2024년2월마지막날",  -- 29
    DAY(LAST_DAY('2025-02-01')) AS "2025년2월마지막날";  -- 28

특정 날짜 유효성 검사: 사용자 입력 날짜의 유효성을 검사할 때 윤년 여부를 확인해야 합니다. LAST_DAY 함수를 사용하면 쉽게 확인할 수 있습니다.


 

이 글에서는 MySQL의 날짜 및 시간 함수에 대해 알아보았습니다. MySQL은 웹 애플리케이션에서 가장 많이 사용되는 데이터베이스로, 날짜와 시간을 효율적으로 다루는 것은 매우 중요합니다. 특히 DATE_FORMAT, STR_TO_DATE, DATE_ADD, DATEDIFF, TIMESTAMPDIFF, LAST_DAY 등의 함수는 MySQL에서 날짜 작업 시 가장 많이 사용되는 함수들이니 반드시 익혀두시길 추천드립니다. 추가 질문이나 특정 날짜 문제에 대한 도움이 필요하면 댓글로 남겨주세요! ~~

 

 

댓글 남기기