Date.prototype.listMonths = new Array("Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь");
Date.prototype.listShortMonths = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
Date.prototype.listWeekdays = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
Date.prototype.listShortWeekdays = new Array("В", "П", "В", "С", "Ч", "П", "С");
Date.prototype.firstWeekDay = "Mo";

Date.prototype.checkDateRange = function()
{
  var minDate = new Date(1753, 0, 1);
  var maxDate = new Date(9999, 11, 31);
  if (this < minDate) return minDate;
  if (this > maxDate) return maxDate;
  return this;
}

Date.prototype.addZero = function(value, resultLength)
{
  var countZero = resultLength - String(value).length;
  var result = String(value);
  for (var i=0; i<countZero; i++)
    result = "0" + result;
  return result;
}

Date.prototype.parseDateFormat = function(strMask)
{
  function isInArray(strValue, arrArray)
  {
    var intResult = -1;
    for ( var j = 0; j < arrArray.length && (strValue != arrArray[j]); j++ );
    if ( j != arrArray.length )
      intResult = j;    
    return intResult;
  }

  var UNDEF;
  var arrResult = new Array();             
  if (strMask == "" || typeof(strMask) == "undefined")
    return arrResult;
  var arrMaskTokens = new Array(
  "d", "w", "m", "M", "q", "y", "h", "H", "n", "s", 
  "dd", "ww", "mm", "MM", "yy", "hh", "HH", "nn", "ss", "S",
  "ddd", "mmm", "MMM", "A/P", "a/p", "dddd", "mmmm", "MMMM", 
  "yyyy", "AM/PM", "am/pm", "LongDate", "LongTime", 
  "ShortDate", "ShortTime", "GeneralDate");
  var arrMaskTokensFirstLetters = new Array("d", "w", "m", "M",
  "q", "y", "h", "H", "n", "s", "A", "a", "L", "S", "G");
  var strMaskLength = strMask.length;
  var i = 0, intMaskPosition = 0;
  var arrMask = new Array();
  var strToken = "";
  while (i < strMaskLength)
  {
  if (strMask.charAt(i) == "\\")
  {
    strToken += strMask.charAt(++i);
    i ++;
  }
  else if (strMask.charAt(i) == "'")
  {
    i ++;
    while ((i < strMask.length) && (strMask.charAt(i) != "'"))
    strToken += strMask.charAt(i++);
    i ++;
  }
  else
  {
    var j = isInArray(strMask.charAt(i), arrMaskTokensFirstLetters);
    if ( j != -1 )
    {
    var k;
    for (k = (arrMaskTokens.length - 1); k >= 0 && 
      strMask.slice(i, i + arrMaskTokens[k].length) != arrMaskTokens[k]; k--);
    if (k != -1)
    {
      if (strToken.length > 0)
      {
      if ( isInArray(strToken, arrMaskTokens) == -1)
        arrMask[intMaskPosition ++] = strToken;
      else
        arrMask[intMaskPosition ++] = "\\" + strToken;
      strToken = "";
      }
      arrMask[intMaskPosition ++] = arrMaskTokens[k];
      i += arrMaskTokens[k].length;
    }
    else
    {
      strToken = strMask.charAt(i);
      i ++;
    }
    }
    else
    {
    strToken += strMask.charAt(i);
    i ++;
    }
  }
  }
  if (strToken.length > 0)
  {
  if ( isInArray(strToken, arrMaskTokens) == -1)
    arrMask[intMaskPosition ++] = strToken;
  else
    arrMask[intMaskPosition ++] = "\\" + strToken;
  strToken = "";
  }
  arrResult = arrMask;
  return arrResult;
}

