Thai-Eng Date Recognition
2022
เลข 4 หลักบางเลข ถ้าถามคนทั่วไปว่าเห็นแล้วนึกถึงอะไร ผมเชื่อว่าแทบทุกคนตอบเหมือนกัน
2565
เป็นอีกเลขที่มีความหมายเหมือนกัน แต่เฉพาะคนไทย
แล้วถ้าเป็น 3248 ล่ะ
ไม่กี่วันมานี้ ผมเจอเลขปีที่เกิดจากการป้อนข้อมูลผิดพลาด แต่ทำให้ต้องตั้งคำถามย้อนกลับในมุมที่ไม่เคยคิดมาก่อน สมมติว่าเรารู้ว่าเลขนี้เป็นเลขปี แต่ควรเป็นปี พ.ศ. หรือ ค.ศ. ล่ะ เรื่องนี้สำคัญกับตรรกะโปรแกรมอย่างไร ผมจะเล่าให้ฟัง
เรื่องของระบบวันที่ ย้อนไปตั้งแต่ยุคแรกเริ่มเขียนโปรแกรม สมัยที่ใช้ MS-DOS ซอฟต์แวร์คอมพิวเตอร์ในเมืองไทยยังสับสน มีตาราง ASCII ภาษาไทยรหัสเกษตรกับรหัส สมอ. ขึ้นอยู่ว่าโปรแกรมไหนจะใช้ภาษาไทยรหัสอะไร พริ้นเตอร์ยุคนั้นก็ต้องทำฟอนต์ให้พิมพ์ภาษาไทยได้ทั้งสองรหัส และระบบปีศักราชในวันที่ก็เป็นความสับสนอีกอย่างหนึ่งในชีวิตการออกแบบโปรแกรม
เราเป็นส่วนน้อยในโลกที่ใช้เลขปี พ.ศ. ดังนั้นจึงไม่ต้องคาดหวังว่าโปรแกรมต่างประเทศจะรองรับระบบปีของเรา รวมไปถึงบรรดา library ที่เอามาใช้ในโปรแกรม ดังนั้นโปรแกรมที่พัฒนาโดยใช้ฐานจาก library เหล่านั้นจึงไม่รองรับระบบปีไทย หรือถ้ารองรับก็จะไม่สมบูรณ์
การแก้ปัญหาก็คิดหาทางกันไปหลายแบบ ง่ายที่สุดไม่ต้องทำอะไรเลย ให้ยูสเซอร์ใช้ระบบปี ค.ศ. ตามสากล บางแห่งหลอกโปรแกรมเก็บข้อมูลเป็นปีไทย ซึ่งจะมีปัญหาปีที่เดือนกุมภาพันธ์ 29 วัน เพราะโปรแกรมยังเข้าใจว่าเป็นปีอังกฤษ
ตอนทำโปรแกรมสมัยนั้น ผมเขียนโค้ดส่วนจัดการวันที่เอง จำได้ว่าใช้ Btrieve เป็นดาต้าเบส ฮาร์ดดิสก์ยังมีราคาสูง ออกแบบให้เก็บวันที่เป็น 3 ไบต์ เรียงกันตามค่าปีเดือนวันเพื่อประหยัดเนื้อที่เก็บข้อมูลมากที่สุด เนื่องจาก 1 ไบต์มี 8 บิต เก็บค่าได้ 0 ถึง 255 ค่าวันและเดือนไม่มีปัญหา แต่ค่าปีต้องเก็บค่าแค่ 2 ตำแหน่งท้าย พอดีเป็นช่วงเปลี่ยนผ่านปี 2000 ถ้าเก็บค่าปี ค.ศ. ข้อมูลจะเรียงลำดับไม่ถูก เพราะปี 1999 ถ้าเก็บค่า 99 ก็จะมีค่ามากกว่าปี 2000 ที่เก็บค่า 0 ด้วยความอินดี้ไม่สนใจมาตรฐานใด ๆ ก็ตัดสินใจเก็บข้อมูลเป็นปีไทยซะเลย เพราะคิดง่าย ๆ ว่าไม่ต้องมีปัญหา Y2K เพราะ ปี 2000 เท่ากับ 2543 การเก็บค่าปีเป็น 43 สะดวกปลอดภัยกว่า
การเอาข้อมูลมาแสดงผลบนจอ หรือพิมพ์ออกมาเป็นรายงาน ก็แปลงค่าปีโดยเอา 2500 มาบวกเลขปีที่เก็บ ใช้มาหลายปีจนกระทั่งวันหนึ่งก็เจอข้อจำกัดเมื่อต้องทำโปรแกรมเก็บข้อมูลวันเดือนปีเกิดของพนักงาน มีคนที่เกิดก่อนปี 2500 ทำให้เก็บปีสองหลักไม่ได้ ที่จริงแล้วเคสนี้แทบไม่เกิดขึ้น ดังนั้นจึงเลือกใช้วิธีปะผุ (work around) โดยปรับส่วนแสดงผลถ้ามีค่าปีมากกว่า 60 ให้แปลงเป็น 24xx แทน
ตอนนั้นปี 2540 ไม่ได้คาดคิดว่าจะมีใครใช้โปรแกรมยาวนานถึง 20 ปี แล้วระเบิดเวลาก็ทำงานในปี 2561 ผลกรรมทำให้รายงานต่าง ๆ กลายเป็นปี 2461 ไม่รู้ว่าจะดีใจหรือเสียใจ สำหรับโปรแกรมเมอร์คนหนึ่งที่รู้ว่ามีคนใช้โปรแกรมกว่า 20 ปีโดยไม่ยอมเปลี่ยน
เมื่อกลับมาทำโปรแกรมอีกครั้ง เงื่อนไขที่เป็นข้อจำกัดเปลี่ยนไปแล้ว คอมพิวเตอร์เร็วกว่าเดิม ฮาร์ดดิสก์ที่เก็บข้อมูลมีขนาดใหญ่และราคาต่ำลงมาก ไม่ต้องกังวลเรื่องขนาดของข้อมูลที่จัดเก็บอีกต่อไป แน่นอนว่าบทเรียนเรื่องการจัดการวันที่และระเบิดเวลาที่เพิ่งเกิดขึ้นทำให้ต้องคิดรอบคอบกว่าเดิม คราวนี้วิธีคิดเกี่ยวกับการออกแบบเริ่มเป็นระบบมากขึ้น ผมแยกการจัดการวันที่เป็น 3 ส่วน สิ่งที่ยูสเซอร์บอกโปรแกรม (input value) สิ่งที่โปรแกรมเก็บและใช้ประมวลผล (store value) และ สิ่งที่ยูสเซอร์ต้องการเห็น (display value)
เริ่มต้นจากกำหนดค่า store value ที่ทำหน้าที่แลกเปลี่ยน (interchange) อยู่ตรงกลางระหว่าง input กับ display หมายความว่า จาก input แปลงเป็น store แล้วใช้ store แปลงเป็น display คราวนี้ผมเลือกใช้ ISO date เป็นข้อความที่มีรูปแบบ YYYY-MM-DD ค่าปี ค.ศ. เป็นเลข 4 หลักเต็ม อ้างอิงตามมาตรฐาน ISO เมื่อเก็บในดาต้าเบสจะเป็นข้อมูลประเภท text มีความยืดหยุ่นสามารถค้นหาแบบ matching หรือ range ได้
ข้อดีของการใช้มาตรฐาน ISO ทำให้สามารถใช้ library open source ได้ ผมเลือกใช้ momentjs สำหรับแปลงวันที่ให้แสดงออกมาตามต้องการ เพราะมีคนทำ locale thai ไว้ให้แล้ว สามารถแสดงชื่อเดือน และวันของสัปดาห์เป็นภาษาไทยได้ถูกต้อง ประหยัดแรงได้มาก
มีอยู่เรื่องหนึ่งที่ผมเองก็เพิ่งเข้าใจ ประเทศไทยเป็นเพียงไม่กี่ประเทศในโลกที่ใช้ศักราชสองระบบปนกันจนคุ้นชิน การเห็นปี 2022 หรือ 2565 ก็เข้าใจได้ แต่ library ทั่วไปที่นักพัฒนาไม่เคยเจออย่างนี้จึงไม่รองรับเงื่อนไขการตั้งค่าให้เลือกศักราชตรงนี้ ยกเว้นไมโครซอฟท์เอ็กเซล ที่มีฟังก์ชั่น BAHTTEXT และฟอร์แมต BBBB สำหรับปีไทยได้ ผมจึงอ้างอิงตามพยายามเพิ่มโค้ดให้ momentjs รองรับ BBBB เหมือนกัน แต่เสียดายที่เจ้าของโปรเจกท์มองว่า น่าจะเป็นส่วน customise มากกว่าเอาไปรวมในโค้ดหลัก momentjs ของผมจึงเป็นเวอร์ชั่นที่แตกต่าง สามารถสั่งฟอร์แมตปี พ.ศ. DD/MM/BBBB ได้
อีกเรื่องที่ผมให้ความสำคัญคือ UX (user experience) ในการป้อนข้อมูลวันที่ เพราะผลพวงจากการใช้ศักราชสองระบบปนกัน ทำให้วันที่เป็นเรื่องซับซ้อนสำหรับผู้ที่ไม่ใช่คนไทย โดยเฉพาะในภาคธุรกิจ บางครั้งเราจะได้บิลหรือเอกสารที่ใช้ปีพ.ศ. บางครั้งก็เป็นปีค.ศ. ทำอย่างไรที่จะช่วยให้ยูสเซอร์สามารถป้อนข้อมูลตามที่เขาเห็น โดยไม่ต้องแปลงให้เป็นระบบปีที่โปรแกรมรู้จัก พูดง่าย ๆ ทำโปรแกรมให้ฉลาดใส่วันที่แบบไหนก็เข้าใจถูกต้อง เหมือนกับมนุษย์ เรื่องนี้โชคดีกว่าระบบวันที่ของอเมริกากับยุโรปบางประเทศ ที่ใช้ MM/DD/YYYY กับ DD/MM/YYYY ถ้าติดต่อค้าขายกันก็มึน เพราะจะไม่สามารถรู้เลยว่า 03/04/2022 เป็น 04 March หรือ 03 April นอกจากจะดูจากบริบทแวดล้อมว่าเอกสารมาจากประเทศอะไร
ย้อนกลับไปสมัยโปรแกรมยุคแรกที่ใช้เลขปีสองหลัก ตอนนั้นการป้อนข้อมูลก็ออกแบบให้รับเลขปีสองหลัก แล้วใช้วิธีแปลงง่าย ๆ ทำให้โปรแกรมดูฉลาด ถ้าเป็นเลข 0–20 ตีความว่าเป็นปีค.ศ. 20xx ถ้าเป็นเลข 61–99 ตีความว่าเป็นปีค.ศ. 19xx แล้วก็แปลงเป็น internal date ของโปรแกรมที่ใช้ระบบพ.ศ. อีกทีหนึ่ง
เมื่อทำโปรแกรมใหม่ต้องไม่น้อยกว่าของเดิม คราวนี้ออกแบบอย่างจริงจัง นอกจากจะรู้จักปีแบบย่อสองหลักแล้ว ก็รู้จักปีแบบเต็ม ถ้าเป็นเลขที่มีค่ามากกว่า 2400 เช่น 2565 ก็แปลเป็นปี ISO 2022 รวมทั้งชื่อเดือนที่เป็นภาษาไทยก็แปลได้ เช่น 31 ธ.ค. 2565 ก็จะแปลได้ว่า 2022–12–31 เป็น input ที่รองรับปีสองระบบและการเรียกวันที่แบบไทยให้ได้กว้างขวางที่สุด
นอกจากนี้ input วันที่ ยังเอาไปใช้ในการรับเงื่อนไข query เพื่อค้นหาข้อมูลตามที่ระบุได้ ในทำนองเดียวกับการป้อนข้อมูลเพื่อบันทึก ดังนั้นยูสเซอร์สามารถสั่งให้โปรแกรมค้นหาข้อมูลโดยใส่ว่า 31 ธ.ค. 2565 แล้วโปรแกรมก็แปลได้ว่าต้องการค้นหาข้อมูล 2022–12–31 ในดาต้าเบส
แต่เมื่อเจอเลขปี 3248 ซึ่งมีค่ามากกว่า 2400 โปรแกรมตีความว่าเป็นปีไทย จึงลบด้วย 543 กลายเป็นปี 2705 เลขนี้ส่งไปบันทึกเก็บในดาต้าเบสตามนั้น
แต่ถ้าส่งไปสร้างเป็น query ค้นหา โปรแกรมก็จะตีความว่า 2705 นั้นมากกว่า 2400 จึงลบด้วย 543 อีกครั้งกลายเป็น 2162 ทำให้ไม่สามารถค้นหาเจอ
งงกับปริศนานี้อยู่นาน กว่าจะแกะรอยจนเข้าใจอย่างที่เล่ามา ใช้เงื่อนไขที่กว้างเกินไปในการตีความปีไทยก็มีปัญหา ต้องเปลี่ยนเป็นตีความแบบแคบ ปีไทยจำกัดอยู่เฉพาะ 2400–2599 เท่านั้น ค่าปีตั้งแต่ 2600 เป็นต้นไป ถือว่าเป็นปีที่ไม่สามารถตีความได้ ดังนั้นจึงไม่ต้องพยายามแปลงค่าใด ๆ
ลองนึกถึงการติดต่อกับโปรแกรมผ่านแชท ถ้าคุณคุยกับบอท ส่งคำถามไปว่า “ยอดขายเดือนนี้” แล้วโปรแกรม สรุปตัวเลขของ “เดือนนี้” จากดาต้าเบสมาให้คุณได้ เพราะเข้าใจภาษาเกี่ยวกับวันเวลา ดูแล้วเป็นเรื่องง่าย ๆ แต่อยากจะบอกว่าในโลกนี้อาจไม่มีใครเขียนโค้ดที่เข้าใจความหมายของวันที่เป็นภาษาไทย โดยเฉพาะปีศักราชไทยได้เท่ากับโปรแกรมเมอร์ไทย
อ้อ.. ถ้าใครไม่ทันสังเกต ระเบิดเวลาลูกใหม่เริ่มนับถอยหลังไม่เกินปี 2600 กว่าจะถึงวันนั้นคงไม่มีใครใช้โปรแกรมนี้อีกแล้ว