EF DateTimes do not match saved values in SQL Server [duplicate] - c#

This question already has answers here:
Milliseconds in my DateTime changes when stored in SQL Server
(4 answers)
Closed 7 years ago.
I save a datetime using C# Entity Framework, and when I load that time back from the database, the time varies from the value that I saved by 1 or more milliseconds.
Here is the C# Code:
public List<DateTime> TestDate()
{
var dates = new List<DateTime>();
DateTime testvalue = DateTime.Now;
dates.Add(testvalue);
IactexGMG2Entities firstContext = new IactexGMG2Entities();
var firstQuery = from p in firstContext.LocationProperties
where p.locationPropertyId == 4
select p;
var firstRec = firstQuery.Single();
firstRec.locationPropertyDateTime = testvalue;
firstContext.SaveChanges();
firstContext.Dispose();
IactexGMG2Entities secondContext = new IactexGMG2Entities();
var secondQuery = from p in secondContext.LocationProperties
where p.locationPropertyId == 4
select p;
var secondRec = secondQuery.Single();
var secondDate = secondRec.locationPropertyDateTime ?? DateTime.Now;
dates.Add(secondDate);
secondContext.Dispose();
return dates;
}
Here are the received values:
5/29/2015 5:43:25 PM . 154 , 635685182051540566
5/29/2015 5:43:25 PM . 153 , 635685182051530000
Here is the razor code that displays the values:
#foreach (var date in Model)
{
counter++;
<div>
#date . #date.Millisecond , #date.Ticks
</div>
}
As you can see, the second value, which was read back from the database, is lower than the first value by 1.0566 milliseconds.
The amount of variation varies, positive and negative, always with a small number of milliseconds.
Does anyone know how the conversion between the date values takes place?
Note: If I use the same context to read the date value, the values match. I assume that is because it is using the cached value, rather than the SQL Server value.

The problem is the different resolution between TSQL datetime and .NET DateTime data types
datetime only has a small resolution and is rounded to increments of .000, .003, or .007 seconds, whereas DateTime has a resultion of 100ns
Just use the new datetime2 SQL Data Type, which has the same resolution as .NET's DateTime, which is anyway recommended in new work, exactly for the issue you noticed

