Technical Article

Excel Date Serials ใน Delphi: 1900 vs 1904 และ numFmt

เมื่อคุณเปิดสเปรดชีต คลิกที่เซลล์ที่แสดงผลเป็น 2026-06-19 แถบสูตรก็ยังคงอ่านค่านั้นเป็นวันที่ เมื่ออ่านข้อมูลเซลล์เดียวกันจากโปรแกรม Delphi คุณจะได้รับตัวเลข 46192 การแสดงผลทั้งสองแบบต่างถูกต้อง เนื่องจาก Excel ไม่เคยจัดเก็บวันที่ไว้ในเซลล์นั้นเลย แท้จริงแล้วมันจัดเก็บเป็นตัวเลขลำดับ (serial number) ซึ่งก็คือตัวนับจำนวนวัน และเชื่อมโยงรูปแบบตัวเลขที่ทำหน้าที่บอกให้หน้าจอนำเสนอตัวนับนั้นให้อยู่ในรูปปฏิทินวันที่ ไม่มีประเภทข้อมูลวันที่ระบุไว้ในค่าของเซลล์ มีเพียงตัวเลขและกฎการแสดงผล และกฎการแสดงผลคือสิ่งเดียวที่ทำหน้าที่แยกความแตกต่างระหว่างฟิลด์วันที่ออกจากฟิลด์ตัวเลขปริมาณทั่วไป

การแยกส่วนนี้เป็นต้นตอของบั๊กเกี่ยวกับวันที่ทุกตัวที่ไลบรารีสเปรดชีตจะต้องหลีกเลี่ยง ตัวเลขลำดับเพียงอย่างเดียวไม่ได้ระบุว่าเป็นวันอะไร เนื่องจากมันไม่ได้บอกว่าวันเริ่มต้นหรือวันศูนย์ (day zero) คือวันใด ตัวเลขเดียวกันอาจมีความหมายเป็นวันที่ที่แตกต่างกันถึงสี่ปีเต็มขึ้นอยู่กับสถานะแฟล็กบนตัวเวิร์กบุ๊กตัวเดียว และตัวเลขที่ควรอ่านกลับมาในฐานะข้อมูลวันที่ก็อาจจะถูกอ่านค่านั้นกลับมาเป็นเพียงตัวเลขปริมาณดิบ ๆ เว้นแต่ว่าระบบจะตรวจวิเคราะห์รูปแบบและพบว่าเป็นโครงสร้างของวันที่ นี่คือรูปแบบโมเดลวันที่ที่สร้างขึ้นในยูนิต HotXLS และเป็นสาเหตุที่ทำไมจึงต้องเป็นแบบนี้

เซลล์วันที่คือข้อมูลตัวเลขควบคู่กับรูปแบบการแสดงผล

Excel จัดเก็บข้อมูลวันที่ในรูปจำนวนวันนับตั้งแต่จุดเริ่มต้น (epoch) โดยระบุข้อมูลส่วนเวลาไว้ที่ส่วนทศนิยม เวลาเที่ยงตรงของตัวเลขลำดับจะมีค่าทศนิยมเป็น .5 และส่วนจำนวนเต็มคือตัวนับจำนวนวัน ไม่มีสิ่งใดในตัวแปรค่าที่จัดเก็บคอยบอกว่าข้อมูลนี้เป็นข้อมูลเชิงเวลา สิ่งที่ระบุคือรูปแบบตัวเลขของเซลล์: มาตรฐาน ECMA-376 จะเรียกสิ่งนี้ว่า numFmt และเซลล์ใดที่มีรหัสรูปแบบระบุเป็นวันที่หรือเวลาก็จะแสดงผลเป็นวันที่ หากล้างค่ารูปแบบออก เซลล์เดิมนั้นจะแสดงผลเป็นตัวเลขทั่วไป โดยที่ค่าข้อมูลเบื้องหลังไม่เคยมีการเปลี่ยนแปลงใด ๆ เลย

