Get nearest dates - c#

List<DateTime>
"2015-03-21 13:00:00"
"2015-05-15 13:00:00"
"2015-05-24 13:00:00"
"2015-05-27 13:00:00"
"2015-06-14 13:00:00"
I am having start date (2015-05-21 13:00:00) and end date (2015-06-09 22:00:00)
Actually I need to get the two dates from the above array which are closer or equal to start date and end date.
Note additionally that the date that is closest to the start date should be equal to or before start date and the date that is closest to the end date should be equal to or after the end date. In other words, given the list of dates, find the smallest date range that encloses start and end date.
In this case, the output will be "2015-05-15 13:00:00" and "2015-06-14 13:00:00".
How to acheive this in c#?

void Main()
{
var dates = new string[]
{
"2015-03-21 13:00:00",
"2015-05-15 13:00:00",
"2015-05-24 13:00:00",
"2015-05-27 13:00:00",
"2015-06-14 13:00:00"
}
.Select(x => DateTime.Parse(x))
.ToList();
var start = DateTime.Parse("2015-05-21 13:00:00");
var end = DateTime.Parse("2015-06-09 22:00:00");
Console.WriteLine(dates
.Where(x => x <= start)
.OrderByDescending(x => x)
.FirstOrDefault());
Console.WriteLine(dates
.Where(x => x >= end)
.OrderBy(x => x)
.FirstOrDefault());
}
// the date must be outside of boundary, so this is no longer good...
//public static DateTime GetClosestDate(IEnumerable<DateTime> source, DateTime date)
//{
// return source
// .OrderBy(x => Math.Abs((x.Date - date).TotalSeconds))
// .First();
//}
Result:
GetClosestDate:
2015-05-24 13:00:00
2015-06-14 13:00:00
Where OrderBy[Descending] FirstOrDefault:
2015-05-15 13:00:00
2015-06-14 13:00:00

public DateTime? GetClosest(List<DateTime> dates, DateTime dateToCompare)
{
DateTime? closestDate = null;
int min = int.MaxValue;
foreach (DateTime date in dates)
{
if (Math.Abs(date.Ticks - dateToCompare.Ticks) < min)
{
min = date.Ticks - dateToCompare.Ticks;
closestDate = date;
}
}
return closestDate;
}
Simple search on google relates to this

Related

How to convert an Interval to a LocalDate range in NodaTime?

I'm running into a scenario where I need to convert an Interval value to Enumerable collection of LocalDate in NodaTime. How can I do that?
Below is the code
Interval invl = obj.Interval;
//Here is the Interval value i.e.,{2016-10-20T00:00:00Z/2016-11-03T00:00:00Z}
How can I form a Date range between these intervals?
Thanks in advance.
A slightly alternative approach to the one given by Niyoko:
Convert both Instant values into LocalDate
Implement a range between them
I'm assuming that the interval is exclusive - so if the end point represents exactly midnight in the target time zone, you exclude that day, otherwise you include it.
So the method below includes every date which is covered within the interval, in the given time zone.
public IEnumerable<LocalDate> DatesInInterval(Interval interval, DateTimeZone zone)
{
LocalDate start = interval.Start.InZone(zone).Date;
ZonedDateTime endZonedDateTime = interval.End.InZone(zone);
LocalDate end = endLocalDateTime.Date;
if (endLocalDateTime.TimeOfDay == LocalTime.Midnight)
{
end = end.PlusDays(-1);
}
for (LocalDate date = start; date <= end; date = date.PlusDays(1))
{
yield return date;
}
}
Use this code:
var l = Enumerable.Range(0, int.MaxValue)
.Select(x => Period.FromDays(x))
.Select(x => LocalDate.Add(interval.Start.InZone(localZone).Date, x))
.TakeWhile(x => x.CompareTo(interval.End.InZone(localZone).Date) <= 0);
Example:
var localZone = DateTimeZone.ForOffset(Offset.FromHours(7));
var start = Instant.FromDateTimeOffset(new DateTimeOffset(new DateTime(2016, 10, 1)));
var end = Instant.FromDateTimeOffset(new DateTimeOffset(new DateTime(2016, 10, 25)));
var interval = new Interval(start, end);
var l = Enumerable.Range(0, int.MaxValue)
.Select(x => Period.FromDays(x))
.Select(x => LocalDate.Add(interval.Start.InZone(localZone).Date, x))
.TakeWhile(x => x.CompareTo(interval.End.InZone(localZone).Date) <= 0);
foreach (var localDate in l)
{
Console.WriteLine(localDate);
}