Date.prototype.formatDate = function (dateToFormat, parsedFormat)
{
  function getDayOfYear(year, month, day)
  {
    var firstDay = new Date(year, 0, 1);
    var date = new Date(year, month, day);
    return (date-firstDay)/(1000*60*60*24);
  }

  function get12Hour(hoursNumber)
  {
    if (hoursNumber == 0)
      hoursNumber = 12;
    else if (hoursNumber > 12)
      hoursNumber = hoursNumber - 12;
    return hoursNumber;
  }

  function getAMPM(HoursNumber, AnteMeridiem, PostMeridiem)
  {
    if (HoursNumber >= 0 && HoursNumber < 12)
      return AnteMeridiem;
    else
      return PostMeridiem;
  }

  var resultArray = new Array(parsedFormat.length);
  for (var i=0; i<parsedFormat.length; i++)
  {
    switch (parsedFormat[i]) 
    {
      case "d": 
        resultArray[i] = dateToFormat.getDate(); 
        break;
      case "w":
        resultArray[i] = dateToFormat.getDay()+1;
        break;
      case "m": case "M": 
        resultArray[i] = dateToFormat.getMonth()+1;
        break;
      case "q": 
        resultArray[i] = Math.floor((dateToFormat.getMonth()+4)/4);
        break;
      case "y": 
        resultArray[i] = getDayOfYear(dateToFormat.getFullYear(), dateToFormat.getMonth(), dateToFormat.getDate());
        break;
      case "h": 
        resultArray[i] = get12Hour(dateToFormat.getHours());
        break;
      case "H": 
        resultArray[i] = dateToFormat.getHours();
        break;
      case "n": 
        resultArray[i] = dateToFormat.getMinutes();
        break;
      case "s": 
        resultArray[i] = dateToFormat.getSeconds();
        break;
      case "dd": 
        resultArray[i] = dateToFormat.addZero(dateToFormat.getDate(), 2);
        break;
      case "ww": 
        resultArray[i] = Math.floor(getDayOfYear(dateToFormat.getFullYear(), dateToFormat.getMonth(), dateToFormat.getDate())/7)+1;
        break;
      case "mm": case "MM": 
        resultArray[i] = dateToFormat.addZero(dateToFormat.getMonth()+1, 2);
        break;
      case "yy": 
        resultArray[i] = String(dateToFormat.getFullYear()).substr(2);
        break;
      case "hh": 
        resultArray[i] = dateToFormat.addZero(get12Hour(dateToFormat.getHours()), 2);
        break;
      case "HH": 
        resultArray[i] = dateToFormat.addZero(dateToFormat.getHours(), 2);
        break;
      case "nn": 
        resultArray[i] = dateToFormat.addZero(dateToFormat.getMinutes(), 2);
        break;
      case "ss": 
        resultArray[i] = dateToFormat.addZero(dateToFormat.getSeconds(), 2);
        break;
      case "S": 
        resultArray[i] = "000";
        break;
      case "ddd": 
        resultArray[i] = dateToFormat.listShortWeekdays[dateToFormat.getDay()];
        break;
      case "mmm": case "MMM": 
        resultArray[i] = dateToFormat.listShortMonths[dateToFormat.getMonth()];
        break;
      case "A/P": 
        resultArray[i] = getAMPM(dateToFormat.getHours(), "A", "P");
        break;
      case "a/p": 
        resultArray[i] = getAMPM(dateToFormat.getHours(), "a", "p");
        break;
      case "dddd": 
        resultArray[i] = dateToFormat.listWeekdays[dateToFormat.getDay()];
        break;
      case "mmmm": case "MMMM":
        resultArray[i] = dateToFormat.listMonths[dateToFormat.getMonth()];
        break;
      case "yyyy": 
        resultArray[i] = dateToFormat.getFullYear();
        break;
      case "AM/PM": 
        resultArray[i] = getAMPM(dateToFormat.getHours(), "AM", "PM");
        break;
      case "am/pm": 
        resultArray[i] = getAMPM(dateToFormat.getHours(), "am", "pm");
        break;
      case ":": 
        resultArray[i] = ":";
        break;
      case "LongDate": 
        resultArray[i] = formatDate(dateToFormat, parseDateFormat("dddd, mmmm dd, yyyy"));
        break;
      case "LongTime": 
        resultArray[i] = formatDate(dateToFormat, parseDateFormat("h:nn:ss AM/PM"));
        break;
      case "ShortDate": 
        resultArray[i] = formatDate(dateToFormat, parseDateFormat("m/d/yy"));
        break;
      case "ShortTime": 
        resultArray[i] = formatDate(dateToFormat, parseDateFormat("H:nn"));
        break;
      case "GeneralDate": 
        resultArray[i] = formatDate(dateToFormat, parseDateFormat("m/d/yy hh:nn AM/PM"));
        break;
      default:
        if (String(parsedFormat[i]).charAt(0)=="\\")
        resultArray[i] = String(parsedFormat[i]).substr(0);
      else
        resultArray[i] = parsedFormat[i];
    }
  }
  return resultArray.join("");
}

