js处理cron表达式

转载 js获取cron表达

cron.js

var __$ = {
  create: function () {
    return function () {
      this.initialize.apply(this, arguments);
    }
  },
  extend: function (destination, source) {
    for (var property in source) {
      destination[property] = source[property];
    }
    return destination;
  }
};

/*
 * 创建SimpleTime类,用于对3种格式的时间进行处理
 * 初始化时入参为时间字符串形如
 *     1.yyyy-mm-dd hh:MM:ss
 *     2.yyyy-mm-dd
 *     3.hh:MM:ss
 * 内建6个字段:year,month,day,hour,minute,second
 * 内建6个字段的get方法,符合java命名规范
 * 注意:
 *     1.日期输入需要校验格式,内部没有校验格式
 *     2.初始化串形如yyyy-mm-dd和hh:MM:ss时,get没有值的域会返回undefined
 */
var SimpleTime = __$.create();
__$.extend(SimpleTime.prototype, {
  initialize: function (time) {
    time = time || "";
    switch (time.length) {
      case 8:
        this.timeAry = ['', '', ''].concat(time.split(":"));
        break;
      case 10:
        this.timeAry = time.split("-").concat(['', '', '']);
        break;
      case 19:
        this.timeAry = time.split(/[:| |-]/g);
        break;
      default:
        this.timeAry = [];
    }
  },
  getYear: function () {
    return this.timeAry[0] ? this.timeAry[0].replace(/^0/g, "") : this.timeAry[0];
  },
  getMonth: function () {
    return this.timeAry[1] ? this.timeAry[1].replace(/^0/g, "") : this.timeAry[1];
  },
  getDay: function () {
    return this.timeAry[2] ? this.timeAry[2].replace(/^0/g, "") : this.timeAry[2];
  },
  getHour: function () {
    return this.timeAry[3] ? this.timeAry[3].replace(/^0/g, "") : this.timeAry[3];
  },
  getMinute: function () {
    return this.timeAry[4] ? this.timeAry[4].replace(/^0/g, "") : this.timeAry[4]
  },
  getSecond: function () {
    return this.timeAry[5] ? this.timeAry[5].replace(/^0/g, "") : this.timeAry[5];
  }
}
);

/*
 * Cron表达式中内建的域对象,封装了域的操作方法
 * 初始化时通过type初始化类型,对应的操作域操作方法如下:
 *     setBase:接受一个参数,用于设置域基值
 *     inc:增量,接受一个参数incr,每隔incr时间
 *     any:任意时刻,即*
 *     manual:接受参数str,手动输入,用于输入比较复杂的域值str
 *     ask:问号,日域或星期域有一个必然是?
 *     last:将当前域设置成按倒数,如果输入参数则为倒数第几天,如果不输入参数,按setBase的值计算
 *     nolast:删除last属性
 *     workDay:日域是否为工作日,如果输入参数则为第几个工作日,如果不输入参数,按setBase的值计算
 *  noWorkDay:删除工作日属性
 *  selectWeek:第几周的周几,接受两个参数,week代表第几周,weekDay代表星期几
 *  toDomainStr:返回此域的Cron表达式域字符串
 */
