I have the value 40880.051388 and am storing it as a double, if I open Excel and paste in a cell and apply the following custom format "m/d/yyyy h:mm" to that cell, I get "12/3/2011 1:14"
How can I do this parsing/Conversion in C#? I don't know if the value is milliseconds from a certain checkpoint, like epoch time, or if the value is in some specific prepared format, but how does excel come up with this particular value? Can it be done in C#?
I've tried working with TimeSpan, DateTime, and other like things in Visual Studio but am not getting anywhere.
Looks like you're using the old OLE Automation date. Use
DateTime.FromOADate(myDouble)
Try something like this:-
double d = 40880.051388 ;
DateTime dt = DateTime.FromOADate(d);
Try using var dateTime = DateTime.FromOADate(40880.051388);.
If you need to format it to a string, use dateTime.ToString("M/d/yyyy H:mm", CultureInfo.InvariantCulture) for that. That will give you 24-hour string (change H to h for a 12-hour system).
If you need greater precision (by a factor 1000 or more) than offered by FromOADate, see my answer in another thread.
The value is an offset in days from December 30th, 1899. So you want:
new DateTime(1899, 12, 30).AddDays(40880.051388)
The following simple code will work
DateTime.FromOADate(myDouble)
However if performance is critical, it may not run fast enough. This operation is very processor intensive because the range of dates for the OLE Automation Date format begins on 30 December 1899 whereas DateTime begins on January 1, 0001, in the Gregorian calendar.
FromOADate calls a DoubleDateToTicks function using myDouble as the only argument. This returns the number of ticks, and this value is used to create a new DateTime with unspecified DateTimeKind.
The vast bulk of this work is done by the DoubleDateToTicks function in mscorlib. This includes code to throw an ArgumentException when the value of the double is NaN, and there are numerous ways in which it can be performance optimized depending on your exact needs.
Related
I get some data from a PICK/UniVerse database that includes dates in a 4 or 5 character numeric format. Here are some examples .. I grabbed the date values from the database, and compared it to the date being shown in an application:
9832 12/1/1994
10027 6/14/1995
10594 1/1/1997
Is it possible to convert these into something that can be put into Access as a Date/Time value?
As A test, I put 9832 in Excel as a General format and then change it to Short Date, it comes up as 12/1/1926. So it's off by exactly 68 years. This was true for 10027 and 10594 as well.
In C# you can use DateTime.FromOADate
DateTime dt = DateTime.FromOADate(41481);
Returns a DateTime equivalent to the specified OLE Automation Date.
That will give you:
dt = {26/07/2013 12:00:00 AM}
Later on you can insert that Date in your Access database.
Access Date/Time values are actually double precision floats. The whole number portion represents the day and the integer portion represents the time of day.
It looks like those Pick date numbers correspond directly to the date portions of Access Date/Time values. So you can use CDate to transform them.
? CDate(41481)
7/26/2013
Experiment some more to get a feel for this:
? Date()
7/26/2013
? CDbl(Date())
41481
Note, although your question is tagged with c#, you don't need that to do these conversions. You can do them with an Access query and ask the db engine to apply those functions.
Since it turned out those date numbers are consistently offset by 68 years, you can still do the conversion in an Access query.
? DateAdd("yyyy", 68, CDate(9832))
12/1/1994
? DateAdd("yyyy", 68, CDate(10027))
6/14/1995
? DateAdd("yyyy", 68, CDate(10594))
1/1/1997
Or ...
? CDate(9832 + CLng(24837))
12/1/1994
? CDate(10027 + CLng(24837))
6/14/1995
? CDate(10594 + CLng(24837))
1/1/1997
A little late to this thread but I'll post some more detail: The Pick / MultiValue DBMS stores dates as an integer with date 0 = 12/31/1967. So as I write this on Jan 16, 2014 the internal Pick date is 16818. If you use the following you'll get that magic number 24837:
DateTime.Parse("12/31/1967").Subtract( DateTime.FromOADate(0)).Days
So add that to your Pick Date to get the OADate.
If you're using any of the common MV DBMS libraries for extracting data (UniObjects, U2.NET, mv.NET ...) you shouldn't need to convert the date like this. A typical function might look like:
string date = OConv( record["PurchaseDate"], "d2/" ); // "01/16/14"
Or rather than extracting the data in the internal DBMS format, you really should be getting it in external format to start. Ask the DBMS developer who provided the data to do this for you. It's real easy on their side to return " date'd2/' " rather than just "date".
Feel free to contact me directly if you need more info in this area.
All multivalue database dates (this includes UniVerse and UniData) are based on a base date of 31st December 1967. You can resolve this to an external data in a number of ways.
The favourite - e.g. if using SQL or one of the internal database tools is to create a data dictionary entry for the field concerned with a date conversion field, For example:
'D2' for a 2-digit year
'D4' for a 4-digit year
'D4/' for a 4-digit year with slash separators
'D4/E' for a 4-digit year with slash separators and explicitly in European format (DD/MM/YYYY) as compared to US format (MM/DD/YYYY).
If no explicit formatting is given then the format will default to environmental settings. There are other formatting options as well and many can be used in combination (as with the above).
As previously advised, the alternative is to adjust the raw date with a formula. The date is in days since 31st December 1967 - The base data for all multivalue databases.
I am trying to simply change the date format from the datatable to universal time format but it formats it wrongly as if I have date for August 7 it changed it to August 8 after formatting it to universal date time. My code for formatting date is,
DateVar[runs] = DateTime.Parse(Convert.ToString(output.Tables[0].Rows[runs][0])).ToUniversalTime().ToString();
Don't get in to code its correct and its a part of loop so "run" is loop and output is data set having one table I have first data in table is "Sunday, August 07, 2011 10:52 PM" and it was converted to "8/8/2011 5:52:00 AM" after implementing universal time format.
Hopes for your suggestions
Universal time isn't a format - it's a time zone, effectively. It's not clear what you're trying to do, but converting a "local" DateTime to "universal" DateTime will usually change the time. If you don't want that to happen, don't call ToUniversalTime.
It's a pity that the .NET date/time API isn't as clear as it could be - the DateTime type itself has some horrible ambiguities about it. I'm trying to improve the situation with my Noda Time project, but you will need to understand what time zones are about etc.
Personally I would suggest not using simply DateTime.Parse or just calling ToString unless you're absolutely sure that the default format is what you want. I usually call DateTime.ParseExact and specify the expected format (and usually CultureInfo.InvariantCulture unless it's a user-entered string) - and likewise I provide a format string to the ToString call.
In your code you're simply converting a string to a string - what are you attempting to accomplish? If you're just trying to change the format (e.g. to dd/MM/yyyyTHH:mm:ss) then you don't need to call ToUniversalTime but you do need to provide the format string.
I suggest you split your code out into several statements to help you debug this (and for general code clarity):
Fetch the string from the DataTable, if you really need to (if it's already a DateTime, there's no point in converting it to a string and then back again)
Parse the string (again, assuming you need to)
Perform any conversions you need to
Format the DateTime with an explicit format string
Now if any single operation is causing a problem, you can isolate it more easily.
If I run ToUniversalTime() from Greenwich it will give same time but if i do it while I live some where else it will get an offset date time object of + or - hours depending on position.
Does anyone possibly recognize the following value "40195.315752" as a date? I need to convert/format this value-based date to a System.DateTime object, but don't understand it's format.
Thanks.
It's a serial date-time, which means it's the number of days since a particular date. Note that you need to know the date which it is an offset to. In Excel, that would be Jan 1st, 1900, which makes your date 17/01/2010 07:34:41, but other programs will vary.
Another common start date is 1st January 1970 (Unix Epoch).
enjoy it:
DateTime.FromOADate(40195.315752).ToLongDateString()
and to convert it to DateTime
DateTime MyDateTime = DateTime.FromOADate(40195.315752);
It means Sunday,January 17 2010
That would possibly be the number of days since a certain date (possibly january 1st 1900), before the decimal point?
the value you have displayed is a double...
var val = 40195.315752;
var span = System.TimeSpan.FromMilliseconds(val);
var time = new DateTime(span.Ticks);
above will convert it to Datetime but besure to note that System.Timespan continas several overloads to load span you need to identify which one is that you want...
I got a binary file, and one of record field stored some date infomation.
The save program is written by VC++ and using the DATE type.
How can read it into C#'s DateTime type ?
BTW: I tried DateTime.FromBinary, but it looks wrong.
Try DateTime.FromOADate.
As noted in Vinay's answer, the VC++ DATE is really a double. Just read in a double and then convert based on the description.
Here is some sample code for the conversion:
double CDate = 8.50; //The DATE from C++
DateTime newDate = new DateTime(1899, 12, 30); //Start at 12/30/1899
int days = (int)Math.Floor(CDate); //Get the days (integer part)
double hours = (CDate-days) * 24; //Get the hours (fraction part)
newDate = newDate.AddDays(days).AddHours(hours);
EDIT
Or use DateTime.FromOADate as suggested by Joe.
The beauty of SO, you get to learn new things.
If it's an OLE DATE, use the information available from here:
The DATE type is implemented using an
8-byte floating-point number. Days are
represented by whole number increments
starting with 30 December 1899,
midnight as time zero. Time values are
expressed as fractional part. Time
precision is 1 second. This type is
also used to represent date-only (the
fractional part is 0) or time-only
(the whole number part is 0) values.
Using this, you can convert to a CLR DateTime.
I Have a legacy database with a field containing an integer representing a datetime in UTC
From the documentation:
"Timestamps within a CDR appear in Universal Coordinated Time (UTC). This value remains
independent of daylight saving time changes"
An example of a value is 1236772829.
My question is what is the best way to convert it to a .NET DateTime (in CLR code, not in the DB), both as the UTC value and as a local time value.
Have tried to google it but without any luck.
You'll need to know what the integer really means. This will typically consist of:
An epoch/offset (i.e. what 0 means) - for example "midnight Jan 1st 1970"
A scale, e.g. seconds, milliseconds, ticks.
If you can get two values and what they mean in terms of UTC, the rest should be easy. The simplest way would probably be to have a DateTime (or DateTimeOffset) as the epoch, then construct a TimeSpan from the integer, e.g. TimeSpan.FromMilliseconds etc. Add the two together and you're done. EDIT: Using AddSeconds or AddMilliseconds as per aakashm's answer is a simpler way of doing this bit :)
Alternatively, do the arithmetic yourself and call the DateTime constructor which takes a number of ticks. (Arguably the version taking a DateTimeKind as well would be better, so you can explicitly state that it's UTC.)
Googling that exact phrase gives me this Cicso page, which goes on to say "The field specifies a time_t value that is obtained from the operating system. "
time_t is a C library concept which strictly speaking doesn't have to be any particular implementation, but typically for UNIX-y systems will be the number of seconds since the start of the Unix epoch, 1970 January 1 00:00.
Assuming this to be right, this code will give you a DateTime from an int:
DateTime epochStart = new DateTime(1970, 1, 1);
int cdrTimestamp = 1236772829;
DateTime result = epochStart.AddSeconds(cdrTimestamp);
// Now result is 2009 March 11 12:00:29
You should sanity check the results you get to confirm that this is the correct interpretation of these time_ts.