Get data based on two dates values filtered by month

I have list of events, each event has two dates; start date and end date. I want to create a filter by months. How do I return dates that ranges between a month that a user selects?
for example, lets say the user selects month October, I want to return all events that are within this month.
I have used this to get the dates that ranges between todays date but now stuck on how to get the range between a month.
DateTime dateToCheck = DateTime.Today.Date;
DateTime startDate = DateTime.Parse(item["Start Time"].ToString());
DateTime endDate = DateTime.Parse(item["End Time"].ToString());
foreach (SPListItem item in collection)
{
if (startDate <= dateToCheck && dateToCheck < endDate)
{
ListBox1.Items.Add(item["EventTitle"].ToString());
}
}
// set up dummy data
var dates = new[] {DateTime.Now, DateTime.Now, DateTime.Now};
int month = GetMonth();
// get result
var result = dates.Where(date => date.Month == month);
EDIT: if you need to make sure the dates have the correct year as well, use
var dates = new[] {DateTime.Now, DateTime.Now, DateTime.Now};
int year = GetYear();
int month = GetMonth();
var result = dates.Where(date => date.Year == year && date.Month == month);
Of course, you can get the year/month numbers as well as the date-list from wherever.
EDIT2: if you get a DateTime object as input modify accordingly:
var dates = new[] {DateTime.Now, DateTime.Now, DateTime.Now};
var input = GetDateTime();
var result = dates.Where(date => date.Year == input.Year && date.Month == input.Month);
You still can use your code with little modifications. As start date you have to select 00:00 time of 1st of the month and as end date you have to use 00:00 time of 1st of the next month. In case of October 2015 it would be: 1 Oct 2015 <= date < 1 Nov 2015.
int year = 2015;
int month = 10;
DateTime dateToCheck = DateTime.Today.Date;
DateTime startDate = new DateTime(year, month, 1);
DateTime endDate = startDate.AddMonths(1);
foreach (SPListItem item in collection)
{
if (startDate <= dateToCheck && dateToCheck < endDate)
{
ListBox1.Items.Add(item["EventTitle"].ToString());
}
}

Convert only date to Date and Time format in c#

I want to count data of each day from database using the for loop. Here, I don't know to get the begining of day (start from 12 am) and end of that day ( 12 pm) from value of only date. In below code startDate and endDate have only date value e.g. 2/11/2012.
for (DateTime dates = startDate; dates <= endDate; dates.AddDays(1))
{
DateTime BeginingOfDay = begining of value variable dates; // 2/2/2012 00:00:00
DateTime EndOfDay = at end of value variable dates; // 2/2/2012 23:59:59
int count = (from u in db.CDRs where (u.StartTime >= BeginingOfDay && u.StartTime <= EndOfDay) select u).Count();;
dictionary.Add(dates.ToString("MM/dd/yyyy"), count);
}
The best way to deal with this is to use the right combination of lessthan/greaterthan operators with midnight on day n, and midnight on day n+1
so given a day, eg
var date = new Date(2012,8,24); // today
get midnight on that day (start of the day)
var start = new Date(date.Year, date.Month, date.Day, 0,0,0); // could also be date.Date
and to get midnight on the next day just add 1 day
var end = start.AddDays(1);
now use greater-than-or-equal-to for the start, and less-than for the end:
var inRange = x.StartTime>=start && x.EndTime<end
Put together into your example becomes:
for (DateTime dates = startDate; dates <= endDate; dates.AddDays(1))
{
DateTime BeginingOfDay = new DateTime(dates.Year,dates.Month,dates.Day,0,0,0);
DateTime EndOfDay = BeginingOfDay.AddDays(1);
int count = (from u in db.CDRs where (u.StartTime >= BeginingOfDay && u.StartTime < EndOfDay) select u).Count();;
dictionary.Add(dates.ToString("MM/dd/yyyy"), count);
}
This should get you the results you want:
using(var dataContext = new YourDataContext())
{
var dictionary = dataContext.CDRs.GroupBy(u => new
{
u.StartTime.Year,
u.StartTime.Month,
u.StartTime.Day
})
.Select(g => new{ Date = g.Key, Count = g.Count() })
.ToDictionary(g => new DateTime(g.Key.Year, g.Key.Month, g.Key.Day), g=>g.Count);
return dictionary;
}

