Disparity between date/time calculations in C# versus Delphi - c#

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?

Related

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.

C# Convert Date To Double

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

Using DateTime for a duration of time e.g. 45:00

I'd just like to know if it is possible to use the DateTime type for durations such as 45:00 (45 minutes) or 120:00 (120 minutes). These values also need to be stored into a Local Sql Server DB. If it is possible, could anyone possibly hint how this could be done using Datetime, or if not just let me know a way it could be done using a different type.
Thank you in advance,
Jamie
You should use the TimeSpan structure
TimeSpan interval = new TimeSpan(0, 45, 0);
Console.WriteLine(interval.ToString());
For the database storing part, you could store the property Ticks because a specific constructor for the TimeSpan structure allows to instantiate a new TimeSpan passing the Ticks value
long ticks = GetTimeSpanValueFromDb();
TimeSpan interval = new TimeSpan(ticks);
I wish to add also that you need a BIGINT T-SQL datatype field to store a long NET datatype
I store durations in seconds in the database and then convert to HH:MM:SS format when comes time to display the data.
Why don't you use TimeSpan instead? You can convert them to Ticks (int), store them in the db and the reverse the process when you need the value.
This is merely a matter of interpretation. SQL Server stores datetime as two four byte integers. One is a signed int count of days from a reference date, the other is an unsigned time of day such that 32bits exactly maps 24 hours. Without the implicit epoch, this isn't a datetime, it's a duration. Nothing prevents you from interpreting it that way.
Of course, it would be more convenient to pick a unit and simply use a float. This is what Windows does, storing datetime as a number of days from a reference date expressed as an 8-byte float (a double).
Personally I don't like "day" as a unit of time. The rotational period of our planet is not constant, and it is necessary to mess about with leap seconds to maintain the illusion that there are 86400 seconds in every day. A better choice is the SI unit, the second, which is defined in terms of repeatable, invariant physical constants.
Better again would be the picosecond, since we could dump the double and use an int64, with all the attendant arithmetical and comparative performance advantages. Depiction in mixed human scale units (yyyy mmm d HH:mm:ss) is already something of a trial. Mapping functions that currently work with fractional days could trivially be scaled to microseconds, although the compensation for leap seconds and leap days would have to be rewritten.
I say picosecond because this is the finest division that fits in 64 bits while encompassing a useful span of time (50,000 years). Femto fits, but fifty years isn't wide enough. I know that eventually there be a year 50K problem but frankly I doubt anyone but archeologists will care about records from 50,000 years ago.

Add 1 week to current date

I've got something like this DateTime.Now.ToString("dd.MM.yy"); In my code, And I need to add 1 week to it, like 5.4.2012 to become 12.4.2012 I tried to convert it to int and then add it up, but there is a problem when it's up to 30.
Can you tell me some clever way how to do it?
You want to leave it as a DateTime until you are ready to convert it to a string.
DateTime.Now.AddDays(7).ToString("dd.MM.yy");
First, always keep the data in it's native type until you are ready to either display it or serialize it (for example, to JSON or to save in a file). You wouldn't convert two int variables to strings before adding or multiplying them, so don't do it with dates either.
Staying in the native type has a few advantages, such as storing the DateTime internally as 8 bytes, which is smaller than most of the string formats. But the biggest advantage is that the .NET Framework gives you a bunch of built in methods for performing date and time calculations, as well as parsing datetime values from a source string. The full list can be found here.
So your answer becomes:
Get the current timestamp from DateTime.Now. Use DateTime.Now.Date if you'd rather use midnight than the current time.
Use AddDays(7) to calculate one week later. Note that this method automatically takes into account rolling over to the next month or year, if applicable. Leap days are also factored in for you.
Convert the result to a string using your desired format
// Current local server time + 7 days
DateTime.Now.AddDays(7).ToString("dd.MM.yy");
// Midnight + 7 days
DateTime.Now.Date.AddDays(7).ToString("dd.MM.yy");
And there are plenty of other methods in the framework to help with:
Internationalization
UTC and timezones (though you might want to check out NodaTime for more advanced applications)
Operator overloading for some basic math calcs
The TimeSpan class for working with time intervals
Any reason you can't use the AddDays method as in
DateTime.Now.AddDays(7)

How to round a DateTime in MySQL?

I want to discretize the DateTime with the resolution of 5 minutes. I did it in C#, but how to convert the following code to MySQL?
DateTime Floor(DateTime dateTime, TimeSpan resolution)
{
return new DateTime
(
timeSpan.Ticks *
(long) Math.Floor
(
((double)dateTime.Ticks) /
((double)resolution.Ticks)
)
);
}
It's a little nasty when you do it with datetime data types; a nice candidate for a stored function.
DATE_SUB(DATE_SUB(time, INTERVAL MOD(MINUTE(time),5) MINUTE ),
INTERVAL SECOND(time) SECOND)
It's easier when you use UNIXTIME timestamps but that's limited to a 1970 - 2038 date range.
FROM_UNIXTIME(UNIX_TIMESTAMP(time) - MOD(UNIX_TIMESTAMP(time),300))
Good luck.
from_unixtime(floor(unix_timestamp('2006-10-10 14:26:01')/(60*5))*(60*5))
+---------------------------------------------------------------------------+
| from_unixtime(floor(unix_timestamp('2006-10-10 14:26:01')/(60*5))*(60*5)) |
+---------------------------------------------------------------------------+
| 2006-10-10 14:25:00 |
+---------------------------------------------------------------------------+
1 row in set (0.00 sec)
you can replace the two 5s with other values
You can look here. This example is a general case for rounding to the nearest X minutes, and is written in T-SQL, but the logic and the majority of the functions will be the same in both cases.
Another alternative:
to get the nearest hour:
TIMESTAMPADD(MINUTE,
ROUND(TIMESTAMPDIFF(MINUTE,CURDATE(),timestamp_column_name)/60)*60,
CURDATE())
Instead of CURDATE() you can use an arbitrary date, for example '2000-01-01'
Not sure if there could be problems using CURDATE() if the system date changes between the two calls to the function, don't know if Mysql would call both at the same time.
changing 60 by 15 would get the nearest 15 minutes interval, using SECOND you can get the nearest desired second interval, etc.
To get the previous hour use TRUNCATE() or FLOOR() instead of ROUND().
Hope this helps.
Have you had a look at the CAST functionality in MySQL?
MySQL Cast
Cast Functions and Operators
Here is another variation based on a solution from this thread.
SELECT DATE_ADD(
DATE_FORMAT(time, "%Y-%m-%d %H:00:00"),
INTERVAL FLOOR(MINUTE(time)/5)*5 MINUTE
);
This solution, unlike ones that use FROM_UNIXTIME, will give the expected value for datetimes that fall within daylight saving time (DST) transitions. (Compare for example 2012-11-03 2:14:00)
Edit - After some quick benchmarking, however, Ollie's first solution appears to perform faster than this. But I still recommend against the FROM_UNIXTIME method.

Categories