---
title: 'Zaman İşlemleri'
source: 'https://academia.sh/tr/kurslar/go-uygulamalar/zaman-islemleri'
course: 'Standart Kütüphane ve Ağ Uygulamaları'
language: tr
updated: '2026-08-23T16:55:14+00:00'
license: 'CC BY-SA 4.0'
---

# Zaman İşlemleri

Bir anın metne dönüp geri gelmesi ölçülür: an kendisi Equal ile korunuyor, ama sayısal saat dilimi ofseti geri kurulsa bile bölgenin adı taşınmıyor. time.Duration'ın bir sayı değil kendi tipiyle taşınan bir değer olduğu gösterilir. Sınırlayıcı ölçüm, aynı anı gösteren iki değerin Equal ile eşit çıkarken == ve String() ile farklı çıktığını koşturarak ortaya koyuyor.

Önceki ders bir bağın koşum zamanına değil derleme zamanına kurulabileceğini gösterdi: bir
kaynak dosyanın içeriği, programın kendisiyle birlikte donuyordu. Zaman bunun tam tersi bir
örnek sunuyor — hiçbir değer, "an" kadar koşumun kendisine bağlı. Bir an, ölçüldüğü ânın
kendisiyle tanımlanıyor; onu bir metne yazıp geri okumak, önceki iki derste ölçülen
kayıplardan farklı bir tür kayba yol açıyor.

Bu farkın somut sonucu şu: dosya ve arabellek dersinde sınırı geçen veri hiçbir zaman tip
bilgisi taşımıyordu — kayıp her defasında tamdı. Zaman değerinde durum daha ince: sınırı geçen
metin bazı bilgiyi taşıyor, bazısını taşımıyor, ve hangisinin hangi kategoriye girdiği
kullanılan yazım düzenine bağlı. Bu ders üç ayrı değeri (an, saat dilimi, süre) aynı
"metne dönüp geri gelme" sınavından geçirip her birinin ne kadarının hayatta kaldığını ayrı
ayrı ölçüyor.

**Belirlenimcilik notu:** bu derste gerçek saat hiç okunmuyor (`time.Now` hiçbir yerde
çağrılmıyor). Bütün örnekler sabit bir metinden ayrıştırılan tek bir ana dayanıyor;
karşılaştırmalar da bu sabit anın üzerine kuruluyor.

## Sabit Bir Andan Başlamak

Go'nun standart kitaplığında bir anı temsil eden tip `time.Time`; `time.Parse` bir dizgiyi
belirli bir **düzene** (`layout`) göre okuyup bir `time.Time` değeri üretiyor. Bu derste
kullanılan düzen RFC 3339 — ağ ve dosya biçimlerinde yaygın kullanılan, saat dilimini de
taşıyan bir zaman yazımı.

```go
// sabit-an.go — gercek saat okunmuyor, an sabit bir metinden ayristiriliyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sabitAn, err := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")
	if err != nil {
		panic(err)
	}
	fmt.Printf("ayristirilan deger tipi=%T\n", sabitAn)
	fmt.Println("saat dilimi (Z = UTC)  :", sabitAn.Location())
}
```

```
ayristirilan deger tipi=time.Time
saat dilimi (Z = UTC)  : UTC
```

Dizginin sonundaki `Z` harfi, RFC 3339 düzeninde "UTC, sıfır ofset" anlamına geliyor;
`time.Parse` bunu tanıyıp sonucu doğrudan `time.UTC` konumuna bağlıyor. Bu ders boyunca
kullanılan tek "gerçek" veri bu sabit dizgi; ondan sonraki her adım bu değerden türetiliyor.
`time.Parse`in ikinci argümanı ayrıştırılacak metin, ilk argümanı ise beklenen **düzen** —
metnin kendisi değil, metnin biçiminin bir örneği. Bu örnek yalnızca yer tutucu değil, gerçek
bir tarih: `time.RFC3339` sabiti Go'nun standart kitaplığında `2006-01-02T15:04:05Z07:00`
biçiminde tanımlı, ve bu belirli tarih (ay/gün/saat/dakika/saniye/yıl'ın Go'nun kendi iç
sıralamasında karşılık gelen rakamları) düzeni belirtmenin standart yolu; başka bir dilin
`YYYY-MM-DD` gibi soyut yer tutucularından farklı bir yaklaşım.

