l-hammer/YDTemplate

View on GitHub
src/utils/es6/date.js

Summary

Maintainability
B
5 hrs
Test Coverage
/**
 * Created by LHammer on 18/03/07.
 * ES6 version
 * @class date parse or format date
 */
const twoDigits = /\d\d?/;
const fourDigits = /\d{4}/;
const token = /d{1,2}|M{1,2}|yy(?:yy)?|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g;
const masks = {
  default: 'yyyy-MM-dd HH:mm:ss',
  date: 'yyyy-MM-dd',
  datetime: 'yyyy-MM-dd HH:mm:ss',
  time: 'HH:mm:ss',
  year: 'yyyy',
  enDate: 'M/d/yy',
  cnDate: 'yyyy 年 MM 月 dd 日',
};

const pad = (val, len) => {
  val = String(val);
  len = len || 2;
  while (val.length < len) {
    val = `0${val}`;
  }
  return val;
};

const formatFlags = {
  yyyy(dateObj) {
    return pad(dateObj.getFullYear(), 4);
  },
  yy(dateObj) {
    return String(dateObj.getFullYear()).substr(2);
  },
  M(dateObj) {
    return dateObj.getMonth() + 1;
  },
  MM(dateObj) {
    return pad(dateObj.getMonth() + 1);
  },
  d(dateObj) {
    return dateObj.getDate();
  },
  dd(dateObj) {
    return pad(dateObj.getDate());
  },
  h(dateObj) {
    return dateObj.getHours() % 12 || 12;
  },
  hh(dateObj) {
    return pad(dateObj.getHours() % 12 || 12);
  },
  H(dateObj) {
    return dateObj.getHours();
  },
  HH(dateObj) {
    return pad(dateObj.getHours());
  },
  m(dateObj) {
    return dateObj.getMinutes();
  },
  mm(dateObj) {
    return pad(dateObj.getMinutes());
  },
  s(dateObj) {
    return dateObj.getSeconds();
  },
  ss(dateObj) {
    return pad(dateObj.getSeconds());
  },
};

/**
 * Format a date
 * @method format
 * @param {Date|number} dateObj new Date(2018, 2, 9)
 * @param {String} mask Format of the date e.g. 'yyyy-MM-dd HH:mm:ss' or 'cnDate'
 */
export const format = (dateObj, mask) => {
  if (typeof dateObj === 'number') {
    dateObj = new Date(dateObj);
  }

  if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) {
    throw new Error('Invalid Date in date.format');
  }
  mask = masks[mask] || mask || masks.default;

  // return 不可省略
  mask = mask.replace(token, ($0) => {
    return $0 in formatFlags ? formatFlags[$0](dateObj) : $0.slice(1, $0.length - 1);
  });

  return mask;
};

const parseFlags = {
  yyyy: [fourDigits, (d, v) => {
    d.year = v;
  }],
  yy: [twoDigits, (d, v) => {
    const da = new Date();
    const cent = +(`${da.getFullYear()}`).substr(0, 2);
    d.year = `${v > 68 ? cent - 1 : cent}${v}`;
  }],
  M: [twoDigits, (d, v) => {
    d.month = v - 1;
  }],
  d: [twoDigits, (d, v) => {
    d.day = v;
  }],
  h: [twoDigits, (d, v) => {
    d.hour = v;
  }],
  m: [twoDigits, (d, v) => {
    d.minute = v;
  }],
  s: [twoDigits, (d, v) => {
    d.second = v;
  }],
};
parseFlags.MM = parseFlags.M;
parseFlags.dd = parseFlags.d;
parseFlags.hh = parseFlags.h;
parseFlags.H = parseFlags.h;
parseFlags.HH = parseFlags.h;
parseFlags.mm = parseFlags.m;
parseFlags.ss = parseFlags.s;

/**
 * Format a date
 * @method parse
 * @param {String} dateStr Date String e.g. '2018-02-09 09:29:29' or '2018 年 02 月 09 日'
 * @param {String} mask Parse of the format date e.g. 'yyyy-MM-dd HH:mm:ss' or 'cnDate'
 * @param {Date}
 */
export const parse = (dateStr, mask) => {
  let isVaild = true;
  const dateInfo = {};
  const today = new Date();

  if (typeof dateStr !== 'string') {
    throw new Error('Invalid format in fecha.parse');
  }

  mask = masks[mask] || mask || masks.default;
  /**
   * @function replace @see https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace;
   * @param {String} $0 匹配的子串
   */
  mask.replace(token, function ($0) {
    if (parseFlags[$0]) {
      const flag = parseFlags[$0];
      /**
       * 搜索匹配到子串(e.g. yyyy)对应flag(fourDigits)的位置
       * @function search 未匹配到时返回-1,即按位取反为0时表示没有对应的flag
       */
      const index = dateStr.search(flag[0]);
      if (!~index) {
        isVaild = false;
      } else {
        /**
         * 为避免重复返回,将已经返回的值result从dateStr中删除
         */
        dateStr.replace(flag[0], function (result) {
          flag[1](dateInfo, result);
          dateStr = dateStr.substr(index + result.length);
          return result;
        });
      }
    }
    return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1);
  });

  if (!isVaild) {
    return false;
  }

  const date = new Date(
    dateInfo.year || today.getFullYear(),
    dateInfo.month || 0,
    dateInfo.day || 1,
    dateInfo.hour || 0,
    dateInfo.minute || 0,
    dateInfo.second || 0,
  );
  return date;
};

export default {
  format,
  parse,
};

/**
 * e.g.
 * @param Date @see https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date
 *
 * @requires import { format, parse } from '../utils/es6/date';
 *
 * @example format(new Date());
 * @returns 2018-03-09 00:00:00 // 默认格式
 *
 * @example format(new Date(), 'yyyy-MM-dd');
 * @returns 2018-03-09
 *
 * @example format(new Date(2018, 1, 9), 'yyyy 年 MM 月 dd 日');
 * @returns 2018 年 03 月 09 日
 *
 * @example parse('2018-02-09 09:29:29');
 * @returns Fri Feb 09 2018 09:29:29 GMT+0800 (CST) // 默认格式,等同于'yyyy-MM-dd HH:mm:ss'
 *
 * @example parse('2018-02-09 09:29:29', 'yyyy-MM-dd HH:mm:ss');
 * @returns Fri Feb 09 2018 09:29:29 GMT+0800 (CST)
 *
 * @example parse('2018 年 02 月 09 日', 'cnDate')
 * @returns Fri Feb 09 2018 00:00:00 GMT+0800 (CST)

/**
 * e.g. 默认导出
 *
 * @requires import date from '../utils/es6/date';
 *
 * @example date.format(new Date());
 * @returns 2018-03-09 00:00:00 // 默认格式
 *
 * @example date.format(new Date(), 'yyyy-MM-dd');
 * @returns 2018-03-09
 *
 * @example date.format(new Date(2018, 1, 9), 'yyyy 年 MM 月 dd 日');
 * @returns 2018 年 03 月 09 日
 *
 * @example date.parse('2018-02-09 09:29:29');
 * @returns Fri Feb 09 2018 09:29:29 GMT+0800 (CST) // 默认格式,等同于'yyyy-MM-dd HH:mm:ss'
 *
 * @example date.parse('2018-02-09 09:29:29', 'yyyy-MM-dd HH:mm:ss');
 * @returns Fri Feb 09 2018 09:29:29 GMT+0800 (CST)
 *
 * @example date.parse('2018 年 02 月 09 日', 'cnDate');
 * @returns Fri Feb 09 2018 00:00:00 GMT+0800 (CST)
 */