בעיית שנה מעוברת

בעיית שנה מעוברת (המכונה גם באג שנה מעוברת או באג יום מעובר) היא בעיה בעולמות המחשב שנובעת מחישוב שגוי של השנים שהן שנים מעוברות, או ממניפולציה של תאריכים ללא התחשבות בהבדל בין שנים מעוברות לשנים שאינן מעוברות.

סוגים

באגים של שנה מעוברת מתחלקים לשתי קטגוריות:[1]

  1. באגים המובילים לקריסת התוכנית, כגון זריקת חריגות, החזרת קוד שגיאה, משתנים לא מאותחלים או לולאות אינסופיות
  2. באגים לוגיים המובילים לתוצאה שגויה

דוגמאות

פייתון

קוד הפייתון הבא הוא דוגמה לבאג שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-today יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור תאריך 29 בפברואר בשנה לא מעוברת, שאינו קיים. הבאי של ה-date יציג ValueError עם ההודעה "day is out of range for month".[2]

from datetime import date
today = date.today()
later = today.replace(year = today.year + 1)

++C

קוד ה-++C הבא הוא דוגמה לבאג של שנה מעוברת שגורם לתוכנית לסיים את ריצתה בצורה לא תקנית, ולהחזיר קוד שגיאה. הקוד יעבוד כמו שצריך עד ש-st יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור 29 בפברואר של שנה לא מעוברת, שאינו קיים. העברה זו לכל פונקציה שמקבלת מבנה SYSTEMTIME תיכשל.

לדוגמה, SystemTimeToFileTime המוצגת כאן תחזיר קוד שגיאה. מכיוון שערך ההחזרה אינו נשמר במשתנה ונבדק לאחר מכן, הדבר יביא לכך ש-ft יישאר לא מאותחל.[3]

SYSTEMTIME st;
FILETIME ft;

GetSystemTime(&st);
st.wYear++;

SystemTimeToFileTime(&st, &ft);

#C

קוד ה-C sharp .NET הבא הוא דוגמה לבאג של שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-dt יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור 29 בפברואר של שנה לא מעוברת, שאינו קיים. הבנאי של DateTime יזרוק את החריגה ArgumentOutOfRangeException.[4]

DateTime dt = DateTime.Now;
DateTime result = new DateTime(dt.Year + 1, dt.Month, dt.Day);

JavaScript

קוד ה-JavaScript הבא הוא דוגמה לבאג בלוגיקה שנגרם עקב שנה מעוברת, ומוביל להתנהגות לא צפויה. הקוד יעבוד כמו שצריך עד ש-dt יהפוך ל-29 בפברואר, למשל בתאריך 29 בפברואר 2020, אז ינסה לקדם את השנה ל-2021. מכיוון ש-29 בפברואר 2021 לא קיים, Date יתגלגל קדימה לתאריך החוקי הבא, שהוא 1 במרץ 2021, שעלול להוביל להתנהגות לא צפויה בהמשך הקוד.[5]

var dt = new Date();
dt.setFullYear(dt.getFullYear() + 1);

אלגוריתם שגוי לחישוב שנה מעוברת (נכון למגוון שפות תכנות)

הקוד הבא הוא דוגמה לבאג נפוץ של שנה מעוברת שיכול להתרחש במגוון שפות תכנות. הבאג עלול לגרום למגוון תופעות שחלקן לוגיות וחלקן גורמות לתוכנית לקרוס, כתלות בשימוש שנעשה בתוצאה. הקוד מניח באופן שגוי ששנה מעוברת מתרחשת בדיוק כל ארבע שנים.[6]

bool isLeapYear = year % 4 == 0;

היסטוריה

