เมนู

วันเกิด กับขอบเขตที่ระบบมักคำนวณผิด

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

เผยแพร่เมื่อ

  • ข้อมูลทดสอบ
  • วันเกิด

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

ปีอธิกสุรทินมีกติกาอย่างไร?

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

ความเข้าใจผิดที่พบได้บ่อยคือการตรวจแค่ว่าปีหารด้วยสี่ลงตัว แล้วถือว่าเดือนกุมภาพันธ์มีวันเพิ่มเสมอ วิธีนี้ทำให้ระบบยอมรับวันที่ที่ไม่มีอยู่จริงในบางปี และปฏิเสธวันที่ถูกต้องในบางปี

ผลกระทบไม่ได้จบที่การตรวจวันที่ การคำนวณจำนวนวันระหว่างสองวันก็ใช้ค่าจำนวนวันในเดือนด้วย ถ้าค่าดังกล่าวผิด การนับอายุ การนับวันครบกำหนด และการคำนวณค่าบริการรายวันจะคลาดเคลื่อนไปพร้อมกัน

วันที่ 29 กุมภาพันธ์ต้องจัดการอย่างไร?

คนที่เกิดในวันนี้มีอยู่จริงและมีจำนวนไม่น้อย พวกเขาคือกลุ่มที่ระบบมักทำร้ายโดยไม่ตั้งใจ ตัวอย่างที่พบบ่อยที่สุดคือฟอร์มที่บังคับให้เลือกวันจากรายการที่ไม่มีวันที่นี้อยู่ในตัวเลือกเลย ผู้ใช้กลุ่มนี้จึงสมัครอะไรไม่ได้เลย

อีกปัญหาหนึ่งคือการแสดงผลในปีที่ไม่ใช่ปีอธิกสุรทิน ระบบที่พยายามเลื่อนวันเกิดไปเป็นวันที่ 1 มีนาคม จะทำให้ข้อมูลของผู้ใช้ถูกแก้ไปตลอดกาลโดยที่เจ้าตัวไม่รู้

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

อายุควรนับเป็นจำนวนปีเต็มหรือจำนวนวัน?

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

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

ประเด็นที่ต่อเนื่องกันคือคำว่า วันนี้ ขึ้นอยู่กับเขตเวลา ระบบที่ทำงานข้ามเขตเวลาจึงอาจคำนวณอายุได้ไม่เท่ากันในเวลาเดียวกัน ขึ้นอยู่กับว่าใช้เวลาของเครื่องแม่ข่ายหรือเวลาของผู้ใช้

ปฏิทินที่ไม่ใช่คริสต์ศักราชทำให้อะไรผิดพลาด?

หลายประเทศใช้ปฏิทินของตนเองในเอกสารราชการและในชีวิตประจำวัน ตัวอย่างที่รู้จักกันดีคือปฏิทินที่เริ่มนับปีต่างจากคริสต์ศักราชเป็นจำนวนหลายปี ความต่างนี้ทำให้ปีเดียวกันเขียนด้วยตัวเลขคนละค่าก็ได้

ปัญหาที่เกิดตามมาคือเมื่อผู้ใช้กรอกปีตามปฏิทินที่ตนคุ้นเคย ระบบที่สมมติว่าทุกคนใช้คริสต์ศักราชจะตีความผิดทันที ผู้ใช้บางคนจึงกลายเป็นคนที่เกิดก่อนคริสตกาลหรือมีอายุเกินหนึ่งร้อยปีทั้งที่ความจริงไม่ใช่

อีกปัญหาหนึ่งคือรูปแบบการเขียนวันที่ที่สลับตำแหน่งวันกับเดือน ระบบที่เดาจากตัวเลขจะสลับความหมายของวันที่หนึ่งกับเดือนหนึ่งเสมอ การบังคับให้ผู้ใช้เลือกเดือนจากรายการแทนการพิมพ์ตัวเลขจึงเป็นวิธีที่ลดความผิดพลาดได้จริง

ค่าแทนวันที่ในชุดทดสอบควรใช้อย่างไร?

ชุดทดสอบจำนวนมากมีวันที่ที่ใส่ไว้เพียงเพื่อให้ฟอร์มผ่าน เช่นวันที่ที่ดูกลมและจำง่าย วันที่เหล่านี้มีประโยชน์เพราะทำให้ผลทดสอบซ้ำได้ แต่ก็มีกับดักอยู่

กับดักแรกคือการที่วันนั้นกลายเป็นวันเกิดจริงของผู้ใช้ในภายหลัง เพราะมีคนคัดลอกชุดทดสอบไปใช้ต่อโดยไม่ทราบที่มา กับดักที่สองคือวันที่กลมมักทำให้การตรวจสอบอายุง่ายเกินไป จนไม่ทดสอบกรณีที่ใกล้ขอบเขตเลย

