Linq group month by quarters - c#

Is it possible to do a linq group by and group months into quarters, Ie Q1 Jan to apr etc etc

Something like this
Enumerable.Range(1,12)
.Select(o => new DateTime(DateTime.Today.Year, o, 1))
.GroupBy(o => (o.Month - 1) / 3)

Here's a basic example demonstrating this:
var dates = new[]
{
new DateTime(2011, 12, 25),
new DateTime(2011, 11, 25),
new DateTime(2011, 5, 4),
new DateTime(2011, 1, 3),
new DateTime(2011, 8, 9),
new DateTime(2011, 2, 14),
new DateTime(2011, 7, 4),
new DateTime(2011, 11, 11)
};
var groupedByQuarter = from date in dates
group date by (date.Month - 1)/3
into groupedDates
orderby groupedDates.Key
select groupedDates;
foreach(var quarter in groupedByQuarter)
{
Console.WriteLine("Q: {0}, Dates: {1}", quarter.Key, string.Join(", ", quarter));
}
The order by is there to simply help the quarters be logically ordered. You can remove the whole clause following the group statement.
With the output of:
Q: 0, Dates: 1/3/2011 12:00:00 AM, 2/14/2011 12:00:00 AM
Q: 1, Dates: 5/4/2011 12:00:00 AM
Q: 2, Dates: 8/9/2011 12:00:00 AM, 7/4/2011 12:00:00 AM
Q: 3, Dates: 12/25/2011 12:00:00 AM, 11/25/2011 12:00:00 AM, 11/11/2011 12:00:00 AM
Obviously you will need to correct the quarter numbers by adding one or perhaps translating them to a corresponding enum.

you can divide an arbitrary list into parts using an overload of the Select method and GroupBy. In your case, assuming the months in the list are in the correct order, the following should work:
var groups = yourList
.Select((item, index) => new { item, index })
.GroupBy(indexedItem=>indexedItem.index/3);

Yes it can be achieved with the LINQ to SQL GroupBy function if you define the qouters somewhere in your database or you can write some code that will handle this action it all depends on what data is available to you for this evaluation.

Related

Get closest day in future in a LINQ expression

I have date list in yyyy/mm/dd:
2020/06/10
2020/06/18
2020/07/17
and given date
2020/06/10
I want to find closest day in future from the given date in LINQ (expected result: 2020/06/18).
If you mean to find the closest date in future then you can filter out all earlier dates (including the same date), order it and then take the first value:
List<DateTime> allDates = new List<System.DateTime>()
{
new DateTime(2020, 06, 10),
new DateTime(2020, 06, 18),
new DateTime(2020, 07, 17),
};
DateTime givenDate = new DateTime(2020, 06, 10);
DateTime closestDateInFuture = allDates.Where(x => x > givenDate).OrderBy(x=> x).First();
Console.WriteLine(closestDateInFuture);
Output:
18.06.2020 00:00:00
Another suggestion by #Johnathan Barclay is to use the Min method, which yields the same result:
DateTime closestDateInFuture = allDates.Where(x => x > givenDate).Min()

how to remove date from datetime in Linq c#

i want to get only time from a datetime variable in linq query.
for eaxample if i have an array of datetime having values
["02/12/1970 14:52:06","14/06/2015 12:32:44"]
then how to extract minimum time from it so that i get output like
"12:32:44"
as if i take minimum these two it will give output
"14:52:44" instead of "12:32:44"
as the datepart of first value is smaller than the other.
i try this code:
time1 = table1.Min(x=>x.StartTime)
but it will give "14:52:06" as output
any suggestions?
First extract Time from DateTime and then get Min value
var dates = new List<DateTime>
{
new DateTime(2020, 6, 9, 12, 35, 45),
new DateTime(2020, 6, 10, 11, 35, 45)
};
var minTime = dates
.Select(d => d.TimeOfDay)
.Min();
#Update
If you want to get DateTime object that has the smallest time part, then use this:
var dateWithMinTime = dates
.OrderBy(d => d.TimeOfDay)
.FirstOrDefault();
Try
table1.Min(c => c.StartTime.TimeOfDay)
assuming StarTime is a DateTime.

How to get a set number of rows after ordering the records using linq?

