DateTime.Compare is not working as expected - c#

I'm inserting customers the following way.
DateTime d = DateTime.Now;
foreach(Customer cus in CustomerList)
{
cus.EntryDate = d;
}
SaveToDatbase(CustomerList);
Date is getting saved successfully with the correct entry date, but however when I retrieve data back and compare it with variable d, it doesn't match.
foreach(Customer cus in GetFromDatabase())
{
Response.Write(DateTime.Compare(cus.EntryDate, d));
}
The output is 1 instead of 0. I checked the inserted data and it matches d variable value with milliseconds. Date is stored in sql server database. One thing I realized is if I reset milliseconds to 0 for cus.EntryDate and d, output is 0. What am I doing wrong here?

SQL Server's datetime type has a lower resolution than .NET's. As you're using DateTime.Now directly (without rounding it to the nearest second) you'll see differences in the milisecond or tick (100 nanosecond) portions.
According to MSDN, the datetime type in SQL Server has a resolution of approximately 3 miliseconds (specifically: 2015-08-18 15:49:10.000 -> 2015-08-18 15:49:10.003 -> 2015-08-18 15:49:10.007 -> 2015-08-18 15:49:10.010) whereas .NET's DateTime type has a resolution of 100 nanoseconds.
If you want to preserve some kind of equality, I suggest rounding DateTime to the nearest second before inserting into the database:
DateTime now = DateTime.Now;
now = new DateTime(
now.Ticks - ( now.Ticks % TimeSpan.TicksPerSecond ),
now.Kind
);
foreach(Customer cus in customerList) cus.EntryDate = now;

SQL Server's datetime value has a precision of 1 milicsecond, but an accuracy of [approximately] 3.33ms. Further, it doesn't actually "round" the millisecond count. Its "rounding" algorithm is...byzantine, to be kind. But it is, at least, documented. My answer to the question, "Round .NET DateTime milliseconds, so it can fit SQL Server milliseconds", which you can find at https://stackoverflow.com/a/5318635/467473, will
point you to the documentation for how the conversion is performend, and
has an datetime extension method that will convert a CLR System.DateTime value to its corresponding SQL Server datetime equivalent.
One should note that to due to the precision/accuracy difference between the two representations, this is not a round trip conversion.

Related

Convert difference in milliseconds to .MaxValue back to Date/Time

For a rowkey on Azure TableStorage entities following prefix is used:
DateTime.MaxValue.Subtract(DateTime.UtcNow).TotalMilliseconds
As far as I know should this timestamp act as a kind of "sorter" so that newer entities are on top of an list. So, this shown code line creates (as I can imagine) the amount of milliseconds of the current date/time till the DateTime.MaxValue.
Is there a simple and safe way, to convert this amount of milliseconds "back" to the date/time when the timestamp was created? I´m not so familiar with date/time conversions...
The DateTime.MaxValue is:
equivalent to 23:59:59.9999999 UTC, December 31, 9999 in the
Gregorian calendar, exactly one 100-nanosecond tick before 00:00:00
UTC, January 1, 10000.
Thus, considering roughly 10,000 years, you have:
10,000 x 365 x 24 x 60 x 60 x 1000 = 315,360,000,000,000 //Note 15-digit
And the double precision is at least 15-digit. In other words, as long as you use the first 15 digit of your TotalMilliseconds as the timestamp, then it should be fine.
I recommend to cast it to long whose integer precision is:
–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 //note, more than 15-digit
And then use ToString("D15") as unique timestamp:
long val = (long)DateTime.MaxValue.Subtract(DateTime.UtcNow).TotalMilliseconds;
string timestamp = val.ToString("D15");
And to convert back, you could cast it back to double and use AddMilliseconds with negative sign from max.
double db = Convert.ToDouble(timestamp);
DateTime dt = DateTime.MaxValue;
dt.AddMilliseconds(-db); //this will give you the datetime back with milliseconds precision
Then you will get precision up to your milliseconds.

Milliseconds value are not getting saved in SQL Server DateTime column

