Storing DateTime in PostgreSQL without loosing precision [duplicate] - c#

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.

Related

Compare dates linq c# [duplicate]

This question already has answers here:
How to compare only date components from DateTime in EF?
(15 answers)
Closed 5 years ago.
I cant seem to get my query to check the database if a date exists. Please help.
DateTime value = new DateTime(2018, 10, 26);
item = await table.Where(todoItem => todoItem.Date == value.date)
.ToListAsync();
I think the format which c# writes their dates and SQL are different so it cant find a match. Also the database is correctly linked to the app as I am able to query other rows in the same table.
As said before, this is likely due to the fact that your DateTime column in the database includes time information.
Rewrite your query like this:
DateTime value = new DateTime(2018, 10, 26);
item = await table.Where(todoItem => todoItem.Date >= value &&
todoItem.Date < value.AddDays(1))
.ToListAsync();
This will retrieve all records that fall within the specified range (that is, dates that match the given day, and the DBMS will be able to use indexes that might be defined on the date-column.
Similar to Brandon's answer.. this is most likely happening due to todoItem.Date including the time portion of the Date property.
I assume the property Date is of type DateTime, so you could do this:
DateTime value = new DateTime(2018, 10, 26);
item = await table.Where(todoItem => DbFunctions.TruncateTime(todoItem.Date) ==
value).ToListAsync();
DbFunctions.TruncateTime
When used as part of a LINQ to Entities query, this method invokes the canonical TruncateTime EDM function to return the given date with the time portion cleared.
Here is more information on DbFunctions.TruncateTime.
Let me know if this helps!
This is most likely caused by including a time in your dates, and not formatting them to just the actual date string. You can resolve this by using the .toLocaleString() method. Something like this should work:
DateTime value = new DateTime(2018, 10, 26);
item = await table.Where(todoItem => todoItem.Date.toLocaleString() ==
value.date.toLocaleString())
.ToListAsync();

multiple date range and check if it is sequential. c# MVC

We have this project and one of the business requirement is it allows the client to input a multiple date range and check the individual dates if it is sequential/continuous or not to the others.
eq.
INPUT
startdate - enddate
10/24/2016 - 10/24/2016
10/26/2016 - 10/28/2016
OUTPUT
10/24/2016 - 10/24/2016 - NOT SEQUENTIAL
10/26/2016 - 10/26/2016 - SEQUENTIAL
10/27/2016 - 10/27/2016 - SEQUENTIAL
10/28/2016 - 10/28/2016 - SEQUENTIAL
For now I am playing around this solution
Check if date range is sequential in c#?
but i hope we i can find a better solution on how to properly do it.
Thank you and have a good day!
If by "sequential" we mean that the second date is the day after the first date then we can do the following:
private bool CheckSequential(DateTime date1, DateTime date2)
{
// strips off time portion
var d1 = date1.Date;
var d2 = date2.Date;
// add 1 to first date
d1 = d1.AddDays(1);
// compare them
if(DateTime.Compare(d1, d2) == 0)
return true;
else
return false;
}

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.

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

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");

How to get work week from two dates [duplicate]

This question already has answers here:
how to calculate number of weeks given 2 dates?
(7 answers)
Closed 9 years ago.
Lets say, I have two date Order date - 1/1/2014 and Delivery date - 6/2/2014. Now if I want to calculate how much work week its taken (Order date-delivery date), how can I do it in c#.
If you want the number of worked days in a date range, you can use this:
var from = DateTime.Today.AddDays(-10);
var to = DateTime.Today;
var daysOfWeek = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday
, DayOfWeek.Wednesday, DayOfWeek.Friday
, DayOfWeek.Thursday };
var days = Enumerable.Range(0, 1 + to.Subtract(from).Days)
.Select((n, i) => from.AddDays(i).DayOfWeek)
.Where(n => daysOfWeek.Contains(n.DayOfWeek));
If you want the number of weeks during a date range, use this:
(int)((to - from).TotalDays/7)
(int)((DeliveryDate-OrderDate).TotalDays/7)
I am presuming by "how much workweek" you mean "how many workdays". This is not so straightforward as it depends on the culture and you need to take holidays into account.
If you rely on Mon through Fri being the work days you could use a solution similar to what was discussed in c# DateTime to Add/Subtract Working Days, counting each day from Order Date to Delivery Date for which the conditions hold.
That Q&A still leaves you with the issue of how to determine the holidays of a certain region (be warned - in Switzerland each part of the country has different holidays!).
Update: From Nagaraj's suggested link I gather that you might also refer to "weeks" as chunks (that is "how many workweeks it has taken"). If so, in turn, you will need to define how many days of a week must be taken to take the week into account...
I'm using strings and convert that to dates, because I'm not sure where you get your dates and in what form. Adjust your code accordingly.
string orderDate = #"1/1/2014";
string deliveryDate = #"6/2/2014";
// This will give you a total number of days that passed between the two dates.
double daysPassed = Convert.ToDateTime(deliveryDate).
Subtract(Convert.ToDateTime(orderDate)).TotalDays;
// Use this if you want actual weeks. This will give you a double approximate. Change to it to an integer round it off (truncate it).
double weeksPassed = daysPassed / 7;
// Use this if you want to get an approximate number of work days in those weeks (based on 5 days a week schedule).
double workDaysPassed = weeksPassed * 5;
I guess you are not interested in working days but weeks. You can use GetWeekOfYear:
http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear%28v=vs.110%29.aspx
EDIT
To respond to the comment, here some code example:
int start = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(new DateTime(2014, 1, 14), System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
int end = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(new DateTime(2014, 2, 3), System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
int weeks = end - start;
That should give you the weeks needed.

Categories

Resources