> ## Documentation Index
> Fetch the complete documentation index at: https://docs.diyanet.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# BuildingBlocks.Time

> Saat soyutlaması — IClock, SystemClock, FakeClock ve AsyncLocal scoped override ile deterministik test.

`BuildingBlocks.Time`, sistem saatini soyutlar. Kodun her yerinde `DateTime.UtcNow` çağırmak yerine `IClock` (veya statik `Time` fasadı) kullanılır; böylece zamana bağlı mantık (OTP süresi, TOTP pencere hesabı, token expiry) **deterministik şekilde test edilebilir** olur.

## Neden zaman soyutlanır?

`DateTime.UtcNow` global ve kontrol edilemez bir bağımlılıktır. Soyutlama olmadan şu testler kararsız (flaky) olur:

* OTP'nin 3 dakika sonra **süresinin dolması**
* TOTP'nin ±1 zaman penceresinde doğrulanması
* Refresh token'ın geçerlilik kontrolü

`IClock`/`FakeClock` ile zaman sabitlenir ve "tam sınırda ne olur?" senaryoları net biçimde sınanır.

## Arayüz ve implementasyonlar

| Tip                    | Üye                                                         | Açıklama           |
| ---------------------- | ----------------------------------------------------------- | ------------------ |
| `IClock`               | `DateTime UtcNow { get; }`                                  | Soyut sistem saati |
| `SystemClock : IClock` | `static SystemClock Instance` · `UtcNow => DateTime.UtcNow` | Prod — singleton   |
| `FakeClock : IClock`   | `FakeClock(DateTime utc)` · `UtcNow => _utc`                | Test — sabit zaman |

```csharp theme={null}
public interface IClock
{
    DateTime UtcNow { get; }
}
```

### Statik `Time` fasadı

DI gerektirmeyen, async-flow güvenli statik bir giriş noktası da vardır. `AsyncLocal` tabanlı scoped override ile testte zamanı geçici olarak değiştirir; ayrıca Türkiye yerel saatini sağlar.

| Üye                     | Döner                                               |
| ----------------------- | --------------------------------------------------- |
| `Time.UtcNow`           | Override-aware UTC (yoksa `SystemClock`)            |
| `Time.Now`              | Europe/Istanbul yerel saati                         |
| `Time.Today`            | Türkiye tarihi                                      |
| `Time.Override(IClock)` | `IDisposable Scope` — dispose'da önceki saate döner |

## DI kaydı

`IClock` singleton olarak kaydedilir (prod'da `SystemClock`).

```csharp theme={null}
// Program.cs / Infrastructure DI
services.AddSingleton<IClock>(SystemClock.Instance);
```

```csharp theme={null}
// Kullanım — zamana bağlı mantık
public sealed class OtpChallenge(IClock clock)
{
    private readonly DateTime _expiresAt;
    public OtpChallenge(IClock clock, int expireMinutes)
        => _expiresAt = clock.UtcNow.AddMinutes(expireMinutes);

    public bool IsExpired(IClock clock) => clock.UtcNow >= _expiresAt;
}
```

## Test — sabit zaman

`FakeClock` ile "şimdi"yi sabitleyip sınır koşullarını deterministik test edin:

```csharp theme={null}
[Fact]
public void Otp_Tam_3_Dakika_Sonra_Suresi_Dolar()
{
    var t0 = new DateTime(2026, 6, 3, 10, 0, 0, DateTimeKind.Utc);
    IClock atStart = new FakeClock(t0);

    var challenge = new OtpChallenge(atStart, expireMinutes: 3);

    // 2 dk 59 sn → hâlâ geçerli
    Assert.False(challenge.IsExpired(new FakeClock(t0.AddSeconds(179))));
    // 3 dk 00 sn → süresi doldu
    Assert.True(challenge.IsExpired(new FakeClock(t0.AddMinutes(3))));
}
```

Statik `Time` kullanan kod için scoped override:

```csharp theme={null}
using (Time.Override(new FakeClock(new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc))))
{
    // bu blok içinde Time.UtcNow sabit; dispose'da gerçek saate döner
    var result = ServiceUsingStaticTime.DoWork();
    Assert.Equal(2026, result.Year);
}
```

<Tip>
  `FakeClock` salt-okunur sabit zaman tutar (mutable "advance" yoktur); ilerleyen zaman gerektiren senaryolarda farklı `FakeClock` instance'ları geçirin ya da `Time.Override`'ı yeni bir saatle tekrar sarın.
</Tip>

<Note>
  `Time` fasadı yerel saat için Europe/Istanbul'u (yoksa "Turkey Standard Time") çözer. Kalıcı veriyi daima UTC saklayın; yerelleştirmeyi yalnızca görüntüleme katmanında yapın.
</Note>

## İlgili

<CardGroup cols={2}>
  <Card title="OTP" icon="key" href="/building-blocks/otp">
    Kod süresi ve throttle hesapları.
  </Card>

  <Card title="Authenticator (TOTP)" icon="mobile-screen" href="/services/authenticator">
    RFC6238 zaman penceresi doğrulaması.
  </Card>

  <Card title="JWT" icon="id-card" href="/building-blocks/jwt">
    Token expiry ve clock skew.
  </Card>

  <Card title="Domain" icon="cube" href="/domain/overview">
    Aggregate'lerde zamana bağlı kurallar.
  </Card>
</CardGroup>