นี่เป็นสาเหตุที่การอ่านค่าเซลล์จะส่งผลให้ได้ตัวแปร Variant ที่อาจอยู่ในประเภท varDate หรือ Double ทั่วไป และเหตุผลที่รูปแบบตัวเลขบนเซลล์เดียวกันทำหน้าที่เป็นตัวส่งสัญญาณชี้วัดว่าผู้ผลิตภายนอกตั้งใจระบุเป็นข้อมูลใด เมื่อ HotXLS เปิดไฟล์ XLSX ช่องเซลล์จะนำส่งทั้งค่า Value และ NumberFormatIndex เข้าสู่ TXLSXCell และตัวดัชนีรูปแบบคือส่วนที่คุณต้องเรียกตรวจสอบเพื่อดูว่าตัวเลขนี้คือฟิลด์วันที่หรือไม่

var
  Book: TXLSXWorkbook;
  Cell: TXLSXCell;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('timesheet.xlsx') <> 1 then
      raise Exception.Create('Cannot open workbook');

    Cell := Book.Sheets[0].Cells[1, 1];   // row 1, col 1 (1-based)
    // Value may arrive as varDate or as a plain numeric serial;
    // the format index is the signal that tells them apart.
    Writeln('raw value : ', VarToStr(Cell.Value));
    Writeln('numFmt idx: ', Cell.NumberFormatIndex);
    Writeln('format    : ', Cell.NumberFormat);
  finally
    Book.Free;
  end;
end;

จุดเริ่มต้นสองระบบที่ห่างกัน 1462 วัน

ระบบวันที่เริ่มต้นซึ่งเวิร์กบุ๊กของ Windows นิยมใช้กันจะเริ่มนับจำนวนวันนับตั้งแต่ช่วงปลายปี 1899 เพื่อให้ตัวเลขลำดับ 1 ตกอยู่บนวันแรกของปี 1900 ส่วนระบบอีกระบบหนึ่งจะอ้างอิงกับระบบปฏิทินของเครื่อง Macintosh รุ่นแรกสุดซึ่งนับจำนวนวันนับตั้งแต่เริ่มต้นปี 1904 ตัวเลขลำดับ 1 จึงมีค่าช้ากว่าระบบแรกอยู่สี่ปีกับอีกหนึ่งวัน ตัวเวิร์กบุ๊กจะบันทึกว่าตนเองเลือกใช้ระบบใดในสถานะแฟล็กตัวเดียว ในส่วนของแพ็กเกจ OOXML แฟล็กนี้ถูกระบุในชื่อ date1904 ภายใต้ยูนิตเวิร์กบุ๊ก ยูนิต HotXLS จะแสดงค่านั้นผ่านพร็อพเพอร์ตี้ Date1904 ของเวิร์กบุ๊ก

ระยะความห่างระหว่างจุดเริ่มต้นทั้งสองระบบนี้คือ 1462 วันพอดิบพอดี ซึ่งประกอบด้วยปีปฏิทินสี่ปี โดยมีสามปีที่มี 365 วัน และหนึ่งปีที่มี 366 วัน รวมเป็น 1461 วัน บวกเพิ่มอีกหนึ่งวันสำหรับระยะเหลื่อมเวลาระหว่างข้อตกลงวันเริ่มต้นที่แตกต่างกัน ตัวเลขนี้มีค่าตายตัวและคุณสามารถจำมันได้ง่าย ความสำคัญของมันอยู่ตรงที่ว่าตัวเลขนี้ไม่ใช่ศูนย์ ตัวเลขลำดับที่คัดลอกมาจากเวิร์กบุ๊กที่อ้างอิงระบบ 1904 แต่นำมาตีความตามเงื่อนไขการคำนวณของระบบ 1900 หรือสลับกันในทางกลับกัน จะส่งผลให้วันที่ทุกจุดมีความเพี้ยนคลาดเคลื่อนไป 1462 วัน ซึ่งทำให้ได้ผลลัพธ์เป็นวันที่ที่ผิดเพี้ยนไปกว่าสี่ปีเต็มและง่ายที่จะเข้าใจผิดว่าเป็นข้อบกพร่องของข้อมูลเสียหาย