Bir `time.Time` değeri her zaman aynı türden veri taşımıyor. Yalnızca `time.Now()`
çağrısından gelen değerler, saat farkı ölçümlerinde kullanılan bir **tek yönlü sayaç**
okuması (`duvar saati`nden ayrı, yalnızca ileri akan bir sayım) taşıyor; `time.Parse` gibi
bir metinden türeyen değerler bu ek okumayı hiç taşımıyor, yalnızca düz bir duvar saati
değeri oluyor. Bu ders yalnızca `time.Parse` kullandığından, ölçülen her değer bu ikinci,
"tek düze" türden.

## Zaman Metne Dönüp Geri Geldiğinde

**SS8.** — Sabit an `Format` ile metne çevrilip aynı düzenle geri `Parse` ediliyor. Bu, Ağ ve
Veri Biçimleri konusunun ortak çekirdeğinde de bir satır olarak geçen geçiş (zaman değeri
metne ve geri: yeniden kuruluyor); o konunun bağlayıcı 1/5/7 dağılımına burada tek cümleyle
atıf yapılıyor, çekirdek yeniden kurulmuyor. Bu ders o satırı doğrulayıp saat dilimine özgü
bir ayrıntıyla genişletiyor.

```go
// metne-geri.go — bir an metne yazilip ayni duzenle geri okunuyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sabitAn, _ := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")

	metin := sabitAn.Format(time.RFC3339)
	geri, _ := time.Parse(time.RFC3339, metin)

	fmt.Println("metne donen yazim :", metin)
	fmt.Println("ayni an mi (Equal):", geri.Equal(sabitAn))
	fmt.Printf("geri gelen tip    : %T\n", geri)
}
```

```
metne donen yazim : 2026-08-23T10:00:00Z
ayni an mi (Equal): true
geri gelen tip    : time.Time
```

Bir `time.Time` değeri bir dizgiye yazıldığında tip bilgisi tamamen kayboluyor — sonuç sıradan
bir metin, içinde "bu bir zaman" diyen hiçbir işaret yok. Ama `time.Parse` çağıran taraf
elindeki dizginin bir zaman **olduğunu zaten biliyor** ve doğru düzeni vererek onu geri
kuruyor; kayan bilgi, çağıranın elindeki bu bilgiyle **yeniden kuruluyor**. `Equal` sonucu
`true`: geri kurulan an, orijinal anla birebir aynı. Konunun ölçü ekseninde bu satır
"yeniden kuruluyor" sınıfına giriyor — tıpkı bir yapı etiketinin JSON'dan geri kurulması gibi,
burada da geri kurmayı sağlayan şey dizginin kendisi değil, çağıranın bildiği **düzen**.

## Saat Dilimi Adı Taşınmıyor

Yukarıdaki ölçüm bir ayrıntıyı gizliyor: sabit an tam olarak UTC'de, yani sıfır ofsette.
RFC 3339 düzeni sıfır ofseti `Z` harfiyle özel olarak işaretlediği için, geri kurulan değer de
tam olarak `time.UTC`'ye bağlanıyor. Sıfırdan farklı bir ofset söz konusu olduğunda tablo
değişiyor.

**SS9.** — Sabit an, adı **`BolgeA`** olan (gerçek bir coğrafi bölgeye değil, yalnızca +03:00
ofsetine sahip **kurgusal** bir saat dilimine) çevriliyor, metne yazılıp geri okunuyor. Ölçüm
hem sayısal ofseti hem bölge adını ayrı ayrı karşılaştırıyor.

```go
// bolge-adi.go — sayisal ofset korunuyor, bolgenin adi tasinmiyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sabitAn, _ := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")
	bolgeA := time.FixedZone("BolgeA", 3*3600)
	yerel := sabitAn.In(bolgeA)

	metin := yerel.Format(time.RFC3339)
	geri, _ := time.Parse(time.RFC3339, metin)

	yerelAd, yerelOfset := yerel.Zone()
	geriAd, geriOfset := geri.Zone()

	fmt.Println("metne donen yazim :", metin)
	fmt.Println("ayni an mi (Equal):", yerel.Equal(geri))
	fmt.Println("ofset korunuyor mu:", yerelOfset == geriOfset)
	fmt.Println("bolge adi tasindi mi:", yerelAd == geriAd)
}
```

