时间查重方案的设计

news/2024/7/5 7:45:36

时间查重方案的设计

    • 项目场景:
    • 需求描述:
    • 解决方案:
      •   1.处理流程
      •   2.周计划的时间段处理
      •   3.时间段处理和比较
    • 总结

项目场景:

  项目场景:上层下发任务计划(包括周计划和日计划),每个计划都有一个对应的时间段,设备要去校验这些时间段是否有重复的地方,如果有两个任务计划之间存在交叉的时间,设备端应当报错,不予保存


需求描述:

 单从需求来看,单个日计划的查重校验比较容易,但是任务计划里还包含有周计划,每个周计划可以选其中某几个周X,根据任务选择的有效期不同,对应时间段中的日期是不确定的。比如指定2021.5.31-2021.6.3的周计划,可以选择周一到周四每一天,也可以选择其中某几天,这就提升了时间段查重的困难性,因为不能直接将任务计划中的时间段拿出来作比较


解决方案:

  1.处理流程

 考虑到周计划的特殊性,因为不能直接跟日计划进行比较,所以我们需要对周计划进行拆解,现将周计划转换成对应的日计划,然后再逐一比较,最后再去判断是否存在交叉的时间段。具体实现流程如下:
时间查重流程图

  2.周计划的时间段处理

 其中又得着重说下周计划的转换流程,是如何将计划中的每个周X转换成对应的日期与天计划来进行比较的,这里得经过好几个步骤,首先是得判断制定的周计划中有几个对应的周X,然后再将有效期内的周X转换成对应的日期
  周计划中时间段的周X转换成对应日期
具体的实现代码如下:

/** @fn : CaculateWeekDay
 * @brief : 计算当前日期是周几
 * @param  date : 待计算的日期 %Y-%m-%d
 * @return : # 周X
 * @author : 
 */
int CaculateWeekDay(char *date)
{
	int y = 0,m = 0, d = 0;

	sscanf(date, "%d-%d-%d", &y,&m,&d);
	
    if(m==1||m==2) {
        m+=12;
        y--;
    }
    int iWeek=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
    switch(iWeek)
    {
    case 0: return 1; break;
    case 1: return 2; break;
    case 2: return 3; break;
    case 3: return 4; break;
    case 4: return 5; break;
    case 5: return 6; break;
    case 6: return 7; break;
    default: return 0;break;
    }
}


 /** @fn : day_diff
  * @brief : 计算两个日期之间的天数
  * @param  start_date : 开始日期 %Y-%m-%d
  * @param  end_date :  结束日期 %Y-%m-%d	
  * @param  day :  		当前周几 1-7
  * @return : # 开始日期和结束日期之间的天数	 2021-03-25 - 2021-03-26  -> 两天
  * @author : 
  */
int day_diff(char *start_date, char *end_date)
{
	int y2, m2, d2;
	int y1, m1, d1;
	int year_start, month_start, day_start;
	int year_end, month_end, day_end;
	
	sscanf(start_date, "%d-%d-%d", &year_start,&month_start,&day_start);
	sscanf(end_date, "%d-%d-%d", &year_end,&month_end,&day_end);
	
	m1 = (month_start + 9) % 12;
	y1 = year_start - m1/10;
	d1 = 365*y1 + y1/4 - y1/100 + y1/400 + (m1*306 + 5)/10 + (day_start - 1);
 
	m2 = (month_end + 9) % 12;
	y2 = year_end - m2/10;
	d2 = 365*y2 + y2/4 - y2/100 + y2/400 + (m2*306 + 5)/10 + (day_end - 1);
	
	return (d2 - d1)+1;
}
 
 /** @fn : get_dayofweek_num
  * @brief : 获取当前时间段中有几个周X
  * @param  start_date : 开始日期 %Y-%m-%d
  * @param  end_date :  结束日期 %Y-%m-%d
  * @param  day :  		当前周几 1-7
  * @return : # 当前日期内的周几的个数
  * @author : 
  */
 int get_dayofweek_num(char *start_date, char *end_date,char day)
 {
	 int dayNum = day_diff(start_date,end_date);	//计算总天数
	 int sDateSpare,eDateSpare;
	 
	 sDateSpare = CaculateWeekDay(start_date); 	//计算起始日期是周几
	 eDateSpare = sDateSpare + dayNum%7 - 1;	//计算多余的日期结束是周几

	 if((eDateSpare > 7) && (day < sDateSpare))	//结束和开始的相对日期跨周 且比开始日期小才需要加一周
	 {
		return dayNum/7 + ((day+7 >= sDateSpare && day+7 <= eDateSpare) ? 1:0);
	 }

	 return dayNum/7 + ((day >= sDateSpare && day <= eDateSpare) ? 1:0);		
 }


  3.时间段处理和比较

  周计划转换成对应的日计划后用,还需要与之前的日计划进行比较,当计划比较多的时候就需要全都记录下来,逐个去比较。这里采用链表的方式记录每个时间段的节点,然后再去遍历判断是否存在交叉的时间段,如果存在则记录错误节点。

