1ms引发的问题

原文:1ms引发的问题

最近在跟SQLServer数据库进行交互的时候发现一个奇怪的问题,在往数据库里边插入日期型数据的时候,在C#里面赋值的为 2014/05/19 23:59:59,但是存到数据库里边就变成了2014/05/20 00:00:00。

问题场景

当时需求是这样的,产品的销售策略要求管理员输入一个产品销售的开始日期SalesStart和结束日期SalesEnd,然后业务会根据当前的时间判断是否在这个产品销售范围内,如果不在则显示未开始或者已过期,所以存储的时候,对SalesEnd进行了处理,在存到数据库的时候,保存的是当天的23:59:59,当时我的处理是这样的:在截止日期加1天然后减去以1毫秒,代码如下:

ProductSalesPolicyModel productSaleModel;
productSaleModel = new ProductSalesPolicyModel();

productSaleModel.SalesStart = item.SaleStartTime;
productSaleModel.ValidStart = item.ValidStartTime;
productSaleModel.SalesEnd = item.SaleEndTime.AddDays(1).AddMilliseconds(-1);
productSaleModel.ValidEnd = item.ValidEndTime.AddDays(1).AddMilliseconds(-1);

然后利用企业库往数据库中使用某个存储过程插入数据,参数赋值的代码如下:

DataParameterCollection parameters;
parameters = new DataParameterCollection();
parameters.Add("SalesStart", DbType.DateTime, salePolicyModel.SalesStart);
parameters.Add("ValidStart", DbType.DateTime, salePolicyModel.ValidStart);
parameters.Add("ValidEnd", DbType.DateTime, salePolicyModel.ValidEnd);
parameters.Add("SalesEnd", DbType.DateTime, salePolicyModel.SalesEnd);

执行插入操作的细节就不写了。

执行完成之后,结果如下:

 

 

在数据库中ProductSalePolicy的表结构如下,其中ValidEnd的类型也是datetime

原因分析

初步分析,有可能是C#中DateTime和SQL Server中datetime数据精度不一致导致的

SQL Server中的时间精度

1. SQL Server中datetime精度

于是到MSDN上去找Transact-SQL中的datetime类型,果不其然,SQL中datetime字段的取值范围为 :

  • 日期范围为:1753.1.1 ~ 9999.12.31
  • 时间范围为:00:00:00 ~23:59:59.997

可见,datetime类型的时间精度是3.33毫秒,如果超过该精度会进行近似到0.000,0.003,0.007 秒,比如:


输入值


SQL 存储值


01/01/98 23:59:59.999


1998-01-02 00:00:00.000


01/01/98 23:59:59.995

01/01/98 23:59:59.996

01/01/98 23:59:59.997

01/01/98 23:59:59.998


1998-01-01 23:59:59.997


01/01/98 23:59:59.992

01/01/98 23:59:59.993

01/01/98 23:59:59.994


1998-01-01 23:59:59.993


01/01/98 23:59:59.990

01/01/98 23:59:59.991


1998-01-01 23:59:59.990

2. SQL Server中datetime2精度

鉴于SQL Server的datetime精度只有3.33毫秒,从SQL Server2008开始,提供了datetime2类型, 该类型的时间精度为00:00:00 ~ 23:59:59.9999999 即100纳秒,10-4毫秒。

System.Data这个主要和外部数据进行交互的名字空间中的DbType枚举可以看到,它提供了DataTime,和DataTime2这两种类型,分别对应了SQL Server中的这两种时间精度,从注释中可以看出,DataTime2的精度是100纳秒

namespace System.Data
{
    // Summary:
    //     Specifies the data type of a field, a property, or a Parameter object of
    //     a .NET Framework data provider.
    public enum DbType
    {
        //
        // Summary:
        //     A type representing a date and time value.
        DateTime = 6,
        //
        // Summary:
        //     Date and time data. Date value range is from January 1,1 AD through December
        //     31, 9999 AD. Time value range is 00:00:00 through 23:59:59.9999999 with an
        //     accuracy of 100 nanoseconds.
        DateTime2 = 26,
    }
}

C#中Datetime精度

现在再看看C#中的DataTime精度,因为我们在给存储过程中的ValidEnd参数进行赋值的时候定义的类型为DbType.Datetime ,同样,在MSDN上,有对其精度的说明:

Time values are measured in 100-nanosecond units called ticks

100ns就是DateTime的精度,即10-4毫秒。10-4 毫秒也是为DateTime类型的精度

通常我们看到的C#中的DateTime类型精确到100纳秒,即最大时间为23:59:59.9999999。这后面的也就是我们常用到的tick的精度。

原因

因为我在C#代码中处理的时候是item.SaleEndTime.AddDays(1).AddMilliseconds(-1);所以时间精度为0.0001毫秒,为2014/12/16 23:59:59.9990000,然而数据库中字段使用的是datetime类型,该类型的精度为3.33毫秒,所以存到SQL Server的时候被round到了2014/12/17 00:00:000000,从前面的分析也可以看出这个问题。

解决方法

根据分析,有两种方式:

  • 一种是将数据库中的该类型从datetime改为datetime2类型,但是这个类型只有SQL Server 2008及以上版本才支持,他的精度和C# 里面的DateTime数据类型的精度是一致的。
  • 再一种就是修改我们传到SQL Server中的值了,在一些不需要那么高的精度的场景下,比如本文中对结束日期添加23:59:59的这一处理,当时想都没想直接是AddMilliseconds,减的是1ms,而数据库中的精度是3.3ms,所以导致被SQL Server Round到了第二天的零点。这里把 AddMilliseconds改成AddSecond(-1)减1s即可。