เนื่องจากตัวแปร TDateTime ของ Delphi อ้างอิงระบบ 1900 ไลบรารีที่แปลงตัวเลขลำดับของ Excel เข้ากับ TDateTime จึงต้องชดเชยค่าเบี่ยงเบนจำนวน 1462 วันในทิศทั้งสองทางเสมอทุกครั้งที่เวิร์กบุ๊กเปิดใช้งานแฟล็ก 1904 การอ่านค่าตัวเลขลำดับ 1904 จะต้องลบออก 1462 วันก่อนนำไปจัดการในรูปแบบ TDateTime ส่วนการเขียนค่า TDateTime ลงในเวิร์กบุ๊ก 1904 จะต้องลบออก 1462 วันจากตัวเลขลำดับเพื่อให้ Excel แสดงผลวันตามที่คุณตั้งใจ ยูนิต HotXLS จะจัดการปรับชดเชยค่านี้ภายในโดยอัตโนมัติเมื่อจัดเตรียมข้อมูลวันที่สำหรับเวิร์กบุ๊กที่ระบุ Date1904 ส่งผลให้ค่า TDateTime ที่คุณกำหนดสามารถบันทึกและเปิดซ้ำได้ตรงตามปฏิทินปฏิทินจริงบนหน้าจอ

ความเพี้ยนจงใจในข้อมูลปีอธิกสุรทิน 1900

มีความเพี้ยนจุดหนึ่งที่เป็นที่รู้จักในระบบ 1900 โดย Excel จะถือว่าปี 1900 เป็นปีอธิกสุรทิน (leap year) และยอมรับให้วันที่ 29 กุมภาพันธ์ 1900 เป็นวันที่ที่ถูกต้อง ซึ่งตรงกับตัวเลขลำดับ 60 แท้จริงแล้วปี 1900 ไม่ได้เป็นปีอธิกสุรทิน เนื่องจากปีขึ้นต้นศตวรรษจะเป็นปีอธิกสุรทินก็ต่อเมื่อหารด้วย 400 ลงตัวเท่านั้น ซึ่งปี 1900 หารไม่ลงตัว วันที่จำลองนี้คือพฤติกรรมการจำลองเพื่อรักษาความเข้ากันได้แบบจงใจซึ่งสืบทอดมาจากสเปรดชีตรุ่นแรก ๆ ที่เคยพบข้อผิดพลาดนี้ และถูกเก็บรักษาไว้ตั้งแต่นั้นเป็นต้นไปเพื่อให้คณิตศาสตร์ตัวเลขลำดับทำงานได้สอดคล้องตรงกันข้ามผ่านไฟล์ต่างยุคต่างสมัย

ผลกระทบที่แท้จริงของการทำงานนี้มีขนาดเล็กมาก: สำหรับวันที่ใด ๆ ที่อยู่ตั้งแต่วันที่ 1 มีนาคม 1900 เป็นต้นไป ตัวเลขลำดับจะมีค่าสูงกว่าตัวนับวันจริงอยู่หนึ่งวัน เนื่องจากวันที่ 29 กุมภาพันธ์ที่ไม่มีอยู่จริงได้จองใช้ตำแหน่งตัวเลขไปหนึ่งหลัก ไลบรารีสเปรดชีตจะจำลองลักษณะความเพี้ยนนี้ตามเงื่อนไขเดิมมากกว่าที่จะทำการแก้ไข เนื่องจากเป้าหมายหลักคือต้องการให้คณิตศาสตร์การคำนวณทำงานสอดคล้องตรงกับ Excel อย่างไร้รอยต่อ การแก้ไขจุดนี้อาจทำให้วันที่ปัจจุบันเพี้ยนไปหนึ่งวันเมื่อเทียบกับที่ Excel แสดงผล ซึ่งเป็นผลลัพธ์ที่แย่กว่าการยอมปล่อยให้มีค่าเหลื่อมล้ำตัวเลขหนึ่งหลักที่ไม่มีวันที่ในเอกสารธุรกิจปกติจะเจอกัน ระบบปฏิทิน 1904 ไม่มีวันที่จำลองนี้ค้างอยู่ ซึ่งเป็นหนึ่งในสาเหตุที่องค์กรบางส่วนเลือกใช้งานระบบปฏิทินนี้ในอดีต

