DateTime.FromOADate vs MSSQL Cast as DateTime - c#

I assumed that DateTime.FromOADate in .NET and casting to a DateTime in MS SQL worked the same way.
However, given the value: 41640
DateTime.FromOADate(value) returns: 2014-01-01
CAST(value AS DATETIME) returns: 2014-01-03
Is this expected behaviour because of different starting days, or is something not right?

This is the third day of January in 2014 in T-SQL:
SELECT CAST(41640 AS DATETIME)
and this is the first day of January in 2014 in .NET:
DateTime dt = DateTime.FromOADate(41640)
The reason is documented in MSDN:
CAST
The "zero"-date is 1900-01-01
DateTime.FromOADate
base date, midnight, 30 December 1899
So there is a two days difference between 01/01/1900 and 12/30/1899.

To investigate this you have to look into the base date first,
In MSSQL print CAST(0 AS DATETIME) will output:
Jan 1 1900 12:00AM
In C# .Net Console.WriteLine(DateTime.FromOADate(0)); will output:
12/30/1899 12:00:00 AM
So you can see there are 2 days of difference between 2 base date. That's why you are facing such problem.

OLE Automation Dates (aka "OADates") are for compatibility with COM interfaces, and used in communicating to things like Microsoft Excel through VBA. You shouldn't use them in communicating with SQL Server. Just return the native SQL date, datetime, or datetime2 type in your query and cast it to a DateTime in your .NET code.
DateTime dt = (DateTime) myDataReader["FooDateTime"];
As others have mentioned, the SQL Server epoch is not the same as the OLE Automation epoch. OLE Automation dates also have some quirky behaviors with negative values, and also that dates before March 1st 1900 might use an epoch of 12/30/1899 or 12/31/1899 depending on which program is using it. SQL Server uses a fixed epoch of 1/1/1900.
And like many of Windows and .NET types, the epoch isn't fixed to UTC, so you have to know what contextual time zone information is in play also. (Though this also occurs with DateTime unless you pay attention to the .Kind property.)

SQL Server's base date is '19000101'; try CASTing 0.
According to this: http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx
FromOADate starts at 1899-12-30

Related

convert a C# datetime object into Excel date format

I need to convert a C# datetime object into the dreaded Excel date format:
https://datapub.cdlib.org/2014/04/10/abandon-all-hope-ye-who-enter-dates-in-excel/
i.e. number of days since 1 Jan 1900 expressed as a floating point number.
Is there any way to do it without resorting to DIY code?
I need it in order to create Excel-friendly CSV exports
Googling around I didn't find anything useful except that good blog post
Excel dates use the OLE Automation date format. You can retrieve it with DateTime.ToOADate
OA Dates are a double whose integer part is the date offset from 30 December 1899 (ie earlier dates are negative) and fractional part is the time divided by 24.
This type was used a lot in the COM/VB6 days. Nowadays it's needed for Excel and when you need to call COM APIs that expect dates or variants with a date content.
You can use following method to convert from Excel Date back to C# DateTime
return DateTime.FromOADate(SerialDate);

How to perform multiplication in date (datetimeoffset format)

I have following 3 fields
startingdate, expirydate, number of months
startingdate = DateTimeOffset.Now;
and number of months, say 24 months
How to calculate expirydate = ?
Can anybody give me an idea?
You don't need multiplication in this case - just addition, specifying the units:
DateTimeOffset startDate = DateTimeOffset.Now;
DateTimeOffset expiryDate = startDate.AddMonths(months);
Two things to note:
Date and time arithmetic can be odd. In your example case it's less likely to be odd than normal, as you've got 2 years, so the only corner case is adding 2 years to February 29th and getting February 28th; normally you'd need to consider (say) adding 1 month to August 31st and getting September 30th. In other words, just because two expiry dates are the same doesn't mean they came from the same start date.
You might want to consider using DateTimeOffset.UtcNow and doing everything in UTC, rather than using the local time zone. Using DateTimeOffset instead of DateTime protects you from time zone problems to some extent, but keeping everything in UTC is clearer.
If you really mean you have dates rather than dates and times, you might want to explicitly use midnight... it's unfortunate that .NET doesn't have any "date-only" type. You might want to consider using my Noda Time which is designed to make things rather clearer than the BCL API.