总结

C# 中的DateTime的精度和SQL Server中的datetime2的精度(SQL Server 2008及以上版本才有) 是一致的,均为100纳秒(10-4毫秒),而SQL Server中的datetime类型精度只有3.33毫秒,所以如果把C# 中的DateTime类型存储到SQL Server中的datetime中时,会出现精度丢失的情况,在对精度要求较高的系统中,需要注意。

时间: 2024-08-12 19:29:04

1ms引发的问题的相关文章

Oracle高并发系列2:事务日志写入引发的Redo log风波

作者介绍 王鹏冲,平安科技数据库技术专家,浸淫数据库行业十多年,对Oracle数据库有浓厚兴趣,也对MySQL.MongoDB.Redis等数据库有一定架构和运维经验,目前正沉迷在PostgreSQL数据库与Oracle数据库的PK之中,重点在关系型数据库的分布式架构研究.   引言   关系型数据库强调事务的ACID特性,对于事务的持久性,主流的关系型数据库都是通过写事务日志来实现的.写数据是随机IO,写日志是顺序IO,常规的机械磁盘,随机IO比顺序IO要昂贵很多.所以虽然写日志同样要刷到磁盘

文件 提取 字-文件按字读取存储引发的一点问题

问题描述 文件按字读取存储引发的一点问题 问题比较复杂: 1.我需要将二进制文件提取出来,加密后存入另一文件 2.由于原始文件按字节(fgetc)提取加密后会变成很大的数(>255),因此不能用fputc来存加密后的数据,这就不可避免的用到putwc.但是putwc会使加密文件变大(由char变成了wchar),而我又想保持源文件大小. 3.我想到了按字提取fgetwc.按字存储fputwc,但是按字提取不能很好解决文件结尾的判定,如果源文件只有"abc"三个字符,那么按字提取只

spring-maven 打jar包,引发程序运行时候报错

问题描述 maven 打jar包,引发程序运行时候报错 java项目A,用maven 打完jar包之后,放入项目B中使用,运行报如下错误java.lang.NoSuchFieldError: ALIAS_TO_ENTITY_MAP: 用MyEclipse 自带的export jar打包,却没有这个问题,很是郁闷,求解... 报错代码:query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); 解决方案 请检查确认项目 B 里的 A.

String copy on write 引发的线程不安全

   一个string对象的读操作是线程安全的么?答案是否定的.读取一个string在某些情况下是线程不安全的.这是为什么呢?原因就是string在优化存储空间时采用的策略cow. 什么是cow      Cow 是copy on write的缩写.String 为了减少内存拷贝,当两个string对象的内容相同时,他们指向同一块内存空间,并通过引用计数来表示有多少对象引用了这块内存.当其中某个string对象的内容发生改变时,string会先重新分配一块空间,把原来的内容拷贝到新空间,原来的空

freertos-在FreeRTOS下开发软件,想延时1ms里面的延时delay的函数是怎么用?

问题描述 在FreeRTOS下开发软件,想延时1ms里面的延时delay的函数是怎么用? 求高人解答,在FreeRTOS下开发软件,想延时1ms里面的延时delay的函数是怎么用? 解决方案 参考:http://blog.chinaunix.net/uid-20564848-id-72931.html

股市热潮引发电脑安全隐患 股民安全八大注意

股市热潮引发电脑安全隐患 近日,由于股票市场的持续火爆,使得越来越多的新股民进入股市.据有关部门统计,目前每13个中国人就有1个炒股.每天A股开户数新增30万户,我国已进入"全民皆股"时代.而网上炒股以其"交易方便快捷.信息量大,紧跟行情.辅助分析系统强大"等特点成为股民炒股的首选方式.但据专家介绍,由于大多数股民缺乏基本的防护意识和措施,使网上炒股面临极大的安全风险. "自5月8日开市以来,因为电脑中毒而向瑞星求助的股民已有数百人,股民已经成为电脑病毒受

一句T-SQL语句引发的思考

语句 ********************************************************** Author:黄山光明顶 mail:leimin@jxfw.com version:1.0.0 date:2004-1-30 (如需转载,请注明出处!,如果有问题请发MAIL给我:-)) ***********************************************************有一网友问:关于MS SQLSERVER索引优化问题: 有表Stres

GridViewRow可以任意位置单击引发事件的方法

GridView 是 ASP.NET 2.0 中应用最为广泛一个控件,几乎所有的数据操作都需要它,正如我们平常所应用的,可以编辑.删除.选择等等,但如果客户有需要通过单击行而引发超链接或者进入行编辑状态时,我们该如何实现,这里介绍了一种方法来实现此功能.它将允许你通过点击行的任何一个位置而引发你所需要的事件. 首先为 GridView  填充数据  private void BindData()    {        SqlConnection myConnection = new SqlCo

CNNIC推广1元注册域名将引发无限商机

推广|注册域名 关于CNNIC以史无前例的超低价格推出的"CN域名1元注册体验活动",最近已经炒得沸沸扬扬,相信大家也有所耳闻,如果是还不清楚事情来龙去脉的朋友,不妨看看下面的简述: --3月7日,我国域名注册管理机构中国互联网络信息中心(CNNIC)在北京召开新闻发布会,正式启动国家域名腾飞行动,并宣布从即日起至5月31日,新注册CN域名第一年将享受1元钱的注册价格.据了解,本次"CN域名一元体验活动暨国家域名腾飞行动"得到信息产业部.国务院信息化工作办公室.国务