views:

958

answers:

4

I hava a jQuery UI datepicker which I intend to use with a textbox in ASP.NET MVC. The date-display in the textbox is localized via CultureInfo and of course should be recognized by jquery to select the correct date in the datepicker:

<%= Html.TextBox("Date", Model.Date.ToString("d", currentCultureInfo),
    new { @class = "datepicker" })%>

What I am trying to do now is to initialize the datepicker with a dateformat like

string jsCode = @"$("".datepicker"").datepicker({
    dateFormat: '" + currentCultureInfo.DateTimeFormat.ShortDatePattern + @"',
});";

The Problem is that the format of the format string of DateTimeFormatInfo (see MSDN Link) is completely different to the format string in jQuery (jQuery formatDate).

msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx (sorry, very funny stackoverflow restriction to one hyperlink for newbies!???)

Sample (German date format like 16.07.2009):

.NET: 'dd.MM.yyyy' should be converted to 'dd.mm.yy' in jQuery/Javascript

Is there a method or a library that does the needed transformation between the two formats?

+1  A: 

It may not be the perfect solution but it can get you started. jQuery doesn't have any methods for working with dates but JavaScript does.

Parsing Date

First it has a method Date.parse() which allows you to parse date strings to value containing number of miliseconds from January 1st 1970. You can then use this value to create a new date object and extract all the data you need from this object.

var dateString = "Jun 1 2006";
var parsedDate = Date.parse(dateString);
var date = new Date(parsedDate);

Unfortunately Date.parse() doesn't handle well 'dotted' strings like 2007.03.01 but there is a solution for that as well. You can just replace all dots with slashes:

var dateString = "2007.03.01".replace(/\./g, '/');

Still this won't make Date.parse() understand any date format that .NET will return but may be useful in some cases.

Formating Date

Now if you have Date object created you may now convert it to any date format you like. This actually is pretty easy. There is an implementation of PHP date format method for JS. You can find it here.

If you add that to your scripts you can than format your date using any tokens described in the documentation and there are plenty. For example

date.format('Y-M-d H:i:s');
RaYell
Asker already has a date formatting library. Asker doesn't need one that understand php's date format. Asker needs one that can understand/translate-to .NET's format.
Crescent Fresh
You don't need to understand php's date format, all switches are explained in the date format for JS documentation.I'm not sure if parser can handle all .NET's formats but surely this solution can be adapted to handle them. As I mentioned in my first sentence this is not a complete solution, more something you can start to work with.
RaYell
Thanks for your answer, but as crescentfresh said it's not really what I need. But it may help to think another way - one could prepare a javascript Date object with an ISO-Format and use that object to initialize the datepicker. Unfortunately the string returned by the datepicker still would be in another format. So, if there is no existing transformation library I guess I will have to write my own...
mattanja
+3  A: 

I've just run into exactly the same problem and came up with the code below. It's not perfect but should cover most cultures and fail gracefully. It's probably also not the shortest version you could come up with!

