“近一个月”、“近三个月”这种查询如何处理更精确?


有的人认为,全都按一个月30天算,查询“近一个月”的数据就是以30天前的0时为起点,以当前时间为终点查询,同理,查询“近三个月”的数据就是以90天前的0时为起点,以当前时间为终点进行查询。举两个例子,如果今天是1月31日,查询“近一个月”的数据就从1月1日0时开始;如果今天是2019年2月28日,查询“近一个月”的数据就从2019年1月29日0时开始。
有的人认为,查询“近三个月”的数据就是包含当前月,无论今天是当前月的几号,1号也行,31号也行,以再往前推2个月的1号的0点为起点,以当前时间为终点进行查询。举个例子,如果现在是2017年1月15日,起点就要追溯到2016年11月1日0时。
以上两种处理算法,都不是特别精确。前几天在做一个项目时遇到了这样的需求,就思考着写了写,感觉还算比较精确。在这里拿出来与大家分享一下。这个项目是用C#语言编写的。
1.首先获取到当前时间,并将其转换为字符串格式。代码如下:
DateTime?nowtime?=?DateTime.Now;
//让DateTime以2016-05-09T13:09:55的格式显示
string?now?=?nowtime.ToString("s");
DateTime.Now.ToString()????2016/5/9?13:09:55???中间一个空格
DateTime.Now.ToString("d")????2016/5/9????只包含年月日
DateTime.Now.ToString("g")????2016/5/9?13:09??包含年月日时分?中间一个空格
DateTime.Now.ToString("G")?????2016/5/9?13:09:55???年月日时分秒
DateTime.Now.ToString("s")????2016-05-09T13:09:55?中间一个T
DateTime.Now.ToString("u")????2016-05-09?13:09:55Z????中间一个空格?最后一个Z
2.第二步,将字符串转换成具体的年月日时分秒的整型数。
string.Substring(int?start,int?length)
start为截取字符串的起始下标,length为需要截取的字符数。代码如下:
//获取当前年
int?yy?=?Convert.ToInt32(now.Substring(0,?4));
//获取当前月
int?mm?=?Convert.ToInt32(now.Substring(5,?2));
//获取当前日
int?dd?=?Convert.ToInt32(now.Substring(8,?2));
//获取当前时
int?hr?=?Convert.ToInt32(now.Substring(11,?2));
//获取当前分
int?min?=?Convert.ToInt32(now.Substring(14,?2));
//获取当前秒
int?sec?=?Convert.ToInt32(now.Substring(17,?2));
3.第三步,推算查询的起始时间。
先文字描述一下算法:
“近一个月”的查询起始时间为上一个月的当前时间。举个例子,现在的时间是2019年8月22日9时45分,查询起始时间就应该为2019年7月22日9时45分,这样才算是满打满算“近一个月”。
可是又出现了新的问题,有的月(平年的2月)有28天,有的月(闰年的2月)有29天,有的月有30天(2月、4月、6月、9月、11月),有的月有31天(1月、3月、5月、7月、8月、10月、12月),因此,如果当前时间是2019年3月31日的某一时刻,按照以上算法推算,是没有2019年2月31日的。为了解决这种问题,我们可以将多于当月天数的那些天减掉,对于以上问题就将查询起始时间定为2019年2月28日的相同时刻。为了方便大家理解,再多举几个例子:
2019年5月31日-2019年4月30日
2017年3月30日-2017年2月28日
2016年3月30日-2016年2月29日(闰年)
2016年3月31日-2016年2月29日(闰年)
2000年3月31日-2000年2月29日(闰年)
完成上述推算,有两个关键点,完成的顺序不可颠倒。一是找到查询起始时间所在的年月,二是计算出查询起始时间所在的月有多少天。
先讲第一步,分为两种情况。
一种是不“跨年”的,如果当前时间是2019年8月,“近一个月”的查询起始时间就是2019年7月,即当前年/当前月-1;“近三个月”的查询起始时间就是2019年5月,即当前年/当前月-3。
另一种是“跨年”的,如果当前时间是2019年1月,“近一个月”的查询起始时间就是2018年12月,即当前年-1/12-(1-当前月);“近三个月”的查询起始时间就是2018年10月,即当前年-1/12-(3-当前月)。
以“近三个月”为例描述。代码如下:
if(cbxTime.Text=="近三个月")
{
????if(mm-3< 1)
????{
????????//年份需要前移
????????ny?=?yy?-?1;
????????nm?=?12?-?(3?-?mm);
????}
????else
????{
????????//还是在本年
????????ny?=?yy;
????????nm?=?mm?-?3;
????}
}
以此类推,“近一个月”的代码如下: if?(cbxTime.Text=="近一个月")
{
????if(mm-1< 1)
????{
????????//年份需要前移
????????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判断需要跨年。代码如下:
else?if(cbxTime.Text=="近一周")
{
????if(dd-7< 1)
????{
????????//月要前移?年可能会前移
????????if(mm-1< 1)
????????{
????????????//年要前移
????????????ny?=?yy?-?1;
????????????nm?=?12;
????????}
????????else
????????{
????????????//还在本年
????????????ny?=?yy;
????????????nm?=?mm?-?1;
????????}
????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????{
????????????//闰年
????????????mon[2]++;
????????}
????????nd?=?mon[nm]?-?(7?-?dd);
????}
????else
????{
????????//还在本月
????????ny?=?yy;
????????nm?=?mm;
????????nd?=?dd?-?7;
????}
}
同理,查询“近一天”的数据以往前推1天的同一时刻为起始时间。代码如下:
else
{
????//近一天
????if(dd-1< 1)
????{
????????if(mm-1< 1)
????????{
????????????ny?=?yy?-?1;
????????????nm?=?12;
????????}
????????else
????????{
????????????ny?=?yy;
????????????nm?=?mm?-?1;???
????????}
????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????{
????????????//闰年
????????????mon[2]++;
????????}
????????nd?=?mon[nm];
????}
????else
????{
????????//还在本年本月
????????ny?=?yy;
????????nm?=?mm;
????????nd?=?dd?-?1;
????}
}
时分秒不存在特殊情况,因此起始时间与当前时间的时分秒都是相同的。
由此生成最终的查询起始时间字符串,放到sql语句中进行比较查询,即可得到最终的查询结果。代码如下:
//形成参照时间
pretime?=?new?DateTime(ny,?nm,?nd,?hr,?min,?sec);
canzhao?=?pretime.ToString("s");
canzhao.Replace('T',?'?');//进行sql查询try
{
????conn.Open();
????ds?=?new?DataSet();
????string?sql?=?"select?recordid?as?'编号',name?as?'姓名',phonenumber?as?'手机号',washer?as?'洗发工工号',server?as?'服务生工号',type?as?'服务类型',arrivetime?as?'到店时间'?from?VipLog?where?arrivetime>'"?+?canzhao?+?"'";
????SqlDataAdapter?da?=?new?SqlDataAdapter(sql,?conn);
????da.Fill(ds);
????dgvList.DataSource?=?ds.Tables[0];
}
catch?(Exception?ex)
{
????MessageBox.Show(ex.Message,?"按时间搜索时出错",?MessageBoxButtons.OK,?MessageBoxIcon.Error);
}
finally
{
????conn.Close();
}
canzhao为最终的查询起始时间,作为比较时参考的字符串而存在。由于用DateTime,ToString("s")转化得到的字符串年月日与时分秒之间是用字母'T'隔开的,如2016-05-09T13:09:55,而在SqlServer中进行比较时时间的形式应该是年月日与时分秒之间用空格隔开,因此要将‘T’替换为空格后再进行比较。
以下是全部代码:
private?void?cbxTime_SelectedIndexChanged(object?sender,?EventArgs?e){
????//清空其他下拉框
????txtName.Text?=?"";
????txtPhoneNumber.Text?=?"";
????cbxEmID.Text?=?"";
????cbxType.Text?=?"";
????nowtime?=?DateTime.Now;
????//让DateTime以2016-05-09T13:09:55的格式显示
????string?now?=?nowtime.ToString("s");
????//获取当前年
????int?yy?=?Convert.ToInt32(now.Substring(0,?4));
????//获取当前月
????int?mm?=?Convert.ToInt32(now.Substring(5,?2));
????//获取当前日
????int?dd?=?Convert.ToInt32(now.Substring(8,?2));
????//获取当前时
????int?hr?=?Convert.ToInt32(now.Substring(11,?2));
????//获取当前分
????int?min?=?Convert.ToInt32(now.Substring(14,?2));
????//获取当前秒
????int?sec?=?Convert.ToInt32(now.Substring(17,?2));
????//参照比较时间字符串
????string?canzhao;
????//参照比较时间
????DateTime?pretime;
????//参照年
????int?ny=0;
????//参照月
????int?nm=0;
????//参照日
????int?nd=0;
????int[]?mon?=?{?0,?31,?28,?31,?30,?31,?30,?31,?31,?30,?31,?30,?31?};
????if?(cbxTime.Text=="近一个月")
????{
????????if(mm-1< 1)
????????{
????????????//年份需要前移
????????????ny?=?yy?-?1;
????????????nm?=?12;
????????}
????????else
????????{
????????????//年份就在本年
????????????ny?=?yy;
????????????nm?=?mm?-?1;
????????}
????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????{
????????????//闰年
????????????mon[2]++;
????????}
????????if?(dd?< =?mon[nm])
????????{
????????????nd?=?dd;
????????}
????????else
????????{
????????????nd?=?mon[nm];
????????}
????}
????else?if(cbxTime.Text=="近三个月")
????{
????????if(mm-3< 1)
????????{
????????????//年份需要前移
????????????ny?=?yy?-?1;
????????????nm?=?12?-?(3?-?mm);
????????}
????????else
????????{
????????????//还是在本年
????????????ny?=?yy;
????????????nm?=?mm?-?3;
????????}
????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????{
????????????//闰年
????????????mon[2]++;
????????}
????????if?(dd< =mon[nm])
????????{
????????????nd?=?dd;
????????}
????????else
????????{
????????????nd?=?mon[nm];
????????}
????}
????else?if(cbxTime.Text=="近一年")
????{
????????ny?=?yy?-?1;
????????nm?=?mm;
????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????{
????????????//闰年
????????????mon[2]++;
????????}
????????if?(dd< =mon[nm])
????????{
????????????nd?=?dd;
????????}
????????else
????????{
????????????nd?=?mon[nm];
????????}
????}
????else?if(cbxTime.Text=="近一周")
????{
????????if(dd-7< 1)
????????{
????????????//月要前移?年可能会前移
????????????if(mm-1< 1)
????????????{
????????????????//年要前移
????????????????ny?=?yy?-?1;
????????????????nm?=?12;
????????????}
????????????else
????????????{
????????????????//还在本年
????????????????ny?=?yy;
????????????????nm?=?mm?-?1;
????????????}
????????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????????{
????????????????//闰年
????????????????mon[2]++;
????????????}
????????????nd?=?mon[nm]?-?(7?-?dd);
????????}
????????else
????????{
????????????//还在本月
????????????ny?=?yy;
????????????nm?=?mm;
????????????nd?=?dd?-?7;
????????}
????}
????else
????{
????????//近一天
????????if(dd-1< 1)
????????{
????????????if(mm-1< 1)
????????????{
????????????????ny?=?yy?-?1;
????????????????nm?=?12;
????????????}
????????????else
????????????{
????????????????ny?=?yy;
????????????????nm?=?mm?-?1;
????????????}
????????????if?(ny?%?4?==?0?&&?ny?%?100?!=?0?||?ny?%?400?==?0)
????????????{
????????????????//闰年
????????????????mon[2]++;
????????????}
????????????nd?=?mon[nm];
????????}
????????else
????????{
????????????//还在本年本月
????????????ny?=?yy;
????????????nm?=?mm;
????????????nd?=?dd?-?1;
????????}
????}
????//形成参照时间
????pretime?=?new?DateTime(ny,?nm,?nd,?hr,?min,?sec);
????canzhao?=?pretime.ToString("s");
????canzhao.Replace('T',?'?');
????//进行sql查询
????try
????{
????????conn.Open();
????????ds?=?new?DataSet();
????????string?sql?=?"select?recordid?as?'编号',name?as?'姓名',phonenumber?as?'手机号',washer?as?'洗发工工号',server?as?'服务生工号',type?as?'服务类型',arrivetime?as?'到店时间'?from?VipLog?where?arrivetime>'"?+?canzhao?+?"'";
????????SqlDataAdapter?da?=?new?SqlDataAdapter(sql,?conn);
????????da.Fill(ds);
????????dgvList.DataSource?=?ds.Tables[0];
????}
????catch?(Exception?ex)
????{
????????MessageBox.Show(ex.Message,?"按时间搜索时出错",?MessageBoxButtons.OK,?????????????MessageBoxIcon.Error);
????}
????finally
????{
????????conn.Close();
????}
}

?热 文?推 荐?
?马云谈 5G 危机;腾讯推出车载版微信;Ant Design 3.22.1 发布 | 极客头条
?漫画:什么是旅行商问题?
?与旷视、商汤等上百家企业同台竞技?AI Top 30+案例评选等你来秀!
?他是叶问制片人也是红色通缉犯, 他让泰森卷入ICO, 却最终演变成了一场狗血的罗生门……
点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 《求是》发表习近平总书记重要文章 7904296
- 2 勇敢夺枪老人与妻子相拥倒在现场 7808319
- 3 中美卫星惊险“擦肩”距离仅200米 7714295
- 4 明年经济工作政策取向确立这八个字 7616035
- 5 “中国最冷小镇”最低温降至-39℃ 7520461
- 6 男子陪女友逛街买刮刮乐中80万元 7423901
- 7 30万级的玛莎拉蒂两天被一抢而空 7333496
- 8 上海商场悬空挂数十件大衣被指吓人 7236766
- 9 男子买炒饼打包5头蒜被老板劝退 7138843
- 10 如何让你我的钱袋子鼓起来 7042226

CSDN
