When are two Datetime variables equal? - c#

I try to compare Datetime.Now with a Datetime variable I set, using the Datetime.CompareTo() method. I use a timer to compare these every second and display the result, but as the current time approaches the time I set, the result changes from 1 to -1, but never 0, which means these two are never equal. I'm suspecting the Datetime structure contains milliseconds?

You're suspecting correctly. It goes further than milliseconds though. The maximum resolution is the "tick", which is equal to 100 nanoseconds.

As other have mentioned here, the resolution is 100ns.
The easiest approach would be to take your DateTime and subtract DateTime.Now. You then end up with a TimeSpan. If the TimeSpan's TotalSeconds property is 0, the difference between them is less than a second.

You are correct in your suspicion. The DateTime struct smallest unit is the "Tick" which is measured in units of 100ns. (One tick is 100ns)
What you more likely want to do is check if everything down to the seconds is equal and you can do that like this by first comparing the Date property and then compare the hour, minute and second properties individually

DateTime comparison is more exact than comparing with seconds. In your scenario, you can define an "error range", e.g. if the gap between two DateTime is less than 1 second, they are considered to be the same(in your program).

Try this... (but change the test date, of course)
DateTime d1 = new DateTime(2011, 12, 27, 4, 37, 17);
DateTime d2 = DateTime.Now;
if (d1.Subtract(d2).Seconds <= 1)
{
//consider these DateTimes equal... continue
}

I prefer to compare Datetime (as well as double) not with exact values but with value ranges, because it is quite unlikely that you have the exact value.
DateTime d1 = new DateTime(2011, 12, 27, 4, 37, 17);
DateTime d2 = DateTime.Now;
if ((d2 >= d1) && (d2 <= d1.AddMinutes(1)))
....

'simulate comparison of two datetimes
d1 = DateTime.Now
Threading.Thread.Sleep(250)
d2 = DateTime.Now
'see if two dates are within a second of each other
Dim ts As Double = ((d2 - d1).TotalSeconds)
If ts < 1 Then
'equal
Debug.WriteLine("EQ " & ts.ToString("n4"))
Else
Debug.WriteLine("neq " & ts.ToString("n4"))
End If

Related

Calculate number of milliseconds until next occurence of a time

I feel like this is something really simple, but my Google Fu is letting me down as I keep finding difference calculations.
I have a time (e.g. 1800 hours) stored in a DateTime object. The date is null and immaterial. All I want to know is how many milliseconds until the NEXT occurrence of that time.
So, if I run the calculation at 0600 - it will return 12 hours (in ms). At 1750, it will return ten minutes (in ms) and at 1900 it will return 24 hours (in ms).
All the things I can find show me how to calculate differences, which doesn't work once you're past the time.
Here is what I tried, but fails once you're past the time and gives negative values:
DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
You're already doing everything you should, except for one thing: handling negative results.
If the result is negative, it means the time you want to calculate the duration until has already passed, and then you want it to mean "tomorrow" instead, and get a positive value.
In this case, simply add 24 hours:
DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result < 0)
result += TimeSpan.FromHours(24).TotalMilliseconds;
The next thing to consider is this: If the time you want to calculate the duration until is 19:00 hours, and the current time is exactly 19:00 hours, do you want it to return 0 (zero) or 24 hours worth of time? Meaning, do you really want the next such occurrence?
If so, then change the above if-statement to use <=:
DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result <= 0)
result += TimeSpan.FromHours(24).TotalMilliseconds;
However, note that this will be prone to the usual problems with floating point values. If the current time is 18:59:59.9999999, do you still want it to return the current time (a minuscule portion of time) until 19:00 today, or do you want it to flip to tomorrow? If so, change the comparison to be slightly different:
DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result <= -0.0001)
result += TimeSpan.FromHours(24).TotalMilliseconds;
where -0.0001 is a value that corresponds to "the range of inaccuracy you're prepared to accept being tomorrow instead of today in terms of milliseconds".
When doing calculations like this it is important to take possible DST changes under consideration so that your results remain correct.
Suppose your operational parameters are:
var shutdownTime = TimeSpan.FromHours(18);
// just to illustrate, in Europe there is a DST change on 2013-10-27
// normally you 'd just use DateTime.Now here
var now = new DateTime(2013, 10, 26, 20, 00, 00);
// do your calculations in local time
var nextShutdown = now.Date + shutdownTime;
if (nextShutdown < now) {
nextShutdown = nextShutdown.AddDays(1);
}
// when you want to calculate time spans in absolute time
// (vs. wall clock time) always convert to UTC first
var remaining = nextShutdown.ToUniversalTime() - now.ToUniversalTime();
Console.WriteLine(remaining);
The answer to your question would now be remaining.TotalMilliseconds.