```
metne donen yazim : 2026-08-23T13:00:00+03:00
ayni an mi (Equal): true
ofset korunuyor mu: true
bolge adi tasindi mi: false
```

RFC 3339 düzeni bir saat diliminin **adını** hiç taşımıyor, yalnızca sayısal ofsetini
(`+03:00`) yazıyor. Geri okunduğunda `time.Parse` bu ofseti doğru biçimde geri kuruyor — an
hâlâ aynı, `Equal` hâlâ `true`, ofset karşılaştırması da `true`. Ama bölge **adı**
(`"BolgeA"`) hiçbir yerde metne yazılmadığı için geri gelmiyor; `Parse`in ürettiği yeni
konumun adı, orijinal `"BolgeA"`dan farklı çıkıyor. Bu, kaydın önceki dersle aynı biçimde
okunuyor: sayısal ofset **yeniden kuruluyor**, çünkü metnin kendisi onu taşıyor; bölge adı ise
**kayboluyor**, çünkü metnin kendisi onu hiç taşımıyor. Aynı geçiş, taşınan bilginin **parçasına**
göre iki farklı sınıfa giriyor.

## time.Duration Bir Tiptir, Bir Sayı Değil

Bir sürenin kendisi de Go'da ayrı bir tip taşıyor: `time.Duration`, altında bir `int64`
saklayan ama kendi başına bir tip olan, nanosaniye cinsinden bir süre. Bir sayıdan farkı,
bir sayının aksine kendi biçimlendirmesini (`1h30m0s` gibi) taşıması ve başka bir süreyle
karıştırılmasının derleyici tarafından reddedilmesi.

**SS10.** — Bir süre dizgisi (`"1h30m"`) ayrıştırılıp tipi ve biçimlendirilmiş yazımı
ölçülüyor; ardından aynı değerin ham bir tam sayı karşılığıyla eşit olup olmadığı ve iki katına
katlandığında biçimlendirmenin nasıl değiştiği koşturuluyor.

```go
// sure-tipi.go — time.Duration kendi tipini tasiyor, ham sayidan ayri
package main

import (
	"fmt"
	"time"
)

func main() {
	sure, _ := time.ParseDuration("1h30m")
	fmt.Printf("sure tipi=%T deger=%s\n", sure, sure)
	fmt.Println("int64 karsiligina esit mi:", int64(sure) == 5400_000_000_000)

	ikiKat := sure * 2
	fmt.Println("iki kati:", ikiKat)
	fmt.Println("saat cinsinden:", ikiKat.Hours())
}
```

```
sure tipi=time.Duration deger=1h30m0s
int64 karsiligina esit mi: true
iki kati: 3h0m0s
saat cinsinden: 3
```

`sure` değişkeninin altında yatan veri bir `int64` — nanosaniye sayısı — ama `%T` onu ham bir
tam sayı olarak değil, `time.Duration` olarak gösteriyor, ve `fmt.Println` onu doğrudan
yazdırdığında `5400000000000` değil `1h30m0s` çıkıyor. Bu, tam sayı ile süre arasında
derleyicinin kurduğu bir ayrım: `sure`ün altındaki `int64` değeri ile başka bir `int64`
değişken arasında örtük dönüşüm yok, ikisi ayrı tipler. `ikiKat := sure * 2` çarpımı süre
tipini koruyor ve biçimlendirmesi de otomatik olarak güncelleniyor — `3h0m0s`, `Hours()`
yöntemiyle sorgulandığında da `3` veriyor.

Süre de, tıpkı bir an gibi, metne dönüp geri gelebiliyor — ve bu geçiş bir anın geçişinden
daha az kayıplı çıkıyor.

**SS11.** — `sure` değişkeni `String()` ile metne çevrilip aynı metin `ParseDuration` ile
geri okunuyor; ayrıca sözdizimi bozuk bir metin de deneniyor.

```go
// sure-metne-geri.go — sure metne donup geri geliyor, gecersiz metin reddediliyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sure, _ := time.ParseDuration("1h30m")
	metin := sure.String()
	geri, hataGeri := time.ParseDuration(metin)
	fmt.Println("sure metne donusumu:", metin)
	fmt.Println("geri ayni deger mi :", geri == sure)
	fmt.Println("geri okuma hatasiz mi:", hataGeri == nil)

	_, hataGecersiz := time.ParseDuration("1h30mx")
	fmt.Println("gecersiz metin hata verdi mi:", hataGecersiz != nil)
}
```