Get List of weeks by giving year and month as parameter C#

I need list of weeks with starting and ending dates by giving int year and int month,
Example Result,
Week1 = 7/1/2012 to 7/1/2012
Week2 = 7/2/2012 to 7/8/2012
Week3 = 7/9/2012 to 7/15/2012
Week4 = 7/16/2012 to 7/22/2012
Week5 = 7/23/2012 to 7/29/2012
Week6 = 7/30/2012 to 7/31/2012
Something like this should work:
// using System.Globalization;
var calendar = CultureInfo.CurrentCulture.Calendar;
var firstDayOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
var weekPeriods =
Enumerable.Range(1, calendar.GetDaysInMonth(year, month))
.Select(d =>
{
var date = new DateTime(year, month, d);
var weekNumInYear = calendar.GetWeekOfYear(date, CalendarWeekRule.FirstDay, firstDayOfWeek);
return new { date, weekNumInYear };
})
.GroupBy(x => x.weekNumInYear)
.Select(x => new { DateFrom = x.First().date, To = x.Last().date })
.ToList();
Of course you can change the Culture (here I have used the CurrentCulture).
check this one and edit according to your need
// Get the weeks in a month
DateTime date = DateTime.Today;
// first generate all dates in the month of 'date'
var dates = Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month)).Select(n => new DateTime(date.Year, date.Month, n));
// then filter the only the start of weeks
var weekends = (from d in dates
where d.DayOfWeek == DayOfWeek.Monday
select d).ToList();
foreach (var d in weekends)
{
Console.WriteLine(d);
}
Console.Write(weekends);
Console.ReadLine();
hope it help you.
you can also take a look here for other stuff HERE

Split a period of time into multiple time periods

