/**
  * 事件统计-趋势
  *
  * @param siteId 网站ID
  * @param subsite 子站ID
  * @param offset 偏移 0=当天 -1=昨天 1=明天 -2 2 -3...
  * @param span 跨度 [day|week|month|year]
  * @param start 开始时间 ("yyyyMMddHHmmss")
  * @param end 结束时间 ("yyyyMMddHHmmss")
  * @return 事件统计-排行 {status:[true|false],data:[{name,num,rn,user,ru},...]}
  */
 @RequestMapping("event/trend/{period:hour|day|week|month}")
 public Object eventTrend(
     @PathVariable int siteId,
     @PathVariable Period period,
     String subsite,
     Integer offset,
     Period span,
     Date start,
     Date end) {
   end = timeEnd(end, span, offset);
   start = timeStart(start, span, offset);
   String idsite = getIdSite(siteId, subsite);
   List<EventTrendValue> list = service.eventTrend(idsite, period, start, end);
   list = fulldata(list, period.getFormat(), period.getField(), start, end, EventTrendValue.class);
   return list;
 }
 /**
  * 根据周期和便宜计算结束时间
  *
  * @param end 结束时间
  * @param span 时间跨度
  * @param offset 偏移
  * @return 结束时间
  */
 private Date timeEnd(Date end, Period span, Integer offset) {
   if (span != null && offset != null /* && !Period.hour.equals(span)*/) {
     DateFormat format = span.getFormat();
     Calendar calendar = Calendar.getInstance();
     try {
       calendar.setTime(format.parse(format.format(calendar.getTime())));
     } catch (ParseException e) {
       e.printStackTrace();
     }
     calendar.add(span.getField(), offset + 1);
     return calendar.getTime();
   }
   if (end == null) {
     return timeEnd(new Date(), Period.year, 1000);
   }
   return end;
 }
 /**
  * 根据周期和便宜计算开始时间
  *
  * @param start 开始时间
  * @param span 时间跨度
  * @param offset 偏移
  * @return 开始时间
  */
 private Date timeStart(Date start, Period span, Integer offset) {
   if (span != null && offset != null) {
     DateFormat format = span.getFormat();
     Calendar calendar = Calendar.getInstance();
     try {
       calendar.setTime(format.parse(format.format(calendar.getTime())));
     } catch (ParseException e) {
       e.printStackTrace();
     }
     calendar.add(span.getField(), offset);
     return calendar.getTime();
   }
   if (start == null) {
     return timeStart(new Date(), Period.year, -1000);
   }
   return start;
 }
 /**
  * 计算分割段数
  *
  * @param period 时段周期 [时|日|周|月]
  * @param start 开始时间
  * @param end 结束时间
  * @return 段数
  */
 private int countDays(Period period, Date start, Date end) {
   Calendar calendar = Calendar.getInstance();
   calendar.setTime(start);
   int count = 0;
   while (calendar.getTime().before(end)) {
     count++;
     calendar.add(period.getField(), 1);
   }
   return count;
 }
 /**
  * 检测时间分段合理性
  *
  * @param period 时段周期 [时|日|周|月]
  * @param start 开始时间
  * @param end 结束时间
  */
 private void doCheckPeriod(Period period, Date start, Date end) throws ServiceException {
   Calendar calendar = Calendar.getInstance();
   calendar.setTime(start);
   int count = 0, max = 200;
   while (calendar.getTime().before(end)) {
     if (count++ > max) {
       throw new ServiceException("数据量偏大,请调整时间跨度再试!");
     }
     calendar.add(period.getField(), 1);
   }
 }