```
sure metne donusumu: 1h30m0s
geri ayni deger mi : true
geri okuma hatasiz mi: true
gecersiz metin hata verdi mi: true
```

Bir anın metne dönüşünden farklı olarak, `time.Duration`ın yazımı hiçbir bilgi kaybetmiyor:
`geri == sure` karşılaştırması `true`, çünkü `String()`ün ürettiği metin (`1h30m0s`) süreyi
oluşturan her birimi (saat, dakika, saniye) tam olarak taşıyor — bir sürenin bir "adı" ya da
"bağlamı" yok, taşıdığı tek bilgi kendi uzunluğu, ve bu bilgi metne tam olarak sığıyor. Bu,
saat diliminin adını taşıyamayan bir önceki ölçümle tam bir karşıtlık: kaybın olup olmaması,
taşınan değerin **kendisinin** ne kadar bilgi içerdiğine bağlı, kullanılan yazım biçiminin
kendisine değil. Son satır ayrı bir gözlem ekliyor: sözdizimi bozuk bir süre metni sessizce
`0`a düşmüyor, `ParseDuration` bunu bir hatayla reddediyor — süre burada da derleme zamanı
değil ama en azından ayrıştırma zamanı bir denetimden geçiyor.

## Sınırlayıcı Ölçüm: Aynı An, İki Yazım

Buraya kadarki ölçümler bir anı **tek** bir saat diliminde inceledi. Aşağıdaki adım aynı anı
**iki farklı** kurgusal bölgede temsil edip üç ayrı karşılaştırma aracını (`Equal`, `==`,
`String`) yan yana koşturuyor.

**SS12.** — İki kurgusal bölge (`BolgeA` +03:00, `BolgeB` −05:00) aynı sabit ana uygulanıyor.
Üçü de "aynı mı" sorusuna farklı bir yanıt veriyor.

```go
// iki-yazim.go — ayni an iki bolgede, uc ayri karsilastirma araciyla olculuyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sabitAn, _ := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")
	bolgeA := time.FixedZone("BolgeA", 3*3600)
	bolgeB := time.FixedZone("BolgeB", -5*3600)

	gorunumA := sabitAn.In(bolgeA)
	gorunumB := sabitAn.In(bolgeB)

	fmt.Println("BolgeA yerel saat :", gorunumA.Format("15:04"))
	fmt.Println("BolgeB yerel saat :", gorunumB.Format("15:04"))
	fmt.Println("Equal ile ayni mi :", gorunumA.Equal(gorunumB))
	fmt.Println("== ile ayni mi    :", gorunumA == gorunumB)
	fmt.Println("String() ayni mi  :", gorunumA.String() == gorunumB.String())
}
```

```
BolgeA yerel saat : 13:00
BolgeB yerel saat : 05:00
Equal ile ayni mi : true
== ile ayni mi    : false
String() ayni mi  : false
```

Üç karşılaştırma aracı üç farklı soruya yanıt veriyor. `Equal`, iki değerin temsil ettiği
**anı** karşılaştırıyor — ikisi de aynı ana ait olduğu için sonuç `true`. `==` işleci ise
`time.Time`in **iç yapısını** birebir karşılaştırıyor; bu yapı saat dilimi bilgisini de
içerdiğinden, iki farklı bölgeye bağlı iki değer `==` ile eşit çıkmıyor. `String()` de aynı
nedenle farklı: her biri kendi yerel saatini ve ofsetini yazıyor, biri "13:00 +03:00" biri
"05:00 -05:00" — metin düzeyinde hiç örtüşmüyorlar.

Bu üçü arasındaki fark, Go'nun belgesinde açıkça uyarılan bir tuzak: `==` işleci `time.Time`
değerleri için **kullanılmaması gereken** bir karşılaştırma, çünkü onu kullanan kod "aynı an
mı" sorusunu değil, "aynı temsil mi" sorusunu yanıtlıyor — çoğu zaman istenen ilk soru, ama
işlecin kendisi ikinciye yanıt veriyor. Konunun ölçü ekseninde bu, bu derse özgü bir sınır
çiziyor: iki değer aynı anı gösterdiğinde bile, karşılaştırma aracının **kendisi** seçilen
soruyu belirliyor; "aynı" sözcüğü tek başına hangi karşılaştırmanın kastedildiğini söylemiyor.

