Convert DateTime.Ticks to MySQL DateTime in query - c#

I have a integer column in MySql storing the DateTime.Ticks.
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
How can I convert this to a DateTime in a query? I've tried many things, but cannot get it to work.
For the ticks 634128921500016150 I hope to get the mysql datetime '2010-06-23 12:06:50'
I would have believed the following should work, but it gives '4009-06-22 12:15:50.001600'. It seems it's off by 2001 years, 1 day and 9 minutes... If the years and days is consistent, I can just fix it manually, but the minutes seems a little odd.
SELECT DATE_ADD('0000-01-01 00:00:00',
INTERVAL 634128921500016150/10000000 SECOND_MICROSECOND);
I've tried adding more zeros, but it never matches :|
I also tried Jon Skeet's suggestion, but it gives nearly the same result (some fraction of a second different)

Rather than adding using SECOND_MICROSECOND, try just adding via MICROSECOND:
SELECT DATE_ADD('0001-01-01 00:00:00',
INTERVAL 634121049314500000/10 MICROSECOND);
EDIT: I've just worked out why the years are so wrong. MySQL's minimum date is the year 1000. So I suggest you change it to:
SELECT DATE_ADD('0001-01-01 00:00:00',
INTERVAL (634121049314500000 - base_ticks)/10 MICROSECOND);
where base_ticks is the value of the ticks from new DateTime(1001, 1, 1).Ticks.
Heck, you could rebase wherever you want (e.g. 2000) - that might even work round the 9 minutes issue. It's possible that it's making up for leap seconds over the years, or something like that.

Found myself doing the same thing today. Between Jon's answer and the comments I was able to figure it out, but here it is as a function, all wrapped up with a nice bow on it:
CREATE FUNCTION TicksToDateTime(ticks BIGINT) RETURNS datetime DETERMINISTIC
RETURN CAST(DATE_ADD('2001-01-01 00:00:00',
INTERVAL (ticks - 631139040000000000)/10 MICROSECOND) AS DATETIME);

And for those of us coding against SQL Server Compact Edition, the above bow wrapped function is written in a query as:
Select DATEADD(second, (CAST(([TickField]-631139040000000000) AS
FLOAT)/10000000), '2001-01-01 00:00:00' ) From [Table]
The previous code does not work in Compact Edition. It took a while to figure out, so I thought worth including.
I suppose it would work in other SQL versions too but haven't tested it. It has the advantage of being part of a query, so no function needs to be created.
Cheers.

Related

GetLastInputTime shows impossible time?

To determine, if PC was not used for certain amount of time, I'm using Win32API.GetLastInputTime() method. I'm just subtracting its value from DateTime.Now, and compare it with some value, stored in settings.
It worked perfectly before, but recently GetLastInputTime started to show completely ridiculous results - it shows me future time. Today it shows me July 2nd of 2016.
So, does anyone has any idea, what's happening? How does GetLastInputTime get time, and how it is possible, that this time is future one?
Since GetLastInputTime returns ticks as UInt32 (DWORD)
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724408(v=vs.85).aspx
you can have an integer overflow:
The elapsed time is stored as a DWORD value. Therefore, the time will
wrap around to zero if the system is run continuously for 49.7 days.
To avoid this problem, use the GetTickCount64 function. Otherwise,
check for an overflow condition when comparing times.
And thus have future dates:
13 May 2016 + 49.7 days == 2 July 2016
I think you can not use DateTime.Now because it depends on the time zone.
As described here, you have to use Environment.TickCount to get the idle time.

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

Display items that are no more than 6 months old