I am using ASP.NET Core with an EF Model. I would like to display a number of rows by Date and then by Time, but I only want 5 records. What am concerned with is it actually ordering all the rows first before taking the 5 records or is it taking the 5 rows from the table and then ordering them. What I need is the former, them to be ordered, than take the 5 records from that already ordered list in linq.
I have tried:
Model.Meetings.OrderBy(x => x.Date).ThenBy(x => x.Time).Take(5)
and also,
Model.Meetings.Take(5).OrderBy(x => x.Date.ThenBy(x => x.Time)
The first one doesn't seem to display or actually does not return anything.
The second one works and shows 5 records, but what 5 records?
#foreach (var meeting in Model.Meetings.Take(5).OrderBy(x => x.Date).ThenBy(x => x.Time))
{
#if (meeting.Date > DateTime.Today)
{
<tr>
<td>#meeting.Name</td>
<td>#meeting.Date</td>
<td>#meeting.Time</td>
</tr>
}
}
I expect to get 5 records to display in order by Date then by Time, but order the records first before displaying them.
Here is example data set:
Id Date Day IsActive Location ThisEventId Time
1 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 2 09:15:00.0000000
2 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 3 09:00:00.0000000
3 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 4 09:30:00.0000000
4 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 5 10:30:00.0000000
5 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 6 11:00:00.0000000
6 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 7 11:30:00.0000000
7 2019-07-19 00:00:00.0000000 Friday 1 On-Campus 8 13:00:00.0000000
8 2019-06-20 00:00:00.0000000 Thursday 1 On-Campus 9 08:45:00.0000000
9 2019-06-20 00:00:00.0000000 Thursday 1 On-Campus 10 09:00:00.0000000
10 2019-06-20 00:00:00.0000000 Thursday 1 On-Campus 11 09:30:00.0000000
EDIT: See end of post for updated answer after clarification by OP in comments below.
I believe the comment by #RufusL is correct that you want to use OrderByDescending. To provide a solution for this question, see the code below. This will order first by date and then by time, taking the first 5 items.
#{ var meetings = Model.Meetings.OrderByDescending(x => x.Date).ThenByDescending(x => x.Time).Take(5) }
#foreach (var meeting in meetings) {
#if (meeting.Date > DateTime.Today) {
<tr>
<td>#meeting.Name</td>
<td>#meeting.Date</td>
<td>#meeting.Time</td>
</tr>
}
}
EDIT:
To get the dates that are in the future, simply using > does not work. You will want to use the .CompareTo method. The first step is to filter by times in the future accomplished by the expression below. This question address comparing DateTime in C#. See also the Microsoft docs for the .CompareTo method.
meetings.Where(x => x.Date.CompareTo(DateTime.Today) > 0)
Then OrderBy will sort them with the closest date to today, so the whole expression becomes
meetings.Where(x => x.Date.CompareTo(DateTime.Today) > 0).OrderBy(x => x.Date).ThenBy(x => x.Time)
A full example is below, where the List<DateTime> represents your Model.Meetings.
class Meeting {
public string Name { get; set; }
public DateTime Date { get; set; }
public TimeSpan Time { get; set; }
}
List<Meeting> allMeetings = new List<Meeting>() {
new Meeting{ Name = "1", Date = new DateTime(2019, 07, 7), Time = new TimeSpan(9, 15, 00) },
new Meeting{ Name = "2", Date = new DateTime(2019, 07, 17), Time = new TimeSpan(9, 15, 00) },
new Meeting{ Name = "3", Date = new DateTime(2019, 07, 17), Time = new TimeSpan(11, 15, 00) },
new Meeting{ Name = "4", Date = new DateTime(2019, 07, 11), Time = new TimeSpan(11, 15, 00) },
new Meeting{ Name = "5", Date = new DateTime(2019, 07, 12), Time = new TimeSpan(11, 15, 00) },
new Meeting{ Name = "6", Date = new DateTime(2019, 07, 13), Time = new TimeSpan(11, 15, 00) },
new Meeting{ Name = "7", Date = new DateTime(2019, 07, 14), Time = new TimeSpan(11, 15, 00) },
};
IEnumerable<Meeting> meetings = allMeetings.Where(x => x.Date.CompareTo(DateTime.Today) > 0).OrderBy(x => x.Date).ThenBy(x => x.Time);
foreach (Meeting meeting in meetings) {
Console.WriteLine($"{meeting.Name}\t{meeting.Date}\t{meeting.Time}");
}
Since today is July 11th, the output I receive is below, which is in the desired order.
5 7/12/2019 12:00:00 AM 11:15:00
6 7/13/2019 12:00:00 AM 11:15:00
7 7/14/2019 12:00:00 AM 11:15:00
2 7/17/2019 12:00:00 AM 09:15:00
3 7/17/2019 12:00:00 AM 11:15:00

c# - Substracting two times returns negative value

