MySQL'de ADDDATE() ve SUBDATE() ile Tarih Aritmetiği
Selamlar, bu yazımda MySQL'in en sık karşımıza çıkan ama bir o kadar da kafa karıştırabilen iki fonksiyonuna, ADDDATE() ve SUBDATE()'e bakacağız. Tarih aritmetiği görünüşte basit bir konu; ne var ki MySQL'in iki ayrı kullanım şekli sunması, bir de aynı işi yapan DATE_ADD() / DATE_SUB()'ın varlığı, yeni başlayanı haklı olarak duraklatıyor. Hadi kafa karışıklığını dağıtalım.
ADDDATE() ne işe yarar?
ADDDATE() bir tarihe belirli bir süre ekler. İki farklı çağırma biçimi var: ya INTERVAL ifadesiyle ay, hafta, saat gibi birimler verirsiniz, ya da ikinci argümana düz bir tam sayı geçip 'şu kadar gün ekle' dersiniz. İkincisi, yani kısa-yol biçimi, ADDDATE()'in DATE_ADD()'den ayrıldığı tek nokta.
-- Tam INTERVAL söz dizimi (DATE_ADD ile aynı)
ADDDATE(tarih, INTERVAL ifade birim)
-- Kısa-yol: N gün ekle
ADDDATE(tarih, gun_sayisi)
Birkaç örnekle netleştirelim:
-- 10 gun ekle (kisa-yol)
SELECT ADDDATE('2026-05-08', 10);
-- Sonuc: '2026-05-18'
-- 3 ay ekle
SELECT ADDDATE('2026-05-08', INTERVAL 3 MONTH);
-- Sonuc: '2026-08-08'
-- 2 saat 30 dakika ekle
SELECT ADDDATE('2026-05-08 09:00:00', INTERVAL '2:30' HOUR_MINUTE);
-- Sonuc: '2026-05-08 11:30:00'
-- Negatif tam sayi: aslinda cikarma yapar
SELECT ADDDATE('2026-05-08', -7);
-- Sonuc: '2026-05-01'
Son örnek ilginç: ikinci argümana negatif değer verince fonksiyon sessizce çıkarma moduna geçiyor. Bence bu pratik ama kodunuzu okuyan biri için niyetinizi gizleyen bir kullanım; tarih çıkarmak istiyorsanız doğrudan SUBDATE() çağırın, okunurluk artar.
SUBDATE() tarafı
SUBDATE() aynı mantığın ters yüzü. INTERVAL'la her birimi çıkarır, ya da kısa-yol biçiminde gün sayısı alır.
-- 10 gun cikar
SELECT SUBDATE('2026-05-08', 10);
-- Sonuc: '2026-04-28'
-- 1 ay cikar
SELECT SUBDATE('2026-05-08', INTERVAL 1 MONTH);
-- Sonuc: '2026-04-08'
-- Bugunden 90 gun once
SELECT SUBDATE(NOW(), 90);
SUBDATE(NOW(), 90) tarzı kullanımlar raporlama sorgularında çok işinize yarar. Aşağıda buna döneceğiz.
Peki DATE_ADD()'den farkı ne?
Şöyle ki: ADDDATE(tarih, INTERVAL ...) ile DATE_ADD(tarih, INTERVAL ...) birebir aynı şey. Tek fark, ADDDATE()'in tam sayı kısa-yol biçimini de kabul etmesi.
-- Bu ucu de ayni sonucu verir
SELECT ADDDATE('2026-05-08', 5);
SELECT ADDDATE('2026-05-08', INTERVAL 5 DAY);
SELECT DATE_ADD('2026-05-08', INTERVAL 5 DAY);
-- Hepsi: '2026-05-13'
Bana sorarsanız ekipte tek tip kullanım belirleyin: ya hep DATE_ADD / DATE_SUB kullanın (birim her zaman açık görünür), ya da ADDDATE / SUBDATE'e geçin ve gün sayısı söz konusu olduğunda kısa-yolu serbest bırakın. Aynı kod tabanında ikisinin karışması okumayı zorlaştırıyor.
Pratik: son tarih hesabı
Görev tablosunda her satıra ait bir 'kaç gün içinde teslim' alanı varsa, son tarihi anlık hesaplamak için ADDDATE() biçilmiş kaftan:
CREATE TABLE gorevler (
id INT AUTO_INCREMENT PRIMARY KEY,
gorev_adi VARCHAR(100),
olusturma_tarihi DATE,
sure_gun INT
);
INSERT INTO gorevler (gorev_adi, olusturma_tarihi, sure_gun) VALUES
('Rapor yaz', '2026-05-08', 7),
('Kod incele', '2026-05-08', 3),
('Prod yayina al', '2026-05-08', 14);
SELECT
gorev_adi,
olusturma_tarihi,
ADDDATE(olusturma_tarihi, sure_gun) AS son_tarih
FROM gorevler;
Burada ikinci argüman hard-coded değil, doğrudan kolondan geliyor. Bu, kısa-yol biçiminin gerçekten kazandığı yer; INTERVAL ile aynısını yapmak için dinamik SQL'e gerek duyardınız.
Raporlama pencereleri
Son N gün, önümüzdeki N gün gibi pencereler hemen her dashboard sorgusunda var:
-- Son 30 gun siparis
SELECT * FROM siparisler
WHERE siparis_tarihi >= SUBDATE(CURDATE(), 30);
-- Onumuzdeki 7 gun randevu
SELECT * FROM randevular
WHERE randevu_tarihi BETWEEN CURDATE() AND ADDDATE(CURDATE(), 7);
Diğer tarih fonksiyonlarıyla da güzel bestelenir; mesela 'üç ay sonraki ayın son günü' tek satırda çıkar:
SELECT LAST_DAY(ADDDATE(CURDATE(), INTERVAL 3 MONTH)) AS gelecek_ay_sonu;
Sık karşılaşılan tuzaklar
- Negatif tam sayıyla
ADDDATE()kullanmak: Çalışır ama okuyucuyu yanıltır. Niyetiniz çıkarmaksaSUBDATE()yazın. - NULL beklemediğiniz yerden gelir:
ADDDATE(NULL, 10)ya daADDDATE(tarih, NULL)her zamanNULLdöner. Kolondan gelen değerler içinCOALESCEile bir varsayılan koymak çoğu zaman iyi fikir. - Ay sonu sürprizleri:
ADDDATE('2026-01-31', INTERVAL 1 MONTH)size2026-02-28verir. MySQL ay sonunu otomatik kırpar; bu davranışın farkında olmak iş kuralınızla uyumsuzluğa düşmenizi engeller. - Index'siz tarih aritmetiği:
WHERE ADDDATE(kolon, 30) > NOW()yazarsanız index kullanılmaz. Aritmetiği sabit tarafa taşıyın:WHERE kolon > SUBDATE(NOW(), 30). Klasik tuzak ama hâlâ sıkça gördüğüm bir şey.
Kapanış
ADDDATE() ve SUBDATE(), MySQL tarih aritmetiğinin günlük araçları; INTERVAL ile esnek, tam sayı kısa-yoluyla pratik. Şahsi kanaatim, ekip içinde tek bir biçim seçip ona sadık kalmak en büyük kazancı veriyor; ondan sonra fonksiyonlar sessizce işini görüyor zaten. Umarım faydalı olur, görüşmek üzere.
