【问题标题】:How organize this function to work correctly?如何组织此功能以正常工作?
【发布时间】:2012-06-21 05:29:39
【问题描述】:

我正在扩展我的插件Ideal Forms 中的日期过滤器,以允许用户配置日期格式,即dd/mm/yyyymm-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]) 有效,但它还将验证 12-13-1986 之类的值,但不会验证 13-13-1986

我该如何着手解决这个问题?有什么想法吗?

【问题讨论】:

  • 您希望13-13-1986 返回什么? 1-13-1987 或 null/false 表示无效日期?
  • 好吧 13-13-1986 显然应该返回 false 并且确实如此,它不是这种格式 dd-mm-yyyy 的有效日期。那么1-13-1987 也应该是false,但它返回true。如果格式是默认的mm/dd/yyyy,那么一切都会按预期进行,1/13/1987 将返回 false,从而阻止验证。
  • 必须是isDate返回值的求值顺序,但是如何解决呢?我一无所知,工作太久了……
  • 正如我在回答的编辑中提到的,isDate 没问题:jsfiddle.net/nQMYe

标签: javascript jquery validation date


【解决方案1】:

编辑

我也想解决您对isDate 回归的评论。该函数按预期运行,问题出在其他地方。我没有对你的代码进行足够的剖析来说明错误在哪里,但isDate 是正确的:http://jsfiddle.net/nQMYe/


原答案

我对这里的 sn-p 变体很幸运:http://joey.mazzarelli.com/2008/11/25/easy-date-parsing-with-javascript/

基本上,它在 Date 对象中实现了一个fromString 方法。我不喜欢这种方法,所以我将我的实现修改为作为一个函数独立运行,并消除了一些不必要的位。也就是说,它工作得很好。

基本思想是首先对输入进行归一化。由于您永远不知道用户是否给您提供了1.11.20113~12~2012 之类的格式,所以第一件事就是去除这些噪音:

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

我们将丢弃所有非字母数字字符并放入-,您似乎更喜欢/——无论如何,只要输入一致即可。我们保留 alpha,以便我们也可以处理 March 18, 2012

sn-p 然后解析输入,提取时间(如果给定,使用 : 标识),然后它建立一个年份。正如 cmets 中所指出的,日期和月份以最合理的格式彼此相邻,因此您希望确定什么不是年份并从那里开始。然后是一个排除过程来确定月份,然后是日期。

不是我的代码,所以我并不是要为这个想法而功劳,但同样,事情就像宣传的那样交付。您可以按原样使用它(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;
  };

})();

【讨论】:

  • 你说得对,我的问题一定出在其他地方。我刚刚尝试在这里隔离我的代码jsfiddle.net/elclanrs/nQMYe/4,它确实有效。无论如何我都会接受你的回答。谢谢。
  • 如果您感到沮丧,或者只是想休息一下,请尝试我发布的 sn-p。无论如何,它可以按原样放入以进行测试,而且从我自己的使用来看,它看起来非常可靠。用户对使用 php-esq strtotime 字符串的能力印象特别深刻,而不必注意格式。
  • 我正在尝试您的代码,但我不太明白如何使用它返回 truefalse 给定日期...
  • Joey Mazzarelli 的代码,它不返回 true 或 false。你给它一个字符串,它移动山脉把那个字符串变成一个日期对象,然后它会交还给它。如果您只是按原样复制/粘贴该代码,您将使用 var date_obj = Date.fromString(user_string_here);
  • 我一直在测试,它似乎也为"AsDfgasdf"之类的随机值吐出时间戳我想我的问题是如何验证时间戳?
猜你喜欢
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-23
  • 2019-08-25
  • 2013-01-06
  • 1970-01-01
相关资源
最近更新 更多