I'm having problems when I'm trying to substract hr2 with hr1 in a specific situation, for example, when hr1 = 13:00 and hr2 = 15:00, ok, the result is 02:00.
But when the values are: hr1 = 22:00 and hr2 = 02:00, the result is 20:00.
The result should be 04:00.
TimeSpan ts1 = hr1.Subtract(hr2).Duration();
TextBox1.Text = ts1.ToString();
How can I solve this problem?
I understand what you want, but how you currently try to achieve it makes no sense. 22 hours minus 20 hours is 2 hours, which is correct.
You probably want this:
new DateTime(1, 1, 2, 2, 0, 0) - new DateTime(1, 1, 1, 22, 0, 0)
You don't want to subtract TimeSpan's, you want to subtract dates (fake dates in this case).
Invoking Duration() will always result in a positive TimeSpan. The problem is coming from the fact that you are discarding days in your calculation. 22:00-02:00 is 20:00. I believe you are expecting it to be 04:00 because 02:00 represents "tomorrow." If that is what you want, you will need to calculate 22:00-(02:00+24:00) which will give you -04:00, which will become 04:00 when you invoke Duration().
You are trying to subtract two "spans", or durations, of time--not fixed points in time. What your code is currently saying is, I want to subtract two hours from twenty hours (which is indeed twenty hours). Instead, you need to use DateTimes. The hard part is going to be deciding the date for your timespans. I would rework the code to use DateTimes and preserve the "moments" in time that you are actually attempting to calculate.
Edit: Converting from a TimeSpan to a DateTime can cause you to lose information that affects the outcome of the result:
var ts1 = new DateTime (1, 1, 1, hr1.Hours, hr1.Minutes, hr1.Seconds, hr1.Milliseconds) -
new DateTime (1, 1, 1, hr2.Hours, hr2.Minutes, hr2.Seconds, hr2.Milliseconds);
is different than:
var ts1 = new DateTime (1, 1, 1, hr1.Hours, hr1.Minutes, hr1.Seconds, hr1.Milliseconds) -
new DateTime (1, 1, 2, hr2.Hours, hr2.Minutes, hr2.Seconds, hr2.Milliseconds);
or:
var ts1 = new DateTime (1, 1, 2, hr1.Hours, hr1.Minutes, hr1.Seconds, hr1.Milliseconds) -
new DateTime (1, 1, 1, hr2.Hours, hr2.Minutes, hr2.Seconds, hr2.Milliseconds);
Which is why you need to maintain the "point in time" with a DateTime.

C# Sorting DateTime issue

I am setting up a list of date times:
DateTime a1
DateTime a2
DateTime a3
DateTime a4
The above looks like this (as DateTime objects):
3/1/2012 10:56
3/1/2012 17:03
3/1/2012 1:38
3/1/2012 5:33
Then I put them in a list and sort:
List<DateTime> ldtBites = new List<DateTime>();
ldtBites.Add(a1);
ldtBites.Add(a2);
ldtBites.Add(a3);
ldtBites.Add(a4);
ldtBites.Sort();
After Sorting I get this:
3/1/2012 1:38:00 AM
3/1/2012 10:56 AM
3/1/2012 5:03:00 PM
3/1/2012 5:33:00 AM
You omitted the definition of w,x,y,z. I defined them as such:
DateTime w = new DateTime(2012, 3, 1, 10, 56, 0);
DateTime x = new DateTime(2012, 3, 1, 17, 3, 0);
DateTime y = new DateTime(2012, 3, 1, 1, 38, 0);
DateTime z = new DateTime(2012, 2, 29, 17, 3, 0);
This causes them to match your values for a1-a4; however, when I run the rest of your code, they sort correctly (a3, a4, a1, a2).
However, I noticed that x and z were the same hour/minute, so my initial test had this:
DateTime z = new DateTime(2012, 3, 1, 17, 3, 0);
When I ran this, I got them to come out in the order you were showing (a3, a1, a2, a4); however, after the AddHours() call went through, the z value was actually 3/2/2012, which is why it was last.
You don't want to convert back and forth. Just do it once. Sort your list first, and only then convert to string.
Converting to string and converting back might cause that result. Why don't you add x,y,w,z to your list directly?
List<DateTime> ldtBites = new List<DateTime>();
ldtBites.Add(DateTime.Parse("3/1/2012 10:56"));
ldtBites.Add(DateTime.Parse("3/1/2012 17:03"));
ldtBites.Add(DateTime.Parse("3/1/2012 1:38"));
ldtBites.Add(DateTime.Parse("3/1/2012 5:33"));
ldtBites.Sort();
foreach (DateTime dt in ldtBites)
Console.WriteLine(dt);
Output:
3/1/2012 1:38:00 AM
3/1/2012 5:33:00 AM
3/1/2012 10:56:00 AM
3/1/2012 5:03:00 PM
Press any key to continue . . .
Above will work only if all the date are same, in case the date are also different you should do the following...
var sortedDates = dates.OrderByDescending(x => x);
or else Don't want to use, or don't know Linq then you can go for following..
static List SortAscending(List list)
{
list.Sort((a, b) => a.CompareTo(b));
return list;
}
static List SortDescending(List list)
{
list.Sort((a, b) => b.CompareTo(a));
return list;
}

Categories

Resources