If i have a time period, lets say DateFrom and DateTo and I have a list of Dates, These dates will be the split dates. For example:
DateTime dateFrom = new DateTime(2012, 1, 1);
DateTime dateTo = new DateTime(2012, 12, 31);
List<DateTime> splitDates = new List<DateTime>
{
new DateTime(2012,2,1),
new DateTime(2012,5,1),
new DateTime(2012,7,1),
new DateTime(2012,11,1),
};
List<Tuple<DateTime, DateTime>> periods = SplitDatePeriod(dateFrom, dateTo, splitDates);
I want the result to be a list of periods, so for the previous example the result should be:
(01/01/2012 - 01/02/2012)
(02/02/2012 - 01/05/2012)
(02/05/2012 - 01/07/2012)
(02/07/2012 - 01/11/2012)
(02/11/2012 - 31/12/2012)
I have already wrote a method to do that:
List<Tuple<DateTime, DateTime>> SplitDatePeriod(DateTime dateFrom, DateTime dateTo, List<DateTime> splitDates)
{
var resultDates = new List<Tuple<DateTime, DateTime>>();
// sort split dates
List<DateTime> _splitDates = splitDates.OrderBy(d => d.Date).ToList();
DateTime _curDate = dateFrom.Date;
for (int i = 0; i <= _splitDates.Count; ++i)
{
DateTime d = (i < _splitDates.Count) ? _splitDates[i] : dateTo;
// skip dates out of range
if (d.Date < dateFrom.Date || d.Date > dateTo.Date)
continue;
resultDates.Add(Tuple.Create(_curDate, d));
_curDate = d.AddDays(1);
}
return resultDates;
}
The Question
It looks so ugly, Is there more neat and shorter way of doing this? using Linq maybe?
This is one that works and takes care of some edge cases also:
var realDates = splitDates
.Where(d => d > dateFrom && d < dateTo)
.Concat(new List<DateTime>() {dateFrom.AddDays(-1), dateTo})
.Select(d => d.Date)
.Distinct()
.OrderBy(d => d)
.ToList();
// now we have (start - 1) -- split1 -- split2 -- split3 -- end
// we zip it against split1 -- split2 -- split3 -- end
// and produce start,split1 -- split1+1,split2 -- split2+1,split3 -- split3+1,end
realDates.Zip(realDates.Skip(1), (a, b) => Tuple.Create(a.AddDays(1), b));
You can do it like this:
List<DateTime> split =
splitDates.Where(d => d >= dateFrom && d <= dateTo).ToList();
List<Tuple<DateTime, DateTime>> periods =
Enumerable.Range(0, split.Count + 1)
.Select(i => new Tuple<DateTime, DateTime>(
i == 0 ? dateFrom : split[i - 1].AddDays(1),
i == split.Count ? dateTo : split[i]
))
.ToList();
While L.B is correct and this probably belongs on Code Review, I felt like taking a crack at this:
Given Your First Code Block, the following code will do what you're asking for:
// List of all dates in order that are valid
var dateSegments = new [] { dateFrom, dateTo }
.Concat(splitDates.Where(x => x > dateFrom && x < dateTo))
.OrderBy(x => x)
.ToArray();
List<Tuple<DateTime, DateTime>> results = new List<Tuple<DateTime, DateTime>>();
for(var i = 0; i < dateSegments.Length - 1; i++)
{
results.Add(new Tuple<DateTime, DateTime>(dateSegments[i], dateSegments[i+1]));
}
If you put all the dates into a single list, then this should work:
var dates = new List<DateTime>
{
new DateTime(2012, 1, 1),
new DateTime(2012, 2, 1),
new DateTime(2012, 5, 1),
new DateTime(2012, 7, 1),
new DateTime(2012, 11, 1),
new DateTime(2012, 12, 31)
};
var z = dates.Zip(dates.Skip(1), (f, s) => Tuple.Create(f.Equals(dates[0]) ? f : f.AddDays(1), s));
List<DateTime> splitDates = GetSplitDates();
DateTime dateFrom = GetDateFrom();
DateTime dateTo = GetDateTo();
List<DateTime> edges = splitDates
.Where(d => dateFrom < d && d < dateTo)
.Concat(new List<DateTime>() {dateFrom, dateTo})
.Distinct()
.OrderBy(d => d)
.ToList();
//must be at least one edge since we added at least one unique date to this.
DateTime currentEdge = edges.First();
List<Tuple<DateTime, DateTime>> resultItems = new List<Tuple<DateTime, DateTime>>();
foreach(DateTime nextEdge in edges.Skip(1))
{
resultItems.Add(Tuple.Create(currentEdge, nextEdge));
currentEdge = nextEdge;
}
return resultItems;
I have Made it simple to get the Dates between the DateRange provided.
Model Object
public class DateObjectClass
{
public DateTime startDate { get; set; }
public DateTime endDate { get; set; }
}
Action :
public List<DateObjectClass> SplitDateRangeByDates(DateTime start,DateTime end)
{
List<DateObjectClass> datesCollection = new List<DateObjectClass>();
DateTime startOfThisPeriod = start;
while (startOfThisPeriod < end)
{
DateTime endOfThisPeriod =new DateTime(startOfThisPeriod.Year,startOfThisPeriod.Month,startOfThisPeriod.Day,23,59,59);
endOfThisPeriod = endOfThisPeriod < end ? endOfThisPeriod : end;
datesCollection.Add(new DateObjectClass() { startDate= startOfThisPeriod ,endDate =endOfThisPeriod});
startOfThisPeriod = endOfThisPeriod;
startOfThisPeriod = startOfThisPeriod.AddSeconds(1);
}
return datesCollection;
}

Categories