2012-06-21 3 views
1

Я работаю на расширение даты фильтра в мой плагин Ideal Forms, чтобы позволить пользователю настроить формат даты, т.е. dd/mm/yyyy, mm-dd-yyyy ... Это то, что я до сих пор:Как организовать эту функцию для правильной работы?

date: { 
    regex: function (input, value) { 
     var 

     // Just grabbing some info from the plugin... 
     data = input.userOptions.data 
     ? input.userOptions.data.date 
     : { format: 'mm/dd/yyyy' }, // default format 

     separator = '\\' + /[^mdy]/.exec(data.format)[0], // extract separator 
     userFormat = data.format.replace(/[^mdy]/g, ''), // convert to proper format 

     isDate = function (m, d, y) { 
     return m > 0 && 
      m < 13 && 
      y > 0 && 
      y < 32768 && 
      d > 0 && 
      d <= (new Date(y, m, 0)).getDate() 
     }, 

     n2 = '(\\d{1,2})', // day and month 
     n4 = '(\\d{4})', // year 

     format = { 
     'mmddyyyy': function() { 
      var re = new RegExp(n2 + separator + n2 + separator + n4), 
       m = re.exec(value) 
      return m && isDate(m[1], m[2], m[3]) 
     }, 
     'ddmmyyyy': function() { 
      var re = new RegExp(n2 + separator + n2 + separator + n4), 
       m = re.exec(value) 
      return m && isDate(m[2], m[1], m[3]) 
     }, 
     'yyyymmdd': function() { 
      var re = new RegExp(n4 + separator + n2 + separator + n2), 
       m = re.exec(value) 
      return m && isDate(m[2], m[3], m[1]) 
     }, 
     'yyyyddmm': function() { 
      var re = new RegExp(n4 + separator + n2 + separator + n2), 
       m = re.exec(value) 
      return m && isDate(m[3], m[2], m[1]) 
     } 
     } 

     return format[userFormat]() || format['mmddyyyy']() 
    }, 

При использовании форматов другое, что проблемы с по умолчанию mm/dd/yyyy возникают, поскольку функция isDate проверяет дату, начинающуюся с значения месяца, поэтому, когда я передаю пользовательский формат, например dd-mm-yyyy, работает звонок isDate(m[2], m[1], m[3]), но он также проверяет такие значения, как , но не 13-13-1986.

Как я могу это исправить? Есть идеи?

+0

Что бы вы ожидаете '13-13-1986' вернуться? '1-13-1987' или null/false для недопустимой даты? –

+0

well '13-13-1986' должен явно возвращать' false', и это так, это не допустимая дата для этого формата 'dd-mm-yyyy'. Тогда '1-13-1987' должен быть' false', но он возвращает 'true'. Если формат по умолчанию равен 'mm/dd/yyyy', тогда все работает так, как ожидалось, и' 1/13/1987' вернет false, что предотвратит проверку. – elclanrs

+0

Это должен быть порядок оценки возвращаемого значения 'isDate', но как его исправить? Я не знаю, работал слишком долго ... – elclanrs

ответ

1

EDIT

Я хотел обратиться комментарий по поводу возвращения isDate тоже. Функция ведет себя так, как ожидалось, проблема в другом месте. Я не расчлененный код достаточно, чтобы сказать, где ошибка есть, но isDate правильно: http://jsfiddle.net/nQMYe/


Оригинал ответа

Я имел счастье с изменением сниппета здесь: http://joey.mazzarelli.com/2008/11/25/easy-date-parsing-with-javascript/

В принципе, он реализует метод fromString в объекте Date. Я не забочусь об этом, поэтому я изменил свою реализацию на автономную как функцию и исключил некоторые ненужные биты. Тем не менее, он отлично работает.

Основная идея - сначала нормализовать ввод. Поскольку вы никогда не знаете, если пользователь дает вам формат, как 1.11.2011 или 3~12~2012, первая вещь, чтобы просто стирает этот шум:

data = data.replace(/[^:a-z0-9]/g, '-'); 

Мы отбрасывая все не алфавитно-цифровые символы и опуская в -, вы, кажется, предпочитаете / - независимо от того, просто введите входной сигнал-иш. Мы сохраняем альфа, поэтому мы можем иметь дело с March 18, 2012.

После этого фрагмент анализирует вход, извлекает время (если даёт, использует: для идентификации), то устанавливается год. Как отмечается в комментариях, день и месяц находятся рядом друг с другом в самых разумных форматах, поэтому вы хотите установить, что НЕ является годом и оттуда. Затем происходит процесс устранения, чтобы определить месяц, затем день.

Не мой код, поэтому я не собираюсь брать кредит на эту идею, но опять-таки вещь доставляет рекламу. Вы можете использовать его как есть (лицензию BSD) или читать через источник и анализировать концепцию.

Вот код, для потомков:

/** 
* @author Joey Mazzarelli 
* @website http://bitbucket.org/mazzarelli/js-date/ 
* @website http://joey.mazzarelli.com/2008/11/25/easy-date-parsing-with-javascript/ 
* @copyright Joey Mazzarelli 
* @license BSD license 
*/ 

Date.fromString = (function() { 

    var defaults = { 
    order : 'MDY', 
    strict : false 
    }; 

    var months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", 
     "SEP", "OCT", "NOV", "DEC"]; 

    var abs = ["AM", "PM", "AFTERNOON", "MORNING"]; 

    var mark = function (str, val) { 
    var lval = val.toLowerCase(); 
    var regex = new RegExp('^' + lval + '|(.*[^:alpha:])' + lval, 'g'); 
    return str.replace(regex, '$1' + val); 
    }; 

    var normalize = function (str) { 
    str = str.toLowerCase(); 
    str = str.replace(/[^:a-z0-9]/g, '-'); 
    for (var i=0; i<months.length; i++) str = mark(str, months[i]); 
    for (var i=0; i<abs.length; i++) str = mark(str, abs[i]); 
    str = str.replace(/[a-z]/g, ''); 
    str = str.replace(/([0-9])([A-Z])/g, '$1-$2'); 
    str = ('-' + str + '-').replace(/-+/g, '-'); 
    return str; 
    }; 

    var find_time = function (norm) { 
    var obj = {date:norm, time:''}; 
    obj.time = norm.replace(
     /^.*-(\d\d?(:\d\d){1,2}(:\d\d\d)?(-(AM|PM))?)-.*$/, '$1'); 
    if (obj.time == obj.date) 
     obj.time = norm.replace(/^.*-(\d\d?-(AM|PM))-.*$/, '$1'); 
    if (obj.time == obj.date) obj.time = ''; 
    obj.date = norm.replace(obj.time, ''); 
    obj.time = ('-' + obj.time + '-').replace(/-+/g, '-'); 
    obj.date = ('-' + obj.date + '-').replace(/-+/g, '-'); 
    return obj; 
    }; 

    var find_year = function (norm) { 
    var year = null; 

    // Check for a 4-digit year 
    year = norm.replace(/^.*-(\d\d\d\d)-.*$/, '$1'); 
    if (year != norm) return year; else year = null; 

    // Check for a 2-digit year, over 32. 
    year = norm.replace(/^.*-((3[2-9])|([4-9][0-9]))-.*$/, '$1'); 
    if (year != norm) return year; else year = null; 

    // Day is always by month, so check for explicit months in 
    // first or third spot 
    year = norm.replace(/^.*-[A-Z]{3}-\d\d?-(\d\d?)-.*$/, '$1'); 
    if (year != norm) return year; else year = null; 
    year = norm.replace(/^.*-(\d\d?)-\d\d?-[A-Z]{3}-.*$/, '$1'); 
    if (year != norm) return year; else year = null; 

    // If all else fails, use the setting for the position of the year. 
    var pos = '$3'; 
    if (defaults.opts.order.charAt(0) == 'Y') pos = '$1'; 
    else if (defaults.opts.order.charAt(1) == 'Y') pos = '$2'; 
    year = norm.replace(/^.*-(\d\d?)-([A-Z]{3}|\d{1,2})-(\d\d?)-.*$/, pos); 
    if (year != norm) return year; else year = null; 

    return year; 
    }; 

    var find_month = function (norm, year) { 
    // Check for an explicity month 
    var matches = norm.match(/[A-Z]{3}/); 
    if (matches && matches.length) return matches[0]; 

    // Remove the year, and unless obviously wrong, use order 
    // to chose which one to use for month. 
    var parts = norm.replace(year + '-', '').split('-'); 
    if (parts.length != 4) return null; 
    var order = defaults.opts.order; 
    var md = order.indexOf('M') < order.indexOf('D')? 1: 2; 
    return (parseInt(parts[md], 10) <= 12)? parts[md]: parts[md==1? 2: 1]; 
    }; 

    var find_day = function (norm, year, month) { 
    return norm.replace(year, '').replace(month, '').replace(/-/g, ''); 
    }; 

    var create_absolute = function (obj) { 

    var time = obj.time.replace(/[-APM]/g, ''); 
    var parts = time.split(':'); 
    parts[1] = parts[1] || 0; 
    parts[2] = parts[2] || 0; 
    parts[3] = parts[3] || 0; 
    var ihr = parseInt(parts[0], 10); 
    if (obj.time.match(/-AM-/) && ihr == 12) parts[0] = 0; 
    else if (obj.time.match(/-PM-/) && ihr < 12) parts[0] = ihr + 12; 
    parts[0] = ("0" + parts[0]).substring(("0" + parts[0]).length - 2); 
    parts[1] = ("0" + parts[1]).substring(("0" + parts[1]).length - 2); 
    parts[2] = ("0" + parts[2]).substring(("0" + parts[2]).length - 2); 
    time = parts[0] + ":" + parts[1] + ":" + parts[2]; 
    var millisecs = parts[3]; 

    var strict = defaults.opts.strict; 
    if (!obj.year && !strict) obj.year = (new Date()).getFullYear(); 
    var year = parseInt(obj.year, 10); 
    if (year < 100) { 
     year += (year<70? 2000: 1900); 
    } 

    if (!obj.month && !strict) obj.month = (new Date()).getMonth() + 1; 
    var month = String(obj.month); 
    if (month.match(/[A-Z]{3}/)) { 
     month = "JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-" 
      .indexOf(month)/4 + 1; 
    } 
    month = ("0" + month).substring(("0" + month).length - 2); 
    if (!obj.day && !strict) obj.day = (new Date()).getDate(); 
    var day = ("0" + obj.day).substring(("0" + obj.day).length - 2); 

    var date = new Date(); 
    date.setTime(Date.parse(year + '/' + month + '/' + day + ' ' + time)); 
    date.setMilliseconds(millisecs); 
    return date; 
    }; 

    var parse = function (norm) { 
    return absolute(norm); 
    }; 

    var absolute = function (norm) { 
    var obj = find_time(norm); 
    obj.norm = norm; 
    obj.year = find_year(obj.date); 
    obj.month = find_month(obj.date, obj.year); 
    obj.day = find_day(obj.date, obj.year, obj.month); 
    return create_absolute(obj); 
    }; 

    return function (fuzz, opts) { 
    defaults.opts = { order: defaults.order, strict: defaults.strict }; 
    if (opts && opts.order) defaults.opts.order = opts.order; 
    if (opts && opts.strict != undefined) defaults.opts.strict = opts.strict; 
    var date = parse(normalize(fuzz)); 
    return date; 
    }; 

})(); 
+0

Вы правы, моя проблема должна быть где-то остальное. Я просто попытался изолировать свой код здесь http://jsfiddle.net/elclanrs/nQMYe/4/, и он действительно работает. Я все равно приму ваш ответ. Спасибо. – elclanrs

+0

Если вы расстроены или просто хотите перерыв, попробуйте опубликованный фрагмент. Во всяком случае, его можно отбросить, так как он все же проверяет, и кажется довольно солидным из-за моего использования. Пользователям особенно понравилась возможность использовать строки php-esq strtotime вместо того, чтобы быть осторожным с форматом. –

+0

Я пробовал свой код, но я не совсем понимаю, как использовать его для возврата 'true' или' false' с датой ... – elclanrs

Смежные вопросы