What is the correct method to display items that are no more than 6 months (180 days) old? I'm using the following code, but it seems to be showing items that don't fit the criterion accurately.
DateTime.Now.Subtract(Convert.ToDateTime(e.DateCreated)).Days <= 180
Where could I have gone wrong?
Edit
Thanks everyone for your help. Turns out the hours were a key factor in deciding the age of an item. I don't really need it to be accurate to the hour, just to the date.
I would just use this to get a date six months ago
var sixMonthsAgo = DateTime.Now.AddDays(-180);
and then compare it with whatever you want to compare. I guess
if (Convert.ToDateTime(e.DateCreated) >= sixMonthsAgo)
in your case.
EDIT:
I performed a test with a test value provided in comments.
var input = DateTime.Parse("2013-06-23 18:14:47.937");
My current date is 21.12.2013 and time is about 11:00 AM.
With that defined, your code yields a result
180.16:39...
So it still meets your requirements, since it is exactly 180 days old + few hours and minutes.
My code yields a result
24.6.2013 about 11:00 AM
and since your date is 23.6. then it is older then the result and therefore does not meet your requirements.
As you can see, the hours play a big role here. So in the end, it very much depends on how you define "180 days ago". If you still feel that neither of the variants work well, give me at least 10 days you compare, both where it works and where it does not work and mark which should be older and which not.
TimeSpan ts = DateTime.Now - Convert.ToDateTime(e.datecreated);
if (ts.TotalDays <= 180)
{
//perform some task
}

if displaying HH:MM:SS as HH:MM, better to truncate seconds or round to nearest minute?

Is there a standard or accepted best practice for how times should be displayed as HH:MM when the source time has HH:MM:SS precision? Should seconds be truncated or rounded to the nearest minute?
Socially, if I looked at a digital clock and saw that it was 4:00:45, I would never tell someone it was 4:01. But I didn't know if this convention is universal or if it applies in computing too.
Also, rounding to the nearest minute might produce unexpected behavior, e.g. if the rounding causes the hour or date to change. This doesn't necessarily apply to the particular use-case we're dealing with today, but I can easily imagine another use case where a list of "Sales in January" includes a sale on 31-Jan 23:59:59 that would be displayed as 1-Feb 00:00
If context is relevant to the answer, this use-case is a SQL Server app that converts a datetime to a smalldatetime, which SQL Server will round to the nearest minute. The result will be displayed as HH:MM in a C# web application. The conversion happens in legacy code that we can't change right now, but we can force truncation of seconds instead of rounding.
But I'm not sure if we should do this.
In general with dates and times it's best to round down.
To me "1 week ago" means "at least 7 days, but less than 14 days". A similar idea applies to times.
Unless it's critical for ordering of the parent object I really wouldn't bother. If you don't need the seconds; they can be considered low-priority. I'd personally round it because I like the precision, even if fractal.
If you're aware that it can cause unexpected behaviour; whomever interprets the data should account for it - but you can make it easier on them by adding a note in your code that it can cause this so that they are aware.

What is a meaningfull datatype to save hours

What is a good data-type for saving hours in .net?
Is it better to use the decimal type or is the double data-type more appropriate. With hours I mean values such as:
2 for two hours
1.5 for 90 minutes
8.25 for 8 hours and 15 minutes.
A good way to represent a number of hours is to use a TimeSpan:
TimeSpan hours = TimeSpan.FromHours(2);
Given the choice between decimal or double I'd probably go for double as there is typically no expectation that the amount of time is represented exactly. If you need an exact decimal representation of your fractional number of hours (which seems unlikely) then use decimal.
You could also consider storing it as an integer in for example seconds, milliseconds or ticks.
The best datatype to store hours is the one designed for it - TimeSpan.
It has methods that allow you to add/subtract/convert it.
As for storage in a database, it really depends on what you are using this for and what kind of resolution is required.
I would use the time datatype - as it will hold the range:
00:00:00.0000000 through 23:59:59.9999999
However, if you need to hold more than 24 hours in this field, you may want to consider a tinyint or int holding the number of minutes (assuming that is the maximum time resolution you require).
In SQL Server use INT or DECIMAL. TIME isn't really ideal for storing a duration because TIME defines a point in time within the 24 hour clock whereas duration is simply an integer or decimal value. You cannot do addition or subtraction with TIME values and there is no obvious way to use TIME to store durations greater than 24hrs.
Why don't use TIME?
You can use DATEADD with TIME to manipulate it easier:
SELECT DATEADD(minute, 30, CAST('2:00:00' AS TIME))
becomes 02:30:00.0000000. And so on..

Categories

Resources