This actually has very little to nothing to do with Entity Framework. SQL Server as of 2008 has two DateTime types:
DateTime
Accuracy : Rounded to increments of .000, .003, or .007 seconds
DateTime2
Accuracy : 100 nanoseconds
Using Code-First Annotations you can set the property type like:
public MyClass
{
[Column(“CreatedOn", TypeName="DateTime2")]
public DateTime CreatedOn { get; set; }
}
Or using Fluent API:
modelBuilder.Entity<MyClass>()
.Property(p => p.CreatedOn)
.HasColumnType("DateTime2");

Related

How to format C# DateTimeOffset exactly same as in SQL Server's DateTime2(7) format?

Saving following two DateTime values in SQL Server's DateTime2(7) column results in same DateTime2 value.
var dt1 = new DateTimeOffset(638124107765100000, TimeSpan.Zero);
var dt2 = new DateTimeOffset(638124107765000000, TimeSpan.Zero);
Value in Sql Server's DateTime2(7) column.
2023-02-19 13:39:36.5066667
This value goes through Entity Framework. Now I can see that SQL Server uses some different form of storage to store value, so the value gets changed when we read it back.
Now I have no problem with little lost precision but I want to format DateTime in such a way that the text should match exactly what is stored in SQL Server.
The only way currently I can do is by ignoring whole milliseconds above 10.
I have tried the following:
private static DateTimeOffset ToSqlServerPrecision(DateTimeOffset dt) {
var n = Math.Round((double)dt.ToUnixTimeMilliseconds() / (double)1000, 1);
n = n * 1000;
return DateTimeOffset.FromUnixTimeMilliseconds((long)n);
}
ToSqlServerPrecision(dt1).ToString("yyyy-MM-dd HH:mm:ss.fffff")
Both result in:
2023-02-19 13:39:36.50000
2023-02-19 13:39:36.50000
But I doubt, this will might fix all edge cases.
I have also tried following,
private static DateTimeOffset ToSqlServerPrecision(DateTimeOffset dt) {
var p = (double)1/3; // or 3.33
var n = Math.Round((double)dt.UtcTicks / p, 1);
n = n * p;
return new DateTimeOffset((long)n, TimeSpan.Zero);
}
Both result in:
2023-02-19 13:39:36.51000
2023-02-19 13:39:36.49999
I guess Ticks to SQL Server compatible time storage isn't simply casting milliseconds/ticks to double conversion.
All I want is to get exact same text representation that is stored in SQL Server.

Storing DateTime in PostgreSQL without loosing precision [duplicate]

This question already has answers here:
What is the most elegant way to store timestamp with nanosec in postgresql?
(3 answers)
Closed 4 years ago.
I have stumped upon an issue, that whenever I load what is presumably a DateTime from Postgresql database and compare it to initial value from C# - then the data does not match. For example, here's an original DateTime in C#:
Date: {09.07.2018 00:00:00}
Ticks: 636667391123714378
Time: {13:18:32.3714378}
Same date, returned from DB (after it was saved):
Date: {09.07.2018 00:00:00}
Ticks: 636667391123714370
Time: {13:18:32.3714370}
It seems like upon save - DateTime has lost some precision. Column type in database is a Timestamp. So, 2 questions:
What will be a proper way of storing the DateTime in PostgreSQL, so I don't loose any precision?
I was thinking about saving a number of UNIX milliseconds into an Integer field instead, of saving DateTime as a Timestamp, i.e.:
DateTime myDT = DateTime.Now;
long ms = new DateTimeOffset(myDT).ToUnixTimeMilliseconds();
// how I do it now
var parameterOld =
new Npgsql.NpgsqlParameter("dateInserted", NpgsqlTypes.NpgsqlDbType.Timestamp) {Value = myDT };
// how I think would be a better approach
var parameterNew =
new Npgsql.NpgsqlParameter("dateInserted", NpgsqlTypes.NpgsqlDbType.Integer) { Value = ms };
Alternatively, how do I compare 2 datetimes with a highest possible precision (C#/PostgreSql)?
My current solution, which is kind of working.. But I am loosing too much precision here:
public static bool IsEqualWithLossOfPrecision(this DateTime timestamp1, DateTime timestamp2)
{
return (
timestamp1.Year == timestamp2.Year &&
timestamp1.Month == timestamp2.Month &&
timestamp1.Day == timestamp2.Day &&
timestamp1.Hour == timestamp2.Hour &&
timestamp1.Minute == timestamp2.Minute &&
timestamp1.Millisecond == timestamp2.Millisecond
);
}
Any advises on 2 questions are welcomed.
I am using the latest available version of DB (10.4), Npgsql library v. 4.0.0, .net framework 4.5ish, windows 10
PostgreSQL's timestamps have a precision limit of microseconds.
If you need more, store the nanoseconds in a separate bigint attribute.

return date without time but not of type string but date

I have a date value that I want to strip the time from. I want the return type to be a date type since I want to order the list of date I have. having a list to string representing Date does not return a correct order.
I know that DateTime always returns the date with the time. What are my options here? How can I better my code and have a list of items of Date type without the time?
Edit: I would like to have the date only. nothing after that. Something like 8/7/2016 not 8/7/2016 00:00:00 or anything after date. and in a date object.
Here is my code:
using (var db = new MyModel.Context())
{
var cert = (
from tr in db.uspTranscripts(personId)
from a in db.PersonTranscripts.Where(x => x.UPID == personId)
from b in db.LU_CreditType.Where(x => x.ID == a.CreditTypeID)
select new CertViewModel
{
ActivityTitle = tr.ActivityTitle,
Score = tr.Score,
Status = tr.Status,
CompletionDate = tr.CompletionDate,
CretitTypeName = b.ShortName,
CompletedDateSorted = a.HK_CreatedOn
}).OrderByDescending(x => x.CompletedDateSorted).ToList();
List<CertViewModel> certlist = cert;
foreach (var item in certlist)
{
string itemWithoutHour = item.CompletionDate.Value.ToShortDateString();
var itemConverted = DateTime.ParseExact(itemWithoutHour, "M/d/yyyy", null);
item.CompletionDate = itemConverted;
}
return certificateslist.GroupBy(x => x.ActivityTitle).Select(e => e.First()).ToList();
}
For any given DateTime object, you can reference its Date property to strip out the time values:
var withTime = DateTime.Now; // 8/7/2016 22:11:43
var withoutTime = withTime.Date; // 8/7/2016 00:00:00
The .NET framework does not have a date-only object.
It may be worth understanding how the DateTime structure works. Internally, it stores an offset in ticks (1 tick = 100 nanoseconds) since 1/01/0001 12:00 am in a single 64-bit unsigned integer. (1 tick = 100 nanoseconds)
The DateTime structure then provides many useful methods and properties for dealing with dates and times, such as adding some days to an existing date, or calculating the difference of two times. One useful property is Date, which rounds a DateTime object down to the nearest day (12:00 am).
Dates, times and dates-with-times are all very similar, the main difference is how you format them, a date-with-time where you omit the time is just a date.
What David has suggested is that you work with the DateTime structure internally, strip any times using the Date property, sort on the DateTime, compare them and modify them as DateTime objects.
Only convert them to a string when they need to be displayed, at which point you can use methods such as ToShortDateString() or ToString(string format) to display only the date.

Getting days between two dates with IQueryable

I have an IQueryable query which I need to use sometimes in the same method.
This query is based on another one which is passed as parameter.
I need to sum the result of a value multiplied by the number of days between two dates.
parameter query = IQueryable lista;
IQueryable<ChildEntity> query = lista.SelectMany(s => s.ChildEntities).Where(w=>w.IsActive.Equals("Y");
DateTime maxDate = lista.Max(m => m.Date);
decimal value = query.Sum(s => (s.Value) * (maxDate - s.ParentEntity.Date).Days);
which gives the exception:
Specified method is not supported.
I've also tried:
decimal value = query.Sum(s => (s.Value) * SqlMethods.DateDiffDay(maxDate, s.Parent.Date);
tried also SqlFunctions.DateDiff and EntityFunctions.DiffDays and all of these last three gives me this exception:
Method 'System.Nullable`1[System.Int32]
DateDiffDay(System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])'
is not supported for execution as SQL.
I do not want to use Enumerable because this can result in a huge number of records.
Is there any other way to find a solution for this?
(by the way, I'm using Devart as provider.)
int days = 0;
DateTime today = DateTime.Now;
DateTime maxDate = lista.Max(m => m.Date);
While (today <= maxDate)
{
today.AddDays(7);
days++
}
Your problem is that the database you are running the query on doesn't have a time-span data type like net does, however most databases store a date as number of days since a official start date, this means that if you convert the dates to a number you can just do straight arithmetic on it
days = ((int)maxdate) - ((int)currentdate)
NOTE:thats sudo not runnable

Converting DateTime to SmallDateTime in c#

How can ı convert datetime to smalldatetime in c# ? I'm taking the date and ı need to convert it to be accordance with database. It is forbidden to change the datatype of column in sql.
You can use the .NET DateTime type for your entity framework model, but tell EF that it uses a non-default column type in the database. You do this by overriding the OnModelCreating method of your DbContext, and using the HasColumnType method:
public class Foo
{
public int Id { get; set; }
public DateTime IAmSoSmall { get; set; } // wants to be smalldatetime in SQL
}
public class MyContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var foo = modelBuilder.Entity<Foo>();
foo.Property(f => f.IAmSoSmall).HasColumnType("smalldatetime");
base.OnModelCreating(modelBuilder);
}
}
Of course, you'll have to do the appropriate range-checking on your DateTime property to be sure that the stored values fall between those supported by SQL's smalldatetime. I guess you could do that with a property attribute like:
[Range(typeof(DateTime), "1/1/1900", "6/6/2079")]
public DateTime IAmSoSmall { get; set; } // wants to be smalldatetime in SQL
...based on a valid range from January 1, 1900, through June 6, 2079, as documented on MSDN.
Sql Server datetime and smalldatetime are both automatically mapped to and from the CLR's System.DateTime. A smalldatetime has a precision of 1 minute; a datetime has a precision of approximately 1/300 of a second (Don't ask why. It just is). Since the CLR's System.DateTime1 has a precision of 100-nanoseconds, the runtime takes care of rounding.
smalldatetime is internally a 32-bit integer, containing a count of minutes since the smalldatetime epoch (1900-01-01 00:00).
In conversion, seconds and fractional seconds are rounded using SQL Server's arcane date/time rounding rules, so the date 2013-01-31 23:59:59 gets rounded to the next date 2013-02-01 00:00:00'.
datetime is a pair of 32-bit integers internally. The high-order word is a count of days since the epoch; the low-order word is a count of milliseconds since start-of-day (00:00:00). The epoch of a datetime is 1900-01-01 00:00:00.000.
And again, values are rounded in the conversion in the same arcane way, with franctional seconds getting placed into one of the appropriate millisecond buckets for SQL Server, a multiple of 3ms — there is no SQL Server `datetime value like 2013-05-01 13:57:23.004. That will get "rounded" to either 23.003ms or 23.006ms.
If you want more control over things, you'll need to adjust your datetime values in C# before sending them to the database.
Maybe you can do something like YourDateTime.Date
Normally, when you do that way, it will set time to 00:00:00.

Categories

Resources