C# Convert Date To Double - c#

I have written a function in VBA which creates a code from the properties of a file.
I need a developer to do the same in C# on their end.
The developer says it is not possible to do the same in c#.
So in VBA, part of my process is to convert a date to a double. The way VBA does this is to basically count the number of days between the given date and 1 Jan 1900. So 19 Mar 2014 would be a double value of 41,717.
How would I say write a function in C# (not a language I am familiar with) that would convert a date data type to the number of days that have passed since 1 January 1900?
Any help would be appreciated.

Subtracting two DateTimes gives you a TimeSpan. You can just use TimeSpan.TotalDays to get the number of days between two dates:
double days = (DateTime.Today - new DateTime(1900,1,1)).TotalDays;
If the DateTime has a time component it will be represented as fractions of a day, so for example:
// current date and time (16:24:15)
(new DateTime(2014, 3, 18, 16, 24, 15) - new DateTime(1900,1,1)).TotalDays
would give you 41714.6835069444
Note that the result is 2 days different that using CDbl() in VBA since a date in VBA is represented by the number of days since 12/30/1899 rather than 1/1/1900.

Use .net DateTime method ToOADate() wich returns a double representing the OLE Automation date
VBA uses this same format to representa a date as a double.

I got exactly 3 days difference. Which might be because I'm in NZ at GMT + 12.
Or it might be because I was multiplying a double by "TicksPerDay" and .Net doesn't allow for some strange numbers.
DateTime.FromOADate(vbaTime) was the perfect solution for me moving dates between MS Access and C#.
Incidentally, I suspect that this is a result of the "date calculation issue" that Joel Spolsky refered to:
http://www.joelonsoftware.com/items/2006/06/16.html
when discussing Lotus notes compatibility in Excel as the program manager at Microsoft.

How about this, without using OLE Automation:
'get time elapsed since some earlier point in time, such as midnight today
Dim tim As TimeSpan = Now.Subtract(Today)
'calc the time elapsed in fractional seconds
'note that tim.Seconds only provides whole seconds, so add tim.Milliseconds
Dim tsec As Double = tim.Hours * 3600 + tim.Minutes * 60 + tim.Seconds + tim.Milliseconds / 1000

Related

Get Milliseconds from Ticks in DateTime c# [duplicate]

This question already has answers here:
How do you convert epoch time in C#?
(14 answers)
Closed 2 years ago.
I have a simple DateTime object, equal to the date: 11/1/2020 8:11:14 AM.
I want to convert it to milliseconds so I do:
myTimestamp?.Ticks / TimeSpan.TicksPerMillisecond.
I get 63739786274788, which seems correct from the pure calculation perspective.
However, when I input it into one of the online converters to validate, I get the date Wed Nov 01 3989 01:11:14, which is of course way off.
Questions:
What is this number 63739786274788 if not time in ms?
How do I get "normal" timestamp in ms?
In .NET, DateTime ticks are based on an epoch of 0001-01-01T00:00:00.0000000. The .Kind property is used to decide whether that is UTC, local time, or "unspecified".
Most online converters, such as the one you linked to, are expecting a Unix Timestamp, where the value is based on an epoch of 1970-01-01T00:00:00.000Z. It is always UTC based. (The precision varies, both seconds and milliseconds are commonly used.)
If you want to get a milliseconds-based Unix Timestamp From .NET, instead of dividing you should use the built-in functions DateTimeOffset.FromUnixTimeMilliseconds and DateTimeOffset.ToUnixTimeMilliseconds. (There are also seconds-based versions of these functions.)
Assuming your input values are UTC-based:
DateTime dt = new DateTime(2020, 11, 1, 8, 11, 14, DateTimeKind.Utc);
DateTimeOffset dto = new DateTimeOffset(dt);
long timestamp = dto.ToUnixTimeMilliseconds();
// output: 1604218274000
DateTimeKind.Local will also work with this, assuming your values are indeed based on the computer's local time zone. DateTimeKind.Unspecified is a bit trickier, as you'll need to convert to a DateTimeOffset with a specific time zone using TimeZoneInfo first.
You could also construct the DateTimeOffset value directly, rather than go through DateTime at all.
Okay, so you start off dividing Ticks by TicksPerMillisecond (10,000)
As you can see, the number you generated is much larger than the current milliseconds:
63739786274788
1607363529803
The short answer is that Ticks are based off of 12:00:00 midnight January 1, 0001 and a your online calculator is based off of unix time, January 1, 1970. So that would explain why you're about 2,000 years off. If you subtracted the Ticks from a new DateTime(1970,1,1), then that would give you about the right number to satisfy the online calculator.
For more info, I would suggest reading through MS's docs on DateTime

