I want to get all dates in the last three months, so I did the following:
protected void BindPermissions(int empNum)
{
var permPeriod = new Dictionary<int, int>();
permPeriod.Add(DateTime.Now.Year, DateTime.Now.Month);
permPeriod.Add(DateTime.Now.AddMonths(-1).Year, (DateTime.Now.AddMonths(-1).Month));
permPeriod.Add(DateTime.Now.AddMonths(-2).Year, (DateTime.Now.AddMonths(-2).Month));
var dt = payload_object.AttendancePermissionBO.permissionList
.Where(x => x.empNum == empNum
&& ((x.permDate.Year == permPeriod.Keys.ElementAtOrDefault(0) && x.permDate.Month == permPeriod.Values.ElementAtOrDefault(0)) ||
(x.permDate.Year == permPeriod.Keys.ElementAtOrDefault(1) && x.permDate.Month == permPeriod.Values.ElementAtOrDefault(1)) ||
(x.permDate.Year == permPeriod.Keys.ElementAtOrDefault(2) && x.permDate.Month == permPeriod.Values.ElementAtOrDefault(2)))).ToList().OrderBy(x => x.permDate);
GV_PermissionHistory.DataSource = dt;
GV_PermissionHistory.DataBind();
}
Is there a better way to do that or this method suits what i need?
It seems like you do not really want all dates in the last three months, but you want all items in your collection where permDate is a date within some date range.
Given your own approach, that some date range seems to be the two previous months plus the entire current month. I.e. for 5th of July 2022, the date range is all of May, June and July 2022.
I think you can simplify your approach by defining a start date and an end date, and compare the permDate values with those two values. A straight-forward way of doing that could be:
var today = DateTime.Today;
var startMonth = today.AddMonths(-2);
var endMonth = today.AddMonths(1);
var startDate = new DateTime(startMonth.Year, startMonth.Month, 1);
var endDate = new DateTime(endMonth.Year, endMonth.Month, 1);
Then, you can use startDate and endDate in your filtering:
var dt = payload_object.AttendancePermissionBO.permissionList
.Where(x =>
x.empNum == empNum &&
x.permDate >= startDate &&
x.permDate < endDate)
.OrderBy(x => x.permDate)
.ToList();
You can use the below code for all the dates of last X- months. You can do some changes based on your requirements.
public static void Main()
{
var list= new List<DateTime>();
for(int i=0;i<3;i++){
var month= DateTime.Now.AddMonths(-i);
var monthDates= GetDates(month.Year, month.Month);
list.AddRange(monthDates);
}
foreach(var item in list){
Console.WriteLine(item.ToString());
}
}
public static List<DateTime> GetDates(int year, int month)
{
return Enumerable.Range(1, DateTime.DaysInMonth(year, month))
.Select(day => new DateTime(year, month, day))
.ToList();
}
Get the date (boundary) three months ago from today.
DateTime threeMonthsAgoDate = DateTime.Now.AddMonths(-3);
Filter the data for permDate that after (inclusive) the date from 3 months ago.
var dt = payload_object.AttendancePermissionBO.permissionList
.Where(x => x.empNum == empNum
&& x.permDate >= threeMonthsAgoDate.Date)
.OrderBy(x => x.permDate)
.ToList();
Updated:
This answer is for querying records from the last 3 months ago until the current date.
Based on Post Owner's requirements and existing code, what he needs is from
Start Date: 2022-05-01
End Date: 2022-07-31 (inclusive)
Hence #Astrid's answer is most accurate.
Related
Please guys,
What i want to achieve is to get the previous 6 month back and search through my Transactions Table and retrieve a list of transactions that fall under each month property of Date Time and sum thier amount.
forexample. the current date is 04/03/2020 the last 6 months date becomes 02/20,01/2020,12/2019,11/2019,10/2019,09/2019 now i want to search through a table transactions which has a DateTime Property DateCreated and retrieve all the transactions that occurred within each month and sum all their amount.
ResponseCode 00 means successful payment
what i have tried.
List<DateTime> months = new List<DateTime>();
List<double> MonthSum= new List<Double>();
DateTime[] lastSixMonths = Enumerable.Range(0, 6).Select(i => DateTime.Now.AddMonths(-i)).ToArray();
foreach (var month in lastSixMonths)
{
var monthString = month.ToString("MM/yyyy");
var trans = await _context.Transactions.Where(c => monthString.Contains(c.DateCreated.ToString()) && c.ResponseCode == "00").Select(c => c.Amount).ToListAsync();
var sum = trans.Sum();
MonthSum.Add(sum);
}
something seems to be wrong with how am doing this. please help
I hope that's what you need:
var fromDate = DateTime.Now.AddMonths(-6);
var sumByMonth = _context.Transactions.Where(d => d.CreateDate > fromDate)
.GroupBy(d => d.CreateDate.Month)
.Select(d => new { Month = d.Key, Sum = d.Sum(docs => docs.Amount) })
.ToDictionary(a => a.Month , b => b.Sum);
The DateTime field is displayed as "yyyy-MM-dd" in linq, so you need to change month to "yyyy-MM" for judgment.
In the where condition, the 'Contains' condition needs to be exchanged.
List<DateTime> months = new List<DateTime>();
List<double> MonthSum = new List<Double>();
DateTime[] lastSixMonths = Enumerable.Range(0, 6).Select(i => DateTime.Now.AddMonths(-i)).ToArray();
foreach (var month in lastSixMonths)
{
var monthString = month.ToString("yyyy-MM");
var trans = await _context.Transactions.Where(c => c.DateCreated.ToString().Contains(monthString) && c.ResponseCode == "00").Select(c => c.Amount).ToListAsync();
var sum = trans.Sum();
MonthSum.Add(sum);
}
I want to fetch data by last week days like last Sunday, last Monday and so on 7 days. I wrote this query but I returns null.
var dateCriteria = DateTime.Now.Date.AddDays(-7);
var one = _context.Sale.Where(m => m.Date >= dateCriteria && m.Date.DayOfWeek.ToString() ==
"Sunday");
DayOfWeek is enum. So just use it without conversion:
var dateCriteria = DateTime.Now.Date.AddDays(-7);
var one = _context.Sale.Where(m => m.Date >= dateCriteria && m.Date.DayOfWeek ==
DayOfWeek.Sunday);
I am not sure if I understood your question correctly but here is what I would do to get the last Sunday's sales.
var one = _context.Sale.Where(m => m.Date == GetLast(DayOfWeek.Sunday));
private DateTime GetLast(DayOfWeek dayOfWeek) {
var currentDate = DateTime.Now.Date;
var currentDayOfWeek = (int)currentDate.DayOfWeek;
if (currentDayOfWeek <= (int)dayOfWeek) {
currentDayOfWeek = currentDayOfWeek + 7;
}
int daysToExtract = currentDayOfWeek - (int)dayOfWeek;
return currentDate.AddDays(-daysToExtract);
}
I am hoping to find a way to get the total number of days in a month with and without the weekends using LINQ in my ViewModel. For example, September would count for 20 days without weekends and 30 days with the weekends.
I also have a datepicker binding to MDate and I have no idea were to start.
Can someone please suggest an easy method? I am just an amateur.
private DateTime _mDate = DateTime.Now;
public DateTime MDate
{
get { return _mDate; }
set
{
if (value == _mDate)
{
return;
}
else
{
_mDate = value;
OnPropertyChanged("MDate");
SetDaysInMonth();
}
}
}
private void SetDaysInMonth()
{
???
}
Thank you.
DateTime.DayOfWeek method could come handy, and this answer by Ani shows how to get all days in a given month.
borrowing from the answer mentioned above:
public static List<DateTime> GetDates(int year, int month)
{
var dates = new List<DateTime>();
// Loop from the first day of the month until we hit the next month, moving forward a day at a time
for (var date = new DateTime(year, month, 1); date.Month == month; date = date.AddDays(1))
{
if(date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday)
{
dates.Add(date);
}
}
return dates;
}
int count = Enumerable.Range(1, DateTime.DaysInMonth(2017, 10)) // year and month
.Select(day => new DateTime(2017, 10, day)) // year and month
.Where(d => d.DayOfWeek != DayOfWeek.Sunday && d.DayOfWeek != DayOfWeek.Saturday) // check each day for weekend
.ToList().Count;
Hope you need only the no of working days in a month
Find the number of days in month then enumerate and excluded Saturday and Sunday.
private static void SetDaysInMonth(DateTime mDate)
{
int numberOfBusinessDays = Enumerable.Range(1, DateTime.DaysInMonth(mDate.Year, mDate.Month))
.Select(day => new DateTime(2017, mDate.Month, day))
.Count(d => d.DayOfWeek != DayOfWeek.Sunday && d.DayOfWeek != DayOfWeek.Saturday);
}
I'm trying to populate my list with missing dates where they have no sales...
I have defined a class like this:
public class GroupedItem
{
public DateTime _Date { get; set; }
public int Sales { get; set; }
}
And now the list is populated like this:
var LineGraph = _groupedItems
.GroupBy(l => l._Date.Date)
.Select(cl => new GroupedItem
{
_Date = cl.Key,
Sales = cl.Sum(c=>c.Sales)
})
.OrderBy(x => x._Date)
.Where(t => t._Date <= DateTime.Now &&
t._Date >= DateTime.Now.Subtract(TimeSpan.FromDays(date_range)))
.ToList();
And the output that I get with this is like following:
11th December 6 sales
13th December 8 sales
18th December 12 sales
19th December 25 sales
This is rather okay, but I'd like to add the dates that are missing in between the first and last date so that I can have an output like this:
11th December 6 sales
12th December 0 sales
13th December 8 sales
14th December 0 sales
15th December 0 sales
16th December 0 sales
17th December 0 sales
18th December 12 sales
21st December 25 sales
How can I achieve this with LINQ ?
This Post has a way to generate a list of dates based on a range. I think we're going to have to union a list of dates to your groupedquery since it looks like to me your query results don't already contain rows for dates with 0 sales.
var LineGraph = _groupedItems.Union(Enumerable.Range(1, date_range)
.Select(offset => new GroupedItem { _Date = DateTime.Now.AddDays(-(date_range)).AddDays(offset), Sales = 0} ))
.GroupBy(l => l._Date.Date)
.Select(cl => new GroupedItem
{
_Date = cl.Key,
Sales = cl.Sum(c=>c.Sales)
})
.Where(t => t._Date <= DateTime.Now &&
t._Date >= DateTime.Now.Subtract(TimeSpan.FromDays(date_range)))
.OrderBy(x => x._Date)
.ToList();
Corrected to include today and order by after the select.
You can generate the list of dates and make a left join with lineGraph to generate the entire list:
var minDate = lineGraph.Min(g => g.Date);
var maxDate = lineGraph.Max(g => g.Date);
var range = GetDateRange(minDate, maxDate);
var result = from date in range
from item in lineGraph.Where(g => g.Date.Date == date)
.DefaultIfEmpty()
select new GroupedItem
{
Date = date,
Sales = item?.Sales ?? 0
};
Use this method to generate the date range:
public static IEnumerable<DateTime> GetDateRange(DateTime startDate, DateTime endDate)
{
var date = startDate.Date;
while (date <= endDate.Date)
{
yield return date;
date = date.AddDays(1);
}
}
Alternatively, you can do something like this:
var min = _groupedItems.Min(g => g.Date);
var max = _groupedItems.Max(g => g.Date);
var range = GetDateRange(min, max).Select(d => new GroupedItem { Date = d, Sales = 0 });
And make your query against range.Concat(_groupedItems) instead of _groupedItems.
Say I have a list of LockedDate.
A LockedDate has a DateTime and an IsYearly bool. If IsYearly is true then the year should not be considered because it could be any year. Time should never be considered.
Ex: X-Mas, Dec 25 is yearly.
Now I have a List of LockedDate.
There are no duplicates.
Now I need this function:
This function will do:
If a LockedDate is NOT yearly and the day, month, and year are within the range from source, add to return list.
If a LockedDate IS yearly, and its month / day fall in the range, then add a new date for each year in the range.
Say I have Dec 25 with IsYearly as true. My range is Jan 22 2013 to Feb 23 2015 inclusive. would need to add Dec 25 2013 as a new date and Dec 25 2014 as a new Date to the list.
List<Date> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{
}
Thanks
Dec 25 Yearly -> Dec 25 2013, Dec 25 2014
Dec 2, 2011 NOT Yearly -> Nothing
March 25, 2013 => March 25 2013
This might give you at least an idea, it's not tested at all yet:
List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{
if (start > end)
throw new ArgumentException("Start must be before end");
var ts = end - start;
var dates = Enumerable.Range(0, ts.Days)
.Select(i => start.AddDays(i))
.Where(d => source.Any(ld => ld.Date == d
|| (ld.IsYearly && ld.Date.Month == d.Month && ld.Date.Day == d.Day)));
return dates.ToList();
}
Update Here's the demo with your sample data, it seems to work: http://ideone.com/3KFi97
This code does what you want without using Linq:
List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{
List<DateTime> result = new List<DateTime>();
foreach (LockedDate lockedDate in source)
{
if (!lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end))
{
result.Add(lockedDate.Date);
}
else if (lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end))
{
DateTime date = new DateTime(start.Year, lockedDate.Date.Month, lockedDate.Date.Day);
do
{
result.Add(date);
date = date.AddYears(1);
} while (date <= end);
}
}
return result;
}
Make sure to ask about parts you don't understand, so I can explain in detail, but I think it's pretty straightforward.
This code assumes your LockedDate class has a property Date for the DateTime object.
var notYearly = lockDates.Where(d => !d.IsYearly && (d.Date.Date >= start && d.Date.Date <= end)).Select(d => d.Date);
var years = ((end - start).Days / 365) + 2;
var startYear = start.Year;
var yearly = lockDates.Where(d => d.IsYearly)
.SelectMany(d => Enumerable.Range(startYear, years)
.Select(e => new DateTime(e, d.Date.Month, d.Date.Day))
.Where(i => i.Date >= start && i.Date <= end));
var allDates = notYearly.Union(yearly)
Should be more efficient than just iterating through all days between start and end and checking, if that date ok.
If you have a Class LockedDate like this:
public class LockedDate
{
public DateTime Date { get; set; }
public bool IsYearly { get; set; }
...
}
Than you could use this code to get your needed dates:
List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{
List<DateTime> dt = new List<DateTime>();
foreach(LockedDate d in source)
{
if(!d.IsYearly)
{
if(start<=d.Date && d.Date<=end)
dt.Add(d.Date);
}
else
{
for(DateTime i = new DateTime(start.Year,d.Date.Month,d.Date.Day);i<=new DateTime(end.Year,d.Date.Month,d.Date.Day);i=i.AddYears(1))
{
dt.Add(i);
}
}
}
return dt;
}