การวิเคราะห์ตรวจสอบวันที่ด้วย numFmt

เมื่อได้รับตัวเลขมาจากไฟล์ที่ถูกเขียนโดยโปรแกรมอื่น รูปแบบการแสดงผลคือหลักฐานชิ้นเดียวที่ช่วยชี้วัดว่าข้อมูลนี้คือวันที่ ข้อกำหนด ECMA-376 จะจองบล็อกของรหัสดัชนีรูปแบบที่สร้างมาพร้อมตัวโปรแกรม (built-in format ids) ซึ่งระบุความหมายตายตัว และรหัสของรูปแบบวันที่และเวลาจะอยู่ในกลุ่มพิกัดที่ระบุชัดเจน รหัสดัชนี 14 ถึง 22 คือรูปแบบปฏิทินและเวลาทั่วไป เช่น m/d/yyyy, h:mm และประเภทที่เกี่ยวข้อง รหัส 45 ถึง 47 คือรูปแบบข้อมูลเวลาที่ล่วงเลยไป (elapsed-time) และกลุ่มรหัสอีกสองกลุ่ม ได้แก่ 27 ถึง 36 และ 50 ถึง 58 คือรูปแบบเฉพาะภาษาสำหรับใช้ระบุปฏิทินกลุ่มประเทศ CJK ตามที่อธิบายใน ECMA-376 18.8.30 เซลล์ใดที่มีรหัสระบุรูปแบบตัวเลขตกอยู่ในพิกัดกลุ่มเหล่านี้จะถือเป็นเซลล์ข้อมูลวันที่หรือเวลาทันที

รหัสเริ่มแรกครอบคลุมกรณีการใช้งานทั่วไปแต่จะไม่ครอบคลุมการระบุรูปแบบเฉพาะของผู้ใช้ เมื่อตัวเวิร์กบุ๊กมีการประกาศรหัสรูปแบบเฉพาะของตนเองขึ้นมา เช่น การจัดเรียงลำดับแบบพิเศษ หรือการใช้ชื่อเดือนแบบระบุภาษา ตัวรหัสดัชนีจะมีค่าสูงกว่าขีดจำกัดรหัสทั่วไปและจะชี้ไปยังตารางรูปแบบเฉพาะของเวิร์กบุ๊กนั้น สำหรับกรณีเหล่านี้ การตรวจสอบวันที่หมายถึงการเข้าไปอ่านรหัสสตริงและค้นหาสัญลักษณ์ (tokens) ของปฏิทิน ยูนิต HotXLS จะรวบรวมขั้นตอนตรวจสอบเข้าด้วยกันภายใต้ฟังก์ชันภายใน XlsxNumFmtIsDate ซึ่งจะส่งคืนค่าความจริงทันทีเมื่อตรงกับรหัสปฏิทินทั่วไป และสำหรับกรณีอื่นจะรันการวิเคราะห์รหัสสตริงเฉพาะผ่านฟังก์ชัน XlsxFormatCodeIsDate โดยในฝั่งของ API สาธารณะคือสตริง NumberFormat ของเซลล์ และตัวดัชนี NumberFormatIndex ซึ่งจะช่วยให้คุณได้ทั้งข้อความรูปแบบรหัสตัวเต็มรวมถึงรหัสสำหรับการทดสอบค่า

ทำไมตัววิเคราะห์รูปแบบจึงไม่สามารถทำแค่การสแกนหาตัวอักษร d และ m

เหตุผลที่ตัววิเคราะห์ไม่สามารถทำเพียงแค่การสแกนหาตัวอักษรที่ใช้แทนข้อมูลวันที่ เช่น d, m, y, h และ s (ซึ่งแทนวัน เดือน ปี ชั่วโมง และวินาที) ได้ตรง ๆ ก็เพราะตัวอักษรเหล่านี้มีโอกาสที่จะถูกพิมพ์ฝังไว้ในโครงสร้างแบบอื่นที่ไม่ได้มีความเกี่ยวข้องกับข้อมูลปฏิทินเลย

