> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL 날짜 및 시간 함수

> MySQL 날짜 및 시간 함수 참조 가이드: NOW, CURDATE, DATE_FORMAT, DATEDIFF, DATE_ADD, EXTRACT, STR_TO_DATE, UNIX_TIMESTAMP, 그리고 일반적인 날짜 조작 패턴입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

MySQL은 날짜 및 시간 함수를 폭넓게 갖추고 있습니다. 주로 다루게 될 유형은 `DATE`(날짜만), `TIME`(시간만), `DATETIME`(날짜 + 시간, 시간대 없음), `TIMESTAMP`(날짜 + 시간, UTC로 저장되고 세션 시간대로 표시)입니다. 시간대 처리에 대한 자세한 내용은 [MySQL의 타임스탬프와 시간대](https://villagesql.com/docs/ko/guides/timestamps-timezones.md)를 참조하세요.

## 현재 날짜와 시간 가져오기

```sql theme={null}
SELECT NOW();            -- '2024-06-15 14:30:00'  (DATETIME, session timezone)
SELECT SYSDATE();        -- same, but evaluated at call time, not statement start
SELECT CURRENT_TIMESTAMP; -- synonym for NOW()

SELECT CURDATE();        -- '2024-06-15'  (DATE only)
SELECT CURTIME();        -- '14:30:00'    (TIME only)
SELECT UTC_TIMESTAMP();  -- '2024-06-15 21:30:00'  (UTC)
```

`NOW()`는 문장 시작 시 한 번 평가됩니다 — 같은 INSERT의 모든 행이 같은 타임스탬프를 받습니다. `SYSDATE()`는 호출될 때마다 평가됩니다.

## 날짜 형식 지정

`DATE_FORMAT`은 형식 문자열을 사용하여 날짜나 datetime을 문자열로 변환합니다:

```sql theme={null}
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');          -- '2024-06-15'
SELECT DATE_FORMAT(NOW(), '%d/%m/%Y');          -- '15/06/2024'
SELECT DATE_FORMAT(NOW(), '%M %d, %Y');         -- 'June 15, 2024'
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- '2024-06-15 14:30:00'
```

일반적인 형식 지정자:

| 지정자 | 의미 | 예시 |
| :- | :- | :- |
| `%Y` | 4자리 연도 | `2024` |
| `%y` | 2자리 연도 | `24` |
| `%m` | 월(01–12) | `06` |
| `%M` | 월 이름 | `June` |
| `%d` | 일(01–31) | `15` |
| `%H` | 시(00–23) | `14` |
| `%i` | 분(00–59) | `30` |
| `%s` | 초(00–59) | `00` |
| `%W` | 요일 이름 | `Saturday` |
| `%w` | 요일(0=일요일) | `6` |
| `%j` | 연중 일(001–366) | `167` |
| `%U` | 주 번호(0–53, 일요일 시작) | `24` |

## 문자열을 날짜로 파싱하기

`STR_TO_DATE`는 같은 형식 지정자를 사용하여 문자열을 날짜로 변환합니다:

```sql theme={null}
SELECT STR_TO_DATE('15/06/2024', '%d/%m/%Y');         -- '2024-06-15'
SELECT STR_TO_DATE('June 15, 2024', '%M %d, %Y');     -- '2024-06-15'
SELECT STR_TO_DATE('2024-06-15 14:30:00', '%Y-%m-%d %H:%i:%s');  -- DATETIME
```

문자열이 형식과 일치하지 않으면 NULL을 반환합니다.

## 날짜 연산

**DATE\_ADD / DATE\_SUB** — 간격을 더하거나 뺍니다:

```sql theme={null}
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY);        -- 7 days from now
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH);      -- 3 months from now
SELECT DATE_SUB(NOW(), INTERVAL 1 YEAR);       -- 1 year ago
SELECT DATE_ADD('2024-01-31', INTERVAL 1 MONTH); -- '2024-02-29' (end of Feb)
```

간격 단위: `SECOND`, `MINUTE`, `HOUR`, `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR`.

`+`와 `-` 연산자를 사용한 축약형:

```sql theme={null}
SELECT NOW() + INTERVAL 1 DAY;
SELECT '2024-06-15' - INTERVAL 1 MONTH;
```

**DATEDIFF** — 두 날짜 사이의 일수:

```sql theme={null}
SELECT DATEDIFF('2024-12-31', '2024-06-15');  -- 199
SELECT DATEDIFF(NOW(), created_at) AS days_old FROM orders;
```

`DATEDIFF`는 시간이 아니라 일수만 셉니다. 시간을 고려한 차이에는 `TIMESTAMPDIFF`를 사용하세요:

```sql theme={null}
SELECT TIMESTAMPDIFF(HOUR, '2024-06-15 08:00', '2024-06-15 14:30');  -- 6
SELECT TIMESTAMPDIFF(MINUTE, created_at, NOW()) AS minutes_ago FROM events;
```

`TIMESTAMPDIFF(unit, from, to)` — `from`이 `to`보다 앞에 온다는 점에 유의하세요.

## 날짜 부분 추출하기

**EXTRACT / YEAR / MONTH / DAY**:

```sql theme={null}
SELECT YEAR(NOW());     -- 2024
SELECT MONTH(NOW());    -- 6
SELECT DAY(NOW());      -- 15 (same as DAYOFMONTH)
SELECT HOUR(NOW());     -- 14
SELECT MINUTE(NOW());   -- 30

-- EXTRACT uses interval unit names
SELECT EXTRACT(YEAR FROM NOW());        -- 2024
SELECT EXTRACT(HOUR FROM NOW());        -- 14
SELECT EXTRACT(YEAR_MONTH FROM NOW());  -- 202406
```

**DAYOFWEEK / DAYOFYEAR / WEEK**:

```sql theme={null}
SELECT DAYOFWEEK(NOW());   -- 7  (1=Sunday, 7=Saturday)
SELECT WEEKDAY(NOW());     -- 5  (0=Monday, 6=Sunday)
SELECT DAYOFYEAR(NOW());   -- 167
SELECT WEEK(NOW());        -- 23  (default mode 0: week 0–53, Sunday-based; mode 1 gives 24)
SELECT YEARWEEK(NOW());    -- 202423  (default mode)
```

## 기간으로 자르기

데이터를 월, 주, 일별로 그룹화하려면 datetime을 기간 경계로 자르세요:

```sql theme={null}
-- Group orders by month
SELECT DATE_FORMAT(created_at, '%Y-%m') AS month, COUNT(*) AS orders
FROM orders
GROUP BY month
ORDER BY month;

-- Group by week
SELECT YEARWEEK(created_at) AS week, COUNT(*) AS orders
FROM orders
GROUP BY week;

-- Truncate to start of month
SELECT DATE_FORMAT(NOW(), '%Y-%m-01');  -- '2024-06-01'
```

## Unix 타임스탬프

```sql theme={null}
SELECT UNIX_TIMESTAMP();                          -- seconds since epoch (session timezone)
SELECT UNIX_TIMESTAMP('2024-06-15 14:30:00');     -- datetime to epoch (session timezone)
SELECT FROM_UNIXTIME(1718451000);                 -- epoch to DATETIME
SELECT FROM_UNIXTIME(1718451000, '%Y-%m-%d');     -- epoch to formatted string
```

## 일반적인 패턴

최근 30일간의 레코드:

```sql theme={null}
SELECT * FROM orders WHERE created_at >= NOW() - INTERVAL 30 DAY;
```

이번 달의 레코드:

```sql theme={null}
SELECT * FROM orders
WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')
  AND created_at <  DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');
```

생년월일로부터 나이:

```sql theme={null}
SELECT TIMESTAMPDIFF(YEAR, birthdate, CURDATE()) AS age FROM users;
```

## 자주 묻는 질문

#### NOW()와 SYSDATE()의 차이는 무엇인가요?

`NOW()`는 문장이 실행을 시작한 시점의 타임스탬프를 반환합니다 — 단일 INSERT나 UPDATE의 모든 행이 같은 값을 받습니다. `SYSDATE()`는 호출되는 순간의 실제 시계 시간을 반환하므로, 루프에서 삽입된 행은 서로 다른 값을 받습니다. 트랜잭션 내 일관성이 중요한 감사 타임스탬프에는 거의 항상 `NOW()`가 올바른 선택입니다.

#### INTERVAL 1 MONTH를 사용한 DATE\_ADD가 월말에 이상하게 동작하는 이유는 무엇인가요?

MySQL은 마지막 유효한 날로 고정합니다. `DATE_ADD('2024-01-31', INTERVAL 1 MONTH)`는 `2024-02-29`(윤년) 또는 `2024-02-28`을 반환합니다. 이는 예상된 동작입니다 — "2월 31일"은 없습니다. 예측 가능한 월 연산이 필요하면 먼저 월의 시작으로 자르세요.

## 문제 해결

| 문제 | 해결 방법 |
| :- | :- |
| `STR_TO_DATE`가 NULL을 반환 | 형식 문자열이 입력과 일치하지 않음 — 각 형식 지정자가 해당 입력 문자와 일치하는지 확인 |
| 같은 날짜의 타임스탬프에 대해 `DATEDIFF`가 0을 반환 | `DATEDIFF`는 시간 부분을 무시함 — 같은 달력 날짜의 두 행은 0을 반환 |
| 날짜 비교가 하루의 끝에 있는 행을 놓침 | `WHERE created_at <= '2024-06-15'`는 자정에서 멈춤 — 하루 전체를 포함하려면 `< '2024-06-16'`을 사용 |
| `TIMESTAMPDIFF`가 예상치 못한 음수 값을 반환 | 인수 순서가 잘못됨 — `(unit, to, from)`이 아니라 `TIMESTAMPDIFF(unit, from, to)` |
| `WEEK()`가 예상과 다른 숫자를 반환 | 주 번호 매기기 모드가 중요함(일요일 시작 대 월요일 시작) — ISO 8601 주 번호에는 `YEARWEEK(date, 3)`을 사용 |

## 함께 보기

* [MySQL의 타임스탬프와 시간대](https://villagesql.com/docs/ko/guides/timestamps-timezones.md) — 날짜 함수가 다루는 저장 유형
* [MySQL BETWEEN](https://villagesql.com/docs/ko/tutorial/between.md) — 날짜 범위를 `>=`와 `<`로 작성하는 것이 더 안전한 이유


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.