Tarihsel Fonksiyonlar

Excel’de Tarihlerin Sayısal Karşılığı

Excel’de tüm tarihlerin sayısal bir karşılığı vardır. Aslında karşılığı vardır demekten ziyade tüm tarihler bir sayıdır demek daha doğru olur. Excel bunları gösterirken tarih formatında gösterir. Tarihler tam sayı depolanırken saatler küsurlu formda tutulur. Bu sayı 1.1.1900'den itibaren geçen gün sayısıdır. Ör: 17.05.2015 arka planda 42141 sayısı olarak tutulur.

Ayraçları, bölgesel ayarlar belirler, ancak tarih “#” işaretleri arasında yazılırsa bölgesel ayarlardan bağımsız olarak Amerikan tarih formatına göre belirtilmiş olur: Ay/gün/yıl. Bunu pek kullanmanızı önermem, ancak görürseniz de şaşırmayın. Biz bildiğimiz formatta kullanalım, yoksa 5 Temmuz yazacağınız yerde 7 Mayıs gibi sonuçlar elde edebilirsiniz, bu da önemli hatalara neden olabilir.

Tarihlerle ilgili dikkat edilmesi gereken bir husus var. Formatlı Gösterim tipi, kaynak tipi veya dönüş tipi. Formatlı Gösterim şekli her zaman stringtir. Ancak kaynak tip veya dönüş tipi farklı tipler de olabilir.

Tarihlerin kaynak/dönüş tipi aşağıdakiler olabilir:

  • String
  • Nümerik
  • Tarihsel
  • # karakterleri arasında
  • Tarihsel bir fonksiyondan dönen değer olarak. (Excel hücresinden veya Date, DateSerial gibi VBA fonksiyonlarından)

Konuyla ilgili daha detaylı bilgiye bu sayfadan ulaşabilirsiniz.

Tarihsel İşlemler ve DateTime Modülü

Tarihsel işlemlerimizi yaparken DateTime modülünü kullanıyor olacağız. Bu modüldeki fonksiyonlara geçmeden önce sık kullanılan property'lere bir bakalım.

Propertyler

Date ve Date$: O anki günü verirler. İlki Variant döndürürken ikincisi String döndürür. Aralarındaki fark, Variant olanda null işlemi yapabilmenizdir. Bir diğer fark da Date ile bir sayıyı matematiksel işleme tabi tutabilirsiniz ancak Date$ ile bunu yapamazsınız.

                        
                                Debug.Print Date + 1 'yarının tarihini verir
                                Debug.Print Date$ + 1 'hata verir. String olduğu için.
                                    
                                    

Aşağıdaki kod, üzerinde çalıştığımız dosyanın son değişikliğin tarihinin bugünden küçük olması durumunda çalışır.

                        
                                'fso tanımının yapıldığı kodlar
                                If fso.DateModified < Date Then
                                   'diğer kodlar
                                End If
                                    
                                    

Time ve Time$: Şu anın saatini verir. Aralarındaki fark Date/Date$ arasındaki farkların aynısıdır.

Now: Şu anın tarih ve saatini verir. Date ve Time'ın birleşimi gibi düşünülebilir.

Değişken Tanımlamalar

DateTime modülünün içindeki Date tipi ile hem tarih hem saat tanımlanabilir. Aşağıdaki örneklerde tüm değişkenleri Variant olarak tanımlıyoruz.

                        
                            Dim tarih1 'As Date
                            Dim tarih2 'As Date
                            Dim stringtarih1 'As String
                            Dim stringtarih2 'As String
                            Dim numeriktarih1 'As Long
                            Dim numeriktarih2 'As Double
                            Dim diyezlitarih1 'As Date
                            Dim diyezlitarih2 'As Date
                            Dim hucredentarih1 'As Date
                            Dim hucredentarih2 'As Date
                                
                                

Örnek kodlara geçmeden önce, Range nesnesinin Value ve Value2 özelliklerinin farkını tekrar edelim. Value, hücrenin içeriğini alırken, Value2 tarihleri numerik değere çevirerek depolar. (Tabii siz bir değişkeni Date olarak tanımladıysanız, ona Value2 sonucunu aktarsanız bile sayısal değer değil yine tarihsel formattaki değeri depolanır.)

