DCSIMG
לוח שנה ותאריך עברי ב-.NET - מאחורי המסך

מאחורי המסך

משה למפרט, על תכנות מתקדם וביצועים ב-Web.

על הבלוג

עוד חדשות

אתרים שיש לי בהם יד ורגל

לוח שנה ותאריך עברי ב-.NET

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

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

HebrewCalendar

ב-.NET, החל מגירסא 1 קיימת המחלקה System.Globalization.HebrewCalendar, המספקת לוח שנה עברי בדומה ללוחות נוספים מרחבי העולם, הממומשים במחלקות היורשות מ-System.Globalization.Calendar.
לכל הלוחות יש שיטות משותפות, בסגנון ה-GetX, כמו למשל GetDayOfMonth, GetMonth וכו', וכולם עובדים עם DateTime הסטנדרטי של הסביבה.

המרת תאריכים מעברי ולועזי ולהיפך:

Dim d as new DateTime(13,11,1987, new HebrewCalendar() 

ב- d יהיה אובייקט DateTime סטנדרטי.

d.ToString() יתן לנו 13/11/87, שזה התאריך הלועזי הרלוונטי.
כמובן שבמקרה העברי צריך להתחשב גם בשקיעה שיכולה להזיז את התאריך העברי יום קדימה.

הצגת תאריך עברי

Public Shared jewishCulture As System.Globalization.CultureInfo = System.Globalization.CultureInfo.CreateSpecificCulture("he-IL")

Public Shared Function ShortDate(ByVal dDate As Date) As String
    jewishCulture.DateTimeFormat.Calendar = HebCal
    Return dDate.ToString("dd MMMM", jewishCulture) End Function


בדיוק כמו תאריך לועזי, רק עם לוח שנה מתאים ואחר. גם שאר האפשרויות של DateTime.ToString() תעבודנה פה

 

חישובי תאריך עברי

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

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

הבעיה עם כל המימושים האלה היא העובדה שהם נכונים מספרית אבל לא הלכתית.& עיבור השנים מוסיף עוד חודש בין השישי לשביעי (אדר ב'), אלא - שהקוד שמוסיף שנה במחלקה הזו, מוסיף אותה במספרים ולא מתחשב בנתון הזה, וכך אדר ב' נהיה ניסן בשנה רגילה במקום להיות אדר רגיל. בעיות נוספות יש גם בחישובים הרלוונטיים לחודש אלול בשנים בהן מס' החודשים הוא 13.

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

לוח השנה של ערוץ 7 – פותח לפני כשנתיים על בסיס המחלקה הזו ונוספות, וכולל יכולות מאוד מעניינות נוספות.

תוכן התגובה

Shai Goldberg כתב/ה:

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

The Hebrew new year (Rosh HaShanah) begins on the 1st of Tishri, the 7th month in the list below

אם מחשבים את החודשים כך שהשנה "מתחילה" בחודש ניסן אז כאשר יש שנה מעוברת נוסף עוד חודש בסוף השנה.

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

לי יש מחלקה שמממשת חישובי לוח שנה עברי וכן DLL שמטפל בהעברה בין לוח שנה עברי, גרגוריאני ויוליאני ע"פ חישובים מספר שנקרא "Calendar Calculations" שהוא מחקר מדעי של משוואות לחישוב תאריכים והמרה בין תאריכים מרוב סוגי הלוחות שקיימים, אני מניח שמיקרוסופט השתמשו בנוסחאות מהספר הזה (אבל כמו שכתבתי, לא בדקתי את הנוסחאות).

אם מעניין אותך (או מישהו אחר) אני יכול לפרסם מידע נוסף.

# November 18, 2009 10:28 PM

Moshe L כתב/ה:

שי,

ראשית - איבחנת את הבעיה נכון. החודשים נספרים כש-1 זה תשרי ואילו הוא היה ניסן הבעיה הייתה פעוטה יותר.

מה שאני עשיתי בזמנו היה בדיקת IsLeapYear על השנה המקורית ועל שנת היעד, ואם צריך הוספת או הסרת חודש.

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

# November 19, 2009 2:07 PM

Shai Goldberg כתב/ה:

כמו שכתבתי לך יותר פשוט לבצע חישובים כאשר ניסן הוא חודש מספר 1 ולחשוף החוצה את החודשים כאשר תשרי הוא חודש מספר 1.

# November 20, 2009 10:28 AM