בעיית שנה מעוברת (המכונה גם באג שנה מעוברת או באג יום מעובר) היא בעיה בעולמות המחשב שנובעת מחישוב שגוי של השנים שהן שנים מעוברות, או ממניפולציה של תאריכים ללא התחשבות בהבדל בין שנים מעוברות לשנים שאינן מעוברות.
באגים המובילים לקריסת התוכנית, כגון זריקת חריגות, החזרת קוד שגיאה, משתנים לא מאותחלים או לולאות אינסופיות
באגים לוגיים המובילים לתוצאה שגויה
דוגמאות
פייתון
קוד הפייתון הבא הוא דוגמה לבאג שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-today יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור תאריך 29 בפברואר בשנה לא מעוברת, שאינו קיים. הבאי של ה-date יציג ValueError עם ההודעה "day is out of range for month".[2]
קוד ה-++C הבא הוא דוגמה לבאג של שנה מעוברת שגורם לתוכנית לסיים את ריצתה בצורה לא תקנית, ולהחזיר קוד שגיאה. הקוד יעבוד כמו שצריך עד ש-st יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור 29 בפברואר של שנה לא מעוברת, שאינו קיים. העברה זו לכל פונקציה שמקבלת מבנה SYSTEMTIME תיכשל.
לדוגמה, SystemTimeToFileTime המוצגת כאן תחזיר קוד שגיאה. מכיוון שערך ההחזרה אינו נשמר במשתנה ונבדק לאחר מכן, הדבר יביא לכך ש-ft יישאר לא מאותחל.[3]
קוד ה-C sharp.NET הבא הוא דוגמה לבאג של שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-dt יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור 29 בפברואר של שנה לא מעוברת, שאינו קיים. הבנאי של DateTime יזרוק את החריגה ArgumentOutOfRangeException.[4]
קוד ה-JavaScript הבא הוא דוגמה לבאג בלוגיקה שנגרם עקב שנה מעוברת, ומוביל להתנהגות לא צפויה. הקוד יעבוד כמו שצריך עד ש-dt יהפוך ל-29 בפברואר, למשל בתאריך 29 בפברואר 2020, אז ינסה לקדם את השנה ל-2021. מכיוון ש-29 בפברואר 2021 לא קיים, Date יתגלגל קדימה לתאריך החוקי הבא, שהוא 1 במרץ 2021, שעלול להוביל להתנהגות לא צפויה בהמשך הקוד.[5]
אלגוריתם שגוי לחישוב שנה מעוברת (נכון למגוון שפות תכנות)
הקוד הבא הוא דוגמה לבאג נפוץ של שנה מעוברת שיכול להתרחש במגוון שפות תכנות. הבאג עלול לגרום למגוון תופעות שחלקן לוגיות וחלקן גורמות לתוכנית לקרוס, כתלות בשימוש שנעשה בתוצאה. הקוד מניח באופן שגוי ששנה מעוברת מתרחשת בדיוק כל ארבע שנים.[6]
boolisLeapYear=year%4==0;
היסטוריה
הופעת באגים שנגרמים עקב שנה מעוברת התרחשה פעמים רבות לאורך ההיסטוריה, וככל הנראה תמשיך להתרחש גם בשנים מעוברות עתידיות. מספר דוגמאות:
בשנת 2020 התרחשו מספר באגים של שנה מעוברת, ואלו קוטלגו ב-List of 2020 Leap Day Bugs באתר Code of Matt.[7]
בשנת 2016, באג שנה מעוברת שהתרחש ב-29 בפברואר במערכת הובלת המזוודות בנמל התעופה דיסלדורף גרם למעל 1,200 משאים להחמיץ את טיסותיהם.[8]
בשנת 2012, התקני ניווט לווייניים של TomTom היו תקולים עקב באג שנה מעוברת שהופיע לראשונה ב-31 במרץ.[10]
בשנת 2010 פלייסטיישן 3 של חברת סוני התייחס באופן שגוי לשנה כאל שנה מעוברת, כך שהתאריך הלא קיים 29 בפברואר 2010 הוצג במקום 1 במרץ 2010 וגרם לשגיאות תוכנה.[11]
בחצות ב-31 בדצמבר 2008, דגמי Zune 30 רבים מהדור הראשון קפאו.[12][13][14] מיקרוסופט הצהירה כי הבעיה נגרמה על ידי מנהל השעון הפנימי שנכתב על ידי פריסקייל, והאופן שבו המכשיר מטפל בשנה מעוברת. הבעיה תוקנה אוטומטית כעבור 24 שעות, אך מי שלא שש להמתין 24 שעות יכול היה לרוקן את הסוללה של המכשיר ואז לטעון אותו מחדש לפי UTC, ב-1 בינואר 2009.[15][16]
בשנת 1996, שני מפעלי התכת אלומיניום - טיוואי פוינט שבניו זילנד ובל ביי שבטסמניה, אוסטרליה - חוו באג שנה מעוברת ב-31 בדצמבר, כאשר כל אחד מ-660 המחשבים השולטים בקווי ההיתוך נסגרו בחצות במקביל, בלי אזהרה. המחשבים לא תוכנתו לטיפול ביום ה-366 בשנה. עלויות התיקון נאמדו ביותר מ-1,000,000 דולר ניו זילנדי.[17]
מאז הגרסאות המוקדמות ביותר שלה, מיקרוסופט אקסל החשיבה באופן שגוי את שנת 1900 כשנה מעוברת, ולכן 29 בפברואר מגיע בין 28 בפברואר ל-1 במרץ של אותה שנה. מקורו של הבאג הוא בלוטוס 1-2-3, והוא הוטמע בכוונה באקסל לצורך תאימות לאחור. מיקרוסופט כתבה מאמר על הבאג, והסבירה את הסיבות שלה להתייחסות לשנת 1900 כשנה מעוברת.[18] באג זה הפך לדרישה במפרט Ecma Office Open XML (OOXML).[19][20]