Dönüş Tipleri
                        
                                tarih1 = Now
                                tarih2 = DateSerial(1979, 1, 21)
                                stringtarih1 = "21.01.1979"
                                stringtarih2 = "01.01.1979"
                                numeriktarih1 = 42574
                                numeriktarih2 = 42574.127
                                diyezlitarih1 = #1/21/1979# 'Amerikan formatında olmak zorunda, önce ay ve ayraç olarak da "/" girilmeli, "." değil. Gün girerken 01 girsen bile enter'a basıp alta geçince kaybolurlar.
                                diyezlitarih2 = #1/21/1979 4:30:00 AM# 'Amerikan formatında olmak zorunda, önce ay ve ayraç olarak da "/"
                                hucredentarih1 = Range("A1").Value 'hücre içeriği: 24.07.17 13:14
                                hucredentarih2 = Range("A1").Value2 'hücre içeriği: 21.01.1979
                                    
                                    

Şimdi bunların çeşitli özelliklerini yazdıralım.

                        
                            Debug.Print "tarih1", vbTab, tarih1, TypeName(tarih1), VarType(tarih1), IsDate(tarih1)
                            Debug.Print "tarih2", vbTab, tarih2, vbTab, TypeName(tarih2), VarType(tarih2), IsDate(tarih2)
                            Debug.Print "stringtarih1", vbTab, stringtarih1, vbTab, TypeName(stringtarih1), VarType(stringtarih1), IsDate(stringtarih1)
                            Debug.Print "stringtarih2", vbTab, stringtarih2, vbTab, TypeName(stringtarih2), VarType(stringtarih2), IsDate(stringtarih2)
                            Debug.Print "numeriktarih1", vbTab, numeriktarih1, vbTab, TypeName(numeriktarih1), VarType(numeriktarih1), IsDate(numeriktarih1)
                            Debug.Print "numeriktarih2", vbTab, numeriktarih2, vbTab, TypeName(numeriktarih2), VarType(numeriktarih2), IsDate(numeriktarih2)
                            Debug.Print "diyezlitarih1", vbTab, diyezlitarih1, vbTab, TypeName(diyezlitarih1), VarType(diyezlitarih1), IsDate(diyezlitarih1)
                            Debug.Print "diyezlitarih2", vbTab, diyezlitarih2, TypeName(diyezlitarih2), VarType(diyezlitarih2), IsDate(diyezlitarih2)
                            Debug.Print "hucredentarih1", hucredentarih1, vbTab, TypeName(hucredentarih1), VarType(hucredentarih1), IsDate(hucredentarih1)
                            Debug.Print "hucredentarih2", hucredentarih2, vbTab, TypeName(hucredentarih2), VarType(hucredentarih2), IsDate(hucredentarih2)
                                
                                

Çıktısı aşağıdaki gibi olacaktır.

post-thumb
Metinsel Tarihleri Tarih Tipine Çevirme Yöntemleri

Bazen, gösterim tipi metinsel olan tarihleri tarih tipine çevirip onlar üzerinden işlemlerinize devam etmek istersiniz. Bunun için VBA bize 4 yöntem sağlamaktadır. Dördü de küçük nüanslar göstermektedir.

1. Yöntem: CDate(Exp)

CDate, bir ifadeyi tarih yaparken tipini de tarih yapar. Üstelik saat bilgisi varsa bunları da korur. İçine her tür ifadeyi alabilir.

                        
                            x1 = CDate(tarih1)
                            x2 = CDate(tarih2)
                            x3 = CDate(stringtarih1)
                            x4 = CDate(stringtarih2)
                            x5 = CDate(numeriktarih1)
                            x6 = CDate(numeriktarih2)
                            x7 = CDate(diyezlitarih1)
                            x8 = CDate(diyezlitarih2)
                            x9 = CDate(hucredentarih1)
                            x10 = CDate(hucredentarih2)
                                
                                

