HotXLS, Excel belge özelliği zaman damgalarını dosyanın içinde UTC olarak saklar ve API üzerinden yerel saat olarak açar: .xls için TXLSWorkbook.CreatedDate ve LastSavedDate, .xlsx için TXLSXWorkbook.Created ve Modified. v2.384.48'den beri her iki motor da yazarken yerel saati UTC'ye, okurken geri çevirir ve bunu damganın kendi tarihinde geçerli olan yaz saati uygulaması kurallarıyla yapar. Oraya varmak iki düzeltme aldı ve iki hata da aynı utanç verici nedenle hayatta kaldı: her otomatik gidiş dönüş geçti, Excel'in Dosya > Info bölmesiyse yanlış günü ya da yanlış saati gösterdi. Delphi'de Excel belge özelliklerini ayarlama genel bakışımızı okuduysanız, tarihlerin basit değer olmayı bıraktığı yer burasıdır
Kaydet ve yeniden aç testi bir günlük hatayı neden gizledi?
Kendi kendine gidiş dönüş hatayı gizledi, çünkü yazıcı ile okuyucu aynı yanlış sabiti paylaşıyordu ve hata kendi kendini iptal ediyordu. OLE özellik kümesi tarihi bir FILETIME'dır, yani 1601-01-01 UTC'den beri 100 nanosaniyelik tiklerin 64 bitlik sayısı ([MS-DTYP] §2.3.3); Delphi TDateTime ise 1899-12-30'dan itibaren gün sayar — Delphi'de Excel tarih serileri ile 1900 ve 1904 sistemleri makalesinin kapsadığı aynı seri başlangıcı. İki dev arasındaki boşluk 109205 gündür ve bunu takvim olmadan denetleyebilirsiniz: 25569 (TDateTime olarak Unix devri) artı 109205, 134774 eder; yani FILETIME günü sayılan Unix devri. v2.384.17 öncesi HotXLS derlemeleri 109206 kullanıyordu; böylece her oluşturma ve kaydetme damgası bir gün geç yazılıyor, bir gün erken okunuyordu. Test paketi atadığı değeri görüyordu; Excel yarını görüyordu
const
// FILETIME devri (1601-01-01) ile TDateTime devri (1899-12-30) arasındaki gün sayısı
// denetim: 25569 + 109205 = 134774, FILETIME günü cinsinden Unix devri
FileTimeDayBias = 109205;
function UtcDateTimeToFileTimeTicks(UtcStamp: TDateTime): Int64;
begin
// Önce tam milisaniyeye yuvarla, sonra 100 ns tikine ölçekle.
// Double'ı doğrudan tike ölçeklemek 04:00'ü 03:59:59.9999 yapar
Result := Round((UtcStamp + FileTimeDayBias) * 86400000.0) * 10000;
end;
O taslaktaki yuvarlama yorumu aynı koddan çıkan ikinci, daha küçük derstir. Kesirli bir TDateTime'ı doğrudan günde 864.000.000.000 tik ile çarpmak, ikili kayan nokta hatasının alt basamaklara sızmasına izin verir ve tam 04:00 olan bir damga 03:59:59.9999 olarak döner. HotXLS v2.384.48, ölçeklemeden önce tam milisaniyeye yuvarlar; böylece tam saatteki değerler yolculuktan sağlam çıkar. Aynı sürüm, bu taslağın bilinçli olarak dışarıda bıraktığı saat dilimi adımını da ekledi; çünkü buradaki girdi hâlihazırda UTC'dir
Tarihleri hangi SummaryInformation özellik kimlikleri taşır?
[MS-OLEPS]'in tanımladığı \005SummaryInformation özellik kümesinde oluşturma zamanı $0C (PIDSI_CREATE_DTM), son kaydetme zamanı $0D (PIDSI_LASTSAVE_DTM), toplam düzenleme süresi ise $0A (PIDSI_EDITTIME) altında yaşar. Eski HotXLS derlemeleri son kaydetme damgasını PIDSI_PAGECOUNT olan $0E'ye yazıyordu; Excel'in gösterecek kaydetme tarihi yoktu ve bir sayfa sayısı özelliği zaman damgası taşıyordu. v2.384.17'den beri okuyucu o eski yerleşimi de tanır: $0D yokken ve $0E bir VT_FILETIME taşıyorken değer son kaydetme zamanı alınır. Okunan her PROPVARIANT ayrıca artık PropVariantClear ile serbest bırakılır; çünkü bozuk bir dosya bu kimliklerden herhangi birinin altına bir dize park edebilir. Bu akışları kendi gözlerinizle görmek isterseniz, COM IStorage olmadan Delphi'de OLE2 bileşik dosyaları okuma anlatımı onlara nasıl ulaşılacağını gösterir
PIDSI_EDITTIME tuzakların içindeki tuzaktır. Özellik VT_FILETIME olarak yazılmıştır ama bir süre tutar; dev eklenmemiş, geçen 100 ns tiklerinin ham sayısıdır. Eski yazıcı ona tarih gibi davranıyor, EditTimeMinutes'i 1440'a bölüp sonucu dev dönüşümünden itiyordu; böylece 125 dakikalık düzenleme dosyaya kabaca 299 yıl olarak düşüyordu. Güncel okuyucu bu kodlamayı boyutundan tanır: gerçek bir düzenleme oturumu üç yüzyıla yayılmaz, dolayısıyla 109206 gün ve üzeri her değerin eski ofseti, EditTimeMinutes doldurulmadan önce çıkarılır
var
Book: TXLSWorkbook;
begin
Book := TXLSWorkbook.Create;
try
Book.Title := 'Q3 settlement';
// API değerleri yerel saattir; dosya UTC FILETIME saklar
Book.CreatedDate := EncodeDate(2026, 1, 15) + EncodeTime(9, 30, 0, 0);
Book.LastSavedDate := Now; // HotXLS atadığınızı yazar, Now damgası basmaz
Book.RevisionNumber := 7;
Book.EditTimeMinutes := 125; // bir süre, ham tik olarak saklanır
if Book.SaveAs('settlement.xls') <> 1 then
raise Exception.Create('Save failed');
finally
Book.Free;
end;
end;
XLSX tarihleri neden tam olarak saat dilimi ofseti kadar saptı?
XLSX tarihleri bölge ofseti kadar saptı, çünkü docProps/core.xml içindeki dcterms:created ve dcterms:modified, Z ile etiketli W3CDTF değerleridir; ECMA-376 Part 2'nin çekirdek özellikler modelinde bu UTC demektir ve HotXLS yerel saati o Z takılıyken damgalıyordu. UTC+8'deki bir makinede 09:30'da oluşturulan bir çalışma kitabı 09:30:00Z taşıyor ve aynı makinedeki Excel onu 17:30'a çeviriyordu. Klasik motorun da FILETIME değerlerinde aynı kusuru vardı ve TXLSXWorkbook.CustomProperties.AddDate (vt:filetime olarak yazılır) üzerinden eklenen özel tarih özellikleri de onu paylaşıyordu. v2.384.48'den beri üç yol da yazmadan önce çevirir ve damga Z taşıdığında okurken geri çevirir; v2.384.59'dan beri okuma tarafı kesirli saniyeleri ve açık +hh:mm / -hh:mm ofsetlerini de işler
Dönüşümün kendisi, naif bir düzeltmenin ters gittiği yerdir. LocalFileTimeToFileTime şu an geçerli olan ofseti uygular; dolayısıyla Temmuz'da çevrilen bir Ocak damgası, yaz saati uygulaması olan her bölgede bir saat sapmış çıkar. HotXLS bunun yerine TzSpecificLocalTimeToSystemTime ve SystemTimeToTzSpecificLocalTime çağırır; ikisi de standart ya da yaz saatini çevrilen tarihe göre seçer ve sıfırdan oluşan atanmamış bir değer dokunulmadan geçer, böylece hiçbir zaman birkaç saat kaymış 1899 tarihine dönüşmez
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('report-template.xlsx') <> 1 then
raise Exception.Create('Template not available');
Book.Created := EncodeDate(2026, 7, 1) + EncodeTime(9, 30, 0, 0);
Book.Modified := Now;
Book.CustomProperties.AddDate('ApprovedOn',
EncodeDate(2026, 1, 20) + EncodeTime(17, 0, 0, 0));
Book.SaveAs('report.xlsx');
// Orta Avrupa Saati'ne ayarlı bir makinede core.xml artık şunu taşır
// <dcterms:created xsi:type="dcterms:W3CDTF">2026-07-01T07:30:00Z</dcterms:created>
// (Temmuz'da UTC+2); ApprovedOn ise 16:00Z (Ocak'ta UTC+1) olarak yazılır
finally
Book.Free;
end;
end;
HotXLS zaman damgalarını okurken neyi çevirmez?
HotXLS W3CDTF okuyucusu profilin bölge etiketli her biçimini v2.384.59'dan beri çevirir ve hâlâ dokunmadığı tek durum bölgesiz bir saattir. O sürümden önce ayrıştırıcı ilk 19 karakteri alıyor ve 20. karakter Z olduğunda yalnızca UTC'den çeviriyordu; kesirli saniyeli (01:30:00.5Z) ya da açık ofsetli (+08:00) bir damga hiç düzeltme olmaksızın yerel saat olarak okunuyor ve bölge ofseti kadar saptı. HotXLS 2.384.59'dan beri Created, Modified ve tarih değerli özel özellikler her uzunlukta kesirli saniyeyi, Z'yi ve +hh:mm / -hh:mm ofsetlerini ayrıştırır, anı önce UTC'ye sonra yerel saate çevirir ve 2026-07-01 gibi yalnızca tarihli bir damgayı o tarih olarak okur. Saat taşıyıp bölge işareti taşımayan bir damga — W3CDTF profilinin izin vermediği ve ECMA-376 Part 2'nin kural vermediği tür — hâlâ değişmeden yerel saat olarak okunur ve hiç ayrıştırılamayan bir damga sıfır olarak döner. Excel'den geçen çalışma kitapları sağlamdır; bölgeyi atan diğer üreticilerin paketleri nokta denetimi hak eder
Eski HotXLS derlemelerinin yazdığı dosyalar öteki dürüst sınırdır. v2.384.48 öncesi yazılan bir XLSX damgası Z takmış yerel saatti ve dosyada onu doğrusundan ayıran hiçbir şey yoktur; bu yüzden güncel okuyucu onu bölge ofseti kadar kaydırır. O derlemelerin klasik FILETIME damgaları aynı kaymayı alır ve v2.384.17 öncesi yazılan bir oluşturma tarihi ayrıca bir gün geç okunur; çünkü eski sabitin fazla günü de saptanamaz. Yalnızca düzenleme süresi kodlaması ile $0E yerleşiminin tanınabilir bir imzası vardır. Bir de şunu unutmayın: API değeri okumayı yapan makineye göredir; UTC'de çalışan bir servis ile Tokyo'daki bir masaüstü aynı dosya için farklı CreatedDate değerleri bildirir ve ikisi de doğrudur
Belge zaman damgalarını nasıl test etmelisiniz?
Belge zaman damgalarını kendi kodunuzun yazmadığı bir şeye karşı test edin. Bu iki hata da kaydet-sonra-yeniden aç denetimini geçti; çünkü simetrik bir hata, simetrik bir teste görünmez. Excel'in kaydettiği bir çalışma kitabıyla karşılaştırın ya da kaydettikten sonra ham baytları ve XML metnini assert edin ve paketi UTC olmayan bir bölgeye ayarlı makinede, yaz saati değişiminin iki yanından test tarihleriyle çalıştırın. UTC'de koşan bir derleme ajanı eski, bozuk kodu gönül rahatlığıyla geçirecektir
Belge zaman damgaları küçüktür ama kayıt sistemlerinin, arama indekslerinin ve denetim izlerinin sıraladığı şey onlardır; bir gün ya da sekiz saat sapan tarih, eksik bir tarihten kötüdür çünkü kimse onu sorgulamaz. HotXLS Delphi elektronik tablo bileşeni dev aritmetiğini, özellik kimliklerini ve UTC dönüşümünü hem .xls hem .xlsx için üstlenir; kodunuz düz yerel TDateTime değerleri atar ve dosya biçimini kütüphaneye bırakır