ทางปฏิบัติที่ปลอดภัยคือกำหนดวันที่ไว้ให้ชัดเจนเป็นชุด และเขียนกำกับไว้เสมอว่าค่าเหล่านี้เป็นค่าที่กำหนดขึ้นเพื่อการทดสอบ ไม่ได้มาจากทะเบียนใด

สำหรับนักพัฒนา: เก็บวันเกิดเป็นวันที่ ไม่ใช่เวลา

ข้อแรกคือเก็บวันเกิดเป็นวันที่ล้วน ไม่เก็บเวลาและไม่เก็บเขตเวลากำกับ เพราะวันเกิดไม่ใช่เหตุการณ์ที่เกิดในวินาทีใดวินาทีหนึ่ง การเก็บเวลาไว้จะสร้างปัญหาเรื่องการเลื่อนวันเมื่อแปลงเขตเวลา

ข้อที่สองคือคำนวณอายุจากผลต่างของวันที่ในปฏิทิน ไม่ใช่จากผลต่างของจำนวนวินาทีหรือจำนวนวัน แล้วแปลงเป็นปีภายหลัง

ข้อที่สามคือเตรียมกรณีทดสอบที่ต่างกันเพียงหนึ่งวัน ได้แก่คนที่เพิ่งครบเกณฑ์เมื่อวาน คนที่ครบเกณฑ์วันนี้ และคนที่จะครบเกณฑ์พรุ่งนี้ สามกรณีนี้คือชุดที่จับข้อบกพร่องได้มากที่สุด

ข้อที่สี่คือกำหนดค่าต่ำสุดและค่าสูงสุดของปีที่ยอมรับไว้อย่างชัดเจน และแยกให้ออกระหว่างค่าที่ไม่สมเหตุสมผลกับค่าที่ไม่น่าเป็นไปได้ ค่าสูงที่เป็นไปไม่ได้จริงควรถูกปฏิเสธ ส่วนค่าที่เพียงแต่หายากควรถูกยอมรับ

ข้อที่ห้าคือทดสอบกับวันที่ 29 กุมภาพันธ์ทั้งในปีที่เป็นและปีที่ไม่เป็นปีอธิกสุรทิน พร้อมกับวันที่ 31 ของเดือนที่มีเพียงสามสิบวัน เพราะทั้งสองกรณีเป็นจุดที่การตรวจแบบหลวม ๆ ปล่อยผ่าน

ข้อที่ควรระวังเมื่อเก็บวันเกิดเป็นวันที่ ไม่ใช่เวลา:

  • ข้อแรกคือเก็บวันเกิดเป็นวันที่ล้วน ไม่เก็บเวลาและไม่เก็บเขตเวลากำกับ
  • ข้อที่สองคือคำนวณอายุจากผลต่างของวันที่ในปฏิทิน ไม่ใช่จากผลต่างของจำนวนวินาทีหรือจำนวนวัน
  • ข้อที่สามคือเตรียมกรณีทดสอบที่ต่างกันเพียงหนึ่งวัน ได้แก่คนที่เพิ่งครบเกณฑ์เมื่อวาน คนที่ครบเกณฑ์วันนี้ และคนที่จะครบเกณฑ์พรุ่งนี้
  • ข้อที่สี่คือกำหนดค่าต่ำสุดและค่าสูงสุดของปีที่ยอมรับไว้อย่างชัดเจน
  • ข้อที่ห้าคือทดสอบกับวันที่ 29 กุมภาพันธ์ทั้งในปีที่เป็นและปีที่ไม่เป็นปีอธิกสุรทิน พร้อมกับวันที่ 31 ของเดือนที่มีเพียงสามสิบวัน

ก้าวต่อไป

ลองเปิดชุดทดสอบของคุณแล้วหาวันที่ที่ใช้อยู่ในนั้น ถ้าทุกวันเป็นวันที่กลมและอยู่ในฤดูเดียวกันทั้งหมด คุณยังไม่ได้ทดสอบความหลากหลายของประชากรมากพอ

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

ข้อมูลทุกชุดที่กล่าวถึงในบทความนี้เป็นข้อมูลที่สังเคราะห์ขึ้นเพื่อการทดสอบเท่านั้น ไม่ตรงกับบุคคลจริงใด และไม่สามารถใช้ผ่านการยืนยันตัวตนหรือการตรวจสอบอายุในโลกจริงได้

อ่านต่อ

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

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

รายการนี้แสดงเฉพาะบทความในหัวข้อของหน้านี้