Şimdi bunları yazdıralım.

                        
                            Debug.Print x1, TypeName(x1), VarType(x1)
                            Debug.Print x2, TypeName(x2), VarType(x2)
                            Debug.Print x3, TypeName(x3), VarType(x3)
                            Debug.Print x4, TypeName(x4), VarType(x4)
                            Debug.Print x5, TypeName(x5), VarType(x5)
                            Debug.Print x6, TypeName(x6), VarType(x6)
                            Debug.Print x7, TypeName(x7), VarType(x7)
                            Debug.Print x8, TypeName(x8), VarType(x8)
                            Debug.Print x9, TypeName(x9), VarType(x9)
                            Debug.Print x10, TypeName(x10), VarType(x10)
                                
                                

Çıktısı şöyle olacaktır:

post-thumb
2. Yöntem: DateValue(Metin)

Bu fonksiyon ile metin formatındaki tarihler gerçek tarihe çevrilir. Saat bilgisi korunmaz. Argüman olarak sadece metin alır.

                        
                                DateValue("21.01.1979") '21 Ocak 1979 tarihini verir
                                DateValue(28876) 'hata verir. Çünkü argüman olarak sadece metin alır.
                                    
                                    
3. Yöntem: Format(exp, format)

Sadece gösterim şeklini tarihsel yapar, dönüş tipi Stringtir. Dönen değerle tarihsel işlem yapılamaz.

İkinci parametre olarak önceden tanımlanmış formatlar da girilebilir, kullanıcı tanımlı formatlar da. Bunların detaylarına buradan ulaşabilirsiniz[^1^][1].