Date.prototype.parseDate = function (dateToParse, parsedMask)
{
  var DateMasks = new Array(26);
    DateMasks["d"] = 0;
    DateMasks["dd"] = 2;
    DateMasks["m"] = 0;
    DateMasks["mm"] = 2;
    DateMasks["mmm"] = 3;
    DateMasks["mmmm"] = 0;
    DateMasks["M"] = 0;
    DateMasks["MM"] = 2;
    DateMasks["MMM"] = 3;
    DateMasks["MMMM"] = 0;
    DateMasks["yy"] = 2;
    DateMasks["yyyy"] = 4;
    DateMasks["h"] = 0;
    DateMasks["hh"] = 2;
    DateMasks["H"] = 0;
    DateMasks["HH"] = 2;
    DateMasks["n"] = 0;
    DateMasks["nn"] = 2;
    DateMasks["s"] = 0;
    DateMasks["ss"] = 2;
    DateMasks["am/pm"] = 2;
    DateMasks["AM/PM"] = 2;
    DateMasks["A/P"] = 1;
    DateMasks["a/p"] = 1;
    DateMasks["w"] = 0;
    DateMasks["q"] = 0;
    DateMasks["S"] = 0;
  var resultDate = new Date(), resultDateArray = new Array(8);
  var MaskPart, MaskLength, TokenLength;
  var IsError;
  var DatePosition, MaskPosition;
  var Delimiter, BeginDelimiter;
  var MonthNumber, MonthName;
  var DatePart;

  var IS_DATE_POS, YEAR_POS, MONTH_POS, DAY_POS, IS_TIME_POS, HOUR_POS, MINUTE_POS, SECOND_POS;

  IS_DATE_POS = 0;  YEAR_POS = 1;  MONTH_POS = 2;  DAY_POS = 3;
  IS_TIME_POS = 4;  HOUR_POS = 5;  MINUTE_POS = 6;  SECOND_POS = 7;

  if (!parsedMask)
    resultDate = null;
  else if (parsedMask[0] == "GeneralDate" && String(dateToParse)!="")
    resultDate = parseDate(dateToParse, parseDateFormat("m/d/yy hh:nn AM/PM"));
  else if (parsedMask[0] == "LongDate" && String(dateToParse)!="")
    resultDate = parseDate(dateToParse, parseDateFormat("dddd, mmmm dd, yyyy"));
  else if (parsedMask[0] == "ShortDate" && String(dateToParse)!="")
    resultDate = parseDate(dateToParse, parseDateFormat("m/d/yy"));
  else if (parsedMask[0] == "LongTime" && String(dateToParse)!="")
    resultDate = parseDate(dateToParse, parseDateFormat("h:nn:ss AM/PM"));
  else if (parsedMask[0] == "ShortTime" && String(dateToParse)!="")
    resultDate = parseDate(dateToParse, parseDateFormat("H:nn"));
  else if (String(dateToParse) == "") 
    resultDate = null;
  else
  {
    DatePosition = 0;
    MaskPosition = 0;
    MaskLength = parsedMask.length;
    IsError = false;

    // Default date
    resultDateArray[IS_DATE_POS] = false;
    resultDateArray[IS_TIME_POS] = false;
    resultDateArray[YEAR_POS] = 0;  resultDateArray[MONTH_POS] = 12;  resultDateArray[DAY_POS] = 1;
    resultDateArray[HOUR_POS] = 0;  resultDateArray[MINUTE_POS] = 0;  resultDateArray[SECOND_POS] = 0;

    while ((MaskPosition < MaskLength) && !IsError)
    {
      MaskPart = parsedMask[MaskPosition];
      if (DateMasks[MaskPart] != null)
      {
        TokenLength = DateMasks[MaskPart];
        if (TokenLength > 0)
        {
          DatePart = String(dateToParse).substr(DatePosition, TokenLength);
          DatePosition = DatePosition + TokenLength;
        }else
        {
          if (MaskPosition < MaskLength)
          {
            Delimiter = parsedMask[MaskPosition + 1];
            BeginDelimiter = dateToParse.indexOf(Delimiter, DatePosition);
            if (BeginDelimiter == -1)
            {
              alert("ParseDate function: The number doesn't match the mask.");
              return null;
            }else 
            {
              DatePart = String(dateToParse).substr(DatePosition, BeginDelimiter - DatePosition);
              DatePosition = BeginDelimiter;
            }
          }else DatePart = String(dateToParse).substr(DatePosition);
        }
        switch (MaskPart)
        {
          case "d": case "dd":
            resultDateArray[DAY_POS] = Math.floor(DatePart);
            resultDateArray[IS_DATE_POS] = true;
            break;
          case "m": case "mm": case "M": case "MM":
            resultDateArray[MONTH_POS] = Math.floor(DatePart);
            resultDateArray[IS_DATE_POS] = true;
            break;
          case "mmm": case "mmmm": case "MMM": case "MMMM":
            MonthNumber = 0;
            MonthName = String(DatePart).toUpperCase();
            if (MaskPart == "MMMM" || MaskPart == "mmmm") 
              MonthNamesArray = resultDate.listMonths;
            else
              MonthNamesArray = resultDate.listShortMonths;
            while (MonthNumber < 11 && String(MonthNamesArray[MonthNumber]).toUpperCase() != MonthName)
            {
              MonthNumber = MonthNumber + 1;
            }
            if (MonthNumber == 11) 
            {
              if (String(MonthNamesArray[11]).toUpperCase() != MonthName) 
              {
                alert("ParseDate function: The number doesn't match the mask.");
                return null;
              }
            }
            resultDateArray[MONTH_POS] = MonthNumber + 1;
            resultDateArray[IS_DATE_POS] = true;
            break;
          case "yy": 
                  var last2Digits = Math.floor(DatePart);
            var centuryDigits = (last2Digits>=50)?1900:2000;
            resultDateArray[YEAR_POS] = centuryDigits + last2Digits;
            resultDateArray[IS_DATE_POS] = true;
            break;
          case "yyyy":
            resultDateArray[YEAR_POS] = Math.floor(DatePart);
            resultDateArray[IS_DATE_POS] = true;
            break;
          case "h": case "hh":
            if (Math.floor(DatePart) == 12) 
              resultDateArray[HOUR_POS] = 0;
            else 
              resultDateArray[HOUR_POS] = Math.floor(DatePart);
            resultDateArray[IS_TIME_POS] = true;
            break;
          case "H": case "HH":
            resultDateArray[HOUR_POS] = Math.floor(DatePart);
            resultDateArray[IS_TIME_POS] = true;
            break;
          case "n": case "nn":
            resultDateArray[MINUTE_POS] = Math.floor(DatePart);
            resultDateArray[IS_TIME_POS] = true;
            break;
          case "s": case "ss":
            resultDateArray[SECOND_POS] = Math.floor(DatePart);
            resultDateArray[IS_TIME_POS] = true;
            break;
          case "am/pm": case "a/p": case "AM/PM": case "A/P":
            if (String(DatePart).toLowerCase().charAt(0) == "p") 
              resultDateArray[HOUR_POS] = resultDateArray[HOUR_POS] + 12;
            else if (String(DatePart).toLowerCase().charAt(0) == "a")
              resultDateArray[HOUR_POS] = resultDateArray[HOUR_POS];
            resultDateArray[IS_TIME_POS] = true;
            break;
          case "w": case "q": case "S":
            //Do Nothing
            break;
        }
      }else DatePosition = DatePosition + parsedMask[MaskPosition].length;
      MaskPosition = MaskPosition + 1
    }
    if (resultDateArray[IS_DATE_POS] && resultDateArray[IS_TIME_POS]) 
    {
      resultDate = new Date(resultDateArray[YEAR_POS], resultDateArray[MONTH_POS] - 1, resultDateArray[DAY_POS], resultDateArray[HOUR_POS], resultDateArray[MINUTE_POS], resultDateArray[SECOND_POS]);
    }else if (resultDateArray[IS_DATE_POS])
    {
      resultDate = new Date(resultDateArray[YEAR_POS], resultDateArray[MONTH_POS] - 1, resultDateArray[DAY_POS]);
    }else if (resultDateArray[IS_TIME_POS])
    {
      resultDate = new Date(0, 0, 0, resultDateArray[HOUR_POS], resultDateArray[MINUTE_POS], resultDateArray[SECOND_POS]);
    }
  }
  return resultDate;
}