/*********************************************************************************
 * Description: 从链表中搜索当前时间段是否冲突
 * Input:   
 * Output:  无     
 * Return:  未冲突 HPR_TRUE  冲突 HPR_ERROR
 * Others:  无
 *******************************************************************************/
HPR_INT32 search_list_for_time_is_conflict(T_DATE_NODE *pDate)
{
	isapi_check(pDate, HPR_ERROR);
	
	T_DATE_NODE *pNode = NULL;
	
	LIST_FOR_EACH(T_DATE_NODE, pNode, &tDateList)
	{	
		if(pDate->level == pNode->level)
		{			
			if((pDate->start_time <= pNode->stop_time) && (pDate->stop_time >= pNode->start_time)
			  &&(pDate->begin_time <= pNode->end_time)&& (pDate->end_time >= pNode->begin_time))
			{
				return HPR_ERROR;
			}
		}		
	}

	return HPR_TRUE;
}



/**@brief  校验计划任务中是否存在时间段冲突		  
 * @param[in]   start_time	任务有效期开始时间
 		        stop_time	任务有效期结束时间
 		        begin_time	任务执行的开始时间
 		        end_time	任务执行的结束时间
 		        weekday		周计划中的星期X
 * @param[out] 
 * @return	校验结果		HPR_ERROR 时间冲突
 						HPR_OK	  时间段未冲突
 */
INT32 check_time_is_conflict(char level,char *start_time,char *stop_time,char *begin_time,char *end_time,char weekday)
{	
	INT32 iRet = HPR_OK;
	T_DATE_NODE tmpResult = {0};
	T_DATE_NODE *tPlanTime = NULL;
	INT32 count=0, dayOfWeek=0, dayNum=0, date=0, i=0;
	INT32 year=0, month=0, day=0, hour=0, minute=0, second=0;
	char tmpDate[16] = {0};

	// 转换传入的日期数据
	tmpResult.level = level;

	sscanf(start_time, "%d-%d-%d", &year,&month,&day);		
	tmpResult.start_time = year*10000 + month*100 + day;
	
	sscanf(stop_time, "%d-%d-%d", &year,&month,&day);	
	tmpResult.stop_time = year*10000 + month*100 + day;	
	
	sscanf(begin_time, "%d:%d:%d", &hour,&minute,&second);		
	tmpResult.begin_time = hour*10000 + minute*100 + second;

	sscanf(end_time, "%d:%d:%d", &hour,&minute,&second);		
	tmpResult.end_time = hour*10000 + minute*100 + second;


	if(false != weekday)
	{	
		count = get_dayofweek_num(start_time,stop_time,weekday);	//计算当前有效期段内周X有多少个
		if(count == 0)
		{
			ISAPI_INFO("the weekday(%d) does not exist in the period(%s---%s) \n",weekday,start_time,stop_time)
			iRet = HPR_NOSUPPORT;
			goto exit;
		}
		
		dayOfWeek = CaculateWeekDay(start_time);								//计算起始日期是周几
		
		dayNum = weekday + (weekday < dayOfWeek ? 7 : 0) - dayOfWeek;	//计算一个周期内周X与起始日期的间隔天数		
		(void)memcpy_s(tmpDate,MAX_TIME_LEN,start_time,MAX_TIME_LEN);

		for(i=0;i<count;i++)
		{
			tPlanTime = malloc_node_from_date_pool();
			if(NULL == tPlanTime)
		    {
		        ISAPI_ERR("node pool malloc error\n");
		        return HPR_ERROR;
		    }
		    
			tPlanTime->level = tmpResult.level;
			tPlanTime->begin_time = tmpResult.begin_time;
			tPlanTime->end_time	= tmpResult.end_time;
			
			date_convert(tmpDate,&date,dayNum+i*7);		//转换当前有效期内对应周X的日期
			tPlanTime->start_time = date;
			tPlanTime->stop_time  = date;

			if(HPR_ERROR == search_list_for_time_is_conflict(tPlanTime))
			{
				ISAPI_INFO("the plan time '%d' is conflict\n",tPlanTime->begin_time)
				iRet = HPR_ERROR;
				goto exit;
			}			
			lstAdd(&tDateList,&tPlanTime->node);
			
		}
	}
	else
	{
		tPlanTime = malloc_node_from_date_pool();
		if(NULL == tPlanTime)
	    {
	        ISAPI_ERR("node pool malloc error\n");
	        return HPR_ERROR;
	    }		
	    
		tPlanTime->level = tmpResult.level;
		tPlanTime->begin_time = tmpResult.begin_time;
		tPlanTime->end_time	= tmpResult.end_time;
		tPlanTime->start_time = tmpResult.start_time;
		tPlanTime->stop_time  = tmpResult.stop_time;
		
		if(HPR_ERROR == search_list_for_time_is_conflict(tPlanTime))
		{
			ISAPI_INFO("the plan time '%d' is conflict\n",tPlanTime->begin_time)
			iRet = HPR_ERROR;
			goto exit;
		}

		lstAdd(&tDateList,&tPlanTime->node);
	}	

exit:
	return iRet;
}