ประเภทแรกคือข้อความอัญประกาศเดี่ยว (quoted string literal) รูปแบบตัวเลขสามารถฝังข้อความดิบไว้ภายใต้เครื่องหมายอัญประกาศคู่ได้ เช่น รูปแบบการเงินอย่าง #,##0 "MM" จะแนบตัวอักษร M และ M ต่อท้ายตัวเลขโดยไม่มีความเกี่ยวข้องใด ๆ กับมิติทางเวลา ตัวสแกนข้อมูลที่นับตัวอักษรภายในเครื่องหมายอัญประกาศคู่เป็นตัวคัดเลือกวันที่ จึงอาจประมวลผลวิเคราะห์ผิดพลาดได้ ประเภทที่สองคือเซกชันวงเล็บเหลี่ยม รูปแบบตัวเลขสามารถเก็บรหัสประมวลผลไว้ภายใต้วงเล็บเหลี่ยมได้ เช่น รหัสระบุสีอักษรอย่าง [Red] เงื่อนไขเปรียบเทียบขนาดอย่าง [>1000] ตัวแจ้งข้อมูลภาษา หรือสัญลักษณ์เวลาผ่านไป [h] และ [mm] ข้อมูลภายใต้วงเล็บเหลี่ยมบางตัวมีตัวอักษรวันที่ในขณะที่บางตัวไม่มี และการจัดการข้อมูลในวงเล็บเหลี่ยมในลักษณะเดียวกันกับเนื้อหารหัสภายนอกจะส่งผลให้ได้ผลลัพธ์การตรวจสอบที่ผิดพลาดหรือข้ามขั้นตอนสำคัญไป

ตัววิเคราะห์ที่ถูกต้องจะต้องทำการอ่านรหัสทีละอักขระ คอยสังเกตว่าปัจจุบันข้อมูลอยู่ภายในเครื่องหมายอัญประกาศคู่หรือไม่ และตรวจสอบระดับความลึกของการซ้อนวงเล็บเหลี่ยม พร้อมทั้งเคารพการใช้เครื่องหมายแบ็กสแลช (backslash) เพื่อละเว้นอักขระตัวถัดไปด้วย ตัวอักษรวันที่ที่ไม่มีตัวละเว้นและอยู่ภายนอกเครื่องหมายอัญประกาศคู่รวมถึงภายนอกวงเล็บเหลี่ยมเท่านั้นที่จะถูกนับเป็นสัญลักษณ์วันที่แท้จริง นี่คือวิธีการสแกนข้อมูลที่ฟังก์ชัน XlsxFormatCodeIsDate เลือกใช้: ตัวอักษรอัญประกาศจะปรับสถานะค่าในอัญประกาศเพื่อสั่งหยุดการสแกนหาสัญลักษณ์จนกว่าจะพบเครื่องหมายอัญประกาศคู่ปิด ตัวแบ็กสแลชจะสั่งข้ามอักขระตัวถัดไป และตัวแปรนับความลึกของวงเล็บเหลี่ยมจะทำหน้าที่หยุดการสแกนภายใต้ช่วงข้อมูล [...] ผลลัพธ์ที่ได้คือรหัส #,##0 "MM" จะถูกอ่านค่าเป็นรูปแบบตัวเลขปกติอย่างถูกต้อง ในขณะที่รหัสสั้นของผู้ใช้งานที่ไม่มีอะไรเลยนอกจากตัวอักษร m หรือ d เดี่ยว ๆ นอกเครื่องหมายอัญประกาศจะได้รับการจำแนกว่าเป็นรูปแบบวันที่ได้อย่างแม่นยำ

การอ่านค่าวันที่จากไฟล์ภายนอก