What is the equivalent of NSDate's 'timeIntervalSince1970' in C#

I need to store dates in a form of number of seconds since 1970.
With this I am getting number of seconds since 1970 with Swift by using Foundation's NSDate:
NSDate().timeIntervalSince1970
And maybe a dumb question but why this is double shouldn't it be int?
What is equivalent of this method in C#?
I am not sure what to use to get the same value.
TimeSpan t = (DateTime.UtcNow – new DateTime(1970, 1, 1));
long timestamp = (long) t.TotalSeconds;
I used the UtcNow property to ensure that the timestamp is the same regardless of what timezone this code is being run in.
Also, use the largest integer type you can find since the current epoch time is slightly less than 32 bit signed integer and you want code to be future proof.
If you do have .NET 4.6 or above, try this:
DateTimeOffset.UtcNow.ToUnixTimeSeconds()
This might work.
(DateTime.Now - new DateTime(1970,1,1)).TotalSeconds
This gets the date and subtracts the default epoch time of C# (01-01-01:00:00:00) making it start from 01-01-1970.
This is most probably the easiest way to get the same value.

strange epoch date number issue

I'm working with an data set in which there is a date field with dates that look like the following:
42437.4261290278
42437.5460402431
42437.5478825116
with the larger of the numbers being the most recent. One of us believes it is relating to unix epoch and alternate time representations. The issue we are facing now is reading those date's above into standard MM-DD-YYYY format. Any one have any ideas on how to convert these alternate date forms into standard dates?
I'm trying to do this in C#. And for reference, I expect that the last two dates listed to be sometime on March 8th, 2016 and the first to be some time before then.
These are OLE Automation VT_DATE values. This is the date system used by Microsoft products such as Excel and pre-.NET versions of Visual Basic. It is a somewhat bizarre date format.
The format is: consider the double to have two parts: a signed integer and an unsigned fraction. The signed integer is the number of days since 30 Dec 1899. Note NOT 31 Dec 1899 and NOT 1 Jan 1900. The fraction is the fraction of the 24 hour (always!) day gone by. No adjustment is made for the 23 or 25 hour days we have twice a year.
This format has an interesting (to me) history; you can read about it in my blog article from 2003:
https://blogs.msdn.microsoft.com/ericlippert/2003/09/16/erics-complete-guide-to-vt_date/
And Stack Overflow founder Joel Spolsky's article from 2006:
http://www.joelonsoftware.com/items/2006/06/16.html
Note that if you have negative VT_DATE values then you must be very careful to get the conversion correct. The code is not hard; it's just a couple lines, but you have to reason about it carefully. I used to ask "take the difference between two VT_DATEs" as an interview question, and a surprising number of candidates cannot actually do subtraction.
Following your assertion that the dates represented are 2016-03-08, I assume the start of the epoch is 1899-12-30:
static string UnixTimeStampToDateAsString(double ts)
{
DateTime epoch = new DateTime(1899, 12, 30);
DateTime d = epoch.AddDays(ts);
return (d.ToString("yyyy-MM-dd HH:mm:ss"));
}
static void Main(string[] args)
{
foreach (double dateNumber in new double[] { 42437.4261290278, 42437.5460402431, 42437.5478825116 })
{
Console.WriteLine(UnixTimeStampToDateAsString(dateNumber));
}
Console.ReadLine();
}
Outputs:
2016-03-08 10:13:37
2016-03-08 13:06:17
2016-03-08 13:08:57
I have to state that the 30th of December 1899 is a rather unlikely value, but I suppose someone might have had a "reason" to use that.
Edit Thanks to #EricLippert I can suggest this instead:
Console.WriteLine(DateTime.FromOADate(dateNumber).ToString("yyyy-MM-dd HH:mm:ss"));

MySQL script to convert DateTime.Ticks values to SQL Date