How to convert year, month and day to ticks without using DateTime

long ticks = new DateTime(2012, 1, 31).ToLocalTime().Ticks; // 634635684000000000
But how to do this without DateTime constructor ?
edit
What I actually want is to keep only the years, months and days from the ticks.
long ALL_Ticks = DateTime.Now.Ticks; // 634636033446495283
long Only_YearMonthDay = 634635684000000000; // how to do this ?
I want to use this in a linq-sql query using Linq.Translations.
If you only want the ticks for the date portion of the current datetime you could use:
long Only_YearMonthDay = DateTime.Now.Date.Ticks; //634635648000000000
//DateTime.Now.Date.Ticks + DateTime.Now.TimeOfDay.Ticks == DateTime.Now.Ticks
You could find out how many days are in the calculation and then multiply by 864,000,000,000 (which is how many ticks are in a day). Is that what you are looking for? Bit of documentation here : http://msdn.microsoft.com/en-us/library/system.timespan.ticksperday.aspx.
Happy coding,
Cheers,
Chris.
OK - didn't think this through properly! Ticks represent the amount of 100 nanosecond intervals since 12:00:00 midnight, January 1, 0001. You would need to calculate how many days have passed since that date and then multiply it by the ticks per day value!
If I understand you right, you are not worried about the ticks up to a particular time of the day?! So, it would be something along the lines of :
var ticksToDate = (DateTime.UtcNow - DateTime.MinValue).Days * 864000000000;
Does that answer your question??
That is going to be rather difficult unless you have some other way of getting the current date and time. According to MSDN:
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, which represents DateTime.MinValue. It does not include the number of ticks that are attributable to leap seconds.
Now, if you know the current date and time, you can calculate how many days have passed since January 1, 0001 and use that to calculate the number of ticks.
I understand you dont want the hour parts of the date. If you use Date, then you only get the day (for example: 01/01/2012 00:00:00)
long ticks = new DateTime(2012, 1, 31).Date.Ticks;
And with any DateTime object already created is the same of course.
long ticks = dateObject.Date.Ticks;
You already have the answer there in your post:
long ALL_Ticks = DateTime.Now.Ticks;
// that's the ticks (from DateTime.MinValue) until 'now' (this very moment)
long ticks = new DateTime(2012, 1, 31).ToLocalTime().Ticks;
// or
long ticks = DateTime.Now.Date.Ticks;
// that's the ticks until the beginning of today
long yearmonthticks = new DateTime(2012, 1, 1).ToLocalTime().Ticks;
// that's the ticks until the beginning of the month
// etc..., the rest is simple subtractions
Since your question doesn't specify any reason not to use the DateTime constructor, this is the best solution for what seems like your problem.
I had a use case where I couldn't use DateTime but needed Years/Months from Ticks.
I used the source behind DateTime to figure out how. To go the other way you can look at the constructor, one of which calls the following code.
private static long DateToTicks(int year, int month, int day) {
if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) {
int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365;
if (day >= 1 && day <= days[month] - days[month - 1]) {
int y = year - 1;
int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
return n * TicksPerDay;
}
}
throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
}
This can be found in link below, of course you will need to re-write to suit your needs and look up the constants and IsLeapYear function too.
https://referencesource.microsoft.com/#mscorlib/system/datetime.cs,602

Cut-/Rounding down a DateTime to a Whole i.e. Hour/Day?