Aynı ayrım sıralama için de geçerli. `Before` ve `After` yöntemleri, tıpkı `Equal` gibi,
temsile değil ana bakıyor; iki değer farklı bölgelerde yazılmış olsa bile hangisinin
zamanda daha önce geldiğini doğru söylüyor.

```go
// siralama.go — Before ve After da temsile degil ana bakiyor
package main

import (
	"fmt"
	"time"
)

func main() {
	sabitAn, _ := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")
	birSaatSonra := sabitAn.Add(time.Hour)

	bolgeA := time.FixedZone("BolgeA", 3*3600)
	gorunumA := sabitAn.In(bolgeA)
	gorunumSonraB := birSaatSonra.In(time.FixedZone("BolgeB", -5*3600))

	fmt.Println("gorunumA, gorunumSonraB'den once mi:", gorunumA.Before(gorunumSonraB))
	fmt.Println("gorunumSonraB, gorunumA'dan sonra mi:", gorunumSonraB.After(gorunumA))
}
```

```
gorunumA, gorunumSonraB'den once mi: true
gorunumSonraB, gorunumA'dan sonra mi: true
```

İki değer birbirinden tamamen farklı bölgelerde ve tamamen farklı yerel saatlerde yazılı
olmasına rağmen `Before` ve `After` doğru sırayı buluyor, çünkü ikisi de karşılaştırmayı
temsil edilen **an** üzerinden yapıyor — `==` işlecinin yaptığı gibi iç yapının birebir
eşleşmesini aramıyor. Bu, önceki paragrafın genel kuralını doğruluyor: `time.Time`
değerlerini karşılaştırırken `Equal`, `Before` ve `After` güvenli bir taban oluşturuyor, `==`
ise yalnızca iki değerin **aynı bölgede, aynı biçimde** üretildiği bilindiğinde güvenli.

## Özet

- Bir an metne dönüp aynı düzenle geri okunduğunda `Equal` ile korunuyor; bu, konunun ortak
  çekirdeğindeki "yeniden kuruluyor" satırının doğrulanmış hâli.
- RFC 3339 düzeni bir saat diliminin sayısal ofsetini taşıyor ama adını taşımıyor: geri
  kurulan değerin ofseti orijinaliyle eşleşirken bölge adı eşleşmiyor.
- `time.Duration` altında bir `int64` taşısa da kendi tipini koruyor; biçimlendirmesi ve
  aritmetiği bu tipe göre işliyor, ham bir sayıyla karıştırılmıyor. Metne dönüp geri gelmesi
  de bilgi kaybetmiyor, çünkü taşıdığı tek şey kendi uzunluğu.
- Sınırlayıcı ölçüm: aynı anı gösteren iki değer `Equal` ile eşit çıkarken `==` ve `String()`
  ile farklı çıkıyor — üç araç üç farklı soruya yanıt veriyor.
- `Before` ve `After` da `Equal` gibi ana bakıyor, temsile değil; `==` işleci ise yalnızca iki
  değerin aynı bölgede ve biçimde üretildiği bilindiğinde güvenli bir karşılaştırma.

## Sonraki Adım

Bu derste bir zaman değerinin metne dönüşürken alan adı taşımadığı, yalnızca ham bir yazım
ürettiği görüldü — `2026-08-23T13:00:00+03:00` metninin hangi alanın hangi değeri olduğunu
söyleyen hiçbir işaret yok, yalnızca konumdan çıkarılabiliyor. Bir okuyucu bu metni doğru
yorumlayabiliyor çünkü RFC 3339 düzenini zaten biliyor — tıpkı bir önceki dersteki gömme
yönergesinin, hedef tipi zaten bilen bir değişkene içerik yerleştirmesi gibi. Ama her biçim bu
kadar cömert değil: konumdan çıkarılan bir alan, konum kaybolduğunda ya da biçim değiştiğinde
bir daha çıkarılamıyor.

Sıradaki ders bu boşluğu tam olarak dolduran bir biçimi ölçüyor: bir olayı günlüğe yazarken
alan adlarını da taşımak, aynı kaydı hem insan hem başka bir program için ayrıştırılabilir
kılıyor mu? Bu dersin sabit zaman damgası, sıradaki dersin günlük kayıtlarında da aynen
kullanılacak — zaman burada da gerçek saatten değil, sabit bir metinden gelecek.