I have an old MySQL database where I stored dates as C# DateTime.Ticks.
Now I want to convert that old database to a new structure for a PHP app that has needs a datefield. How do I convert DateTime.Ticks to MySQL dates?
I am looking for something in the following format YYYY-MM-DD HH:mm:ss:
SELECT someconversion(olddate) as newDate FROM table;
Thank you so much in advance
Dotnet Ticks are stored in 64-bit integers in units of 100ns (ten million per second) since an epoch of 0001-01-01 00:00:00 UTC.
MySQL Days (as used in FROM_DAYS()) count elapsed days from 0000-01-01.
For example 2016-01-09 00:00:00 in Ticks is 635879124000000000 or, for readability
635 879 124 000 000 000
So, presumably your oldate column datatype is BIGINT or DOUBLE in MySQL. Either that, or it's a text string.
The thing to know is that the UNIX Epoch, 1970-01-01 00:00:00 UTC, has this Ticks value: 621355968000000000. This is the ultimate magic number.
At any rate, here's how to convert Ticks within MySQL. We'll convert to UNIX timestamps, then to DATETIME columns.
SELECT FROM_UNIXTIME((yourcolumn/10000000.0) - (62135596800.0))
But, here's the thing. The output of this FROM_UNIXTIME() gets converted implicitly to your local time. You may want to preserve the UTC times when you store this data.
There are two ways to do that. One is to use the TIMESTAMP datatype to store these converted times. The other is to set your MySQL session timestamp to 'UTC' before you do this conversion operation, like this:
SET time_zone = 'UTC';
Here is another way to do the same thing, but one that doesn't depend on using Unix timestamps. (Those timestamps are only valid from 1970 to 2038.) It depends on converting ticks to days, then on converting the remainder to seconds. It converts ticks directly to a DATETIME data type.
select FROM_DAYS(365+(yourcolumn / 864000000000))
+ INTERVAL (yourcolumn % 864000000000) / 10000000 SECOND
The constant 864000000000 (864 000 000 000) is the number of ticks in a day.
Breaking this down:
yourcolumn / 864000000000 is the number of days since 0001-01-01
FROM_DAYS(365+(yourcolumn / 864000000000)) is the date.
(yourcolumn % 864000000000) / 10000000 is the remainder of the division in step 1, in seconds.
FROM_DAYS(date) + INTERVAL seconds SECOND gets the full timestamp.
is this what you want?
select DATE_FORMAT([yourcolumn],'%Y-%M-%D %H:%m:%s') from [yourtable];
Here's the link for variant date format Date format options
This was a pain for me, but what I did was to store datetime.ticks in DB as Bigint then...
Datetime MyDateTimeVar = new datetime(Convert.toint64(DB.ticks)); //This gets the datetime from ticks!

Disparity between date/time calculations in C# versus Delphi

Delphi:
SecondsBetween(StrToDateTime('16/02/2009 11:25:34 p.m.'), StrToDateTime('1/01/2005 12:00:00 a.m.'));
130289133
C#:
TimeSpan span = DateTime.Parse("16/02/2009 11:25:34 p.m.").Subtract(DateTime.Parse("1/01/2005 12:00:00 a.m."));
130289134
It's not consistent either. Some dates will add up the same, ie..
TimeSpan span = DateTime.Parse("16/11/2011 11:25:43 p.m.").Subtract(DateTime.Parse("1/01/2005 12:00:00 a.m."));
SecondsBetween(StrToDateTime('16/11/2011 11:25:43 p.m.'), StrToDateTime('1/01/2005 12:00:00 a.m.'));
both give
216905143
The total amount of seconds is actually being used to encode data, and I'm trying to port the application to C#, so even one second completely throws everything off.
Can anybody explain the disparity? And is there a way to get c# to match delphi?
Edit: In response to suggestions that it might be leap second related: Both date ranges contain the same amount of leap seconds (2), so you would expect a mismatch for both. But instead we're seeing inconsistency
16/02/2009 - 1/01/2005 = Delphi and C# calculate a different total seconds
16/11/2011 - 1/01/2005 = They calculate the same total seconds
The issue it seems related to this QC 59310, the bug was fixed in Delphi XE.
One will likely deal with Leap Seconds. However, .NET does not as far as I'm aware.
You don't mention how you convert the c# TimeSpan into a number. The TotalSeconds property is a floating point value - perhaps it's a rounding problem in the double to int conversion?

Categories