รายละเอียดทั้งหมดข้างต้นรวมกันเป็นกระบวนการทำงานเดียว: คือการแปลงตัวเลขที่แอปพลิเคชันอื่นเขียนเข้ามาให้กลับมาเป็นวันที่ที่คุณสามารถไว้วางใจได้ ตัวเลขลำดับจะบอกจำนวนนับ แฟล็ก Date1904 ของเวิร์กบุ๊กจะทำหน้าที่ชี้ว่าตัวนับนั้นเริ่มต้นจากวันใด และรหัสระบุรูปแบบตัวเลขหรือรูปแบบเฉพาะของเซลล์คือหลักฐานชิ้นเดียวที่ช่วยยืนยันว่าจำนวนตัวเลขนี้คือฟิลด์วันที่ตั้งแต่ต้น หากตัดฟังก์ชันใดฟังก์ชันหนึ่งในสามส่วนนี้ไป คุณจะได้ข้อมูลผลลัพธ์ที่ดูปกติแต่มีค่าที่ผิดเพี้ยนไป แทนที่จะเป็นรายงานข้อความแสดงความผิดพลาดแบบปกติตามปกติ

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Cell: TXLSXCell;
  r: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('vendor-export.xlsx') <> 1 then
      raise Exception.Create('Cannot open export');

    // The 1904 flag is workbook-wide: read it once, apply it to
    // every serial the workbook hands back.
    if Book.Date1904 then
      Writeln('workbook uses the 1904 date system')
    else
      Writeln('workbook uses the 1900 date system');

    Sheet := Book.Sheets[0];
    for r := 1 to 10 do
    begin
      Cell := Sheet.Cells[r, 1];
      // A date is only a date when its format says so; the same numeric
      // value with a plain format is just a quantity.
      Writeln(Format('row %d  value=%s  numFmt=%d  code="%s"',
        [r, VarToStr(Cell.Value), Cell.NumberFormatIndex, Cell.NumberFormat]));
    end;
  finally
    Book.Free;
  end;
end;

ในฝั่งของ BIFF ระบบเก่าดั้งเดิมจะมีกับดักเพิ่มเติมอีกหนึ่งประเด็นที่ควรค่าแก่การอธิบาย ในกระบวนการอ่านสตรีมของไฟล์ .xls เก่า กลุ่มของช่องเซลล์ตัวเลขที่อยู่ติดกันอาจจะถูกแพ็กรวมไว้ในเรกคอร์ดหลายเซลล์เรกคอร์ดเดียว (MULRK record) ซึ่งจัดเก็บค่าตัวเลขหลายตัวคู่ขนานกับรหัสรูปแบบอ้างอิงไว้ในโครงสร้างชุดเดียว เซลล์ข้อมูลวันที่ที่จัดเก็บในลักษณะดังกล่าวจะยังคงเป็นฟิลด์วันที่ตามปกติแม้จะถูกแพ็กรวมกันมา การตรวจสอบรหัสรูปแบบจึงต้องเจาะลึกเข้าไปอ่านพิกัดข้างในเรกคอร์ดหลายเซลล์นั้นเพื่อวิเคราะห์รายเซลล์ และค่าชดเชย 1904 จะยังคงทำหน้าที่ควบคุมข้อมูลตัวเลขลำดับแต่ละตัวที่ได้มา โปรแกรมอ่านข้อมูลที่ตรวจเฉพาะเรกคอร์ดตัวเลขเดี่ยว ๆ และข้ามกลุ่มเรกคอร์ดแพ็ก จะส่งผลเสียเงียบ ๆ ทำให้ฟิลด์คอลัมน์ของข้อมูลวันที่กลายเป็นข้อมูลจำนวนเต็มทั่วไปทั้งหมด

การจับคู่พิกัดตัวเลขลำดับกับ TDateTime ในการทำงานจริง