Is there any kind of mathematical way to cut DateTime down to a exact Hour, Day or so? Similiar to round of a decimal to int.
Period.Day
If the original value was 2011-01-01 13:00:00, it ends up in 2011-01-01 00:00:00
if Period.Hour
If the original value was 2011-03-11 13:32:00, it ends up in 2011-03-11 13:00:00
I think about something like below. This are of course works fine, but the range-array are iterated through anyway, later. Better if I was possible to calculate directly on that iteration, instead of it's own. But someType can't be put into that iteration (it depends on someType).
if (someType == Period.Day)
range.ForEach(d => d.time = new DateTime(d.time.Year, d.time.Month, d.time.Day,0,0,0));
if (someType == Period.Hour)
range.ForEach(d => d.time = new DateTime(d.time.Year, d.time.Month, d.time.Day, d.time.Hour, 0, 0));
Rounding down to a day is equivalent to time.Date, rounding to nearest (up on midpoint) is simply ( time + 12hours ).Date.
For rounding down to a full hour I can't think of code that's nicer to read than yours. For rounding up to the nearest hour you can apply your code to time + 30mins.
There is probably a faster method for rounding to the nearest hour:
const Int64 HourInTicks=...;
Int64 timeInTicks=time.Ticks;
Int64 trucatedToHour=timeInTicks-timeInTicks%HourInTicks;
But I'd avoid that, unless you really need the performance, which is unlikely.
(My round to nearest might have issues on days where the local time offset changes if you're using local time)
To round down to day you can use the DateTime.Date Property.
To round down to hour, I'm afraid you'll have to either use what you did in your example or something like:
d.Date.AddHours(d.Hour)
I'll do the following:
private static readonly DateTime Epoch = new DateTime(1970, 1, 1);
public static DateTime Round(this DateTime d, Period p)
{
var ts = d - Epoch;
if (p == Period.Hour)
{
var hours = (long)ts.TotalHours;
return Epoch.AddHours(hours);
}
else if (p == Period.Days)
{
var days = (long)ts.TotalDays;
return Epoch.AddDays(days);
}
// ...
}
I believe the following C# code will round a DateTime value to nearest minute, and I think it will be easy to generalize it to round to other units.
//round to nearest minute; add 30 seconds for rounding to nearest minute
effectiveDateTime = effectiveDateTime.AddSeconds(30);
TimeSpan timeComponent = effectiveDateTime.TimeOfDay;
effectiveDateTime = effectiveDateTime.Date;
effectiveDateTime = effectiveDateTime.AddHours(timeComponent.Hours).
AddMinutes(timeComponent.Minutes);
Not sure if this approach is effective, but looks quite nice using string format (in this case cutting down to hours):
var date = DateTime.UtcNow;
var cutDownDate = Convert.ToDateTime(date.ToString("yyyy-MM-dd hh"));
Answer Is there a better way in C# to round a DateTime to the nearest 5 seconds? contains an excellent generic DateTime rounding approach.
Edit:
This answer was before the updated question title and is an algorithm for rounding to nearest not rounding down.
Best method for day:
DateTime now = DateTime.Now;
DateTime roundDay = now.Date;

Convert DateTime.Now to Seconds

I am trying to write a function that will convert a DateTime.Now instance to the number of seconds it represents so that I can compare that to another DateTime instance. Here is what I currently have:
public static int convertDateTimeToSeconds(DateTime dateTimeToConvert)
{
int secsInAMin = 60;
int secsInAnHour = 60 * secsInAMin;
int secsInADay = 24 * secsInAnHour;
double secsInAYear = (int)365.25 * secsInADay;
int totalSeconds = (int)(dateTimeToConvert.Year * secsInAYear) +
(dateTimeToConvert.DayOfYear * secsInADay) +
(dateTimeToConvert.Hour * secsInAnHour) +
(dateTimeToConvert.Minute * secsInAMin) +
dateTimeToConvert.Second;
return totalSeconds;
}
I realize that I am truncating the calculation for seconds in a year, but I don't need my calculation to be precise. I'm really looking to know if the method that I am using to calculate seconds is correct.
Does anyone have anything that could better compute seconds given from a DateTime object?
Also, Should the return type be int64 if I am coding in C# if I am going to calculate all the seconds since 0 AD?
The DateTime type supports comparison operators:
if (dateTimeA > dateTimeB)
{
...
This also works for DateTime values returned by DateTime.AddSeconds:
if (dateTimeA.AddSeconds(42) > dateTimeB)
{
...
If you really want the number of seconds that elapsed since 01/01/0001 00:00:00, you can calculate the difference between the two DateTime values. The resulting TimeSpan value has a TotalSeconds property:
double result = DateTime.Now.Subtract(DateTime.MinValue).TotalSeconds;
It really doesn't make sense to convert a DateTime object to seconds. Seconds only make sense if you are dealing with a length of time (TimeSpan). Should you want to compare two dates to get the number of seconds between them:
TimeSpan diff = DateTime.Now - PreviousDateTime;
double seconds = diff.TotalSeconds;
If the purpose is finding the number of seconds between two dates, you'd be much better off using the TimeSpan object.
TimeSpan span = date2 - date1;
double seconds = span.TotalSeconds;
See suggestion from thread below:
How do I convert ticks to minutes?
TimeSpan.FromTicks(DateTime.Now.Ticks).TotalSeconds;
Assuming you really need to get at the seconds for the datetime object, you could directly get the "Ticks" property from it. These aren't in seconds but you can easily divide by the proper factor to convert the Ticks to seconds.
See: http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx
So, something like:
DateTime.Now.Ticks/TimeSpan.TicksPerSecond
If you want to compare 2 DateTime object, why just not use the provided operators?
http://msdn.microsoft.com/en-us/library/aa326723%28v=VS.71%29.aspx
DateTime a, b;
if (a > b) //a is after b
I would use the TimeSpan class to get the exact difference between two DateTime instances. Here is an example:
DateTime dt1 = DateTime.Now;
DateTime dt2 = new DateTime(2003,4,15);
TimeSpan ts = dt1.Subtract(dt2);
Once the TimeSpan value (ts, in the code snippet above) is available, you can examine its values to correctly convert the TimeSpan to a given number of seconds.
Using a TimeSpan to get the elapsed time between two DateTimes is probably the best way to go but if you really want to get the number of seconds for a given DateTime you could do something like the following:
DateTime dateTimeToConvert = DateTime.Now;
TimeSpan tsElapsed = dateTimeToConvert - DateTime.MinValue;
return tsElapsed.TotalSeconds;
Note that tsElapsed.TotalSeconds is a Double, not an Int.
Do note that the goal is to get the number of seconds since DateTime.MinVal (the first day of the calendar). I say this, because I see all of these answers for "you do time comparisons like this... add in the object, multiply by that object and do cross-calculus on them, divide by the quotient of the summed result, and Boom! not what you asked."
There's a really simple answer here. Ticks are 100-nanosecond increments. DateTime object.Ticks is the number of ticks that have occurred since 1/1/0001. Ie, year zero. There are 10 million nanoseconds in a second. so...
public static long convertDateTimeToSeconds(DateTime dateTimeToConvert) {
// According to Wikipedia, there are 10,000,000 ticks in a second, and Now.Ticks is the span since 1/1/0001.
long NumSeconds= dateTimeToConvert.Ticks / 10000000;
return NumSeconds;
}

Convert DateTime to String value?

How do I convert DateTime to an Integer value?
Edit: How do I convert DateTime to a String value?
Example
String return value of 20100626144707 (for 26th of June 2010, at 14:47:07)
That could not be represented as an integer, it would overflow. It can be a long, however.
DateTime dateTime = new DateTime(2010, 6, 26, 14, 44, 07);
long time = long.Parse(dateTime.ToString("yyyyMMddHHmmss"));
However, it would be more intuitive to simply express it as a string, but I don't know what you intend to do with the information.
Edit:
Since you've updated the question, the answer is simpler.
string time = dateTime.ToString("yyyyMMddHHmmss");
A 32-bit integer is not large enough to hold a DateTime value to a very precise resolution. The Ticks property is a long (Int64). If you don't need precision down to the tick level, you could get something like seconds since the epoch:
TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
int dateAsInteger = (int)t.TotalSeconds;
It's generally a bad idea to use a numeric datatype to store a number you can't do arithmetic on. E.g. the number in your example has no numeric meaning or value, adding it or subtracting it is pointless. However, the number of seconds since a certain date is useful as a numeric data type.
Note: this was posted before the question was changed to "string value" rather than "integer value".
Essentially, you want to shift the number along by the number of places needed for each part and then add it:
var x = new DateTime(2010,06,26,14,47,07);
long i = x.Year;
i = i * 100 + x.Month;
i = i * 100 + x.Day;
i = i * 100 + x.Hour;
i = i * 100 + x.Minute;
i = i * 100 + x.Second;
Console.WriteLine(i); // 20100626144707

Categories