Wrong datetime in sqlite expert personal

I'm trying to write to my sqlite db from visual studio in c#. When using datetime. Now in visual studio it shows me the correct date and time but when writing to the db it shows something like 1899/30/12. Why is that? Here is my code:
SQLiteCommand cmd = new SQLiteCommand("INSERT INTO tblLicenseInfo (ID, UserID, MachineID, ExpirationDate, DateOfChange, LicenseKey)
VALUES(1, 1, 1, #test, #test, 'sdfsafge45345345');", SqLite);
cmd.Parameters.Add("#test", DateTime.Now);
SqLite.Open();
cmd.ExecuteNonQuery();
SqLite.Close();
Thanks for your help.
DateTime.Now is in the incorrect format, so you have 2 options:
Use CURRENT_TIMESTAMP as value. This is a SQLite keyword.
Or
Format Datetime: DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
I'm not quite sure why SQLiteParameterCollection.Add(String,Object) method overload doesn't work because it says:
Adds a SQLiteParameter to the SQLiteParameterCollection given the
parameter name and value.
As an alternative, you can use other overloads or AddWithValue as well like;
cmd.Parameters.Add("#test", SQLiteType.DateTime).Value = DateTime.Now;
or
cmd.Parameters.AddWithValue("#test", DateTime.Now);
More informations;
Using Parameters
But wait a second.. You said your column type is DATETIME but there is no data type like that in SQLite.
From Datatypes In SQLite Version 3
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic
Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Please tell the real type of your columns. I assume DateTime.Now doesn't fit these 3 type formats (or values) and that's why you get 1899/30/12 used as a "default" date in SQLite.
From Date And Time Functions
The date and time functions use a subset of IS0-8601 date and time
formats. The date() function returns the date in this format:
YYYY-MM-DD.
I feel like if you make your column type as TEXT and if you send your DateTime.Now with YYYY-MM-dd format, your code should work;
cmd.Parameters.Add("#test", SQLiteType.TEXT).Value = DateTime.Now.ToString("YYYY-MM-dd");

How can I convert a DateTime value to a double?

How do I convert a DateTime value to a double?
If, by double you mean an OLE Automation date, then you can use DateTime.ToOADate(). From the linked MSDN topic:
An OLE Automation date is implemented as a floating-point number whose value is the number of days from midnight, 30 December 1899. For example, midnight, 31 December 1899 is represented by 1.0; 6 A.M., 1 January 1900 is represented by 2.25; midnight, 29 December 1899 is represented by -1.0; and 6 A.M., 29 December 1899 is represented by -1.25.
The base OLE Automation Date is midnight, 30 December 1899. The maximum OLE Automation Date is the same as MaxValue, the last moment of 31 December 9999.
If you're talking about some other date representation that can also be stored in a double, please specify...
DateTime.ToOADate() converts to a double OLE Automation Date in C#
Yes, OLE Automation date enable Datetime to convert to Decimal/double type. However, the outcome/value to decimal/double is not exact system Datetime.
For example,
Decimal dateIndDec = Convert.Decimal (Datetim.Today.ToOADate());
is not equal to MS SQL
Select Convert (Decimal (10, 9), GetDate())
Conclusion: OLE Automation date is not a true system datetime info... cannot use it.
I've been searched everywhere about convert Datetime value to Decimal value in C# without any luck.
You can calculate difference between your DateTime and DateTime.MinValue, and then get any Total* value.
var difference = DateTime.Now - DateTime.MinValue;
Console.WriteLine(difference.TotalMinutes);
Console.WriteLine(difference.TotalMilliseconds);

Convert UTC/GMT time to local time

We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();

Categories