เมื่อการตรวจสอบรูปแบบยืนยันว่าเป็นวันที่และพารามิเตอร์แฟล็ก Date1904 ได้รับการอ่านค่าเรียบร้อยแล้ว ขั้นตอนการแปลงพิกัดจะทำงานโดยอัตโนมัติ ค่าข้อมูลที่ยูนิต HotXLS ส่งกลับคืนมาในประเภท varDate คืออ็อบเจกต์ TDateTime ที่คุณสามารถนำไปประมวลผลต่อได้ทันที ส่วนค่าข้อมูลที่ส่งมาในรูปตัวเลข Double ดิบ (ซึ่งพบได้เมื่อแหล่งข้อมูลเขียนตัวเลขลำดับโดยไม่มีรหัสปฏิทินอ้างอิง) จะถูกแปลงโดยดึงค่าตัวเลขมานับจำนวนวันตามพิกัด 1900 และสำหรับกรณีของเวิร์กบุ๊ก 1904 ให้หักค่าระยะชดเชย 1462 วันออกก่อนเพื่อให้วันเริ่มต้นตรงกัน ในทิศตรงกันข้าม การมอบหมายสิทธิ์ TDateTime ให้แก่ช่องเซลล์จะทำการบันทึกค่าตัวเลขลำดับพิกัด 1900 และยูนิต HotXLS จะจัดการปรับชดเชยระยะห่าง 1462 วันให้โดยอัตโนมัติในขั้นตอนการบันทึกไฟล์หากเวิร์กบุ๊กนั้นระบุการใช้งานระบบ 1904 ส่งผลให้ไฟล์ที่จัดเก็บแสดงวันปฏิทินตรงตามวัตถุประสงค์ของคุณจริง ๆ แทนที่จะเหลื่อมเวลากระโดดไปสี่ปีเต็ม

ควรกำหนดระดับแฟล็กให้รอบคอบเมื่อสร้างเวิร์กบุ๊ก ค่าเริ่มต้นของ Date1904 จะเป็น false ซึ่งสอดคล้องกับโปรแกรม Excel ของ Windows และมักเป็นสิ่งที่คุณต้องการใช้เสมอ ให้ปรับตั้งค่าเป็น true เฉพาะเมื่อต้องการเลียนแบบไฟล์ที่มีที่มาจากเครื่อง Mac หรือเมื่อระบบปลายทางต้องการพิกัดอ้างอิง 1904 โดยเฉพาะ กฎข้อเดียวที่จะช่วยป้องกันปัญหาคลาดเคลื่อนสี่ปีเต็มในระบบปฏิทินคือความสม่ำเสมอในการจัดการ: ให้เลือกจุดเริ่มต้นระบบใดระบบหนึ่งต่อเวิร์กบุ๊กเสมอ เขียนข้อมูลวันที่ภายใต้เงื่อนไขข้อกำหนดนั้น และอ่านค่าข้อมูลกลับคืนโดยอ้างอิงตามแฟล็กที่ระบุไว้ในไฟล์จริง ๆ

ฟิลด์วันที่คือหนึ่งในข้อมูลเชิงลึกเกี่ยวกับเนื้อหาที่แท้จริงในช่องเซลล์ ข้อมูลเมตาในระดับชั้นเคียงคู่กัน เช่น ชื่อเรื่อง ผู้สร้าง และบันทึกเวลาที่แนบมากับตาราง มีอธิบายไว้ใน บทความของเราเกี่ยวกับข้อมูลเมตาและพร็อพเพอร์ตี้เอกสารของเวิร์กบุ๊ก ซึ่งค่าของ Created และ Modified จะจัดเก็บในรูปแบบ TDateTime ภายใต้ข้อตกลงแบบเดียวกัน และเมื่อวันที่เป็นผลลัพธ์จากการคำนวณจากสูตรแทนที่จะเป็นค่าดิบที่จองไว้ กฎคำนวณใน บทความการคำนวณสูตรและฟังก์ชันปรับแต่งของเรา จะระบุตัวเลขลำดับที่รูปแบบนำไปเรนเดอร์ ทั้งหมดนี้ทำงานประสานกับตัวโมเดลวันที่ที่มีพร้อมใช้งานในฐานะส่วนหนึ่งของ HotXLS Component สำหรับ Delphi และ C++Builder ซึ่งสามารถเขียนและอ่านข้อมูลวันที่ของ XLS และ XLSX ได้โดยไม่ต้องพึ่งพาระบบอัตโนมัติของ Excel