总结

  本文仅仅简单实现了时间查重的比较方法,可以对下发的任务计划进行时间段的查重校验,实际使用中功能是都可以基本满足,就是在效率上还应该进一步优化,由于是遍历查询,当任务计划到达上限时,效率比较低。在时间段转换上或许也可能存在更优的方法


http://www.niftyadmin.cn/n/3879836.html

相关文章

社会生活中的著名法则 选择自 muse2008 的 Blog

社会生活中的著名法则 一、马太效应 《新约?马太福音》中有这样一个故事&#xff0c;一个国王远行前&#xff0c;交给三个仆人每人一锭银子&#xff0c;吩咐他们&#xff1a;“你们去做生意&#xff0c;等我回来时&#xff0c;再来见我。”国王回来时&#xff0c;第一个仆…

***常见复杂SQL语句(含统计类SQL)

1、SQL统计某字段的出现次数 比如统计某个表中&#xff0c;姓名出现的次数&#xff1a;select name,count(*) from biao group by name having count(*) > 2 关键是用分组&#xff1a;group by&#xff0c;且经常和聚合函数一起使用 比如&#xff1a;统计用户表中的匿名字段…

C++大师Stan Lippman:我对中国程序员的忠告 www.ASPCool.com

C大师Stan Lippman:我对中国程序员的忠告作者&#xff1a; www.ASPCool.com 时间:2004-9-20 18:07:29 C语言的创立者&#xff0c;斯坦.利普曼(Stan Lippman) 9月17日参加了在北京召开的微软技术大会Tech.Ed2004并做了"The C Binding, Integrating a Static and dyn…

浅析SSL/TLS的会话流程和源码实现

浅析SSL/TLS的会话流程和源码实现一、SSL/TLS的概念二、SSL/TLS的会话交互流程(1) client_hello(2) server_hello certificate sever hello done(3) client key exchange change cipher spec encrypted handshake message(4) new session ticketchange cipher specenvrypte…

每天一道算法题(7)——在字符串中删除特定的字符

题目&#xff1a;输入两个字符串&#xff0c;从第一字符串中删除第二个字符串中所有的字符。例如&#xff0c;输入”They are students.”和”aeiou”&#xff0c;则删除之后的第一个字符串变成”Thy r stdnts.”。 1.思路 最简单的。设source长n&#xff0c;key 长m(n>>…

将文本藏入图片 选择自 VirleneCheng 的 Blog

一般看来文字与图片是毫不相同的&#xff0c;但是它们却有共同点。图片是由一个个点组成的&#xff0c;而这些点的颜色值可由数字组成&#xff0c;文字可由ASCII码表示&#xff0c;这就使得数字成为它们之间沟通道桥梁。因此就可以将文本藏入图片中。这可以用Visual Basic 6.0实…

创建组件“AxLicenseControl”失败

打开以前的程序&#xff0c;准备来添加一个功能&#xff0c;打开主程序就报错&#xff1a; 我未曾改变过版本&#xff0c;原来是由于破解测试需要&#xff0c;修改了系统时间&#xff0c;时间对不了&#xff0c;ArcGIS的问题&#xff0c;改过来就正常了。

在中文下打开日文文件:)

private void button1_Click(object sender, System.EventArgs e) { openFileDialog1.Filter "所有文件*.*|*.*|文本文件*.txt|*.txt"; openFileDialog1.FilterIndex 2; if(openFileDialog1.ShowDialog ()DialogResult.OK ) { FileStream frnew FileStre…