27.02.2023

Timespan'i tarih ve saate çevirmek

Bazı yerlerde tarih ve saat verisi yerine bir "timespan" veri türünün kullanıldığını görüyorum. Bu timespan veritipi, 1 Ocak 1970 00:00:00'ı milat kabul ederek bu tarih, saat, dakika ve saniyeden sonra geçen saniyeleri bize söyler. Örneğin 1659590505 gibi bir veri, bu dijital milat tarihinden sonra 1,659,590,505 saniye geçtiğini gösterir. Bunu mantıklı bir tarih saat verisine çevirmek için

PS> (Get-Date 01.01.1970).AddSeconds(1659590505)

4 Ağustos 2022 Perşembe 05:21:45

kullanabiliriz. Burada 01.01.1970'in de, dönülen tarih ve saatin de UTC (merkezi saat) olduğu varsayılır. Yani üzerine bulunulan saat dilimini (Türkiye için +03:00) eklemek gerekir. Tam tersi için

PS> [int][double]::Parse((Get-Date (get-date).touniversaltime() -UFormat %s))

kullanılması önerilmiş, epochconverter.com sitesinde. Get-Time cmdlet'inin -UFormat parametresi ile %s kullanımının aslında dökümanlarda 1 Ocak 1970'ten bu yana geçen zamanı verdiği söylenmiş, ama bunu yerel zamanda veriyor. Türkiye'nin +3 saat diliminde olduğunu düşünerek kısaca bu değerden 10800 (3 x 60 x 60 ya da kısaca 3 saatin saniye cinsinden değeri) çıkararak da yapabiliriz.

PS> [int][double]::Parse((Get-Date -UFormat %s)) - 10800

Python'da ise

>>> import time

>>> int(time.time())

kullanılmış. Timestamp diye kısalttığım veri tipi aslında epoch timetamp ya da Unix timestamp olarak adlandırılıyor. .Net framework'te 8 byte olarak yer kaplayan ve 1.1.0000 tarihinden 31.12.9999 tarihine kadar olan aralıkta saniye hassasiyetinde çözünürlüğe sahip bir veri tipi. Ancak Unix, 4 byte hassasiyete sahip bu veri tipi ile hem yarısı kadar hafıza kullanımı hem de Unix/Linux dünyasında bir standardizasyon sunuyor. 32 bitlik tamsayı kullandığımızı varsayarak timestamp kullanarak 01.01.1970 00:00:00 ile 07.02.2106 06:28:16 zaman aralığında saniye hassasiyetinde çözünürlük mümkün. Bazı durumlarda signed int kullanılmışsa son tarih 19.01.2038 03:14:08 olabilir. Önümüzde kabaca bi 15 sene var, yeni bir Y2K38 dijiatal kıyameti için.

2023-08-03 Ek: Windows'da timestamp konusu genişmiş. Bazen daha büyük tamsayılar görüyorum, tarih ve saat verisi saklamak için. Bunları yukarıda anlatıldığı gibi tarih ve saat verisine dönüştüremiyorum. Bu ihtimallerden bir tanesi 64 bit dosya zamanı. Bunları anlamlı tarih ve saat bilgisine dönüştürmek için DateTime.FromFileTimeUtc(Int64) kullanılabilir. Şu adreste de bir örnek verilmiş. Temel olarak .Net'te bir veri tipinin asgari ve azami değerlerini öğrenmek için MinValue ve MaxValue özellikleri kullanılır. Örneğin int32 için

PS> [int32]::MaxValue

2147483647

döner. Bunu işaretsiz (unsigned) veri tipi için yaparsak

PS> [UInt32]::MaxValue

4294967295

çıkar. Verimiz bu değerlerden büyükse bir UInt64 olabilir, bu durumda FromFileTimeUtc() veya yerel zaman için FromFileTime() kullanılabilir. Bu 64 bitlik tamsayıların 01.01.1601 (Milattan Sonra) tarihinden sonra 100 nano saniyelik zaman dilimlerini saydığı belirtilmiş. Geniş bir aralık için ince bir hassasiyete sahip veri tipi. Tersten giderek bir örnek yapalım. Şu anda bulunduğumuz andan 01.01.1601 tarihini çıkartıp aradaki zaman dilimini "ticks" olarak hesaplayalım:

PS> ((Get-Date) - (Get-Date "1601-01-01")).Ticks

133355361042309112

döndü. Bu bir zaman dilimi verisi. Çıkarma işlemindeki tarafların ikisinin de aynı zaman diliminde olduğunu varsayarsak bu farkın bir zaman dilimi yok. Bu sebeple üzerinde ek bir zaman dilimi konmaması açısından yerel zamanda işlem yapan FromFileTime() yerine FromFileTimeUtc() kullanmak daha doğru. 1 Ocak 1601 tarihine bu değeri ekleyerek hesaplayalım:

PS> [datetime]::FromFileTimeUtc(133355361042309112)

3 Ağustos 2023 Perşembe 11:35:04

Bu işlemi bilgisayarımda yaptığım anın değerini döndü.

Bundan başka Fortigate loglarında eventtime adında bir alan var.  Bunun ise nano saniye cinsinden (sürüme bağlı değişir) epoch timestamp'ini tuttuğunu öğrendim.

eventtime=1691046040108745777

Dotnet'te .AddNanoseconds() olmadığı için 100 nano saniyelik işlemler yapan AddTicks() fonksiyonunu kullanabiliriz. Ama bu durumda değerimizi kabaca 100'e bölmek için sağ taraftan 2 basamak silerek işlem yaptım (bu arada bu veri tipi milat için 1 Ocak 1970'i almış):

PS> (Get-Date "1970-01-01").AddTicks(16910460401087457)

Bu da bana Fortigate loglarındaki olayın meydana geldiği anı UTC olarak verdi. Türkiye saat dilimine çevirmek için 3 saat eklemeliyim.

Hiç yorum yok: