作者
宋广泽
责编
胡雪蕊
有的人认为,全都按一个月30天算,查询“近一个月”的数据就是以30天前的0时为起点,以当前时间为终点查询,同理,查询“近三个月”的数据就是以90天前的0时为起点,以当前时间为终点进行查询。举两个例子,如果今天是1月31日,查询“近一个月”的数据就从1月1日0时开始;如果今天是年2月28日,查询“近一个月”的数据就从年1月29日0时开始。
有的人认为,查询“近三个月”的数据就是包含当前月,无论今天是当前月的几号,1号也行,31号也行,以再往前推2个月的1号的0点为起点,以当前时间为终点进行查询。举个例子,如果现在是年1月15日,起点就要追溯到年11月1日0时。
以上两种处理算法,都不是特别精确。前几天在做一个项目时遇到了这样的需求,就思考着写了写,感觉还算比较精确。在这里拿出来与大家分享一下。这个项目是用C#语言编写的。
1.首先获取到当前时间,并将其转换为字符串格式。代码如下:
DateTimenowtime=DateTime.Now;//让DateTime以-05-09T13:09:55的格式显示stringnow=nowtime.ToString(s);
此外,C#对于将时间转换成字符串有多种格式,有如下几种主要格式:
DateTime.Now.ToString()/5/:09:55中间一个空格DateTime.Now.ToString(d)/5/9只包含年月日DateTime.Now.ToString(g)/5/:09包含年月日时分中间一个空格DateTime.Now.ToString(G)/5/:09:55年月日时分秒DateTime.Now.ToString(s)-05-09T13:09:55中间一个TDateTime.Now.ToString(u)-05-0:09:55Z中间一个空格最后一个Z
2.第二步,将字符串转换成具体的年月日时分秒的整型数。
string.Substring(intstart,intlength)
start为截取字符串的起始下标,length为需要截取的字符数。代码如下:
//获取当前年intyy=Convert.ToInt32(now.Substring(0,4));//获取当前月intmm=Convert.ToInt32(now.Substring(5,2));//获取当前日intdd=Convert.ToInt32(now.Substring(8,2));//获取当前时inthr=Convert.ToInt32(now.Substring(11,2));//获取当前分intmin=Convert.ToInt32(now.Substring(14,2));//获取当前秒intsec=Convert.ToInt32(now.Substring(17,2));
3.第三步,推算查询的起始时间。
先文字描述一下算法:
“近一个月”的查询起始时间为上一个月的当前时间。举个例子,现在的时间是年8月22日9时45分,查询起始时间就应该为年7月22日9时45分,这样才算是满打满算“近一个月”。
可是又出现了新的问题,有的月(平年的2月)有28天,有的月(闰年的2月)有29天,有的月有30天(2月、4月、6月、9月、11月),有的月有31天(1月、3月、5月、7月、8月、10月、12月),因此,如果当前时间是年3月31日的某一时刻,按照以上算法推算,是没有年2月31日的。为了解决这种问题,我们可以将多于当月天数的那些天减掉,对于以上问题就将查询起始时间定为年2月28日的相同时刻。为了方便大家理解,再多举几个例子:
年5月31日-年4月30日
年3月30日-年2月28日
年3月30日-年2月29日(闰年)
年3月31日-年2月29日(闰年)
年3月31日-年2月29日(闰年)
完成上述推算,有两个关键点,完成的顺序不可颠倒。一是找到查询起始时间所在的年月,二是计算出查询起始时间所在的月有多少天。
先讲第一步,分为两种情况。
一种是不“跨年”的,如果当前时间是年8月,“近一个月”的查询起始时间就是年7月,即当前年/当前月-1;“近三个月”的查询起始时间就是年5月,即当前年/当前月-3。
另一种是“跨年”的,如果当前时间是年1月,“近一个月”的查询起始时间就是年12月,即当前年-1/12-(1-当前月);“近三个月”的查询起始时间就是年10月,即当前年-1/12-(3-当前月)。
以“近三个月”为例描述。代码如下:
if(cbxTime.Text==近三个月){if(mm-31){//年份需要前移ny=yy-1;nm=12-(3-mm);}else{//还是在本年ny=yy;nm=mm-3;}}
以此类推,“近一个月”的代码如下:
if(cbxTime.Text==近一个月){if(mm-11){//年份需要前移ny=yy-1;nm=12;}else{//年份就在本年ny=yy;nm=mm-1;}}
再讲第二步,有了查询起始时间所在的年和月,就计算出这个月有多少天就很容
易了。先将一般情况(平年)每个月有多少天进行初始化。代码如下:
根据推算出的查询起始时间的年判定是不是闰年,如果是闰年就将2月的天数增加1。
ny、nm、nd为推算起始时间所在年、月、日;
yy、mm、dd为当前时间所在年、月、日。代码如下:
有了以上数据,就可以套用前面讲过的将多出来的天数剪掉以确定起始时间的算
法了。代码如下:
if(dd=mon[nm]){nd=dd;}else{nd=mon[nm];}
查询“近一周”的数据以往前推7天的同一时刻为查询起始时间,需要注意的是“跨月”、“跨年”的情况。当前日-7小于1就需要跨到上一个月,既然要跨到上一个月就要考虑当前月是不是1月,如果是1月还需要跨年,通过当前月-1小于1判断需要跨年。代码如下:
elseif(cbxTime.Text==近一周){if(dd-71){//月要前移年可能会前移if(mm-11){//年要前移ny=yy-1;nm=12;}else{//还在本年ny=yy;nm=mm-1;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}nd=mon[nm]-(7-dd);}else{//还在本月ny=yy;nm=mm;nd=dd-7;}}
同理,查询“近一天”的数据以往前推1天的同一时刻为起始时间。代码如下:
else{//近一天if(dd-11){if(mm-11){ny=yy-1;nm=12;}else{ny=yy;nm=mm-1;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}nd=mon[nm];}else{//还在本年本月ny=yy;nm=mm;nd=dd-1;}}
时分秒不存在特殊情况,因此起始时间与当前时间的时分秒都是相同的。
由此生成最终的查询起始时间字符串,放到sql语句中进行比较查询,即可得到最终的查询结果。代码如下:
//形成参照时间pretime=newDateTime(ny,nm,nd,hr,min,sec);canzhao=pretime.ToString(s);canzhao.Replace(T,);//进行sql查询try{conn.Open();ds=newDataSet();stringsql=selectrecordidas编号,nameas姓名,phonenumberas手机号,washeras洗发工工号,serveras服务生工号,typeas服务类型,arrivetimeas到店时间fromVipLogwherearrivetime+canzhao+;SqlDataAdapterda=newSqlDataAdapter(sql,conn);da.Fill(ds);dgvList.DataSource=ds.Tables[0];}catch(Exceptionex){MessageBox.Show(ex.Message,按时间搜索时出错,MessageBoxButtons.OK,MessageBoxIcon.Error);}finally{conn.Close();}
canzhao为最终的查询起始时间,作为比较时参考的字符串而存在。由于用DateTime,ToString(s)转化得到的字符串年月日与时分秒之间是用字母T隔开的,如-05-09T13:09:55,而在SqlServer中进行比较时时间的形式应该是年月日与时分秒之间用空格隔开,因此要将‘T’替换为空格后再进行比较。
以下是全部代码:
privatevoidcbxTime_SelectedIndexChanged(objectsender,EventArgse){//清空其他下拉框txtName.Text=;txtPhoneNumber.Text=;cbxEmID.Text=;cbxType.Text=;nowtime=DateTime.Now;//让DateTime以-05-09T13:09:55的格式显示stringnow=nowtime.ToString(s);//获取当前年intyy=Convert.ToInt32(now.Substring(0,4));//获取当前月intmm=Convert.ToInt32(now.Substring(5,2));//获取当前日intdd=Convert.ToInt32(now.Substring(8,2));//获取当前时inthr=Convert.ToInt32(now.Substring(11,2));//获取当前分intmin=Convert.ToInt32(now.Substring(14,2));//获取当前秒intsec=Convert.ToInt32(now.Substring(17,2));//参照比较时间字符串stringcanzhao;//参照比较时间DateTimepretime;//参照年intny=0;//参照月intnm=0;//参照日intnd=0;int[]mon={0,31,28,31,30,31,30,31,31,30,31,30,31};if(cbxTime.Text==近一个月){if(mm-11){//年份需要前移ny=yy-1;nm=12;}else{//年份就在本年ny=yy;nm=mm-1;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}if(dd=mon[nm]){nd=dd;}else{nd=mon[nm];}}elseif(cbxTime.Text==近三个月){if(mm-31){//年份需要前移ny=yy-1;nm=12-(3-mm);}else{//还是在本年ny=yy;nm=mm-3;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}if(dd=mon[nm]){nd=dd;}else{nd=mon[nm];}}elseif(cbxTime.Text==近一年){ny=yy-1;nm=mm;if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}if(dd=mon[nm]){nd=dd;}else{nd=mon[nm];}}elseif(cbxTime.Text==近一周){if(dd-71){//月要前移年可能会前移if(mm-11){//年要前移ny=yy-1;nm=12;}else{//还在本年ny=yy;nm=mm-1;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}nd=mon[nm]-(7-dd);}else{//还在本月ny=yy;nm=mm;nd=dd-7;}}else{//近一天if(dd-11){if(mm-11){ny=yy-1;nm=12;}else{ny=yy;nm=mm-1;}if(ny%4==0ny%!=0
ny%==0){//闰年mon[2]++;}nd=mon[nm];}else{//还在本年本月ny=yy;nm=mm;nd=dd-1;}}//形成参照时间pretime=newDateTime(ny,nm,nd,hr,min,sec);canzhao=pretime.ToString(s);canzhao.Replace(T,);//进行sql查询try{conn.Open();ds=newDataSet();stringsql=selectrecordidas编号,nameas姓名,phonenumberas手机号,washeras洗发工工号,serveras服务生工号,typeas服务类型,arrivetimeas到店时间fromVipLogwherearrivetime+canzhao+;SqlDataAdapterda=newSqlDataAdapter(sql,conn);da.Fill(ds);dgvList.DataSource=ds.Tables[0];}catch(Exceptionex){MessageBox.Show(ex.Message,按时间搜索时出错,MessageBoxButtons.OK,MessageBoxIcon.Error);}finally{conn.Close();}}
未经优化,代码略显冗余,还望见谅。
作者:宋广泽,青岛某普通一本大学计算机专业在校生,本科在读,学生开发者。喜欢用C/C++编写有意思的程序,解决实际问题。