SQL Server datetime2 ve datetimeoffset: PG’den Geçiş
PostgreSQL’den SQL Server veya Azure SQL’e geçen geliştiricilerin ilk gün takıldığı konulardan biri, tarih ve saat tiplerinin nasıl davrandığı. Jerry Nixon’ın Azure SQL Dev Corner’da yayımlanan “PostgreSQL to SQL Field Notes” yazısı tam bu noktaya bakıyor: PostgreSQL’deki timestamp ve timestamptz tiplerinin SQL tarafındaki karşılıkları, hangi bilgiyi saklayıp hangisini kaybettikleri, depolama açısından ne anlama geldikleri. Aşağısı, o karşılaştırmanın Türkçe derlenmiş hali.
PostgreSQL’de timestamp: saat dilimi bilgisi yok
PostgreSQL’de timestamp, tarih ve saati saat dilimi bilgisi olmadan saklar. Tipin adı PostgreSQL 7.0 öncesine kadar uzanıyor ama anlamı yolda değişti: 7.0 sürümü eski datetime tipinin yerine timestamp‘i getirdi, 7.2 sürümü de bugün bildiğimiz timestamp without time zone ile timestamp with time zone ayrımını tanımladı. Bugün çıplak bir timestamp yazdığınızda kastedilen timestamp without time zone.
SELECT TIMESTAMP '2026-09-21 10:30:00';
Değer verildiği gibi saklanır; ortada saat dilimi bilgisi yoktur, saklanan da yoktur. Peki değere bir UTC ofseti eklerseniz?
SELECT TIMESTAMP '2026-09-21 10:30:00-06:00';
Bu durumda timestamp ofseti yok sayar, verdiğiniz -06:00 bilgisi atılır. PostgreSQL belgelerinde de bu davranış bugün hala böyle tanımlı. Uygulamanızın orijinal saat dilimini veya ofseti koruması gerekiyorsa bu bilgiyi ayrıca saklamanız gerekir:
CREATE TABLE events (
event_id SERIAL PRIMARY KEY,
event_name TEXT NOT NULL,
event_timestamp TIMESTAMP NOT NULL,
event_timezone TEXT NOT NULL
);
Çalışır, ama artık tek bir olayı iki ayrı sütun tarif ediyor. İki değerin birlikte taşınması ve doğru yorumlanması da tamamen uygulamanın sorumluluğuna kalıyor.
SQL tarafındaki en yakın karşılık: datetime2
PostgreSQL timestamp tipinin SQL’deki en yakın karşılığı datetime2. SQL Server’ın eski datetime tipinin modern yerine geçen seçeneği bu; Microsoft yeni geliştirmeler için datetime2 kullanılmasını öneriyor.
Dikkat çeken fark hassasiyette. datetime2, 0 ile 7 basamak arasında değişken kesirli saniye hassasiyeti destekliyor ve varsayılan olarak datetime2(7) ile geliyor, yani varsayılan ayarda zamanı 100 ns adımlarıyla temsil edebiliyor. PostgreSQL’deki timestamp ise 6 kesirli saniye basamağı, yani 1 μs adımı destekliyor. SQL Server tarafı bu haliyle 10 kat daha ince bir temsil sunuyor.
Bilimsel cihaz verisi, akış (streaming) verisi veya finansal uygulamalar gibi yüksek hassasiyet isteyen senaryolarda datetime2 bu konuda ödün vermenizi gerektirmiyor.
timestamptz ne yapar, ne yapmaz
PostgreSQL’in timestamptz kısaltmasıyla yazılan timestamp with time zone tipinde ofset önemsenir:
SELECT TIMESTAMPTZ '2026-09-21 10:30:00-06:00';
Burada PostgreSQL ofseti kullanarak gerçek zaman anını belirler, bu anı dahili olarak UTC biçiminde saklar. Orijinal saat dilimini veya ofseti ise saklamaz; değer okunurken oturumun geçerli TimeZone ayarına göre dönüştürülür.
Yani “uygulama başlangıçta hangi ofseti gönderdi?” sorusunun cevabı PostgreSQL’de yok. Üstelik oturumun TimeZone ayarı da kullanıcının ya da uygulamanın yerel saat dilimini kendiliğinden bilmez; onu uygun şekilde ayarlamak veya dönüşümü kendi yapmak uygulamanın işi. Aynı saklanan değer bu yüzden kimin sorduğuna göre farklı görünebilir:
SET TIME ZONE 'America/Denver';
SELECT TIMESTAMPTZ '2026-09-21 10:30:00-06:00';
-- 2026-09-21 10:30:00-06
SET TIME ZONE 'America/New_York';
SELECT TIMESTAMPTZ '2026-09-21 10:30:00-06:00';
-- 2026-09-21 12:30:00-04
İki sonuç da tam olarak aynı zaman anını temsil eder, PostgreSQL’in bilinçli davranışıdır bu. Fakat uygulamanız orijinal değerin 10:30 -06:00 olduğunu bilmek zorundaysa timestamptz bunu söyleyemez, o bilgi ekleme sırasında kaybolur. Orijinal ofsete ihtiyaç duyan geliştiriciler bilgiyi değerin içine gömmek yerine ayrıca saklamak zorunda kalıyor. timestamptz‘ın kazandırdığı şey ise zaman damgalarını ortak bir ana normalleştirmesi, okuma sırasında da oturumun yapılandırılmış saat dilimine otomatik çevirmesi.
datetimeoffset: yerel zaman ve ofset birlikte
SQL tarafında saat dilimi bilgisi önemliyse devreye datetimeoffset giriyor. Bu tip hem yerel tarih ve saati hem de UTC’den ofseti saklıyor, zaman damgasının orijinal bağlamı böylece korunuyor.
DECLARE @dt DATETIMEOFFSET = '2026-09-21 10:30:00-06:00';
Tip SQL Server 2008’den beri var ve modern SQL Server uygulamalarında yaygın olarak kullanılıyor. '2026-09-21 10:30:00-06:00' gibi bir değer eklediğinizde SQL Server -06:00 ofsetini tarih ve saatle birlikte saklar.
Değeri UTC olarak göstermek isterseniz iki basit yol var:
SELECT @dt AT TIME ZONE 'UTC';
SELECT SWITCHOFFSET(@dt, '+00:00');
İkisi de aynı anı UTC olarak döndürür. AT TIME ZONE, adlandırılmış saat dilimleri ve bunların dönüşüm kurallarıyla çalışırken işe yarıyor. Elinizde zaten bir datetimeoffset varsa ve yalnızca gösterilen ofseti UTC’ye çevirmek istiyorsanız SWITCHOFFSET daha basit kalıyor.
datetime2 ile gelen yüksek hassasiyet datetimeoffset için de geçerli, üstüne saat dilimi farkındalığı ekleniyor:
-- Example showing high precision with datetimeoffset
DECLARE @dtHighPrecision DATETIMEOFFSET(7) = '2026-09-21 10:30:00.1234567-06:00';
SELECT @dtHighPrecision;
Depolama farkı ve varsayılan tip seçimi
datetimeoffset, kesirli saniye hassasiyetine bağlı olarak 8 ila 10 bayt yer kaplıyor. 6 ila 8 bayt gerektiren datetime2‘ye göre biraz daha fazla; fazladan 2 bayt saat dilimi ofsetini saklıyor.
| Satır | datetimeoffset | datetime2 |
|---|---|---|
| 1 milyar | 8–10 GB | 6–8 GB |
Bir milyar satırda fark 2 GB. Tarih alanları çoğu uygulamada bol bol kullanıldığından bu fark, toplam depolama ihtiyacında ve performansta hissedilir bir etki yaratabiliyor. Kazanç sadece diskte de olmuyor; G/Ç yükü, bellek baskısı ve dizin boyutu da aşağı inebiliyor.
Bu nedenle varsayılan tercihiniz her zaman datetimeoffset olmak zorunda değil. Uygulamanız saat dilimiyle ilgilenmiyorsa datetime2 pek çok senaryoda mükemmel bir seçim olmayı sürdürüyor. Hassasiyet değişken olduğu için, saat dilimi farkındalığına ihtiyaç duyduğunuz durumlarda bile uygun hassasiyeti seçip depolama ile ihtiyaç arasında denge kurabilirsiniz:
| Satır | datetimeoffset(0) | datetimeoffset(7) |
|---|---|---|
| 1 milyar | 8 GB | 10 GB |
En düşük ve en yüksek hassasiyet arasında bir milyar satırda yine 2 GB’lık bir fark oluşuyor, üstelik saat dilimi desteğinden vazgeçmeden.
Geçiş yaparken akılda tutulacaklar
Kaynak yazının özeti kabaca şöyle toparlanabilir: PostgreSQL’den geçiş gerçek bir iş yükü ve eski PostgreSQL sürümünüze bağlı olarak karmaşıklığı ciddi biçimde değişebiliyor. SQL standardı iki motorun şeklini büyük ölçüde hizaladığı için bu tanıdıklık hızlı ilerlemenize yardımcı oluyor, yine de her şeyin birebir karşılığı bulunmuyor. Tarih ve saat tarafında pratik karşılık tablosu şöyle:
timestamp(saat dilimsiz) →datetime2, daha ince hassasiyetle.timestamptz→datetimeoffset, ancak orijinal ofseti kaybetmeden.- Saat dilimi önemli değilse
datetime2ile depolamadan kazanç sağlayın.
Uygulamanız için doğru tarih ve saat tipini seçmek önemli bir karar; SQL tarafında bu kararı vermek için gereken seçenekler tip düzeyinde hazır geliyor.
Kaynaklar ve İleri Okuma
- PostgreSQL to SQL Field Notes: Date & Time — Jerry Nixon, Azure SQL Dev Corner
- Azure SQL Dev Corner blogu
- .NET ve PostgreSQL ile Azure’da Cache’i Ciddiye Almak







Yorum gönder