PostgreSQL'de tarih ve saat tutmak için dört temel tip kullanırsınız: yalnızca gün için date, gün ve saat için timestamp ya da timestamptz, iki an arasındaki süre için interval. Kullanıcıların farklı saat dilimlerinde olabileceği her uygulamada doğru seçim timestamptz (uzun adıyla timestamp with time zone) tipidir: değer içeride UTC olarak saklanır ve oturumun TimeZone ayarına göre gösterilir.
Bu yazı tipleri, saat dilimi davranışını, now() ailesini, tarih aritmetiğini, date_trunc, extract, age fonksiyonlarını ve to_char ile biçimlendirmeyi anlatır. Bütün örnekler PostgreSQL 18.1 üzerinde psql ile çalıştırıldı; çıktılar gerçek çıktılardır. Örneklerde oturum saat dilimi aksi yazmadıkça Europe/Istanbul olarak ayarlıdır. Diğer veri tipleri için PostgreSQL veri tipleri yazısına, serinin tamamı için PostgreSQL öğrenme rehberi sayfasına bakabilirsiniz.
Tarih ve saat tipleri tablosu

Belgelerdeki tip tablosunun özeti aşağıdadır. time, timestamp ve interval isteğe bağlı bir hassasiyet alır: timestamp(0) saniyenin kesirini tutmaz, en fazla 6 basamak (mikrosaniye) yazabilirsiniz. Hassasiyet vermezseniz girilen değerin hassasiyeti korunur.
| Tip | Boyut | Ne tutar | Çözünürlük |
|---|---|---|---|
| date | 4 bayt | yalnızca gün | 1 gün |
| timestamp (without time zone) | 8 bayt | gün ve saat, dilim bilgisi yok | 1 mikrosaniye |
| timestamptz (with time zone) | 8 bayt | gün ve saat, UTC olarak saklanır | 1 mikrosaniye |
| time | 8 bayt | günün saati | 1 mikrosaniye |
| time with time zone | 12 bayt | günün saati ve sabit fark | 1 mikrosaniye |
| interval | 16 bayt | süre (ay, gün, mikrosaniye) | 1 mikrosaniye |
Adı yanıltıcı olsa da timestamptz saat dilimini saklamaz. Girdide bir dilim ya da fark yazılmışsa değer o farka göre UTC'ye çevrilir; yazılmamışsa oturumun TimeZone ayarındaki dilim kabul edilir. Hangi dilimle girildiği bilgisi kaybolur, yalnızca an saklanır. Çıktıda da değer UTC'den o anki TimeZone dilimine çevrilerek gösterilir. timestamp ise bir duvar saati değeridir: hangi dilimde olduğunu bilmez ve hiçbir çevirme yapmaz.
Belgeler time with time zone tipini önermez. Gerçek hayatta bir saat diliminin UTC farkı yaz saati kuralları yüzünden tarihe bağlıdır, tarih içermeyen bir saat değerinde bu fark anlamlı olarak bilinemez. Tarih ve saati birlikte tutan tipleri kullanın.
timestamp ile timestamptz farkını görmek
Aynı metni iki tipe çevirdiğinizde fark hemen ortaya çıkar. timestamp girdideki +00 farkını sessizce yok sayar; timestamptz ise bu farkı kullanır ve sonucu oturum diliminde (İstanbul, UTC+3) gösterir:
SET TimeZone = 'Europe/Istanbul';
SELECT timestamptz '2026-03-15 14:30:00+00' AS zamanli,
timestamp '2026-03-15 14:30:00+00' AS zamansiz; zamanli | zamansiz
------------------------+---------------------
2026-03-15 17:30:00+03 | 2026-03-15 14:30:00
(1 row)SQL standardına göre sonunda fark bulunan bir TIMESTAMP '...+02' sabiti zaman dilimli sayılmalıdır, ancak PostgreSQL tipi belirlerken metnin içine bakmaz: TIMESTAMP '...' yazdığınızda her zaman dilimsiz tip oluşur. Dilimli sabit için timestamptz '...' ya da TIMESTAMP WITH TIME ZONE '...' yazın.
Şimdi küçük bir sipariş tablosu kuralım. olusturma sütunu timestamptz, teslim günü ise saat bilgisi gerekmediği için date:
CREATE TABLE siparis (
id int PRIMARY KEY,
musteri text NOT NULL,
olusturma timestamptz NOT NULL DEFAULT now(),
teslim date
);
INSERT INTO siparis VALUES
(1, 'Ayşe Yılmaz', '2026-03-15 09:05:00+03', '2026-03-18'),
(2, 'Mehmet Kaya', '2026-03-15 23:40:00+03', '2026-03-20'),
(3, 'Zeynep Demir', '2026-03-16 00:15:00+03', NULL);
SELECT id, musteri, olusturma FROM siparis ORDER BY id;
SET TimeZone = 'UTC';
SELECT id, musteri, olusturma FROM siparis ORDER BY id; id | musteri | olusturma
----+--------------+------------------------
1 | Ayşe Yılmaz | 2026-03-15 09:05:00+03
2 | Mehmet Kaya | 2026-03-15 23:40:00+03
3 | Zeynep Demir | 2026-03-16 00:15:00+03
(3 rows)
id | musteri | olusturma
----+--------------+------------------------
1 | Ayşe Yılmaz | 2026-03-15 06:05:00+00
2 | Mehmet Kaya | 2026-03-15 20:40:00+00
3 | Zeynep Demir | 2026-03-15 21:15:00+00
(3 rows)Tablodaki veri değişmedi; yalnızca gösterim değişti. Dikkat edin: İstanbul saatine göre 16 Mart'ta verilen 3 numaralı sipariş, UTC'ye göre 15 Mart'a düşüyor. "Günlük sipariş sayısı" gibi raporlarda hangi dilimin gününü kastettiğinizi açıkça belirtmezseniz sayılar sunucunun ya da istemcinin ayarına göre değişir.
TimeZone ayarı ve saat dilimi adları
TimeZone parametresi postgresql.conf içinde, SET TimeZone = ... ya da SQL standardına daha yakın SET TIME ZONE ... komutuyla oturum için ayarlanabilir. libpq istemcileri PGTZ ortam değişkeni varsa bağlanırken bu ayarı sunucuya gönderir. Parametrelerin nasıl ve hangi seviyede ayarlandığı postgresql.conf ve ALTER SYSTEM yazısında anlatılıyor.
Bir dilimi üç biçimde yazabilirsiniz: Europe/Istanbul gibi tam IANA adı, PST gibi kısaltma ve POSIX biçimi. Aradaki temel fark şudur: kısaltma tek bir sabit UTC farkını belirtir, tam ad ise yaz saati geçişleri dahil bütün tarihsel kuralları taşır. Bu yüzden kayıt ve hesaplamalarda tam adı kullanmak daha güvenlidir. TimeZone parametresine kısaltma atayamazsınız, kısaltmalar yalnızca girdi değerlerinde ve AT TIME ZONE içinde geçerlidir. Tanınan adlar pg_timezone_names görünümünde listelenir:
SELECT * FROM pg_timezone_names WHERE name = 'Europe/Istanbul'; name | abbrev | utc_offset | is_dst
-----------------+--------+------------+--------
Europe/Istanbul | +03 | 03:00:00 | f
(1 row)POSIX biçiminde işaretin anlamı ISO 8601'in tersidir: '+05' POSIX yazımında UTC-5 demektir. Bu tuzağa düşmemek için sayısal fark yerine adlandırılmış dilim kullanın. PostgreSQL 18 sürüm notları bir uyumluluk değişikliği de bildiriyor: kısaltmalar çözülürken artık önce oturumun geçerli saat diliminin kısaltmalarına, sonra timezone_abbreviations ayarına bakılıyor; önceki sürümlerde sıra tersti.
AT TIME ZONE ile dilim çevirme
AT TIME ZONE iki yönde çalışır ve sonucun tipi yöne göre değişir. timestamptz değerine uygulanırsa "bu an o dilimde duvar saatinde kaçı gösteriyordu" sorusunu yanıtlar ve dilimsiz timestamp döndürür. timestamp değerine uygulanırsa "bu duvar saati o dilimdeydi" der ve bir an, yani timestamptz üretir:
SET TimeZone = 'Europe/Istanbul';
SELECT olusturma AT TIME ZONE 'Asia/Tokyo' AS tokyo_saati,
pg_typeof(olusturma AT TIME ZONE 'Asia/Tokyo') AS tip
FROM siparis WHERE id = 1;
SELECT timestamp '2026-03-15 09:05:00' AT TIME ZONE 'Europe/Berlin' AS berlin_girdisi; tokyo_saati | tip
---------------------+-----------------------------
2026-03-15 15:05:00 | timestamp without time zone
(1 row)
berlin_girdisi
------------------------
2026-03-15 11:05:00+03
(1 row)İkinci sorguda Berlin'de saat 09:05 olan an, İstanbul oturumunda 11:05+03 olarak gösterildi (Mart ortasında Berlin UTC+1'dedir). Aynı işi yapan timezone(zone, deger) fonksiyonu da vardır. Oturum dilimine çevirmek için AT LOCAL kısaltması kullanılabilir.
now(), CURRENT_TIMESTAMP ve clock_timestamp()