I need to store a DateTime value which is sent to the Database from a C# application which is using DateTime.UtcNow. If I save it to the DateTime column, the milliseconds value are always 000. But while debugging from the application, the milliseconds value is sent from the application to the database.
What am I missing?
It might happen because datetime column rounds milliseconds part. From documentation;
Accuracy
Rounded to increments of .000, .003, or .007 seconds
Since you didn't show us how often you store your UtcNow value (I assume you store it as a DateTime, not it's string representation because parameterless ToString and other standard formats does not generates millisecond part usually), this may happen but if you do it in short time intervals, it would be really weird always rounding to 000 as milliseconds part. But of course, we can't know that, yet.
On the other hand, datetime2 type does not do any rounding. And it's accuracy is 100 nanoseconds.
Accuracy
100 nanoseconds
Here's no pleasant way to use Datetime because
SQL Server only stores time to approximately 1/300th of a second.
These always fall on the 0, 3 and 7 milliseconds
SQL Server 2008 has much more precision available. The datetime2 datatype will accurately store values like this: 2008-12-19 09:31:38.5670514
See reference documentation
It looks to me like something/someone is doing a default-ToString instead of using ToString with the proper ISO-standard format.
Proper ISO-format for date with time is
yyyy-MM-ddTHH:mm:ss.fff
while date-only ISO-format is
yyyyMMdd
You can check:
static void Main(string[] args)
{
System.DateTime cur = System.DateTime.UtcNow;
string strDefault = cur.ToString();
string str = cur.ToString("yyyy-MM-ddTHH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture);
System.Console.WriteLine(str);
System.Console.WriteLine(strDefault);
}
This outputs
2016-03-03T08:31:27.324
03.03.2016 08:31:27
You might also want to use the HEX-format, as this enhances precision, or at least preserves a value that already was in SQL-Server. If you don't use hex-representation, you can get a 23:59:59.997 value from SQL-server and resave, and you'll have 00:00:00 with day+1. Using the hex-format preserves .997, while saving an ISO-string will yield day+1.
public static string GetTimeAsHex(System.DateTime dt)
{
System.DateTime zero = new System.DateTime(1900, 1, 1);
System.TimeSpan ts = dt - zero;
System.TimeSpan ms = ts.Subtract(new System.TimeSpan(ts.Days, 0, 0, 0));
double x = System.Math.Floor(ms.TotalMilliseconds / 3.3333333333);
string hex = "0x" + ts.Days.ToString("X8") + System.Convert.ToInt32(x).ToString("X8");
return hex;
}
Anyway, as others have already told you, SQL-server datetime is only precise to within a 4 ms error margin. This is why you should use datetime2, as it fixes many issues (bugs/"features") in datetime, including insufficient precision in the milliseconds range.
If you are building your INSERT statement as a string, try specifying the output of milliseconds in the string conversion
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);

Accuracy of comparing DateTime.now of C# and GetDate() from SQL

What i am doing is that, i need to select a row that i have just recently added through DateTime to get the PK since i need it.
I store the DateTime through:
DateTime nw = DateTime.now and i use nw to search through my table.
My question is that, what if let's say i put 2 rows within a span of 1 minute?
My sql table stores them like this:
Since milliseconds isn't visible, will both of them be selected?(assuming everything happened within 1 minute)
Edit: this is from my asp mvc project. So the DateTime is new everytime my action is run.
The problem is precision. The GetDate() function in TSQL is not at the precision as c# DateTime, as GetDate() returns an TSQL DateTime.
TSQL DateTime:
Defines a date that is combined with a time of day with fractional seconds that is based on a 24-hour clock.
Rounded to increments of .000, .003, or .007 seconds
C# DateTime:
The Ticks property expresses date and time values in units of one ten-millionth of a second, and the Millisecond property returns the thousandths of a second in a date and time value. However, if you are using repeated calls to the DateTime.Now property to measure elapsed time, and you are concerned with small time intervals less than 100 milliseconds, you should note that values returned by the DateTime.Now property are dependent on the system clock, which on Windows 7 and Windows 8 systems has a resolution of approximately 15 milliseconds.
However you could use the newer (avail as of SQL Server 2008) SysDateTime() which returns a datetime2(7) value that should match the precision of C# Datetime.
datetime2(7):
Defines a date that is combined with a time of day that is based on 24-hour clock. datetime2 can be considered as an extension of the existing datetime type that has a larger date range, a larger default fractional precision, and optional user-specified precision.
This only academically interesting because you should never use a datetime as a PK.
Let's say it's Nov 6, 2016 at 1:15AM. You create a record:
MyPk
------
2016-11-06 01:15:00
One hour later you create another record...
MyPk
------
2016-11-06 01:15:00
2016-11-06 01:15:00
Duplicate PKs due to daylight savings. Don't have daylight savings? There are a multitude of reasons to not use DateTime for a PK (simply google search for datetime as primary key).
Just to name a few:
Exact select can be very difficult (milliseconds matter!)
Foreign Keys become a Nightmare
Replication is very difficult unless all systems are in the same timezone
If you really want to use the DateTime.Now with second precision as a way to find the PK of your data, you should not declared it once and use it everywhere. Rather, you should use it like this:
insertDataToDataBase(data, DateTime.Now);
and then 10-20 seconds later
insertDataToDataBase(data, DateTime.Now); //still use DateTime.Now
This way your DateTime.Now will always be updated

