Bitsin bu Tarih/Saat işkencesi(TDateTime tipleri ile oynamak..)
// 23 Mayıs 2009 // Delphi, Programlama
Hemen hemen hepimiz yazdığımız projelerde tarih/saat verilerini kullanır, bunlar üzerinde çeşitli maniplasyonlar yaparız. Kimi zaman belli bir tarihe bir değer eklemek , kimi zamanda çıkartmak isteriz. Kimi zaman muhasebe/finansman uygulamalarında vade gün ve tarihlerini hesaplarken tarih/saat hesaplama rutinlerine ihtiyaç duyarız. Bazen de daha spesifik tarih/saat hesaplarına ihtiyacımız olur, artık yıl ile başımızı derde sokarız.
Tabii ki her modern programlama dilinin bu sorunları aşmak için hazır fonksiyon/kütüphaneleri vardır. Delphi’nin de var. Ancak bizim makalemize konu olacak gibi değil
Genellikle, kullanıcılarımıza tarih ve saat verilerini girebilmeleri için, veri biçimlendirme denetimleri kullanırız. Bunların başında sanıyorum ki hepimizin kullandığı TDateTimePicker gelir. Ancak TDateTimePicker bileşeni bile tarih saat girmek için aslında meşakkatli bir bileşendir. Bu bileşenle uğraşmak istemeyenler TMaskEdit’in tarih saat formatındaki maskelerini kullanarak giriş işleminin yapılmasını sağlamak isterler. Ancak bu bileşen TDateTimePicker’dan bile daha yorucudur. Bu bileşenlerin birbirlerine göre güzel tarafları bulunmakla birlikte her ikisi de tam manası ile kusursuz tarih/saat girişleri için yeterlidir denilemez. TDateTimePicker’ın hem tarih hem saat gösterme ve değiştirmesine yarayan format harici bir property’si yokken, Format kullanıldığında da çeşitli garipliklerle karşılaşırız. TMaskEdit’in ise geçersiz tarih formatı hatalarından hem size hemde kullanıcılara eminim gına gelmiştir.
Herhangi bir tarihe 07 ay 25 gün 06 saat 05 dk 48 saniye eklemek istesek, bahsedilen bileşenler ile bunu yapmamız son derece zor olacaktır. Evet tüm bu zorlukları yaşadığınızı, yada siz yaşamasanız bile yazdığınız programın kullanıcılarının yaşadıklarını biliyorum. Belki artık onlar daha iyi bir alternatife rastlamadıkları için bu durumu kanıksamış olabilirler ama biz şimdi tarih/saat girişlerindeki kalıplaşmış yapıyı kırmaya hazırlanıyoruz.. Nasıl mı ?
Önce biraz hayalinizde canlandırmanızı istiyorum. Herhangi bir TDateTime verisini tutan bir veribilinçli denetimde aşağıdaki şekilde girişler yapabildiğinizi düşünün:
+5g -> Mevcut tarihten 5 gün sonrası
+5a -> Mevcut tarihten 5 ay sonrası
+5y -> Mevcut tarihten 5 yıl sonrası
+5s -> Mevcut tarihten 5 saat sonrası
+5dk-> Mevcut tarihten 5 dakika sonrası
+5sn-> Mevcut tarihten 5 saniye sonrası
+5g* -> Bugünden 5 gün sonrası
+5a* -> Bugünden 5 ay sonrası
+5y* -> Bugünden 5 yıl sonrası
+5s* -> Bugünden 5 saat sonrası
+5dk* -> Bugünden 5 dakika sonrası
+5sn* -> Bugünden 5 saniye sonrası
bugün-> Bugünün tarihi
bugun-> Bugünün tarihi
şimdi -> Bugünün tarihi
simdi -> Bugünün tarihi
today -> Bugünün tarihi
now -> Bugünün tarihi
yarın -> Yarının tarihi
yarin -> Yarının tarihi
tomorrow -> Yarının tarihi
dün -> Dün
dun -> Dün
yesterday -> Dün
23052009 -> 23/05/2009
230509 -> 23/05/2009
23/05 -> 23/05/2009
23.05 -> 23/05/2009
23.05/2009 -> 23/05/2009
23/05.2009 -> 23/05/2009
23.05/09 -> 23/05/2009
23/05.09 -> 23/05/2009
Tabii yukarıda + olarak verdiğim örneklerin – olarak da çalışacağını söylemeye gerek duymuyorum.Sanırım yazdığımız programların kullanıcıları bu durumdan son derece memnun olacaklardır. Ayrıca belki bazı hesaplamalarda kodsal anlamda bizimde işimize yarayacaktır. Bu kadar kêlamın ardından arzu ederseniz bu sihirli metodu sizlerin beğenisine sunayım:
function ConvertToDateTime(const AOldValue, AValue : String) : TDateTime; type TSeperator = record AlphaSection : String; NumSection : Integer; UseCurrentDate: Boolean; end; function Parse(const Value : String) : TSeperator; var iCounter : Integer; sNum, sValue : String; TAlpha : set of Char; //'a'..'z'; TNums : set of Char; //'0'..'9'; begin sNum := ''; sValue := LowerCase(Value); TAlpha := ['a'..'z']; TNums := ['0'..'9']; Result.AlphaSection := ''; Result.NumSection := 0; Result.UseCurrentDate := false; for iCounter := 1 to Length(sValue) do begin if sValue[iCounter] in TAlpha then Result.AlphaSection := Result.AlphaSection + sValue[iCounter]; if sValue[iCounter] in TNums then sNum := sNum + sValue[iCounter]; if sValue[iCounter] = '*' then Result.UseCurrentDate := true; end; if sNum <> '' then Result.NumSection := StrToIntDef(sNum, 0); end; var sVal : String; iMultiplier : Integer; OldDate : TDateTime; Separator : TSeperator; begin Result := 0; iMultiplier := 1; OldDate := Now; if Trim(AOldValue) <> '' then OldDate := StrToDateTimeDef(Trim(AOldValue), Now); sVal := Trim(AValue); sVal := StringReplace(sVal, 'Ü', 'ü', [rfReplaceAll]); sVal := StringReplace(sVal, 'Ş', 'ş', [rfReplaceAll]); sVal := StringReplace(sVal, 'İ', 'i', [rfReplaceAll]); sVal := LowerCase(sVal); sVal := StringReplace(sVal, '.', DateSeparator, [rfReplaceAll]); sVal := StringReplace(sVal, ',', DateSeparator, [rfReplaceAll]); sVal := StringReplace(sVal, '/', DateSeparator, [rfReplaceAll]); if Pos(DateSeparator, sVal) <> 0 then begin try Result := StrToDate(sVal); Exit; except end; end; if Length(sVal) = 0 then Exit; if (sVal = 'bugün') or (sVal = 'bugun') or (sVal = 'şimdi') or (sVal = 'simdi') or (sVal = 'today') or (sVal = 'now') then begin Result := Now; Exit; end; if (sVal = 'yarın') or (sVal = 'yarin') or (sVal = 'tomorrow') then begin Result := Now + 1; Exit; end; if (sVal = 'dün') or (sVal = 'dun') or (sVal = 'yesterday') then begin Result := Now - 1; Exit; end; if sVal[1] = '-' then iMultiplier := -1; if (sVal[1] in ['-', '+']) and (Length(sVal) >= 3) then begin Delete(sVal, 1, 1); // -, + Separator := Parse(sVal); if Separator.AlphaSection = '' then Separator.AlphaSection := 'g'; if Separator.AlphaSection = 'g' then // Gün begin if Separator.UseCurrentDate then Result := IncDay(Now, iMultiplier * Separator.NumSection) else Result := IncDay(OldDate, iMultiplier * Separator.NumSection); Exit; end; if Separator.AlphaSection = 'a' then // Ay begin if Separator.UseCurrentDate then Result := IncMonth(Now, iMultiplier * Separator.NumSection) else Result := IncMonth(OldDate, iMultiplier * Separator.NumSection); Exit; end; if Separator.AlphaSection = 'y' then // Yıl begin if Separator.UseCurrentDate then Result := IncYear(Now, iMultiplier * Separator.NumSection) else Result := IncYear(OldDate, iMultiplier * Separator.NumSection); Exit; end; if Separator.AlphaSection = 's' then // Saat begin if Separator.UseCurrentDate then Result := IncHour(Now, iMultiplier * Separator.NumSection) else Result := IncHour(OldDate, iMultiplier * Separator.NumSection); Exit; end; if Separator.AlphaSection = 'dk' then // Dakika begin if Separator.UseCurrentDate then Result := IncMinute(Now, iMultiplier * Separator.NumSection) else Result := IncMinute(OldDate, iMultiplier * Separator.NumSection); Exit; end; if Separator.AlphaSection = 'sn' then // Saniye begin if Separator.UseCurrentDate then Result := IncSecond(Now, iMultiplier * Separator.NumSection) else Result := IncSecond(OldDate, iMultiplier * Separator.NumSection); Exit; end; end; if (Length(sVal) mod 2) <> 0 then sVal := '0' + sVal; if ( Length(sVal) = 6 ) or ( Length(sVal) = 8 ) then // 23052009 , 230509 gibi tarih girişleri begin Insert( DateSeparator, sVal, 5 ); Insert( DateSeparator, sVal, 3 ); TryStrToDate(sVal, Result); Exit; end; raise Exception.Create('Tarih/Saat dönüşümlerinde hata.!'); end;
Şimdi yeni bir uygulama açıyoruz ve formumuzun üzerine bir grid atıyoruz. Veritabanı bağlantılarını ayarladıktan sonra içinde tarihsel bir veri ihtiva eden bir sql sonucunu yada bir tabloyu TDataSet türevli bir nesneye atıyoruz. Ardından tarih alanımızı o nesneye ekliyoruz.(TDataSet türevi component üzerinde Fields Editor/Add All Fields).
Ardından TDateTimeField türündeki field’ın olaylarından OnSetText‘e aşağıdaki gibi bir kod yazacağız;
procedure TForm1.ClientDataSet1SaleDateSetText(Sender: TField; const Text: String); begin try Sender.AsDateTime := ConvertToDateTime(Sender.AsString, Text); except Sender.AsString := Text; end; end;
Şimdi programı çalıştıralım ve grid yada bir TDBEdit üzerinden denemelerimizi yapalım. İyi eğlenceler
Saygılar, sevgiler..
bir proğramaın sattini belli bie saat arasında nasıl gösteririm 17:00-19:00
ilginc bilgiler icin tesekkurler