“Zaman zekâsı” ve “Gelişmiş zaman hesapları” derslerinde her şey ocakta başlayan Gregoryen takvimle çalıştı. Şirketlerde bu nadiren yeterlidir. Finans ekibi yılı temmuzda başlatır, mağaza ekibi haftayla yaşar, satın alma ekibi 4-4-5 dönemleriyle plan yapar. Bu derste aynı Tarih tablosunu üç takvime çevirecek ve hazır fonksiyonların nerede yanlış sayı ürettiğini göreceksin.
Üç ekip, üç takvim
Anadolu Market’te pazartesi sabahı üç ayrı istek geliyor:
- Finans: “Mali yılımız 1 Temmuz’da başlıyor. Mart 2024 satırında mali yılbaşından bugüne satışı görmek istiyorum.”
- Mağaza operasyonu: “Geçen haftayı, geçen yılın aynı haftasıyla karşılaştır. Pazartesiyi pazartesiyle karşılaştırmalıyız.”
- Satın alma: “Dönemlerimiz 4-4-5 haftalık. Her dönem pazartesi başlayıp pazar bitiyor. Dönem 3’ün toplamı lazım.”
| Takvim | Yıl nasıl başlar? | En küçük birim | Hazır fonksiyonlar çalışır mı? |
|---|---|---|---|
| Gregoryen | 1 Ocak | Gün → ay | Evet |
| Kaydırılmış Gregoryen (mali yıl) | Sabit bir tarih (1 Temmuz) | Gün → ay | Büyük ölçüde evet, yıl sonu parametresiyle |
| Hafta tabanlı (ISO, 4-4-5) | Bir pazartesi; tarihi her yıl değişir | Gün → hafta → dönem | Hayır; aylar ve yıllar tutmaz |
Modeldeki Tarih[HaftaNo] ISO 8601 hafta numarası, Tarih[GunNo] haftanın günüdür (1 = Pazartesi).
Mali yıl: Temmuz başlangıçlı yıl
Hazır yol: yıl sonu parametresi
DATESYTD ve TOTALYTD, isteğe bağlı bir yıl sonu tarihi (year_end_date) alır. Microsoft Learn’e göre bu bir metin sabitidir, yıl kısmı yok sayılır ve biçimi raporu oluşturan istemcinin yerel ayarına bağlıdır: bir makinede "6-30", diğerinde "30-6" olabilir. Varsayılan 31 Aralık’tır.
Mali YTD (hazır) = TOTALYTD([Net Satış], Tarih[Tarih], "6-30") Mali YTD (DATESYTD) = CALCULATE([Net Satış], DATESYTD(Tarih[Tarih], "6-30"))
Sütun ve tarih aritmetiğiyle aynı hesap
Mali YTD = VAR son = MAX(Tarih[Tarih]) VAR bas = IF(MONTH(son) >= 7, DATE(YEAR(son), 7, 1), DATE(YEAR(son) - 1, 7, 1)) RETURN CALCULATE([Net Satış], DATESBETWEEN(Tarih[Tarih], bas, son)) Mali YTD GY = CALCULATE([Mali YTD], SAMEPERIODLASTYEAR(Tarih[Tarih]))
Motor görünen dönemin son gününü (son) okur, mali yılın ilk gününü (bas) hesaplar, sonra DATESBETWEEN Tarih[Tarih] filtresini bu aralıkla değiştirir; işaretli tarih tablosunda Yıl ve Ay filtreleri de kalkar. Sonuçlar:
| Satır | Takvim YTD | Mali YTD | Mali YTD GY |
|---|---|---|---|
| Mart 2024 | 155.390,75 | 401.796,75 (Tem 2023–Mar 2024) | 169.796,10 (Tem 2022–Mar 2023) |
| Temmuz 2024 | — | 60.948,00 (yeni mali yılın ilk ayı) | — |
Tam mali yıllar: MY2023 256.705,75; MY2024 546.898,75; MY2025 henüz yarım, 446.572,95.
Mali yıl sütunları
Ölçülerin yanında rapor da mali yılı göstermeli. Tarih tablosuna üç sütun eklenir. Aşağıdaki sorgu bu sütunları üretip her ayın ilk gününde gösterir:
EVALUATE
ADDCOLUMNS(
FILTER(Tarih, Tarih[Gun] = 1),
"MaliYil", Tarih[Yil] + IF(Tarih[AyNo] >= 7, 1, 0),
"MaliAyNo", MOD(Tarih[AyNo] + 5, 12) + 1,
"MaliCeyrek", "MÇ" & (INT(MOD(Tarih[AyNo] + 5, 12) / 3) + 1)
)
- Adlandırma: Mali yıl bittiği yılla adlandırılır (Tem 2023–Haz 2024 = MY2024). Bu bir şirket kararıdır; belgele.
- Sıralama: Mali raporda ayları
MaliAyNo’ya göre sırala. - Toplam satırı: Toplamda son gün 31 Aralık 2024’tür; Mali YTD 446.572,95 gösterir, bu bütün yılların toplamı değildir. Gizle ya da
ISINSCOPEile boş döndür.
ISO hafta ve hafta tabanlı yıl
ISO 8601’e göre hafta pazartesi başlar. Yılın ilk haftası, o yılın ilk perşembesini içeren haftadır. Bu yüzden bir yıl 52 ya da 53 hafta sürer. Yılın ilk birkaç günü önceki yılın son haftasına, son birkaç günü sonraki yılın ilk haftasına düşebilir. DAX’ta WEEKNUM(tarih, 21) ISO hafta numarasını verir.
Modelde bunu görmek kolay: 1–2 Ocak 2022’nin HaftaNo değeri 52, 30–31 Aralık 2024’ün değeri 1’dir.
Anti-kalıp: Yıl × HaftaNo
Mağaza müdürü bir matrise Tarih[Yil] ve Tarih[HaftaNo] koyuyor. 2024 / Hafta 1 hücresinde 27.516,05 görünüyor. Oysa ISO 2024’ün ilk haftası (1–7 Ocak) 16.728,05’tir. Aradaki 10.788,00, 30–31 Aralık 2024’e aittir. O iki gün ISO 2025’in ilk haftasıdır ama Gregoryen yıl 2024 olduğu için aynı hücreye girer. Yani hafta 1 iki ayrı haftanın toplamıdır.
EVALUATE
ROW(
"Yanlis", CALCULATE([Net Satış], Tarih[Yil] = 2024, Tarih[HaftaNo] = 1),
"Dogru", CALCULATE([Net Satış],
FILTER(ALL(Tarih), YEAR(Tarih[Tarih] - Tarih[GunNo] + 4) = 2024 && Tarih[HaftaNo] = 1))
)
Çözüm, haftayla birlikte hafta tabanlı yılı da saklamaktır. Kural basit: bir günün ISO yılı, o haftanın perşembesinin yılıdır. Perşembe = Tarih - GunNo + 4. Haftanın başlangıcı = Tarih - GunNo + 1.
EVALUATE
ADDCOLUMNS(
FILTER(Tarih, Tarih[Tarih] >= DATE(2024, 12, 28)),
"ISOYil", YEAR(Tarih[Tarih] - Tarih[GunNo] + 4),
"HaftaBaslangic", Tarih[Tarih] - Tarih[GunNo] + 1,
"HaftaAnahtari", YEAR(Tarih[Tarih] - Tarih[GunNo] + 4) & "-H" & IF(Tarih[HaftaNo] < 10, "0", "") & Tarih[HaftaNo]
)
28–29 Aralık “2024-H52”, 30–31 Aralık “2025-H01” çıkar. Görselde ve dilimleyicide Yıl × HaftaNo yerine HaftaAnahtari (ya da ISOYil × HaftaNo) kullan.
Perakende 4-4-5 takvimi
Perakendede aylar karşılaştırılabilir değildir: bir ayda beş, diğerinde dört cumartesi olur. 4-4-5 takviminde yıl 52 haftadır, her çeyrek 13 haftadır ve çeyrek 4 + 4 + 5 haftalık üç döneme bölünür. Her dönem aynı gün başlar ve biter. 4-5-4 ve 5-4-4 de yaygındır.
Bedeli: Gregoryen yılla her yıl bir gün (artık yılda iki) kayma birikir ve 5–6 yılda bir 53. hafta eklenir. Bu haftanın hangi döneme gireceği bir iş kararıdır. 2026, 53 haftalık bir ISO yılıdır.
ISO haftayı perakende haftası olarak kabul edersek dönem numarası haftadan hesaplanır:
EVALUATE
VAR g =
ADDCOLUMNS(
FILTER(Tarih, YEAR(Tarih[Tarih] - Tarih[GunNo] + 4) = 2024),
"Donem",
VAR hw = Tarih[HaftaNo]
VAR c = MIN(4, INT((hw - 1) / 13) + 1)
VAR wq = hw - (c - 1) * 13
RETURN (c - 1) * 3 + IF(wq <= 4, 1, IF(wq <= 8, 2, 3)),
"S", [Net Satış]
)
RETURN GROUPBY(g, [Donem], "SatisliGun", COUNTX(CURRENTGROUP(), [S]), "Satis", SUMX(CURRENTGROUP(), [S]))
MIN(4, …) 53. haftayı dördüncü çeyreğe, wq 14 olduğu için de son döneme (D12) koyar. 2024 perakende yılının sonuçlarından birkaçı: D1 (4 hafta) 43.545,85; D3 (5 hafta) 63.251,60; D12 (5 hafta) 105.592,25. Beş haftalık dönemi dört haftalıkla doğrudan karşılaştırma; haftalık ortalamaya bak.
Hafta bazlı karşılaştırma: 364 gün geri
Mağaza ekibinin sorusuna dönelim: ISO 2024’ün 10. haftası (4–10 Mart 2024) net satışı 23.869,65. Geçen yılın karşılığı ne?
| Yöntem | Karşılaştırılan günler | Sonuç |
|---|---|---|
SAMEPERIODLASTYEAR | 4–10 Mart 2023 (Cumartesi–Cuma) | 7.998,30 |
DATEADD(Tarih[Tarih], -364, DAY) | 6–12 Mart 2023 (Pazartesi–Pazar) | 7.126,30 |
SAMEPERIODLASTYEAR takvim tarihini korur, haftanın gününü değil. “Zaman serisi analizi” dersindeki gün etkisi yüzünden farklı gün karışımlı iki pencereyi karşılaştırmak büyüme oranını bozar. 364 = 52 × 7 olduğu için DATEADD(…, -364, DAY) her günü haftanın aynı gününe taşır.
Satış GY Hafta Hizalı = CALCULATE([Net Satış], DATEADD(Tarih[Tarih], -364, DAY))
Kenar durumlar
- Yıl düzeyi: 2024 satırında 364 gün kaydırma 2 Ocak 2023–2 Ocak 2024 penceresini verir: 402.716,95;
[Satış GY]ise 400.869,55. Hizalı ölçüyü yalnızca hafta ve gün kırılımlarında kullan. - 53 haftalık yıl: 53. haftanın geçen yılda karşılığı yoktur. Boş mu bırakılacak, 52. haftayla mı karşılaştırılacak? Kararı iş birimiyle ver ve ölçü açıklamasına yaz.
- Eksik veri: Satışlar 22 Haziran 2022’de başlıyor; 2022’de hizalı geçen yıl boştur, büyüme için
DIVIDEkullan.
Hazır fonksiyonlar nerede bozulur?
| Fonksiyon | Mali yıl (kaydırılmış) | Hafta tabanlı / 4-4-5 |
|---|---|---|
TOTALYTD, DATESYTD | Yıl sonu parametresiyle doğru | Yanlış: yıl başı sabit bir tarih değil |
SAMEPERIODLASTYEAR, DATEADD(…, YEAR) | Doğru (12 ay kaydırma) | Haftanın günü kayar |
TOTALMTD, PREVIOUSMONTH | Doğru (aylar aynı) | Yanlış: dönem ay değildir |
PARALLELPERIOD(…, QUARTER) | Takvim çeyreği döner, mali çeyrek değil | 13 haftalık çeyrek değil |
STARTOFYEAR, ENDOFYEAR | Yıl sonu parametresi alır | Gregoryen yıl sınırları |
Hazır fonksiyonlar takvimi tarih aritmetiğiyle bilir; mantık sütunlarda yaşıyorsa (ISOYil, Donem, HaftaSira) bunu göremez.
Sütun tabanlı özel zaman zekâsı
Hazır fonksiyonların yerine üç adımlı bir kalıp kullanılır:
- Görünen bağlamdan konumu oku:
MAX(Tarih[Tarih]),MAX(Tarih[HaftaSira]). - Tarih tablosundaki filtreleri kaldır:
REMOVEFILTERS(Tarih)ya daALL(Tarih). - Yeni dönemi sütunlarla tarif et:
Tarih[ISOYil] = y && Tarih[Tarih] <= son.
Örneğin hafta başından bugüne (WTD) yalnızca tarih aritmetiğiyle yazılabilir:
Hafta Başından Satış = VAR son = MAX(Tarih[Tarih]) VAR bas = son - WEEKDAY(son, 2) + 1 RETURN CALCULATE([Net Satış], DATESBETWEEN(Tarih[Tarih], bas, son))
Üretim modelinde ise sütunlar fiziksel olarak Tarih tablosunda (Power Query ya da kaynakta) bulunur. HaftaSira, ilk haftadan itibaren 1, 2, 3… diye artan bir sıradır. “Önceki hafta” için HaftaNo - 1 yeterli değildir, çünkü 1. haftanın öncesi 0 değil, geçen yılın 52. ya da 53. haftasıdır:
Önceki Hafta (sütunla) = VAR s = MAX(Tarih[HaftaSira]) RETURN CALCULATE([Net Satış], REMOVEFILTERS(Tarih), Tarih[HaftaSira] = s - 1) Perakende YTD (sütunla) = VAR y = MAX(Tarih[ISOYil]) VAR son = MAX(Tarih[Tarih]) RETURN CALCULATE([Net Satış], REMOVEFILTERS(Tarih), Tarih[ISOYil] = y, Tarih[Tarih] <= son)
| Yol | Ne zaman? | Performans | Bakım |
|---|---|---|---|
Tarih aritmetiği (DATESBETWEEN, DATEADD … DAY) | Kural sabit gün sayısıyla anlatılabiliyorsa | İyi | Kolay ama kural kodda gizli |
FILTER(ALL(Tarih), ifade) | Hızlı deneme, sütun eklenemiyorsa | Her satırda ifade hesaplanır; büyük takvimde yavaşlar | Zor: aynı ifade her ölçüde tekrar eder |
Fiziksel sütunlar + REMOVEFILTERS | Kalıcı model, ekip çalışması | En iyi: basit sütun filtreleri depolama motoruna gider | Kolay: kural tek yerde, Tarih tablosunda |
“DAX optimizasyonu” dersinde gördüğün gibi basit sütun eşitlikleri depolama motorunda çözülür; satır satır ifade hesaplayan FILTER formül motoruna iş bırakır.
REMOVEFILTERS(Tarih) olmadan, rapordaki Gregoryen Yıl = 2024 dilimleyicisi 2025-H01’in 30–31 Aralık günleriyle kesişir ve hafta yarım görünür.Test: Her özel ölçüyü DAX sorgu görünümünde bilinen bir haftayla (2024-H10 = 23.869,65) ve yılın ilk/son haftasıyla dene.
Takvim tabanlı zaman zekâsı (önizleme)
Power BI 2025’te bu sorunu doğrudan çözen bir özellik getirdi: takvim tabanlı zaman zekâsı (calendar-based time intelligence). Tarih tablosunda bir ya da birkaç takvim tanımlarsın; zaman zekâsı fonksiyonlarına tarih sütunu yerine takvimin adını verirsin. Microsoft Learn sayfası özelliği Ekim 2026 itibarıyla hâlâ önizleme olarak etiketliyor.
Nasıl açılır, nasıl tanımlanır?
- Dosya → Seçenekler ve ayarlar → Seçenekler → Önizleme özellikleri altında “Enhanced DAX Time Intelligence” seçeneğini işaretle ve Desktop’ı yeniden başlat.
- Tarih tablosuna sağ tıkla → Takvim seçenekleri (Calendar options) → Yeni takvim.
- Kategori ekle ile sütunları kategorilere bağla: Yıl, Çeyrek, Ay, Hafta, Tarih ve “yılın haftası”, “haftanın günü” gibi kısmi kategoriler. Her kategorinin bir birincil sütunu, isteğe bağlı ilişkili sütunları olur. “Tam” (complete) kategoriler bir dönemi tek başına tanımlar (2024-H10); “kısmi” kategoriler tanımlamaz (H10).
table Tarih
calendar 'Perakende 445'
calendarColumnGroup = year
primaryColumn: ISOYil
calendarColumnGroup = month
primaryColumn: DonemAnahtari
calendarColumnGroup = week
primaryColumn: HaftaAnahtari
calendarColumnGroup = date
primaryColumn: Tarih
Perakende YTD = TOTALYTD([Net Satış], 'Perakende 445')
Perakende WTD = TOTALWTD([Net Satış], 'Perakende 445')
Perakende GY = CALCULATE([Net Satış], DATEADD('Perakende 445', -1, YEAR))
Böylece TOTALWTD gibi hafta fonksiyonları kullanılabilir, “geçen yıl” takvimin kendi yılına göre hesaplanır. DATEADD ve SAMEPERIODLASTYEAR “sabit” fonksiyonlardır: yalnızca yana doğru kaydırır. Diğerleri esnektir. Bir takvim sütununa bağlam koymak, o kategorinin üstündeki ve altındaki kategorilerdeki bağlamı temizler.
| Klasik | Takvim tabanlı (önizleme) | |
|---|---|---|
| Takvim türü | Gregoryen ya da kaydırılmış Gregoryen | Her türlü takvim |
| Hafta hesapları | Yok | Var |
| Yazım | SAMEPERIODLASTYEAR(Tarih[Tarih]) | TOTALYTD([Net Satış], 'Mali') |
Sınırlamalar (Learn’e göre)
- Canlı bağlantılı ve bileşik (composite) modellerde takvim kullanılamaz.
- Takvimler henüz Power BI Service’te yazılamaz; Desktop ya da harici araç gerekir.
- Otomatik tarih/saat tablolarıyla birlikte kullanılmamalı.
- Takvim tanımlı ve satır düzeyi güvenliğe (RLS) tabi bir olgu tablosunda beklenmedik sonuçlar çıkabilir.
- Takvim kullanan zaman zekâsı fonksiyonları iç içe yazılamaz:
PREVIOUSDAY(PREVIOUSMONTH('Takvim'))yerineCALCULATETABLE(PREVIOUSDAY('Takvim'), PREVIOUSMONTH('Takvim')). - Bir sütun tek kategoriye bağlanır; tabloda 200’den az sütun olmalı.
- Yıl sonu parametresi (
"6-30") yalnızca tarih sütunu yazımında geçerlidir; takvim yazımında mali yıl, takvim tanımının içindedir.
Üretim kararı: Önizleme özelliği kurumsal bir modelde ana yol olmamalı. Bugün sütun tabanlı kalıbı kur; ISOYil, HaftaAnahtari, DonemAnahtari gibi sütunları zaten hazırlamış olacağın için özellik genel kullanıma geçtiğinde takvim tanımına taşımak kolaylaşır.
Kontrol listesi
- Mali yıl adlandırması (bittiği yıl mı, başladığı yıl mı) belgelendi mi?
- Hafta görsellerinde Yıl × HaftaNo değil, ISOYil × HaftaNo ya da HaftaAnahtari mı kullanılıyor?
- Hafta karşılaştırmaları 364 gün mü, takvim tarihi mi? 53. hafta kuralı ne?
- Sütun tabanlı ölçülerde
REMOVEFILTERS(Tarih)var mı? Toplam satırı ne gösteriyor?