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

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

## סוגים
באגים של שנה מעוברת מתחלקים לשתי קטגוריות:

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

## דוגמאות
### פייתון
קוד הפייתון הבא הוא דוגמה לבאג שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-`today` יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור תאריך 29 בפברואר בשנה לא מעוברת, שאינו קיים. הבאי של ה-`date` יציג `ValueError` עם ההודעה "day is out of range for month".
```python
from datetime import date
today = date.today()
later = today.replace(year = today.year + 1)
```


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

לדוגמה, `SystemTimeToFileTime` המוצגת כאן תחזיר קוד שגיאה. מכיוון שערך ההחזרה אינו נשמר במשתנה ונבדק לאחר מכן, הדבר יביא לכך ש-`ft` יישאר לא מאותחל.
```cpp
SYSTEMTIME st;
FILETIME ft;

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

SystemTimeToFileTime(&st, &ft);
```


### #C
קוד ה-C sharp .NET הבא הוא דוגמה לבאג של שנה מעוברת שגורם לזריקת חריגה. הוא יעבוד כמו שצריך עד ש-`dt` יהפוך ל-29 בפברואר. לאחר מכן, הוא ינסה ליצור 29 בפברואר של שנה לא מעוברת, שאינו קיים. הבנאי של `DateTime` יזרוק את החריגה `ArgumentOutOfRangeException`.
```csharp
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, שעלול להוביל להתנהגות לא צפויה בהמשך הקוד.
```js
var dt = new Date();
dt.setFullYear(dt.getFullYear() + 1);
```


### אלגוריתם שגוי לחישוב שנה מעוברת (נכון למגוון שפות תכנות)
הקוד הבא הוא דוגמה לבאג נפוץ של שנה מעוברת שיכול להתרחש במגוון שפות תכנות. הבאג עלול לגרום למגוון תופעות שחלקן לוגיות וחלקן גורמות לתוכנית לקרוס, כתלות בשימוש שנעשה בתוצאה. הקוד מניח באופן שגוי ששנה מעוברת מתרחשת בדיוק כל ארבע שנים.
```csharp
bool isLeapYear = year % 4 == 0;
```


## היסטוריה
הופעת באגים שנגרמים עקב שנה מעוברת התרחשה פעמים רבות לאורך ההיסטוריה, וככל הנראה תמשיך להתרחש גם בשנים מעוברות עתידיות. מספר דוגמאות:
* בשנת 2020 התרחשו מספר באגים של שנה מעוברת, ואלו קוטלגו ב-List of 2020 Leap Day Bugs באתר Code of Matt.
* בשנת 2016, באג שנה מעוברת שהתרחש ב-29 בפברואר במערכת הובלת המזוודות בנמל התעופה דיסלדורף גרם למעל 1,200 משאים להחמיץ את טיסותיהם.
* בשנת 2016 התרחשו מספר באגים של שנה מעוברת, ואלו קוטלגו ב-List of 2016 Leap Day Bugs באתר Code of Matt.
* בשנת 2012, Microsoft Azure ירד ממצב מקוון בעקבות באג השנה המעוברת ב-28 בפברואר, בשעה 17:45 בשעון של החוף המערבי. צוות Windows Azure טען שהבאג התרחש בגלל חישוב שגוי.
* בשנת 2012, היסטוריית הצ'אטים של Gmail הציגה את התאריך 31 בדצמבר 1969 לכל הצ'אטים שנשמרו ב-29 בפברואר.
* בשנת 2012, התקני ניווט לווייניים של TomTom היו תקולים עקב באג שנה מעוברת שהופיע לראשונה ב-31 במרץ.
* בשנת 2010 פלייסטיישן 3 של חברת סוני התייחס באופן שגוי לשנה כאל שנה מעוברת, כך שהתאריך הלא קיים 29 בפברואר 2010 הוצג במקום 1 במרץ 2010 וגרם לשגיאות תוכנה.
* בחצות ב-31 בדצמבר 2008, דגמי Zune 30 רבים מהדור הראשון קפאו. מיקרוסופט הצהירה כי הבעיה נגרמה על ידי מנהל השעון הפנימי שנכתב על ידי פריסקייל, והאופן שבו המכשיר מטפל בשנה מעוברת. הבעיה תוקנה אוטומטית כעבור 24 שעות, אך מי שלא שש להמתין 24 שעות יכול היה לרוקן את הסוללה של המכשיר ואז לטעון אותו מחדש לפי UTC, ב-1 בינואר 2009.
* בשנת 1996, שני מפעלי התכת אלומיניום - טיוואי פוינט שבניו זילנד ובל ביי שבטסמניה, אוסטרליה - חוו באג שנה מעוברת ב-31 בדצמבר, כאשר כל אחד מ-660 המחשבים השולטים בקווי ההיתוך נסגרו בחצות במקביל, בלי אזהרה. המחשבים לא תוכנתו לטיפול ביום ה-366 בשנה. עלויות התיקון נאמדו ביותר מ-1,000,000 דולר ניו זילנדי.
* מאז הגרסאות המוקדמות ביותר שלה, מיקרוסופט אקסל החשיבה באופן שגוי את שנת 1900 כשנה מעוברת, ולכן 29 בפברואר מגיע בין 28 בפברואר ל-1 במרץ של אותה שנה. מקורו של הבאג הוא בלוטוס 1-2-3, והוא הוטמע בכוונה באקסל לצורך תאימות לאחור. מיקרוסופט כתבה מאמר על הבאג, והסבירה את הסיבות שלה להתייחסות לשנת 1900 כשנה מעוברת. באג זה הפך לדרישה במפרט .

## ראו גם
* באגים הקשורים לשעה ותאריך
* באג 2000

## הערות שוליים

קטגוריה:באגים הקשורים לשעה ותאריך
קטגוריה:באגים
קטגוריה:לוחות שנה