"7일 뒤"를 계산했는데 결과가 하루씩 밀린 적, 한 번쯤 있으시죠? 저는 회원 쿠폰 만료일을 strtotime과 문자열로 대충 계산했다가, 월말과 윤년에서 보기 좋게 틀렸습니다. PHP에서 날짜를 안전하게 다루는 길은 생각보다 단순합니다. DateTime 클래스 하나만 손에 익히면 됩니다.

날짜는 '문자열'이 아니라 '객체'로 다뤄야 실수가 줄어듭니다.

왜 문자열 계산이 위험한가

date('Y-m-d', strtotime('+1 month')) 같은 코드는 평소엔 잘 동작합니다. 문제는 경계입니다. 1월 31일에 한 달을 더하면 2월 31일은 없으니 3월로 넘어가고, 윤년이 끼면 또 달라집니다. 이런 경계 상황을 사람이 일일이 신경 쓰다 보면 결국 어딘가에서 구멍이 납니다.

DateTime은 이런 달력 규칙을 내부에서 알아서 처리해 줍니다. 그래서 우리가 규칙을 외울 필요가 없습니다.

현재 시각과 포맷

가장 기본은 현재 시각을 만들고 원하는 형태로 출력하는 것입니다.

$now = new DateTime();
echo $now->format('Y-m-d H:i:s');  // 2026-06-24 09:00:00

format의 문자들은 date()와 똑같습니다. 즉 기존 지식을 그대로 쓰면서, 더 안전한 객체로 다루는 셈입니다.

더하고 빼기 — modify

기간 계산은 modify로 합니다. 읽기도 쉽습니다.

$d = new DateTime('2026-01-31');
$d->modify('+1 month');
echo $d->format('Y-m-d');  // 경계도 규칙대로 처리

"+7 days", "-2 weeks", "+1 year" 처럼 자연스러운 표현을 그대로 씁니다. 문자열을 잘라 붙이던 코드와 비교하면 의도가 훨씬 분명하게 드러납니다.

두 날짜의 차이 — diff

"가입한 지 며칠 됐지?" 같은 계산은 diff가 깔끔합니다.

$a = new DateTime('2026-01-01');
$b = new DateTime('2026-06-24');
echo $a->diff($b)->days;  // 174

diff는 일수뿐 아니라 연·월·일을 각각 꺼낼 수 있어, "3년 2개월" 같은 표현도 만들 수 있습니다.

가장 흔한 함정 — 시간대

사실 날짜 버그의 절반은 계산이 아니라 시간대(timezone)에서 옵니다. 서버 기준이 한국과 다르면, 아무리 계산이 맞아도 결과가 통째로 어긋납니다. 그래서 공통 설정 파일 맨 위에 한 줄을 박아두는 습관이 중요합니다.

date_default_timezone_set('Asia/Seoul');

이 한 줄이 있으면 어느 서버에 올리든 같은 기준으로 동작합니다.

정리하며

정리하면 세 가지입니다. 단순 출력은 format, 기간 계산은 modify, 차이는 diff. 그리고 무엇보다, 코드 시작점에서 시간대를 먼저 고정하세요.

처음엔 DateTime이 번거로워 보이지만, 한 번 손에 붙으면 문자열로 날짜를 주무르던 시절로 돌아가고 싶지 않을 겁니다. 다음에 만료일·예약일을 다룰 일이 생기면, 문자열 대신 DateTime부터 떠올려 보세요.