Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Get English Month Name From Hebrew Calendar In C#

Tags:

c#

datetime

I am trying to output a Hebrew calendar date in English with C#. The following outputs the date in Hebrew:

    var ci = System.Globalization.CultureInfo.CreateSpecificCulture("he-IL");
    ci.DateTimeFormat.Calendar = new System.Globalization.HebrewCalendar();
    Response.Write(DateTime.Today.ToString("MMM d, yyyy", ci));
    Response.Write(DateTime.Today.ToString("d-M-y", ci));

Gives

כסלו כ"ו, תשע"ה
כ"ו-ג'-תשע"ה

for December 18, 2014. Change the CultureInfo to "en-US" raises an "Not a valid calendar for the given culture." error. I am trying to get

26 Kislev 5775

and

26-09-5775
like image 530
MarkF Avatar asked Dec 18 '14 08:12

MarkF


2 Answers

I could not figure out how to set the array of month names for leap years or the array of day numbers so that they are rendered as English numbers rather than hebrew letters. My solution was:

Globals.cs

    public static string[] HebrewMonthNames =
    {
      "Tishrei",
      "Cheshvan",
      "Kislev",
      "Tevet",
      "Shevat",
      "Adar",
      "Nissan",
      "Iyar",
      "Sivan",
      "Tamuz",
      "Av",
      "Elul"
    };

    public static string[] HebrewMonthNamesLeapYear =
    {
      "Tishrei",
      "Cheshvan",
      "Kislev",
      "Tevet",
      "Shevat",
      "Adar I",
      "Adar II",
      "Nissan",
      "Iyar",
      "Sivan",
      "Tamuz",
      "Av",
      "Elul"
    };

Utils.cs

public string FormatHebrewDate(DateTime dtGregorian)
{
                System.Globalization.HebrewCalendar hCal = new System.Globalization.HebrewCalendar();
                string sDate = hCal.GetDayOfMonth(dtGregorian).ToString() + " ";
                if (hCal.IsLeapYear(hCal.GetYear(dtGregorian)))
                {
                    sDate += Globals.HebrewMonthNamesLeapYear[hCal.GetMonth(dtGregorian) - 1];
                }
                else
                {
                    sDate += Globals.HebrewMonthNames[hCal.GetMonth(dtGregorian) - 1];
                }
                sDate += " " + hCal.GetYear(dtGregorian).ToString();
                return sDate;
}
like image 77
MarkF Avatar answered Oct 09 '22 21:10

MarkF


Option 1:

You can override the DateTimeFormatInfo.MonthNames and MonthGenitiveNames properties as well as their corresponding AbbreviatedMonthNames and AbbreviatedMonthGenitiveNames properties.

They are simple 1-dimensional string[] arrays and have a public setters, which allows you to add your custom translations to the CultureInfo:

When this property is set, the array must be one-dimensional and must have exactly 13 elements. Calendar objects accommodate calendars with 13 months. The first element (the element at index zero) represents the first month of the year defined by the Calendar property.

If you set the MonthNames property, you must also set the MonthGenitiveNames property.

If the custom pattern includes the format pattern "MMMM", DateTime.ToString displays the value of MonthNames in place of the "MMMM" in the format pattern.

This property is affected if the value of the Calendar property changes.

So you could modify your code example to this:

// I am just using German Number representations for the example.
// Use additional string Arrays to suit the abbrevated
// and the Genetive names.
// Replaye with whatever suits your needs.
string[] monthNames =
    {
      "Eins",
      "Zwei",
      "Drei",
      "Vier",
      "Fünf",
      "Sechs",
      "Sieben",
      "Acht",
      "Neun",
      "Zehn",
      "Elf",
      "Zwölf",
      string.Empty
    };

// Assign each string Array to its corresponding property.
// I am using the same Array here just as an example for
// what is possible and because I am lazy... :-)
ci.DateTimeFormat.MonthNames = monthNames;
ci.DateTimeFormat.MonthGenitiveNames = monthNames;
ci.DateTimeFormat.AbbreviatedMonthNames = monthNames;
ci.DateTimeFormat.AbbreviatedMonthGenitiveNames = monthNames;

These names will then be used in with your format string in the output, just as you want it to have.

Each time you change the calendar, these overrides will be lost. So you need to make sure to re-assign the custom values if you need it.

[Update] Option 2:

A more persistent approach might be to use the CultureAndRegionInfoBuilder Class.

Defines a custom culture that is new or based on another culture and country/region. The custom culture can be installed on a computer and subsequently used by any application that is running on that computer.

You can either create a complete replacement version of the "he-IL" culture or create a variation with just your custom translations, or anything in between.

Using this approach you do not have to manually make sure that the translations are in place after each Culture-switch in the appliaction like in Option 1. Once the new Custom Culture is registered, you can use it like any other CultureInfo.

Please note that your application will need administrative priviledges to register a new Custom Culture.

The creation of a Custom Culture is not too complicated as the following code snippet shows.

Example from MSDN: CultureAndRegionInfoBuilder

The following example defines a custom ru-US culture that represents the Russian language in the United States. The example defines the custom culture by loading settings from the Russian (Russia) CultureInfo object and the U.S. RegionInfo object, and then sets a number of CultureAndRegionInfoBuilder properties. The example registers the custom culture, and then instantiates it and makes it the current thread culture.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Create a custom culture for ru-US.
      CultureAndRegionInfoBuilder car1 = new CultureAndRegionInfoBuilder("ru-US", 
                                             CultureAndRegionModifiers.None);
      car1.LoadDataFromCultureInfo(CultureInfo.CreateSpecificCulture("ru-RU"));
      car1.LoadDataFromRegionInfo(new RegionInfo("en-US"));

      car1.CultureEnglishName = "Russian (United States)";
      car1.CultureNativeName = "русский (США)";
      car1.CurrencyNativeName = "Доллар (США)";
      car1.RegionNativeName = "США";

      // Register the culture. 
      try {
         car1.Register();
      }    
      catch (InvalidOperationException) {
         // Swallow the exception: the culture already is registered.
      }

      // Use the custom culture.
      CultureInfo ci = CultureInfo.CreateSpecificCulture("ru-US");
      Thread.CurrentThread.CurrentCulture = ci;
      Console.WriteLine("Current Culture: {0}", 
                        Thread.CurrentThread.CurrentCulture.Name);
      Console.WriteLine("Writing System: {0}", 
                        Thread.CurrentThread.CurrentCulture.TextInfo);
   }
}
// The example displays the following output: 
//     Current Culture: ru-US 
//     Writing System: TextInfo - ru-US
like image 45
Jens H Avatar answered Oct 09 '22 20:10

Jens H