sql server datetime取年月_“近一个月”、“近三个月”这种查询如何处理更精确?...

00ceb6298de1c6f55eaf6de9dccad556.gif

815383de73fb58af4464d63c54b793b5.png

作者 | 宋广泽 责编 | 胡雪蕊 出品 | CSDN(ID:CSDNnews)

有的人认为,全都按一个月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");

此外,C#对于将时间转换成字符串有多种格式,有如下几种主要格式:
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 中间一个TDateTime.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;
    }
}

再讲第二步,有了查询起始时间所在的年和月,就计算出这个月有多少天就很容

易了。先将一般情况(平年)每个月有多少天进行初始化。代码如下:

287bab57a97dedbdbe08eb0201e3b1ee.png

根据推算出的查询起始时间的年判定是不是闰年,如果是闰年就将2月的天数增加1。

ny、nm、nd为推算起始时间所在年、月、日;

yy、mm、dd为当前时间所在年、月、日。代码如下:

0c4a6bd0257aea57f6f9152e8e8fdfb5.png

有了以上数据,就可以套用前面讲过的将多出来的天数剪掉以确定起始时间的算

法了。代码如下:

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();    }}
未经优化,代码略显冗余,还望见谅。 作者:宋广泽,青岛某普通一本大学计算机专业在校生,本科在读,学生开发者。喜欢用C/C++编写有意思的程序,解决实际问题。 【END】

e3d26202ad567661cf02ab3b0558d462.png

 热 文 推 荐 

☞马云谈 5G 危机;腾讯推出车载版微信;Ant Design 3.22.1 发布 | 极客头条

☞漫画:什么是旅行商问题?

☞程序员易踩的 9 大坑!

☞公开课 | 如何用图谱挖掘商业数据背后的宝藏?

☞开学了,复旦老师教你如何玩转“0”“1”浪漫!| 人物志

☞与旷视、商汤等上百家企业同台竞技?AI Top 30+案例评选等你来秀!

☞“根本就不需要 Kafka 这样的大型分布式系统!”

☞他是叶问制片人也是红色通缉犯, 他让泰森卷入ICO, 却最终演变成了一场狗血的罗生门……

☞如何写出让同事无法维护的代码?

33986fb1e55498dbc7e1befa6e4f3fe3.gif

37b7069b447c0e50aa0cb84356997d92.png 你点的每个“在看”,我都认真当成了喜欢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值