var _Domain = __$.create();
__$.extend(_Domain.prototype, {
  initialize: function (arg, type) {
    this.type = type;
    this.base = arg || "0";
    if (type == 'weekDay' || type == 'day' || type == 'month') {
      this.base = this.base == "0" ? 1 : this.base;
    }
    if (!arg) {
      this.anyType = true;
      return;
    }
  },
  setBase: function (baseStr) {
    this.base = baseStr;
  },
  inc: function (incr) {
    delete this.anyType;
    delete this.askType;
    delete this.manualType;
    this.incStep = incr;
  },
  any: function () {
    delete this.incStep;
    delete this.askType;
    delete this.manualType;
    this.anyType = true;
  },
  manual: function (str) {
    delete this.incStep;
    delete this.anyType;
    delete this.askType;
    this.manualType = true;
    this.manualStr = str;
  },
  ask: function () {
    delete this.anyType;
    delete this.incStep;
    delete this.manualType;
    this.askType = true;
  },
  last: function (num) {
    delete this.askType;
    delete this.anyType;
    if (typeof num != "undefined") {
      this.base = num + "";
    }
    var newBase = (this.base.match(/[\d]+/) || [this.base][0]) + "L";
    this.base = newBase == "1L" ? "L" : newBase;
  },
  nolast: function () {
    this.base = this.base.replace(/L$/, "");
  },
  workDay: function (num) {
    delete this.askType;
    delete this.anyType;
    if (typeof num != "undefined") {
      this.base = num + "";
    }
    this.base = (this.base.match(/[\d]+/) || [this.base][0]) + "W";
  },
  noworkDay: function () {
    this.base = this.base.replace(/W$/, "");
  },
  selectWeek: function (week, weekDay) {
    this.manual(week + "#" + weekDay);
  },
  toDomainStr: function () {
    if (this.anyType) {
      return "*";
    }
    if (this.incStep) {
      return this.base + "/" + this.incStep;
    }
    if (this.manualType) {
      return this.manualStr;
    }
    if (this.askType) {
      return "?";
    }
    return this.base;
  }
}
)

/*
 * Cron表达式类对象
 * 初始化时入参为时间字符串形如
 *     1.yyyy-mm-dd hh:MM:ss
 *     2.yyyy-mm-dd
 *     3.hh:MM:ss
 * 内建7个域:year,weekDay,month,day,hour,minute,second
 *     可以通过Cron的实例对象.domain[域].方法(参数)访问指定域的指定方法
 *    可以通过内建的set方法访问
 * 内建方法:
 *     set:可以通过Cron的实例对象.set('域','方法',参数1,[...,参数n])访问指定域的指定方法
 *     toCron:返回当前Cron表达式对象的Cron表达式串
 * 注意:
 *     1.日期输入需要校验格式,内部没有校验格式
 *     2.weekDay域中,初始化后为?
 *     3.设置day域时,weekDay域会自动转换为?,反之亦然
 *     4.具体域方法见_Domain类的内建方法
 */
var Cron = __$.create();

Cron.pack = function (input) {
  var lines = [];
  var line = [input[0]];
  for (var i = 1; i < input.length; i++) {
    if (line.length == 0 || input[i] - 1 == line[line.length - 1]) {
      line.push(input[i]);
    } else {
      lines.push(line);
      line = [input[i]];
    }
  }
  lines.push(line);
  for (var i = 0; i < lines.length; i++) {
    lines[i] = lines[i].length > 2 ? lines[i].shift() + "-" + lines[i].pop() : lines[i].join(",");
  }
  return lines.join(",");
}

__$.extend(Cron.prototype, {
  initialize: function (baseTime) {
    this.time = new SimpleTime(baseTime);
    this.domain = {
      hour: new _Domain(this.time.getHour(), "hour"),
      minute: new _Domain(this.time.getMinute(), "minute"),
      second: new _Domain(this.time.getSecond(), "second"),
      day: new _Domain(this.time.getDay(), "day"),
      month: new _Domain(this.time.getMonth(), "month"),
      weekDay: new _Domain(null, "weekDay"),
      year: new _Domain(this.time.getYear(), "year")
    }
    this.domain.weekDay.ask();
  },
  toCron: function () {
    var domainAry = [];
    domainAry.push(format(this.domain['second'].toDomainStr()));
    domainAry.push(format(this.domain['minute'].toDomainStr()));
    domainAry.push(format(this.domain['hour'].toDomainStr()));
    domainAry.push(format(this.domain['day'].toDomainStr()));
    domainAry.push(format(this.domain['month'].toDomainStr()));
    domainAry.push(this.domain['weekDay'].toDomainStr());
    domainAry.push(this.domain['year'].toDomainStr());
    return domainAry.join(" ");
  },
  set: function (domain, operationType) {
    if (domain == "weekDay" && (operationType != "ask")) {
      this.domain['day']["ask"]();
    } else if (domain == "day" && (operationType != "ask")) {
      this.domain['weekDay']["ask"]();
    }
    var args = [];
    for (var i = 2; i < arguments.length; i++) {
      args.push(arguments[i]);
    }
    this.domain[domain][operationType].apply(this.domain[domain], args);
  }
}
)