Update datetime in Database

Consider this code:
var datetime = DateTime.Now;
var instantMessage = InstantMassageingManager.GetConverationMessages().FirstOrDefault();
InstantMassageingManager.UpdateConversationMessageReadDateTime(instantMessage.InstantMessageInstanceId, datetime);
var message = InstantMassageingManager.GetMessageById(instantMessage.InstantMessageInstanceId);
Assert.IsTrue(message.ReadDateTime.Value == datetime);
in the first line I get DateTime.Now
then I update a record in database: UpdateConversationMessageReadDateTime
and get the message again from the database:
Both message.ReadDateTime and datetime has same value but with different Tick.
So my test doesn't pass.
Why do I get different values for tick?
I strongly suspect that the type you're using in the database doesn't have the same level of precision - I suspect it's only accurate to the millisecond.
If you want to round-trip the time, you should truncate your "input" time to the nearest millisecond too. For example:
TimeSpan rounded = TimeSpan.FromMilliseconds(original.Ticks / 10000);
Or for a DateTime:
DateTime rounded = new DateTime(original.Year, original.Month, original.Day,
original.Hour, original.Minute, original.Second, original.Millisecond,
original.Kind);
You should also consider whether you really want to take the local time (which depends on the system time zone) or a UTC value. It depends on the context, but it's more frequently appropriate to store UTC values for timestamps, which is what it looks like you've got here.

How to get current Time with Milli second precision ( C#)

I use System.DateTime.Now , but it return like 5/28/2011 1:45:58 AM .(no Milli second precision)
I would like to save current time (or Date time ) with Milli second precision in database .
Update : Sorry , I meant Milli Second
System.DateTime manages precision to the millisecond, 5/28/2011 1:45:58 AM is just how it was formatted to a String.
To format with millisecond included use format string: "d/M/yyyy hh:mm:ss.fff tt"
If you want to store it in a SQL Server database, ADO.Net automatically converts the CLR System.DateTime datatype to a SQL Server datetime datatype (and vice-versa).
The CLR System.DateTime has 100-nanosecond precision (e.g., each tick is 100 nanoseconds; 10,000 ticks per millisecond, 10 million ticks per second.
The SQL Server datetime datatype is precise to (approximately) 3ms.
You shouldn't need to worry about it: ADO.Net will take care of it for you.
OTOH, if you really want to throw away extra nanoseconds, something like this ought to do the trick:
public static DateTime ToExactMillisecondPrecision( DateTime dt )
{
const long TICKS_PER_MILLISECOND = 10000 ;
long totalMilliseconds = dt.Ticks / TICKS_PER_MILLISECOND ;
return new DateTime( totalMilliseconds * TICKS_PER_MILLISECOND ) ;
}
Can't really see the need myself.
Look under the properties list in this link. All the different options are there.
http://msdn.microsoft.com/en-us/library/system.datetime.aspx
Including seconds, milliseconds, and ticks
The string you posted contains seconds, so I suppose you're not asking for second precision, but for more precise timing.
The value of DateTime.Now is returned with more than millisecond precision. it's just that with default formatting, the milliseconds aren't displayed. To display the value with milliseconds, you can either use the o standard format string, or write your own custom format string, that includes the millisecond format specifier fff.
Note that just because the returned value is precise, it doesn't mean it's as much accurate. The actual accuracy is not defined exactly, but tends to be in tens of milliseconds.
It should not be necessary to convert the date to string. Perhaps the real problem is that you using dynamic SQL.

Categories

Resources