[^1^][1]: [Statology - Convert String to Date in VBA](https://www.statology.org/vba-convert-string-to-date/)
Metinsel Tarihleri Tarih Tipine Çevirme Yöntemleri

Bazen, gösterim tipi metinsel olan tarihleri tarih tipine çevirip onlar üzerinden işlemlerinize devam etmek istersiniz. Bunun için VBA bize 4 yöntem sağlamaktadır. Dördü de küçük nüanslar göstermektedir.

1. Yöntem: CDate(Exp)

CDate, bir ifadeyi tarih yaparken tipini de tarih yapar. Üstelik saat bilgisi varsa bunları da korur. İçine her tür ifadeyi alabilir.

                        
                                x1 = CDate(tarih1)
                                x2 = CDate(tarih2)
                                x3 = CDate(stringtarih1)
                                x4 = CDate(stringtarih2)
                                x5 = CDate(numeriktarih1)
                                x6 = CDate(numeriktarih2)
                                x7 = CDate(diyezlitarih1)
                                x8 = CDate(diyezlitarih2)
                                x9 = CDate(hucredentarih1)
                                x10 = CDate(hucredentarih2)
                                    
                                    

Şimdi bunları yazdıralım.

                        
                        Debug.Print x1, TypeName(x1), VarType(x1)
                        Debug.Print x2, TypeName(x2), VarType(x2)
                        Debug.Print x3, TypeName(x3), VarType(x3)
                        Debug.Print x4, TypeName(x4), VarType(x4)
                        Debug.Print x5, TypeName(x5), VarType(x5)
                        Debug.Print x6, TypeName(x6), VarType(x6)
                        Debug.Print x7, TypeName(x7), VarType(x7)
                        Debug.Print x8, TypeName(x8), VarType(x8)
                        Debug.Print x9, TypeName(x9), VarType(x9)
                        Debug.Print x10, TypeName(x10), VarType(x10)
                            
                            

Çıktısı şöyle olacaktır:

post-thumb
2. Yöntem: DateValue(Metin)

Bu fonksiyon ile metin formatındaki tarihler gerçek tarihe çevrilir. Saat bilgisi korunmaz. Argüman olarak sadece metin alır.

                        
                            DateValue("21.01.1979") '21 Ocak 1979 tarihini verir
                            DateValue(28876) 'hata verir. Çünkü argüman olarak sadece metin alır.
                                
                                
3. Yöntem: Format(exp, format)

Sadece gösterim şeklini tarihsel yapar, dönüş tipi Stringtir. Dönen değerle tarihsel işlem yapılamaz.

İkinci parametre olarak önceden tanımlanmış formatlar da girilebilir, kullanıcı tanımlı formatlar da. Bunların detaylarına buradan ulaşabilirsiniz[^1^][1].

                        
                        y1 = Format(tarih1, "Short Date") 'önceden tanımlanmış parametre
                        y2 = Format(tarih2, "dd.mm.yyyy") 'bu ve aşağıdakiler ise kullanıcı tanımlı parametrelerdir
                        y3 = Format(stringtarih1, "dd.mm.yyyy")
                        y4 = Format(stringtarih2, "dd.mm.yyyy")
                        y5 = Format(numeriktarih1, "dd.mm.yyyy")
                        y6 = Format(numeriktarih2, "dd.mm.yyyy")
                        y7 = Format(diyezlitarih1, "dd.mm.yyyy")
                        y8 = Format(diyezlitarih2, "dd.mm.yyyy")
                        y9 = Format(hucredentarih1, "dd.mm.yyyy")
                        y10 = Format(hucredentarih2, "dd.mm.yyyy")
                            
                            

Şimdi de bunların çıktısını alalım.

                        
                            Debug.Print y1, TypeName(y1), VarType(y1)
                            Debug.Print y2, TypeName(y2), VarType(y2)
                            Debug.Print y3, TypeName(y3), VarType(y3)
                            Debug.Print y4, TypeName(y4), VarType(y4)
                            Debug.Print y5, TypeName(y5), VarType(y5)
                            Debug.Print y6, TypeName(y6), VarType(y6)
                            Debug.Print y7, TypeName(y7), VarType(y7)
                            Debug.Print y8, TypeName(y8), VarType(y8)
                            Debug.Print y9, TypeName(y9), VarType(y9)
                            Debug.Print y10, TypeName(y10), VarType(y10)
                                
                                

Çıktı sonucu aşağıdaki gibidir:

4. Yöntem: FormatDateTime(d, constant)

FormatDateTime da string döndürür, ama kullanımı daha basittir, seçenekler sınırlıdır. Seçeneklerde constantlar var, ön tanımlı veya kullanıcı tanımlı parametre yok.

                        
                            z1 = FormatDateTime(tarih1, vbShortDate)
                            z2 = FormatDateTime(tarih2, vbLongDate)
                            z3 = FormatDateTime(stringtarih1, vbLongDate)
                            z4 = FormatDateTime(stringtarih2, vbLongDate)
                            z5 = FormatDateTime(numeriktarih1, vbLongDate)
                            z6 = FormatDateTime(numeriktarih2, vbLongDate)
                            z7 = FormatDateTime(diyezlitarih1, vbLongDate)
                            z8 = FormatDateTime(diyezlitarih2, vbLongDate)
                            z9 = FormatDateTime(hucredentarih1, vbLongDate)
                            z10 = FormatDateTime(hucredentarih2, vbLongDate)
                                
                                

Şimdi de çıktı alalım.

                        
                            Debug.Print z1, vbTab, TypeName(z1), VarType(z1), IsDate(z1) 'short olduğu ve içinde gün ismi geçmediği için True, aşağıdakiler false
                            Debug.Print z2, TypeName(z2), VarType(z2), IsDate(z2)
                            Debug.Print z3, TypeName(z3), VarType(z3), IsDate(z3)
                            Debug.Print z4, TypeName(z4), VarType(z4), IsDate(z4)
                            Debug.Print z5, TypeName(z5), VarType(z5), IsDate(z5)
                            Debug.Print z6, TypeName(z6), VarType(z6), IsDate(z6)
                            Debug.Print z7, TypeName(z7), VarType(z7), IsDate(z7)
                            Debug.Print z8, TypeName(z8), VarType(z8), IsDate(z8)
                            Debug.Print z9, TypeName(z9), VarType(z9), IsDate(z9)
                            Debug.Print z10, TypeName(z10), VarType(z10), IsDate(z10)
                                
                                

Sonuç aşağıdaki gibi olacaktır:

post-thumb
VBA'de Tarihsel İşlemler İçin Matematiksel Fonksiyonlar

VBA'de, Excel'deki gibi +1/-1 diyerek toplama çıkarma yapılamıyor. Matematiksel işlemler için belirli fonksiyonlar kullanılmalıdır.

DateDiff/DateAdd

Örnekler:

  • DateValue("21.01.1979") + 1
  • DateSerial(1979, 1, 21) + 1
  • CDate("21.01.1979") + 1
  • #5/22/97# - #1/10/97#
  • Date döndüren herhangi bir fonksiyonla (Date/Now veya UDF gibi)
                        
                            c1 = diyezlitarih1 + 1 'DateValue veya DateAdd demeye gerek kalmadan doğrudan kullanılabilir
                            c2 = DateAdd("d", 1, stringtarih1)
                            c3 = stringtarih1 + 1 'istenmeyen sonuç: noktaları uçup ekleme yapar, yani yıla eklenmiş olur, 21011980
                            c4 = DateValue(stringtarih1) + 1
                            c5 = CDate(stringtarih1) + 1
                            c6 = tarih1 - tarih2
                            c7 = DateDiff("d", tarih2, tarih1)
                            c8 = (tarih1 - tarih2) / 30 'yaklaşık ay sayısı
                            c9 = DateDiff("m", tarih2, tarih1) 'kesin ay sayısı
                            c10 = (tarih1 - tarih2) / 365
                                
                                

Şimdi de çıktılarını alalım.

                        
                            Debug.Print vbNewLine
                            Debug.Print c1, vbTab, TypeName(c1), IsDate(c1)
                            Debug.Print c2, vbTab, TypeName(c2), IsDate(c2)
                            Debug.Print c3, vbTab, TypeName(c3), IsDate(c3)
                            Debug.Print c4, vbTab, TypeName(c4), IsDate(c4)
                            Debug.Print c5, vbTab, TypeName(c5), IsDate(c5)
                            Debug.Print c6, TypeName(c6), IsDate(c6)
                            Debug.Print c7, vbTab, TypeName(c7), IsDate(c7)
                            Debug.Print c8, TypeName(c8), IsDate(c8)
                            Debug.Print c9, vbTab, TypeName(c9), IsDate(c9)
                            Debug.Print c10, TypeName(c10), IsDate(c10)
                                
                                

Çıktı şöyle olacaktır:

post-thumb
IsDate ile "Tarih mi?" Sorgulaması

Bir değerin tarih olup olmadığını sorgulamak için içeriğin Short Date veya saatli Short Date olması lazım. Long Date veya numerik olursa tarih olarak algılamaz.

Aşağıdaki örnekte, schedule edilmiş bir makro ile, içindeki dosya isimleri "Falanfilan raporu - 25.07.2017 Sonuçları.xlsm" gibi olan dosyalara bakıyor ve belirtilen süreden önce eski olanları sildiriyorum. Belirli süreyi tespit etme işlemini "Diğer kodlar" bölümünde yapıyorum, şu an bu kısım önemli değil. Her rapor için tespit ettiğim bu süre değerini bir dictionary'de depoluyorum. Mid(isim, Len(isim) - 19, 10) ile kestiğim kısım 25.07.2017'ye denk gelen kısım ve bunun tarih olup olmadığını sorguluyorum. Ancak bazen ilgili klasörde manuel kaydedilmiş dosyalar olabiliyor, bunların silinmesini istemiyorum, keza içinde Format ifadesi geçen dosyaların da silinmesini istemiyorum.

                        
                                Sub eskilerisil()
                                    'Diğer kodlar
                                    For Each d In klasor.Files
                                        isim = fso.GetBaseName(d)
                                        If Len(isim) > 19 Then
                                            If IsDate(Mid(isim, Len(isim) - 19, 10)) Then tarih = DateValue(Mid(isim, Len(isim) - 19, 10))
                                        Else
                                            tarih = DateSerial(2099, 12, 31)
                                        End If

                                        If Not aysonumu(Date - dict(kls)) = True And _
                                        tarih < Date - dict(kls) And InStr(isim, "Format") = 0 Then
                                            Kill d
                                        End If
                                    Next d
                                End Sub
                                    
                                    
Saat Karşılaştırma

Hour, TimeSerial veya TimeValue ile yapabiliriz.

                        
                                    If Hour(Now) > 13 Then 'dakika detayı gerekli değilse
                                    If TimeValue(Now) > #1:00 PM# Then
                                    If TimeValue(Now) > #13:00# Then 'otomatik PM'e çevrilir
                                    If TimeValue(Now) > #13:30:00# Then 'otomatik PM'e çevrilir
                                    If TimeValue(Now) > TimeSerial(13, 0, 0) Then
                                        
                                        
Bir Tarihin Belirli Kısımlarını Alma

Parça fonksiyonları:

                        
                                    tarih = "31.12.2016 13:35:00"

                                    Debug.Print Year(tarih) '2016
                                    Debug.Print Month(tarih) '12
                                    Debug.Print Day(tarih) '31

                                    'Hour, Minute ve Second ile de saat, dakika ve saniye döndürülür
                                        
                                        
DatePart

Yukarıdaki parça parça alan fonksiyonların hepsini tek bir fonksiyon ve parametre ile de yapabiliriz, mesela yıl almak için DatePart("yyyy", tarih) kullanılabilir. Ancak yukarıdakileri kullanmak daha kolaydır. Yani basit parça alma için bu fonksiyonu kullanmayacağız. Bununla beraber yılın kaçıncı günü, yılın hangi çeyreği, yılın hangi haftası gibi bilgiler için bu fonksiyon lazım. Mesela bu söylediğim son 3 amaç için sırayla y, q, ww parametrelerini kullanırız.

Dikkat: y ile yyyy karıştırmayın. yyyy yılı verirken tek y yılın gününü verir, d de ayın gününü verir. Parametre olarak kullanılabilecek tüm ifadelere yine yukarıda linkini verdiğimiz bu sayfadan erişebilirsiniz.

Ay ve Hafta Adı
                        
                            Debug.Print MonthName(Month(tarih)) 'Aralık
                            Debug.Print WeekdayName(Weekday(tarih)) 'Pazar
                                
                                
TimeSerial ve DateSerial

Yıl, Ay, Gün veya Saat, Dakika, Saniye bilgilerinin bir yerden temin edilmesi durumunda da belirli tarih ve saatler elde edilebilmektedir.

                        
                                Debug.Print DateSerial(2017, 1, 5)
                                Debug.Print TimeSerial(8, 3, 12)
                                    
                                    
Bazı Özel Tarihler
                        
                                Aybaşı: DateSerial(Year(Date), Month(Date), 1)
                                Aysonu: DateSerial(Year(Date), Month(Date) + 1, 1) - 1 veya daha sade olarak DateSerial(Year(Date), Month(Date) + 1, 0)
                                Haftabaşı: Date - WeekDay(Date, vbUseSystem) + 1 'veya vbMonday
                                Haftasonu: Date - WeekDay(Date, vbUseSystem) + 7
                                Yılbaşı: DateSerial(Year(Date), 1, 1)
                                Yılsonu: DateSerial(Year(Date) + 1, 1, 0)
                                    
                                    
Timer ile Geçen Süreyi Hesaplama

Timer property'sini genelde bir prosedürün ne kadar sürede çalıştığını bulmak amaçlı kullanırız.

                        
                                Sub timerkontrol()
                                    Dim başlangıç As Single
                                    Dim bitiş As Single
                                    Dim i As Long

                                    başlangıç = Timer

                                    For i = 1 To 100000000 'Bu yapı For-Next döngüsüdür. Şimdilik bu döngünün nasıl kullanıldığını bilmiyor olabilirsiniz, buna takılmayın. Sonraki bölümlerde detaylıca incelenecek.
                                        k = k + 1
                                    Next i

                                    bitiş = Timer

                                    MsgBox ("İşlem süresi:" & vbNewLine & Round(bitiş - başlangıç, 2) & " saniyedir.")
                                End Sub