function format (val) {
  if (val < 10) {
    return "0" + val
  }
  return val
}

参数封装scheduler.js

function getCronExpression ({onceTime,cron,startTime, cycle, hourFlag, minuteFlag, interValDay, endTime, hourInterval, minuteInterval, weekArray, MonthArray, day}) {
  var cronExpression = "";
  if (cycle == "1") {
    cronExpression = getCronByStartTime(onceTime);
  } else if (cycle == "5") {
    cronExpression = getCronBySelf(cron);
  } else {
    cronExpression = getCronByTimePoint(startTime, cycle, hourFlag, minuteFlag, interValDay, endTime, hourInterval, minuteInterval, weekArray, MonthArray, day);
  }
  return cronExpression;
}

//onlyOne
function getCronByStartTime (startTime) {
  var _startTime = new SimpleTime(startTime);
  var cron = "";
  cron = new Cron(startTime);
  return cron.toCron();
}

//selfDef
function getCronBySelf (cron) {
  if (cron == null || cron == "") {
    return;
  }
  return cron;
}

//getCronByTimePoint
function getCronByTimePoint (timePoint, planType, hourFlag, minuteFlag, interValDay, endTime, hourInt, minuteInt, weekDayArr, selectMonth, day) {
  endTime = endTime || timePoint;
  var cron = "";
  if (planType == "2") {
    cron = createCronByTimePoint(timePoint, hourFlag, minuteFlag, endTime, hourInt, minuteInt);
    cron.set('day', 'setBase', '*');
    cron.set('day', 'inc', interValDay + "");
  } else if (planType == "3") {

    var selectedDays = Cron.pack(weekDayArr);
    if (selectedDays == "") {
      selectedDays = "1-7";
    }
    cron = createCronByTimePoint(timePoint, hourFlag, minuteFlag, endTime, hourInt, minuteInt);
    cron.set('weekDay', 'manual', selectedDays);
  } else if (planType == "4") {
    cron = createCronByTimePoint(timePoint, hourFlag, minuteFlag, endTime, hourInt, minuteInt);
    cron.set('month', 'manual', selectMonth);
    day == "-1" ? cron.set('day', 'last', 1) : cron.set('day',
      'manual', day);
  }
  return cron.toCron();
}

function createCronByTimePoint (timePoint, hourFlag, minuteFlag, endTime, hourInt, minuteInt) {
  var cron = new Cron(timePoint);
  if (endTime) {
    var timeAry = endTime.split(":");
    if (timeAry[0].charAt(0) == "0") {
      timeAry[0] = timeAry[0].charAt(1);
    }
    cron.set('hour', 'setBase', timePoint.split(":")[0].replace(/^0/g,
      "")
      + "-" + timeAry[0]);
  }
  if (minuteFlag) {
    cron.set('minute', 'inc', minuteInt);
  } else if (hourFlag) {
    cron.set('hour', 'inc', hourInt);
  }
  return cron;
}

测试

<script>
    var cycle = "1";//周期类型
    
    //第一种形式 cycle等于1:指定时间点            
    var onceTime = "2020-04-01 15:50:27";//时间点
    
    //第二种形式 cycle等于2:以天为间隔
    var startTime = "06:15:15";//开始时间
    var endTime = "10:15:15";//结束时间
    var hourFlag = false;//是否以分钟为间隔
    var minuteFlag = true;//是否以分钟为间隔
    var interValDay = 3;//间隔天数
    var hourInterval = 4;//间隔小时数
    var minuteInterval= 3;//间隔分钟数
    
    //第三种形式 cycle等于3:以周为间隔
    var weekArray = ['2','4'];//指定每周周几
    
    //第四种形式 cycle等于4:以月为间隔
    var MonthArray = [4,7];//指定那几个月份            
    var day =21;//指定哪天
    
    //第五种形式 cycle等于5:指定表达式
    var cron = "0/1 * * * * ? ";//Cron表达式                

    var cronExpression = getCronExpression({onceTime,cron,startTime, cycle, hourFlag, minuteFlag, 
                            interValDay, endTime, hourInterval, minuteInterval,
                            weekArray, MonthArray, day});
    console.log(cronExpression)

</script>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354