@Override
 public String toString() {
   // 返回形如: 30s/5m@2m30s,读作: 以30秒切割5分钟周期,当前偏移量为第2分钟30秒
   return TimeInterval.parse(interval)
       + "/"
       + TimeInterval.parse(total)
       + "@"
       + TimeInterval.parse(currentOffset);
 }
 @Override
 public BoundaryCronTrigger create(TimeInterval frequency, Schedule schedule, TimeSpan window) {
   if (frequency.getMilliseconds() % 15 * DateUtils.MILLIS_PER_SECOND != 0) {
     throw new IllegalArgumentException(
         "The frequency " + frequency + " can't be divided by system minimal interval(15s)");
   }
   int pos, val;
   String interval = frequency.getInterval();
   if (interval.contains("h")) {
     pos = 2;
     val = Integer.valueOf(interval.substring(0, interval.indexOf('h')));
   } else if (interval.contains("m")) {
     pos = 1;
     val = Integer.valueOf(interval.substring(0, interval.indexOf('m')));
   } else if (interval.contains("s")) {
     pos = 0;
     val = Integer.valueOf(interval.substring(0, interval.indexOf('s')));
   } else {
     throw new IllegalArgumentException(
         "The interval " + interval + " is invalid, we only support h/m/s");
   }
   // 如果连系统都没有设置默认的监控的频度,那么我们默认设置为所有时间
   String[] cron =
       schedule == null
           ? new String[] {"*", "*", "*", "*", "*", "*"}
           : schedule.getCron().split("\\s");
   Granularity granularity = getGranularity(frequency);
   // 不同的频度,还需要削峰填谷
   // 在频度之前的每个字段,先归置为0
   for (int i = 0; i < pos; i++) {
     cron[i] = granularity.getSegment(i);
   }
   // 在小时这里,schedule和frequency的偏移量可能出现冲突
   // 原则是,保留 schedule的限制
   cron[pos] = granularity.getSegment(pos) + "/" + val;
   // 向上计数,下个该间隔的计划自然向上偏移
   granularity.stepUp();
   String expression = StringUtils.join(cron, " ");
   BoundaryCronTrigger trigger = new BoundaryCronTrigger(expression);
   trigger.include(schedule);
   trigger.exclude(window);
   return trigger;
 }
 /**
  *
  *
  * <h2>返回当前偏移量在特定cron位置上面的表达</h2>
  *
  * @param i cron位置
  * @return 偏移量表达
  */
 public String getSegment(int i) {
   // 0(second):     1 (s)
   // 1(minute):    60 (s)
   // 2(hour)  : 36,00 (s)
   if (i > 2) throw new UnsupportedOperationException("Can't support offset greater than hour");
   // 1h1m30s
   String offset = TimeInterval.parse(currentOffset);
   Pattern pattern = patterns[i];
   Matcher matcher = pattern.matcher(offset);
   if (matcher.find()) {
     return matcher.group(1);
   } else {
     return "0";
   }
 }
 void setGranularity(TimeInterval frequency, int granularity) {
   int interval = (int) (frequency.getMilliseconds() / granularity);
   Granularity g = new Granularity((int) frequency.getMilliseconds(), interval);
   granularities.put(frequency, g);
 }