บทความเทคนิค

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];   // แถว 1, คอลัมน์ 1 (1-based)
    // ค่าอาจมาถึงเป็น varDate หรือเป็นตัวเลขลำดับธรรมดา;
    // ดัชนีรูปแบบคือสัญญาณที่แยกแยะทั้งสอง.
    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 วัน ซึ่งทำให้ได้ผลลัพธ์เป็นวันที่ที่ผิดเพี้ยนไปกว่าสี่ปีเต็มและง่ายที่จะเข้าใจผิดว่าเป็นข้อบกพร่องของข้อมูลเสียหาย

ไทม์ไลน์เปรียบเทียบระบบวันที่ 1900 กับ 1904 ของ Excel แสดงช่องว่างคงที่ 1462 วันระหว่างจุดอ้างอิงทั้งสอง และวันอธิกสุรทินผี 29 กุมภาพันธ์ 1900 ที่ HotXLS ใน Delphi จัดการให้
ระบบปี 1900 และ 1904 นับจากวันเริ่มนับที่ต่างกัน วันปฏิทินเดียวกันจึงห่างกันพอดี 1462 serial และมีเพียงแกน 1900 เท่านั้นที่มีวันที่ 29 กุมภาพันธ์ที่ไม่มีจริงอยู่ที่ serial 60

เนื่องจากตัวแปร 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');

    // แฟล็ก 1904 ครอบคลุมทั้งเวิร์กบุ๊ก: อ่านครั้งเดียว ใช้กับ
    // ทุกตัวเลขลำดับที่เวิร์กบุ๊กคืนมา
    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];
      // วันที่จะเป็นวันที่ก็ต่อเมื่อรูปแบบระบุเช่นนั้น; ตัวเลขเดียวกัน
      // ที่มีรูปแบบธรรมดาก็เป็นเพียงปริมาณ
      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 จะยังคงทำหน้าที่ควบคุมข้อมูลตัวเลขลำดับแต่ละตัวที่ได้มา โปรแกรมอ่านข้อมูลที่ตรวจเฉพาะเรกคอร์ดตัวเลขเดี่ยว ๆ และข้ามกลุ่มเรกคอร์ดแพ็ก จะส่งผลเสียเงียบ ๆ ทำให้ฟิลด์คอลัมน์ของข้อมูลวันที่กลายเป็นข้อมูลจำนวนเต็มทั่วไปทั้งหมด

การตรวจจับวันที่สองด่านสำหรับเซลล์ HotXLS: ช่วง id รูปแบบตัวเลขในตัวมาก่อน แล้วตามด้วยการสแกนรหัสรูปแบบกำหนดเองที่รู้เรื่องเครื่องหมายคำพูดกับวงเล็บ ใน Delphi
รหัสรูปแบบในตัวระบุเซลล์ส่วนใหญ่ได้ทันที ส่วนรหัสแบบกำหนดเองจะตกไปใช้การไล่ตรวจอักขระที่ละเว้น literal ในเครื่องหมายคำพูด ส่วนของวงเล็บ และ escape ด้วยเครื่องหมายแบ็กสแลช

การจับคู่พิกัดตัวเลขลำดับกับ 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 Delphi Component สำหรับ Delphi และ C++Builder ซึ่งสามารถเขียนและอ่านข้อมูลวันที่ของ XLS และ XLSX ได้โดยไม่ต้องพึ่งพาระบบอัตโนมัติของ Excel

ขั้นตอนอ่านวันที่จากสเปรดชีตผู้ให้บริการอื่นด้วย HotXLS: รูปแบบตัวเลขต้องประกาศว่าเป็นวันที่ และ flag Date1904 ตัดสินว่า serial ต้องเลื่อน 1462 วันก่อนกลายเป็น TDateTime ของ Delphi หรือไม่
ข้อเท็จจริงสามข้อกำหนดการแปลงทุกครั้ง: รูปแบบต้องระบุว่าเป็นวันที่ แฟลก Date1904 ตรึง epoch และ Double เปล่าจะได้รับการแก้ 1462 วัน ส่วน varDate ถูกใช้ตามที่เป็น