Related
In my app I've a ticker which runs every 5 seconds. I've also an internal clock and I want to detect when the day chages.
To test, I have tried the following code without success:
DateTime A = new DateTime(2019, 6, 20, 23, 58, 29);
DateTime B = new DateTime(2019, 6, 21, 00, 01, 12);
Int32 dd = (B-A).Days; // it returns 0
double dd = (B-A).TotalDays; // it return 0.00002136213
If I check if TotalDays > 0 I succesfully detect the day change but in the follwing case (with a difference of a minute)
DateTime C = new DateTime(2019, 6, 20, 12, 58, 29);
DateTime D = new DateTime(2019, 6, 20, 12, 59, 29);
the compare fails. Since I need to call a method when day changes, with the example above its called every time and I do not want this behevior. Any hint?
compare Date part of DateTime directly
bool isSameDay = (A.Date == B.Date);
Look at only the Date parts
DateTime A = new DateTime(2019, 6, 20, 23, 58, 29);
DateTime B = new DateTime(2019, 6, 21, 00, 01, 12);
Int32 dd = (B.Date-A.Date).Days;
For your ticker why not use TimeSpan variables to complete your comparison. You set 1 static timespan variable to 24 hours (1 day) and then create a secondary one to store the values. You then set your second timespan variable equal to the subtraction of your two days and this would let you know if a day had gone by.
`
TimeSpan newDayReference = new TimeSpan(24,0,0);
TimeSpan comparison;
//These two variables set to show difference.
DateTime A= DateTime.Now.AddDays(-1);
DateTime B = DateTime.Now;
comparison = B - A;
if(comparison > newDayReference){ //success }
`
I have a list of DateTime values with dates that contain hours and minutes:
List<DateTime> times = times = new List<DateTime>()
{
new DateTime(2019, 01, 01, 17, 00, 00),
new DateTime(2019, 01, 01, 18, 45, 00),
new DateTime(2019, 01, 01, 19, 00, 00),
new DateTime(2019, 01, 01, 19, 30, 00),
new DateTime(2019, 01, 01, 22, 30, 00)
};
DateTime current = DateTime.Now;
I put them all in a ComboBox, and I want to make some sort of algorithm so when I load my form, it will check for the current time and find the closest value to the current time and select the ComboBox item that contains that hour.
How can I achieve this? I tried to loop through them all and check for the least hour, but that doesn't seem to work. Is there a smarter way to do it?
For example: If the current time is 17:32, it will choose 17:00, because that's the closest. But, if the current time is 18:20, it will choose 18:45 and so on.
Compare to the Ticks property of DateTime (MSDN). It can be seen as a linear representation of the whole date and timestamp and is sortable.
Do something like
comboBox.SelectedItem = times.OrderBy(t => Math.Abs(t.Ticks - current.Ticks)).First()
You could take the difference with DateTime.Now for all your datetimes, order by this difference and take the first result.
times.OrderBy(m => Math.Abs((DateTime.Now - m).TotalMilliseconds)).First();
You would have to select an instance of DateTime which minimizes the temporal distance to the current time. You could use an extension method for IEnumerable<T> to do that as follows.
public static T ArgMin<T, R>(T t1, T t2, Func<T, R> f)
where R : IComparable<R>
{
return f(t1).CompareTo(f(t2)) > 0 ? t2 : t1;
}
public static T ArgMin<T, R>(this IEnumerable<T> Sequence, Func<T, R> f)
where R : IComparable<R>
{
return Sequence.Aggregate((t1, t2) => ArgMin<T, R>(t1, t2, f));
}
var iNow = DateTime.Now;
var iResult = times.ArgMin(iTime => Math.Abs((iTime - iNow).Ticks));
Although very generic, this implementation does not involve any sorting.
You are looking for ArgMax which is not implemented in standard Linq, but can be emulated via Aggreagte
List<DateTime> times = new List<DateTime>() {
new DateTime(2019, 01, 01, 17, 00, 00),
new DateTime(2019, 01, 01, 18, 45, 00),
new DateTime(2019, 01, 01, 19, 00, 00),
new DateTime(2019, 01, 01, 19, 30, 00),
new DateTime(2019, 01, 01, 22, 30, 00),
};
DateTime toFind = new DateTime(2019, 5, 8, 18, 20, 0);
var closestTime = times
.Aggregate((best, item) => Math.Abs((item.TimeOfDay - toFind.TimeOfDay).Ticks) <
Math.Abs((best.TimeOfDay - toFind.TimeOfDay).Ticks)
? item
: best);
Please, note, that if we should find the closest time, we have to get rid of date part - TimeOfDay. If date part should be count, just remove TimeOfDay -
var closestDateAndTime = times
.Aggregate((best, item) => Math.Abs((item - toFind).Ticks) <
Math.Abs((best - toFind).Ticks)
? item
: best);
One option is to use MoreLinq's MinBy:
var actualNow = DateTime.Now;
// set `current` up however you need it
var current = new DateTime(2019, 01, 01, actualNow.Hour, actualNow.Minute, actualNow.Minute, actualNow.Millisecond); // set this up however you need it
var min = times.MinBy(z => Math.Abs((current - z).Ticks)).First();
It avoids the memory pressure of the OrderBy based solutions (since it avoids allocating a list to store the entire set of times).
Note you may want to check whether times is empty before using this (or other) solutions. If you don't wish to do that, consider using:
var min = times.MinBy(z => Math.Abs((current - z).Ticks)).Cast<DateTime?>().FirstOrDefault();
which will return null (rather than default(DateTime), or throw an exception) if times is empty.
I am trying to predict tide in c# using a formula given below:
The program was already done in excel, however when translating it to c# I am encountering some problems.
This is the formula in excel:
=PI()*((C18)/(C19)+1)
Cells C18 and C19 just contain subtraction of two date cells each
In C# I am having trouble finding A.
There are 2 problematic areas in finding A.
Problem1: When I do (t - t1)/(t2 - t1) the answer in C# is 0, but in excel the answer is 1.
Problem 2: the +1 at the end of equation. How do you add a number to timeSpan(in excel this works, maybe because they parse it as a datetime value?)
Here is my code:
DateTime t = new DateTime(2016, 6, 21, 13, 41, 00);
DateTime t1 = new DateTime(2016, 6, 21, 7, 13, 00);
DateTime t2 = new DateTime(2016, 6, 21, 13, 57, 00);
double h1 = 1.421;
double h2 = 2.337;
double h2_minus_h1 = h2 - h1;
TimeSpan t_minus_t1 = TimeSpan.FromTicks(t.Subtract(t1).Ticks);
TimeSpan t2_minus_t1 = TimeSpan.FromTicks(t2.Subtract(t1).Ticks);
TimeSpan MainCalculationForA = TimeSpan.FromTicks((t.Subtract(t1).Ticks) / (t2.Subtract(t1).Ticks));
MessageBox.Show(MainCalculationForA.ToString());
The answer for this which is (t - t1)/(t2 - t1) is: 00:00:00, while in excel it is just 1
Note:The formula is taken from here
tide prediction pdf
note:(t - t1) and (t2 - t1) both have exactly the same answer in both C# and excel. So why the difference in answer upon division?
From the PDF provided, t, t1 and t2 are in decimal hours, so you need .TotalHours instead
DateTime t = new DateTime(2016, 6, 21, 13, 41, 00);
DateTime t1 = new DateTime(2016, 6, 21, 7, 13, 00);
DateTime t2 = new DateTime(2016, 6, 21, 13, 57, 00);
double h1 = 1.421;
double h2 = 2.337;
double t_min_t1 = (t - t1).TotalHours;
double t2_min_t1 = (t2 - t1).TotalHours;
double A = Math.PI*(t_min_t1/t2_min_t1 + 1);
double h = h1 + (h2 - h1)*((Math.Cos(A) + 1)/2);
MessageBox.Show(h.ToString());
The end result is 2.33345960154238.
I'm trying to workout the amount of time between two LocalDateTime values and exclude specific dates (in this example, it's bank holidays).
var bankHolidays = new[] { new LocalDate(2013, 12, 25), new LocalDate(2013, 12, 26) };
var localDateTime1 = new LocalDateTime(2013, 11, 18, 10, 30);
var localDateTime2 = new LocalDateTime(2013, 12, 29, 10, 15);
var differenceBetween = Period.Between(localDateTime1, localDateTime2, PeriodUnits.Days | PeriodUnits.HourMinuteSecond);
The differenceBetween value shows the number of days/hours/minutes/seconds between the two dates, as you would expect.
I could check every single day from the start date and see if the bankHolidays collection contains that date e.g.
var bankHolidays = new[] { new LocalDate(2013, 12, 25), new LocalDate(2013, 12, 26) };
var localDateTime1 = new LocalDateTime(2013, 11, 18, 10, 30);
var localDateTime2 = new LocalDateTime(2013, 12, 29, 10, 15);
var differenceBetween = Period.Between(localDateTime1, localDateTime2, PeriodUnits.Days | PeriodUnits.HourMinuteSecond);
var london = DateTimeZoneProviders.Tzdb["Europe/London"];
for (var i = 1; i < differenceBetween.Days; ++i)
{
var x = localDateTime1.InZoneStrictly(london) + Duration.FromStandardDays(i);
if (bankHolidays.Any(date => date == x.Date))
{
//subtract one day for the period.
}
}
I feel like I'm missing some obvious and there should be an easier method, is there a simpler way to find a period between two dates whilst excluding certain dates?
I also need to include weekends in this exclusion too, the obvious way seems to be to check the day of the week for weekends whilst checking bank holidays, this just doesn't seem like the best/correct way of handling it though.
I feel like I'm missing some obvious and there should be an easier method, is there a simpler way to find a period between two dates whilst excluding certain dates?
Well, it's relatively easy to count the number of bank holidays included in a date-to-date range:
Sort all the bank holidays in chronological order
Use a binary search to find out where the start date would come in the collection
Use a binary search to find out where the end date would come in the collection
Subtract one index from another to find how many entries are within that range
Work out the whole period using Period.Between as you're already doing
Subtract the number of entries in the range from the total number of days in the range
The fiddly bit is taking into account that the start and/or end dates may be bank holidays. There's a lot of potential for off-by-one errors, but with a good set of unit tests it should be okay.
Alternatively, if you've got relatively few bank holidays, you can just use:
var period = Period.Between(start, end,
PeriodUnits.Days | PeriodUnits.HourMinuteSecond);
var holidayCount = holidays.Count(x => x >= start && x <= end);
period = period - Period.FromDays(holidayCount);
Just use TimeSpan to get the difference, all times are in your current local time zone:
var bankHolidays = new[] { new DateTime(2013, 12, 25), new DateTime(2013, 12, 26) };
var localDateTime1 = new DateTime(2013, 11, 18, 10, 30, 0);
var localDateTime2 = new DateTime(2013, 12, 29, 10, 15, 0);
var span = localDateTime2 - localDateTime1;
var holidays = bankHolidays[1] - bankHolidays[0];
var duration = span-holidays;
Now duration is your time elapsed between localDateTime1 and localDateTime2.
If you want to exlude two dates via the bankHolidays you can easiely modify the operations above.
You might use an extra method for this operation:
public static TimeSpan GetPeriod(DateTime start, DateTime end, params DateTime[] exclude)
{
var span = end - start;
if (exclude == null) return span;
span = exclude.Where(d => d >= start && d <= end)
.Aggregate(span, (current, date) => current.Subtract(new TimeSpan(1, 0, 0, 0)));
return span;
}
Now you can just use this:
var duration = GetPeriod(localDateTime1, localDateTime2, bankHolidays);
Does someone knows how to calculate the total hours between 2 times?
For example if a worker clocks in at 8:00 and out at 16:00, I would like to know that in decimal it's 8.0 hours and it's 8:00 hours.
I'm using C# framework 2.0.
The variables that hold the in and out time are of type string.
TY
DateTime start = new DateTime(2010, 8, 25, 8, 0, 0);
DateTime end = new DateTime(2010, 8, 25, 16, 0, 0);
Console.WriteLine((end - start).TotalHours);
for strings:
DateTime start = DateTime.Parse("8:00");
DateTime end = DateTime.Parse("16:00");
Console.WriteLine((end - start).TotalHours);
I came up with this daylight saving time safe method. The function is correct for both UTC and local timezones. If the DateTimeKind is Unspecified on either of the inputs then the return value is undefined (which is a fancy way of saying it could be incorrect).
private double TotalHours(DateTime earliest, DateTime latest)
{
earliest = (earliest.Kind == DateTimeKind.Local) ? earliest.ToUniversalTime() : earliest;
latest = (latest.Kind == DateTimeKind.Local) ? latest.ToUniversalTime() : latest;
return (latest - earliest).TotalHours;
}
System.DateTime punchIn = new System.DateTime(2010, 8, 25, 8, 0, 0);
System.DateTime punchOut = new System.DateTime(2010, 8, 25, 16, 0, 0);
System.TimeSpan diffResult = punchOut.Subtract(punchIn);
Check out TimeSpan.TotalHours:
TimeSpan difference = datetime2 - datetime1;
double totalHours = difference.TotalHours;
You can do it by subtracting two datetimes and using the TotalHours property of the resulting Timespan. Heres an example:
DateTime start = new DateTime(2010, 8, 25, 8, 0, 0);
DateTime end = new DateTime(2010, 8, 25, 16, 0, 0);
int hours = end.Subtract(start).TotalHours;