出生日期邊界之所以麻煩,是因為它牽動兩件事:日期本身是否合法,以及由這個日期算出來的年齡是否正確。閏日、時區與曆法差異都會讓原本簡單的比較產生偏移。以下逐一說明這些情況,並整理幾個值得放進測試的日期。
閏年與二月二十九日
公曆的閏年規則是:能被四整除的年份是閏年,但世紀年必須能被四百整除才算。所以 1900 年不是閏年,2000 年是。這條規則不難,卻常在自行實作的日期檢查中被簡化成「能被四整除」。
簡化的後果是接受了一個不存在的日期,或拒絕了一個真實存在的日期。對測試來說,值得準備的樣本包括:二月二十九日出生且年份為閏年、二月二十九日出生但年份不是閏年、以及二月三十日這種任何年份都不該通過的值。
換年也是同一類問題。跨年時若程式用「今年的年份減去出生年份」當成年齡,就會在生日之前多算一歲;這種錯誤在十二月底與一月初特別容易出現,因為兩個日期落在不同的年份,而使用者的生日還沒到。
還有一種情況是輸入方式造成的:有些表單分成三個欄位,各自的下拉選單會依月份調整天數;有些只有一個文字欄位,完全靠驗證規則把關。前者要測的是選單在切換月份時會不會留下無效值,後者要測的是規則本身對不對。
生日當天算不算滿一歲?
通行的算法是:生日過了才算滿一歲,而生日當天通常算已經滿了。換句話說,今天出生的人,當天就滿零歲;等到隔年同一天,他滿一歲。這個慣例會直接影響年齡門檻的判定。
最容易出錯的地方是把「滿」與「未滿」的界線放在日期比較的符號上。差一個等號,就會出現整整一天的誤判,而這一天正好是使用者最容易申訴的那一天。
測試時建議明確挑三個日期:剛好滿門檻的當天、門檻前一天、門檻後一天。這三個日期能把大於、小於與等於三種比較都涵蓋到,比隨機挑幾十個生日有效得多。
還有一點值得注意:年齡計算最好只負責算出數字。同一個門檻在不同情境下可能還要搭配其他條件,把判斷一起寫進計算函式,日後就很難在不影響其他流程的情況下調整其中一項。
為什麼同一個生日在不同時區會差一天?
因為「今天」不是一個絕對值。年齡是用出生日期與當前日期算出來的,而當前日期取決於你在哪個時區計算。伺服器在一個時區、使用者在另一個時區時,兩邊可能落在不同的日曆日,於是同一筆資料在兩地的判定結果差一天。
這個問題在接近午夜時最明顯:使用者的當地時間已經跨日,伺服器所在時區還沒。若系統只保留日期而不記錄時區,這個差異就無法還原,也就難以解釋為什麼同一筆資料上午與下午的結果不同。
實務上的處理方式是固定基準:約定年齡一律以哪個時區的當日計算,並在文件與介面上寫清楚。測試資料不需要為每個時區都準備樣本,但至少要涵蓋基準日的前後一天。
非公曆國家的生日怎麼寫?
世界上存在非公曆的曆法,例如衣索比亞、尼泊爾與伊朗各自使用自己的曆法。同一個日子在兩套曆法下的年月日寫法不同,這使得「生日」這個欄位在跨國情境下不能只假設公曆。
對系統而言,通常的做法是要求輸入公曆日期,並在需要時於介面上顯示當地曆法的對照;反過來,若某個國家的使用者習慣填寫當地曆法,表單就必須明確標示它期待的是哪一種。含糊不清的欄位標籤,是這類錯誤最常見的起點。
本站的身份產生器在產生各國資料時,出生日期與年齡互相對應;生成內容只供測試,不能當成任何人的真實生日,也不能用來冒充真人。想理解證件號裡若編入生日會帶來什麼麻煩,可延伸閱讀各國身份證號長度。
使用者為什麼會填出不可能的生日?
填錯的原因很多:把年份與日期寫反、用當地曆法填進公曆欄位、把小鍵盤的數字打錯,或是直接照著某個不允許的格式輸入。這些錯誤在真實資料裡很常見,系統需要的是溫和的提示,而不是直接清空整個欄位。
準備測試樣本時,可以刻意放入這些輸入:順序顛倒的日期、超出合理範圍的年份、只有月與日沒有年份,以及含有多餘分隔符號的字串。它們對應不同的處理路徑,能一次檢查提示訊息是否說得清楚。
佔位日期為什麼不能當成真實生日?
因為佔位值會悄悄變成有效值。當一筆資料的生日被填成某個顯眼的年份,它在系統裡就是一個可以計算、可以排序、可以觸發行銷活動的日期,而不是「還沒填」。如果程式或使用者把這個值當真,後續所有判斷都建立在錯誤的基礎上。
常見的補救方式是把「未提供」與「填錯」分開:前者應該允許留白,後者才需要提示。硬塞一個日期來避免空值,等於用一個錯誤換取一時的方便。
給開發者:年齡只從日期算起
- 生日只存日期,不存時區;時區差異在計算年齡時才處理。
- 年齡當成衍生的結果即時計算,不要另存一個會過期的數字欄位。
- 邊界用例至少涵蓋:生日當天、門檻前一天、門檻後一天、二月二十九日。
- 日期比較前先確認兩邊都是有效日期,再進行換算。
- 對外的輸入介面要標示它期待的曆法與格式,不要讓使用者猜。
- 測試資料裡不要用真實人物的生日,也不要讓同一組生日在整個套件裡重複出現。
還有一個常被忽略的點:顯示與儲存可以分開。儲存用一種標準格式,顯示依使用者語言調整順序與分隔符號,兩者不必一致;把顯示格式直接當成儲存格式,日後換語系時就會出現無法解析的舊資料。
下一步
打開你的年齡或生日驗證,用「今天」與「明天」各跑一次邊界日,確認結果符合預期;再把二月二十九日的樣本補上。若你的流程還涉及門檻設定,接著讀年齡驗證測試怎麼做。
測完之後,把這幾個邊界日期寫進測試資料並加上註解,說明它們各自要驗證什麼;否則半年後沒有人知道那筆二月二十九日的樣本為什麼存在。