הופעת באגים שנגרמים עקב שנה מעוברת התרחשה פעמים רבות לאורך ההיסטוריה, וככל הנראה תמשיך להתרחש גם בשנים מעוברות עתידיות. מספר דוגמאות:

  • בשנת 2020 התרחשו מספר באגים של שנה מעוברת, ואלו קוטלגו ב-List of 2020 Leap Day Bugs באתר Code of Matt.[7]
  • בשנת 2016, באג שנה מעוברת שהתרחש ב-29 בפברואר במערכת הובלת המזוודות בנמל התעופה דיסלדורף גרם למעל 1,200 משאים להחמיץ את טיסותיהם.[8]
  • בשנת 2016 התרחשו מספר באגים של שנה מעוברת, ואלו קוטלגו ב-List of 2016 Leap Day Bugs באתר Code of Matt.[9]
  • בשנת 2012, Microsoft Azure ירד ממצב מקוון בעקבות באג השנה המעוברת ב-28 בפברואר, בשעה 17:45 בשעון של החוף המערבי. צוות Windows Azure טען שהבאג התרחש בגלל חישוב שגוי.
  • בשנת 2012, היסטוריית הצ'אטים של Gmail הציגה את התאריך 31 בדצמבר 1969 לכל הצ'אטים שנשמרו ב-29 בפברואר.[דרוש מקור]
  • בשנת 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]

ראו גם

הערות שוליים

  1. ^ Johnson-Pint, Matt. "What are some examples of leap year bugs?". Stack Overflow. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  2. ^ Johnson-Pint, Matt. "Python - Replacing the year". Stack Overflow. נבדק ב-29 בפברואר 2020. {{cite web}}: (עזרה)
  3. ^ Johnson-Pint, Matt. "Win32 / C++ SYSTEMTIME struct manipulation". Stack Overflow. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  4. ^ Johnson-Pint, Matt. ".NET / C# - Construction from date parts". Stack Overflow. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  5. ^ Johnson-Pint, Matt. "JavaScript - Adding Year(s)". Stack Overflow. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  6. ^ Johnson-Pint, Matt. "Determining if a Year is a Leap Year". Stack Overflow. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  7. ^ Johnson-Pint, Matt. "List of 2020 Leap Day Bugs". Code of Matt. נבדק ב-9 במרץ 2020. {{cite web}}: (עזרה)
  8. ^ "Airport hiccup leaves 100s of passengers pantless". The Local (de). נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  9. ^ Johnson-Pint, Matt. "List of 2016 Leap Day Bugs". Code of Matt. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  10. ^ "TomTom sat-nav devices hit by GPS 'leap year bug'". BBC News. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  11. ^ "Sony fixes PS3 leap year bug". Metro (באנגלית). 2 במרץ 2010. נבדק ב-10 באוקטובר 2019. {{cite news}}: (עזרה)
  12. ^ "Home - Microsoft Answers". Forums.zune.net. אורכב מ-המקור ב-30 באוגוסט 2009. נבדק ב-2011-07-27. {{cite web}}: (עזרה)
  13. ^ John Herrman (2008-12-31). "30GB Zunes Failing Everywhere, All At Once". Gizmodo.com. נבדק ב-2011-07-27.
  14. ^ Geere, Duncan. "BREAKING: Zunes worldwide hit by mystery crash : Tech Digest". Techdigest.tv. נבדק ב-2011-07-27.
  15. ^ "Zune 30 FAQ". Microsoft. 31 בדצמבר 2008. נבדק ב-1 בינואר 2009. {{cite web}}: (עזרה)
  16. ^ Zadegan, Bryant (3 בינואר 2009). "A lesson on infinite loops". AeroXperience. נבדק ב-5 בינואר 2009. {{cite web}}: (עזרה)
  17. ^ Towler, Jim. "Leap-Year software bug gives "Million-dollar glitch"". The RISKS Digest. ACM Committee on Computers and Public Policy. נבדק ב-5 בפברואר 2020. {{cite web}}: (עזרה)
  18. ^ Excel incorrectly assumes that the year 1900 is a leap year. Retrieved 2019-05-01.
  19. ^ Standard ECMA-376 / Open Office XML File Formats. Retrieved 2016-09-10.
  20. ^ ISO/IEC 29500 / Open Office XML File Formats. Retrieved 2016-09-10.