/calendar
// import { LIFETIME, cycleKey, cycleWindow, monthKey, monthWindow } from "pricemeter/calendar";const t = Date.parse("2026-09-30T22:30:00Z"); // already October 1st in Istanbul (UTC+3)
monthKey({ at: t }); // "2026-09"monthKey({ at: t, tz: "Europe/Istanbul" }); // "2026-10"monthWindow({ at: t, tz: "Europe/Istanbul" }); // { from: 2026-09-30T21:00Z, to: 2026-10-31T21:00Z }
// A subscription started on Jan 31st renews on the last day of shorter months.const anchor = Date.parse("2026-01-31T00:00:00Z");cycleKey({ at: Date.parse("2026-03-10T00:00:00Z"), anchor }); // "2026-02-28"cycleWindow({ at: Date.parse("2026-03-10T00:00:00Z"), anchor }); // { from: 2026-02-28, to: 2026-03-31 }
LIFETIME; // "*" — the period key for counters that never resetÇekirdek takvim okumaz (A72); “bu dönem” nedir sorusu uygulamanındır. pricemeter/calendar bu soruyu yanıtlamanın saf yardımcılarını verir: usedSoFar sayacının hangi döneme ait olduğunu seçen anahtarlar ve integrate() ile sayaç sorguları için pencereler.
| API | Döner |
|---|---|
monthKey({ at, tz? }) |
"2026-09": tz saat dilimindeki takvim ayı (varsayılan UTC) |
monthWindow({ at, tz? }) |
O ayın yarı açık [from, to) penceresi, epoch ms |
cycleKey({ at, anchor, tz? }) |
"2026-09-15": anchor’ın ayın gününe bağlı döngünün yerel başlangıç tarihi |
cycleWindow({ at, anchor, tz? }) |
O döngünün [from, to) penceresi. 31’inde başlayan döngü kısa aylarda ayın son günü yenilenir |
LIFETIME |
"*": hiç sıfırlanmayan sayaçların dönem anahtarı (B16) |
Saat dilimleri Intl ile çözülür; yerel gece yarısının var olmadığı günler (00:00’da DST) doğru işlenir. Pencereler yarı açıktır: dönem sonu gözlemi at: window.to − 1 ile yapılır, çünkü window.to bir sonraki dönemi seçer (A98).
getRate içinde
Bölüm başlığı “getRate içinde”const mem = memoryAdapters({ rates: { sms: flat(0) }, periodOf: (at) => monthKey({ at, tz: "Europe/Istanbul" }) });const metering = buildMetering() .context<{ accountId: string; tz: string }>() .refs(["send"]) .meter("sms") .getRate(async (meter, _dims, ctx, at) => ({ rate: { model: "graduated", tiers: [{ from: 0, unitPriceMicroUsd: 0 }, { from: 500, unitPriceMicroUsd: 20_000 }], policy: { tierPeriod: "month" } }, usedSoFar: mem.store.used(ctx.accountId, meter, monthKey({ at, tz: ctx.tz })), // this local month's counter })) .commit(mem.commit);Sayaç deposu ve getRate aynı anahtarı kullanmalıdır: burada memoryAdapters({ periodOf }) satırları yerel aya göre sayar, getRate de aynı ayın sayacını okur. policy.tierPeriod: "month" bu seçimi tarifeye not eder; lib onu okumaz. SQLite’ta anahtar yerine pencere kullanılır: usedSoFar({ account, meter, from, to }).
Bunu kullanmadan nasıl yapardım
Bölüm başlığı “Bunu kullanmadan nasıl yapardım”UTC takvim ayı için new Date(at).toISOString().slice(0, 7) yeterlidir. Modül şu durumlarda işe yarar: UTC dışı bir saat dilimi (İstanbul’da 30 Eylül 22:30 UTC zaten Ekim’dir), abonelik gününe bağlı döngüler (31 Ocak → 28 Şubat → 31 Mart) ve DST geçişleri. Zaten bir takvim kütüphanen (Temporal, date-fns-tz, Luxon) varsa onunla aynı anahtarı üret; kütüphane anahtarın nereden geldiğini bilmez.