now(), CURRENT_TIMESTAMP ve transaction_timestamp() aynı şeyi döndürür: transaction'ın başladığı an. Bir transaction içinde kaç kez çağırırsanız çağırın değer değişmez; belgeler bunu bilinçli bir özellik olarak açıklar, böylece aynı transaction'daki bütün değişiklikler aynı zaman damgasını alır. statement_timestamp() o komutun başladığı anı, clock_timestamp() ise çağrıldığı gerçek anı verir ve tek bir komut içinde bile değişebilir. CURRENT_DATE, LOCALTIME ve LOCALTIMESTAMP de transaction başlangıcına göre çalışır; LOCAL ile başlayanlar dilimsiz değer döndürür.
SELECT now() = statement_timestamp() AS tek_komut;
BEGIN;
SELECT pg_sleep(0.2);
SELECT now() = statement_timestamp() AS sonraki_komut,
clock_timestamp() > now() AS saat_ilerledi;
COMMIT; tek_komut
-----------
t
(1 row)
sonraki_komut | saat_ilerledi
---------------+---------------
f | t
(1 row)Tek komutluk otomatik transaction'da now() ile komut başlangıcı aynıdır. Açık bir transaction içinde ise sonraki komutlarda statement_timestamp() ilerler, now() sabit kalır. Uzun süren bir toplu işlemde her satırın gerçek işlem anını kaydetmek istiyorsanız clock_timestamp() kullanın. Transaction davranışının ayrıntısı BEGIN, COMMIT ve ROLLBACK yazısında.
CREATE TABLE kayit_hatali (id int, zaman timestamptz DEFAULT 'now');
CREATE TABLE kayit_dogru (id int, zaman timestamptz DEFAULT now());
SELECT c.relname, pg_get_expr(d.adbin, d.adrelid) AS varsayilan
FROM pg_attrdef d JOIN pg_class c ON c.oid = d.adrelid
WHERE c.relname LIKE 'kayit%' ORDER BY 1; relname | varsayilan
--------------+-----------------------------------------------------------
kayit_dogru | now()
kayit_hatali | '2026-11-07 12:18:36.322266+03'::timestamp with time zone
(2 rows)Aynı uyarı 'today', 'tomorrow' ve 'yesterday' özel girdileri için de geçerlidir: görünümlerde, fonksiyon gövdelerinde ve hazırlanmış komutlarda bayatlayabilirler. Belgelerin önerisi 'tomorrow'::date yerine CURRENT_DATE + 1 yazmaktır. 'infinity' ve '-infinity' ise gerçek özel değerlerdir; örneğin bitiş tarihi belirsiz bir kaydı 'infinity' ile işaretleyip isfinite() ile sınayabilirsiniz.
Tarih aritmetiği ve interval
İki date çıkarıldığında tam sayı (gün) döner, date ile tam sayı toplanınca yine date elde edilir. date ile interval toplandığında ise sonuç timestamp olur. Ay eklerken PostgreSQL ayın gününü korumaya çalışır; yeni ayda o gün yoksa ayın son günü kullanılır:
SELECT date '2026-03-20' - date '2026-03-15' AS gun_farki,
date '2026-03-15' + 30 AS otuz_gun_sonra,
date '2026-01-31' + interval '1 month' AS ocak31_arti_ay,
pg_typeof(date '2026-03-15' + interval '1 day') AS tip; gun_farki | otuz_gun_sonra | ocak31_arti_ay | tip
-----------+----------------+---------------------+-----------------------------
5 | 2026-04-14 | 2026-02-28 00:00:00 | timestamp without time zone
(1 row)interval içeride üç ayrı tam sayı alanı olarak saklanır: ay, gün ve mikrosaniye. Ayların gün sayısı farklı olduğu ve yaz saati geçişinde bir gün 23 ya da 25 saat sürebildiği için bu alanlar birbirine çevrilmez. Bunun pratik sonucu, yaz saati uygulayan bir dilimde interval '1 day' eklemenin interval '24 hours' eklemekle aynı olmamasıdır. Türkiye yaz saati uygulamadığı için örneği Berlin diliminde, 29 Mart 2026'daki saat ileri alma gününde çalıştırdık:
SET TimeZone = 'Europe/Berlin';
SELECT timestamptz '2026-03-28 12:00:00' + interval '1 day' AS bir_gun,
timestamptz '2026-03-28 12:00:00' + interval '24 hours' AS yirmi_dort_saat; bir_gun | yirmi_dort_saat
------------------------+------------------------
2026-03-29 12:00:00+02 | 2026-03-29 13:00:00+02
(1 row)"Yarın aynı saatte" anlamı için 1 day, "tam 24 saat sonra" için 24 hours kullanın. Gösterimde de normalleştirme kuralları vardır: dakika ve saniye 59'u geçmez ama saat alanı büyüyebilir. justify_hours 24 saatlik parçaları güne, justify_days 30 günlük parçaları aya çevirir:
SELECT interval '90 minutes' AS a, interval '36 hours' AS b,
justify_hours(interval '36 hours') AS c,
justify_days(interval '45 days') AS d,
extract(minute FROM interval '90 minutes') AS dakika_alani,
extract(epoch FROM interval '90 minutes') / 60 AS toplam_dakika; a | b | c | d | dakika_alani | toplam_dakika
----------+----------+----------------+---------------+--------------+---------------------
01:30:00 | 36:00:00 | 1 day 12:00:00 | 1 mon 15 days | 30 | 90.0000000000000000
(1 row)Bu çıktıdaki sık yapılan hataya dikkat edin: extract(minute ...) toplam dakikayı değil, gösterimdeki dakika alanını (30) verir. Bir sürenin toplam dakika ya da saniye değerine ihtiyacınız varsa extract(epoch FROM ...) ile saniyeyi alıp bölün. Süreleri make_interval(days => 10, hours => 2) gibi adlandırılmış parametrelerle de üretebilirsiniz; make_date ve make_timestamptz parçalardan tarih ve an kurar.
age() ile eksi operatörü arasındaki fark
İki zaman damgasını - ile çıkardığınızda sonuç gün ve saat cinsinden bir interval olur. age() ise alan alan çıkarma yaparak yıl ve ay içeren "insan okumasına uygun" bir sonuç verir. Kısmi ayları hesaplarken iki tarihten erken olanın ayını kullanır:
SELECT timestamp '2026-05-10 12:00' - timestamp '2026-03-31 12:00' AS eksi_operatoru,
age(timestamp '2026-05-10 12:00', timestamp '2026-03-31 12:00') AS age_sonucu;
SELECT age(date '2026-03-15', date '1990-07-28') AS yas,
date '2026-03-15' - date '1990-07-28' AS gun,
extract(year FROM age(date '2026-03-15', date '1990-07-28')) AS tam_yil; eksi_operatoru | age_sonucu
----------------+---------------
40 days | 1 mon 10 days
(1 row)
yas | gun | tam_yil
-------------------------+-------+---------
35 years 7 mons 18 days | 13014 | 35
(1 row)Yaş hesabında extract(year FROM age(...)) kalıbı tam yıl sayısını verir. Saniye cinsinden kesin fark gerekiyorsa iki değerin extract(epoch ...) sonucunu çıkarın; belgeler bu yöntemin ay uzunluklarını ve yaz saati geçişlerini de hesaba kattığını belirtir. Tek argümanlı age(ts) ise değeri bugünün gece yarısından çıkarır.
date_trunc, date_bin ve günlük raporlar
date_trunc(alan, deger) verilen alandan küçük kısımları sıfırlar (gün ve ay için bire çeker). Raporlarda gruplamanın temel aracıdır. timestamptz girdide kırpma bir saat dilimine göre yapılır: varsayılan olarak oturum dilimi, isterseniz üçüncü argümanla başka bir dilim. Aynı üç sipariş, hangi dilimin gününe göre saydığınıza bağlı olarak farklı gruplanır:
SET TimeZone = 'Europe/Istanbul';
SELECT date_trunc('day', olusturma) AS gun, count(*) AS adet
FROM siparis GROUP BY 1 ORDER BY 1;
SELECT date_trunc('day', olusturma, 'UTC') AS utc_gunu, count(*) AS adet
FROM siparis GROUP BY 1 ORDER BY 1; gun | adet
------------------------+------
2026-03-15 00:00:00+03 | 2
2026-03-16 00:00:00+03 | 1
(2 rows)
utc_gunu | adet
------------------------+------
2026-03-15 03:00:00+03 | 3
(1 row)Rapor üretirken dilimi açıkça yazmak, sonucun sunucu ayarına bağlı kalmasını önler. Sipariş olmayan günlerin de sıfır olarak görünmesini istiyorsanız generate_series ile bir takvim üretip LEFT JOIN yapın. Koşulu >= başlangıç ve < sonraki gün biçiminde yazmak, sütun üzerindeki bir indeksin kullanılabilmesini de kolaylaştırır:
SELECT g::date AS gun, count(s.id) AS siparis
FROM generate_series(date '2026-03-14', date '2026-03-17', interval '1 day') AS g
LEFT JOIN siparis s ON s.olusturma >= g AND s.olusturma < g + interval '1 day'
GROUP BY g ORDER BY g; gun | siparis
------------+---------
2026-03-14 | 0
2026-03-15 | 2
2026-03-16 | 1
2026-03-17 | 0
(4 rows)date_bin(adim, deger, baslangic) ise date_trunc'ın tam birimlerle sınırlı kalmayan hâlidir; değeri 15 dakika, 5 dakika gibi istediğiniz genişlikte kutulara yerleştirir. Adım sıfırdan büyük olmalı ve ay ya da daha büyük birim içermemelidir:
SELECT date_bin('15 minutes', timestamp '2026-03-15 09:52:41', timestamp '2026-01-01') AS ceyrek; ceyrek
---------------------
2026-03-15 09:45:00
(1 row)Gruplama ve toplama fonksiyonlarının kendisi GROUP BY ve aggregate fonksiyonlar yazısında, önceki günle karşılaştırma gibi işlemler window function yazısında anlatılıyor.
extract ile alan almak
extract(alan FROM deger) yıl, ay, gün, saat gibi parçaları numeric olarak döndürür. Eski date_part('alan', deger) aynı alanları kabul eder ama double precision döndürdüğü için belgeler extract'ı önerir. Haftanın günü iki farklı numaralandırmayla gelir: dow pazarı 0, isodow pazarı 7 sayar. week ISO 8601 hafta numarasıdır ve yıl başında önceki yılın 52. ya da 53. haftasına düşebilir; bu yüzden hafta ile birlikte isoyear kullanılması önerilir.
SELECT extract(year FROM d) AS yil, extract(month FROM d) AS ay,
extract(dow FROM d) AS dow, extract(isodow FROM d) AS isodow,
extract(week FROM d) AS hafta, extract(quarter FROM d) AS ceyrek
FROM (VALUES (date '2026-03-15')) AS t(d);
SELECT extract(epoch FROM timestamptz '2026-03-15 12:00:00+00') AS epoch,
to_timestamp(1773576000) AS geri; yil | ay | dow | isodow | hafta | ceyrek
------+----+-----+--------+-------+--------
2026 | 3 | 0 | 7 | 11 | 1
(1 row)
epoch | geri
-------------------+------------------------
1773576000.000000 | 2026-03-15 15:00:00+03
(1 row)epoch, timestamptz için 1970-01-01 UTC'den bu yana geçen saniyedir ve tek argümanlı to_timestamp() bunu geri çevirir. Belgelerin uyarısı: dilimsiz timestamp ya da date değerinden alınan epoch, değerin UTC'de olduğu varsayımıyla hesaplanır; onu to_timestamp ile geri çevirmek yanıltıcı sonuç verebilir. Sürüm notlarına göre PostgreSQL 18'de EXTRACT() fonksiyonuna WEEK seçeneği eklendi ve negatif değerler için QUARTER çıktısı iyileştirildi.
to_char ile biçimlendirme, to_date ile okuma
Ekranda "05.03.2026" gibi yerel bir biçim göstermek için to_char(deger, sablon) kullanılır. Şablondaki DD, MM, YYYY, HH24, MI, SS gibi kalıplar değerle değiştirilir; çift tırnak içindeki metin olduğu gibi yazılır. FM öneki baştaki sıfırları ve dolgu boşluklarını kaldırır. Ay ve gün adları varsayılan olarak İngilizcedir; TM önekiyle lc_time ayarındaki dile çevrilir. Bu örnekte Windows'taki tr-TR yerel ayarını kullandık:
SELECT to_char(timestamp '2026-03-05 09:07:03', 'DD.MM.YYYY HH24:MI:SS') AS tr_bicim,
to_char(timestamp '2026-03-05 09:07:03', 'FMDD Month YYYY, Day') AS ingilizce,
to_char(timestamp '2026-03-05 09:07:03', 'YYYY-"Q"Q IW. "hafta"') AS ceyrek_hafta;
SET lc_time = 'tr-TR';
SELECT to_char(timestamp '2026-03-05 09:07:03', 'FMDD TMMonth YYYY, TMDay') AS turkce;
RESET lc_time; tr_bicim | ingilizce | ceyrek_hafta
---------------------+-----------------------------+-------------------
05.03.2026 09:07:03 | 5 March 2026, Thursday | 2026-Q1 10. hafta
(1 row)
turkce
-----------------------
5 Mart 2026, Perşembe
(1 row)İkinci sütundaki boşluklar Month ve Day kalıplarının 9 karaktere dolgu yapmasından gelir; FM yalnızca hemen arkasındaki kalıbı etkiler (Oracle'dan farklı olarak). TM öneki dolgu boşluklarını kendiliğinden kaldırır. lc_time değerinin adı işletim sistemine bağlıdır; Linux sistemlerde yerel ayar adları farklı yazılır. Yerel ayar ve Türkçe sıralama konusu collation ve Türkçe sıralama yazısında.
Ters yön için to_date ve to_timestamp(metin, sablon) vardır. Belgeler, standart biçimlerde bu fonksiyonlara gerek olmadığını, basit bir tip dönüşümünün yeterli olduğunu söyler; bu fonksiyonlar "05.03.2026" gibi dönüşümün tanımadığı biçimler içindir:
SELECT to_date('05.03.2026', 'DD.MM.YYYY') AS tarih,
to_timestamp('05.03.2026 14:20', 'DD.MM.YYYY HH24:MI') AS zaman; tarih | zaman
------------+------------------------
2026-03-05 | 2026-03-05 14:20:00+03
(1 row)DateStyle ve belirsiz tarih girdileri
03/04/2026 gibi bir girdinin 4 Mart mı 3 Nisan mı olduğu DateStyle ayarındaki alan sırasına bağlıdır. Varsayılan sıra MDY'dir; aynı metin ayar değişince başka bir güne dönüşür. Bu hata sessizdir, çünkü iki yorum da geçerli bir tarih üretir:
SHOW DateStyle;
SELECT date '03/04/2026' AS mdy;
SET DateStyle = 'ISO, DMY';
SELECT date '03/04/2026' AS dmy;
RESET DateStyle; DateStyle
-----------
ISO, MDY
(1 row)
mdy
------------
2026-03-04
(1 row)
dmy
------------
2026-04-03
(1 row)Uygulamadan veritabanına tarih gönderirken her zaman 2026-03-04 biçimindeki ISO 8601 yazımını kullanın; belgeler de bu biçimi her modda aynı anlaşıldığı için önerir. Kullanıcıdan gelen yerel biçimi to_date ile açık bir şablonla okuyun. Geçersiz bir gün ise sessizce düzeltilmez, hata verir:
SELECT date '2026-02-30';ERROR: date/time field value out of range: "2026-02-30"
LINE 1: SELECT date '2026-02-30';
^Bu hatanın SQLSTATE kodu ve benzeri girdi hataları sık hatalar ve SQLSTATE kodları yazısında ele alınıyor.
Aralıkların çakışması: OVERLAPS
İki zaman aralığının çakışıp çakışmadığını OVERLAPS operatörü söyler. Her aralık başlangıç dahil, bitiş hariç kabul edilir; bu yüzden yalnızca uç noktası ortak olan iki aralık çakışmaz. Rezervasyon ve vardiya kontrolü gibi işlerde bu kural tam istediğiniz şeydir:
SELECT (date '2026-03-01', date '2026-03-10') OVERLAPS (date '2026-03-10', date '2026-03-20') AS uc_uca,
(date '2026-03-01', date '2026-03-11') OVERLAPS (date '2026-03-10', date '2026-03-20') AS ortusur; uc_uca | ortusur
--------+---------
f | t
(1 row)Çakışmayı veritabanı seviyesinde engellemek isterseniz EXCLUDE kısıtına bakın; PRIMARY KEY, FOREIGN KEY ve kısıtlar yazısında anlatılıyor.
Sık yapılan hatalar

- Olay anlarını
timestampile tutmak: sunucu ya da uygulama farklı dilimde çalışınca değerlerin hangi dilime ait olduğu bilinmez. Olay anları içintimestamptzkullanın. timestamptztipinin dilimi sakladığını sanmak: yalnızca an saklanır. Kullanıcının yerel dilimini de göstermeniz gerekiyorsa dilim adını ayrı birtextsütununda tutun.DEFAULT 'now'yazmak: tablonun oluşturulduğu an sabitlenir.DEFAULT now()yazın.- Uzun bir transaction içinde
now()değerinin ilerlediğini varsaymak: transaction başlangıcında sabit kalır, gerçek an içinclock_timestamp(). WHERE olusturma::date = '2026-03-15'gibi sütuna dönüşüm uygulamak: bu biçim sütundaki sıradan bir indeksi kullanamaz ve dilime bağlıdır. Aralık koşulu (>=ve<) yazın. İndeks türleri için PostgreSQL indeks türleri.extract(minute FROM interval)ile toplam dakika almaya çalışmak: alan değerini verir; toplam içinepoch.01/02/2026gibi belirsiz biçimlerle veri yüklemek:DateStyledeğişince sonuç değişir.
Sık Sorulan Sorular
timestamptz mi timestamp mı kullanmalıyım?
Gerçek bir anı (sipariş zamanı, giriş zamanı, log kaydı) tutuyorsanız timestamptz. Dilimden bağımsız bir duvar saati değeri (örneğin "her gün 09:00'da açılır" gibi bir takvim kuralı) tutuyorsanız timestamp ya da time. Saat gerekmiyorsa date. İkisinin de boyutu 8 bayttır, depolama açısından fark yoktur.
Sunucunun saat dilimini nasıl öğrenirim?
SHOW TimeZone; geçerli oturumun dilimini gösterir. Bu değer postgresql.conf dosyasından, veritabanı ya da rol için yapılmış ayarlardan veya istemcinin bağlanırken gönderdiği PGTZ değerinden gelebilir. Oturum için SET TimeZone = 'Europe/Istanbul'; yazmanız yeterlidir.
Unix zaman damgasını tarihe nasıl çeviririm?
to_timestamp(1773576000) bir timestamptz döndürür. Ters yön extract(epoch FROM deger). Milisaniye cinsinden bir değeri önce 1000'e bölün.
Ayın son gününü nasıl bulurum?
Ayın başına kırpıp bir ay ekleyin ve bir gün çıkarın: (date_trunc('month', d) + interval '1 month' - interval '1 day')::date. Ay ekleme kuralı ayın gününü otomatik olarak son güne çektiği için bu kalıp şubat ve 30 çeken aylarda da doğru çalışır.
Türkçe ay adlarını nasıl gösteririm?
to_char şablonunda ay ve gün kalıplarının başına TM ekleyin ve lc_time parametresini sistemde bulunan bir Türkçe yerel ayara ayarlayın. Yerel ayarın adı işletim sistemine göre değişir; sunucunuzda geçerli olan adı kullanın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · PostgreSQL veri tipleri · GROUP BY ve aggregate · string fonksiyonları · collation ve Türkçe sıralama · tablo bölümleme · PostgreSQL nedir