///========================================================================
///  Method : ConvertDateFormat
/// 
/// <summary>
///   Takes a culture and returns matching C# and jQuery date format
///   strings. If possible the C# string will be the ShortDatePattern for
///   the supplied culture.
/// </summary>
///========================================================================
private static void GetDateFormats(CultureInfo xiCulture, out string xoCSharpFormat, out string xoJQueryFormat)
{
  //=======================================================================
  // Start by assigning formats that are hopefully unambiguous in case we
  // can't do better.
  //=======================================================================
  xoCSharpFormat = "yyyy-MM-dd";
  xoJQueryFormat = "yy-mm-dd";

  if (xiCulture.IsNeutralCulture)
  {
    try
    {
      xiCulture = CultureInfo.CreateSpecificCulture(xiCulture.Name);
    }
    catch
    {
      //===================================================================
      // Some cultures are neutral and don't have specific cultures.
      // There's not much we can do here.
      //===================================================================
      return;
    }
  }

  string lCSharpFormat = xiCulture.DateTimeFormat.ShortDatePattern;

  //=======================================================================
  // Handle:
  //  C#     jQuery  Meaning
  //  d      d       Day of month (no leading 0)
  //  dd     dd      Day of month (leading 0)
  //  M      m       Month of year (no leading 0)
  //  MM     mm      Month of year (leading 0)
  //  yy     y       Two digit year
  //  yyyy   yy      Not an exact match but good enough:
  //                 C# means: The year in four or five digits (depending on
  //                 the calendar used), including the century. Pads with
  //                 leading zeros to get four digits. Thai Buddhist and
  //                 Korean calendars have five-digit years. Users
  //                 selecting the "yyyy" pattern see all five digits
  //                 without leading zeros for calendars that have five
  //                 digits. Exception: the Japanese and Taiwan calendars
  //                 always behave as if "yy" is selected.
  //                 jQuery means: four digit year
  //
  //  Copy '.', '-', ' ', '/' verbatim
  //  Bail out if we find anything else and return standard date format for
  //  both.
  //=======================================================================
  StringBuilder lJQueryFormat = new StringBuilder();
  bool lError = false;
  for (int ii = 0; ii < lCSharpFormat.Length; ++ii)
  {
    Char lCurrentChar = lCSharpFormat[ii];

    switch (lCurrentChar)
    {
      case 'd':
        //=================================================================
        // d or dd is OK, ddd is not
        //=================================================================
        if (ii < (lCSharpFormat.Length - 1) &&
          lCSharpFormat[ii+1] == 'd')
        {
          if (ii < (lCSharpFormat.Length - 2) &&
          lCSharpFormat[ii+2] == 'd')
          {
            //=============================================================
            // ddd
            //=============================================================
            lError = true;
          }
          else
          {
            //=============================================================
            // dd
            //=============================================================
            lJQueryFormat.Append("dd");
            ii++;
          }
        }
        else
        {
          //===============================================================
          // d
          //===============================================================
          lJQueryFormat.Append('d');
        }
        break;
      case 'M':
        //=================================================================
        // M or MM is OK, MMM is not
        //=================================================================
        if (ii < (lCSharpFormat.Length - 1) &&
          lCSharpFormat[ii + 1] == 'M')
        {
          if (ii < (lCSharpFormat.Length - 2) &&
          lCSharpFormat[ii + 2] == 'M')
          {
            //=============================================================
            // MMM
            //=============================================================
            lError = true;
          }
          else
          {
            //=============================================================
            // MM
            //=============================================================
            lJQueryFormat.Append("mm");
            ii++;
          }
        }
        else
        {
          //===============================================================
          // M
          //===============================================================
          lJQueryFormat.Append('m');
        }
        break;
      case 'y':
        //=================================================================
        // yy or yyyy is OK, y, yyy, or yyyyy is not
        //=================================================================
        if (ii < (lCSharpFormat.Length - 1) &&
          lCSharpFormat[ii + 1] == 'y')
        {
          if (ii < (lCSharpFormat.Length - 2) &&
            lCSharpFormat[ii + 2] == 'y')
          {
            if (ii < (lCSharpFormat.Length - 3) &&
              lCSharpFormat[ii + 3] == 'y')
            {
              if (ii < (lCSharpFormat.Length - 4) &&
                lCSharpFormat[ii + 4] == 'y')
              {
                //=========================================================
                // yyyyy
                //=========================================================
                lError = true;
              }
              else
              {
                //=========================================================
                // yyyy
                //=========================================================
                lJQueryFormat.Append("yy");
                ii = ii + 3;
              }
            }
            else
            {
              //===========================================================
              // yyy
              //===========================================================
              lError = true;
            }
          }
          else
          {
            //=============================================================
            // yy
            //=============================================================
            lJQueryFormat.Append("y");
            ii++;
          }
        }
        else
        {
          //===============================================================
          // y
          //===============================================================
          lError = true;
        }
        break;
      case '.':
      case '-':
      case ' ':
      case '/':
        lJQueryFormat.Append(lCurrentChar);
        break;
      default:
        lError = true;
        break;
    }

    if (lError)
    {
      break;
    }
  }

  //=======================================================================
  // If we didn't get an error return the culture specific formats
  //=======================================================================
  if (!lError)
  {
    xoCSharpFormat = lCSharpFormat;
    xoJQueryFormat = lJQueryFormat.ToString();
  }
}
Dan
Yea, thanks for the code... I've been thinking about writing some similar conversion code, but for now I've just been using the ISO-date format at both sides. Guess I'll use your class now.
mattanja
Well, after taking a closer look at the code it seems way too complicated to me - using such a complex handling would be only justifiable if ALL cases are handled - including month names and day names.Since the provided code only handles ShortDatePattern, the string-replacement code provided in my answer will do about the same in 4 lines. Or did I miss the point of your code?
mattanja
It's quite large because it's fairly defensive and I had half an eye on extending it in the future (although given the limited overlap between the jQuery and MS format strings that may not be possible). In the (probably unlikely I admit) case that Microsoft were to add a short date format that used ddd or MMM or some other new character the simple code would leave in extra letters while mine would use it's default format instead.BTW I think you could shorten your code further by removing the MM replace?
Dan
Of course your code is pretty defensive :-) Still if you only handle ShortDatePattern, the short version will do. However, when extending to (almost) all possible formats, some construct like yours will be needed.And you're right, I removed the MM replace...
mattanja
+1  A: 

I think this will be the easiest way...

string dateFormat = currentCultureInfo.DateTimeFormat.ShortDatePattern.Replace("MM", "mm");
string jsCode = @"$("".datepicker"").datepicker({
    dateFormat: '" + dateFormat + @"',
});";
Josh Stodola
What about the different year format? But yeah if you add a replacement for the year format, this is a lot easier way than Dan's answer.
mattanja
+2  A: 

If only ShortDatePattern must be converted, the following code provides what I need:

public class wxDateTimeConvert
{
    /// <summary>
    /// Gets the javascript short date pattern.
    /// </summary>
    /// <param name="dateTimeFormat">The date time format.</param>
    /// <returns></returns>
    public static string GetJavascriptShortDatePattern(DateTimeFormatInfo dateTimeFormat)
    {
        return dateTimeFormat.ShortDatePattern
            .Replace("M", "m")
            .Replace("yy", "y");
    }
}

Including Javascript in page:

    /// <summary>
    /// Inserts the localized datepicker jquery code
    /// </summary>
    private void InsertLocalizedDatepickerScript()
    {

        string dateformat = wxDateTimeConvert.GetJavascriptShortDatePattern(Thread.CurrentThread.CurrentUICulture.DateTimeFormat);
        String js = @"$(document).ready(function() {
$("".datepicker"").datepicker({
    changeYear: true,
    dateFormat: '" + dateformat + @"',
    maxDate: new Date()
  });
});";
        this.Page.Header.Controls.Add(
            new LiteralControl("<script type=\"text/javascript\">" + js + "</script>")
        );
    }

However, this does not handle month or day names, time formatting or other special cases.

mattanja