Linq Select row Where date in Current month - c#

I need to get data from the current month.Haven't been able to find a solution that works.
This is my code, which gives me the data I need, but I get data from a whole month back, instead of from the current month we are in.
I chose the date "limit" twice with row > DateTime.Today.Addmonths(-1)
Any ideas ?
var userQuery =
from timeEntry in TimeEntries
//this displays a month back, not current month TODO: change to current month.
where timeEntry.DateEntity > DateTime.Today.AddMonths(-1)
select new {
UserName = timeEntry.User.FirstName + " " +timeEntry.User.LastName,
HoursEntered = timeEntry.HoursEntered,
User = timeEntry.User
};
var localrows = userQuery.ToList();
var grouping = localrows.GroupBy(x => x.User);
var userList = grouping.Select(q => new {
UserName = q.FirstOrDefault().UserName,
Hours = q.Sum(hr => hr.HoursEntered), //AbsenceTypeID = holiday(1) // still takes from a whole month, instead of current month.
Holiday = q.FirstOrDefault().User.Absences.Where(a => a.AbsenceTypeID == 1).Where(date => date.DateEntity > DateTime.Today.AddMonths(-1)).Count(),
});
EDIT:
Keyur patel' answer worked, though not for the bottom one.
so there i have to thank Jules for this one:
DateTime.Today.AddDays((DateTime.Today.Day -1) * -1)

Try using this:
DateTime today = DateTime.Today;
var userQuery =
from timeEntry in TimeEntries
where timeEntry.DateEntity.Month == today.Month && timeEntry.DateEntity.Year == today.Year
select new {
UserName = timeEntry.User.FirstName + " " +timeEntry.User.LastName,
HoursEntered = timeEntry.HoursEntered,
User = timeEntry.User
};
Added check for .Year since it may match with months from other years, if you have any.
Edit
As for the holiday part:
var userList = grouping.Select(q => new {
UserName = q.FirstOrDefault().UserName,
Hours = q.Sum(hr => hr.HoursEntered),
Holiday = q.FirstOrDefault().User.Absences.Where(a => a.AbsenceTypeID == 1 && a.DateEntity.Month == today.Month && a.DateEntity.Year == today.Year).Count(),
});

You can simply compare only Month part of the date like this:
timeEntry.DateEntity.Month == DateTime.Now.Month

You can use Month and Year properties of the DateTime class as follows:
var userQuery = TimeEntries
.Where (te => te.DateEntity.Month == DateTime.Today.Month && te.DateEntity.Year == DateTime.Today.Year)
.Select(timeEntry =>
new {
UserName = timeEntry.User.FirstName + " " + timeEntry.User.LastName,
HoursEntered = timeEntry.HoursEntered,
User = timeEntry.User
}
);

You can try this:
.Where(x => x.EntityDate >= new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1));

Related

Fill list/result with empty object to complete days in month

I have an anonymous object returned by a EntityFramework query for all records that have data for the given time period.
var results = (from record in this.context.Records
where record.Owner == owner && record.Date >= firstDay && record.Date <= lastDay
select new
{
record.Date,
PID = record.SubProcess.Process.Pid,
SPID = record.SubProcess.SPid,
ProcessName = record.SubProcess.Process.Name,
SubProcessName = record.SubProcess.Name,
record.Task,
record.SubTask,
record.Hours
}).ToList();
How can I fill the dates that don't have data so that on my presentation layer, it shows the all days of the month but shows 0 for those days that don't have data?
Thanks.
I may have found a workaround, I'm not sure if this is the best and/or efficient way of doing it but it works for my needs (atm).
I basically check if the result objects that don't have an entry for all the days in a month and inserted an empty object for that day.
var emptyResults = new List<object>();
var days = Enumerable.Range(1, DateTime.DaysInMonth(firstDay.Year, firstDay.Month))
.Select(day => new DateTime(firstDay.Year, firstDay.Month, day))
.ToList();
foreach (var date in days)
{
var exists = results.Any(x => x.Date == date);
if (!exists)
{
emptyResults.Add(new
{
Date = date,
PID = "",
SPID = "",
ProcessName = "",
SubProcessName = "",
Task = "",
SubTask = "",
Hours = 0
});
}
}
var filledResults = results.Concat(emptyResults).ToList();
It doesn't look the most efficient way but it works for me. Please feel free to improve. Thanks

How can i get date from foreach for linq

I have this two codes.First one create date from today to seven days before except weekends. How can i combine second code to first one. I need to get dates from first code and use it for compare with m.CreationDate . I will use this code for : get typeid 1 and that days total book number for everydays. Thanks for answer...
public static List<DateTime> GetBusinessDays(DateTime startDate, int numDays)
{
var dates = new List<DateTime>();
var step = (numDays < 0) ? -1 : 1;
var date = startDate;
var absNumDays = Math.Abs(numDays);
while (dates.Count() < absNumDays)
{
date = date.AddDays(step);
if (date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)
continue;
dates.Add(date);
}
return dates;
}
string DateString = "";
var start = DateTime.Now;
var Dates = GetBusinessDays(start,-7);
Dates.Reverse();
foreach (var date in Dates)
{
DateString = DateString + "'" + date.ToShortDateString() + "',";
}
DateString = DateString.TrimEnd(',');
var book = from m in Connection.Db.Materials
where m.TypeId == 1 && m.25.05.2015,.ToShortDateString() == xx//need to write days here but for everyday
group m by m.TypeId into g
select new { Count = g.Count()};
get data from Dates :18.5.2015, 19.05.2015,20.05.2015,21.05.2015,22.05.2015,25.05.2015,26.05.2015.
I trying to get: m.CreationDate ==
19.05.2015 and typeid ==1 total book numbers:50
m.CreationDate ==
20.05.2015 and typeid ==1 total book numbers:15
If you toss the dates into a collection then you can use Contains in linq
var book = from m in Connection.Db.Materials
where m.TypeId == 1 && CreationDatesArray.Contains(m.CreationDate)
group m by m.TypeId into g
select new { Count = g.Count()};
Added m. as pointed out
Ok. You have date collection in Dates.
Then you perform grouping as
var book = from m in Connection.Db.Materials
where m.TypeId == 1
group m by m.CreationDate into g
select g
Then you can do
var result = Dates.Select(d => new {
Date = d,
Count = book.Where(g => g.Key == d).Count() })
And in result you get collection of dates from Dates with count from your second collection.
string DateString = "";
var start = DateTime.Now;
var Dates = GetBusinessDays(start,-7);
Dates.Reverse();
foreach (var date in Dates)
{
DateString = DateString + "'" + date.ToShortDateString() + "',";
}
DateString = DateString.TrimEnd(',');
var book = from m in Connection.Db.Materials
where m.TypeId == 1
group m by m.CreationDate into g select g;
var results = Dates.Select(d => new { Date = d.Day + "/" + d.Month + "/" + d.Year, Count = book.Where(g => g.Key.Day == d.Day && g.Key.Month == d.Month && g.Key.Year == d.Year).Count() }).ToList();
//put day, month and year. Because only dates equals with ohter dates.(I need only dates not times)
string Books = "";
foreach(var r in results)
{
Books = Books + r.Count + ',';
}
Thanks Everbody for Helping

how to get the month name

using (DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData meta = new LinqMetaData(adapter);
var datas = (from x in meta.Table
where x.DateCreated >= startDate && x.DateCreated <= endDate && x.ViaTo > 0 && !x.Cancelled
group x by new { month = x.DateCreated.Value.Month } into g
select new
{
MonthNr = g.Key,
//MonthName = ?
TotalMonthAmount = g.Sum(x => x.Amount)
});
.....
}
And startDate & endDate are valid Dates.
I only get the month number, how to get the month name for the DateCreated?
You can get the month name using this function:
CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(monthNumber);
new { month = x.DateCreated.Value.Month.ToString("MMM") }
I think you are asking about Month property. Check this:
using System;
class Program
{
static void Main()
{
DateTime now = DateTime.Now;
//
// Write the month integer and then the three-letter month.
//
Console.WriteLine(now.Month); //outputs 5
Console.WriteLine(now.ToString("MMM")); //outputs May
}
}

Linq group by month/year with empty months for past 12 months

How would I get this query to get the monthly count data for the past 12 months? I don't want to hard code the range, I want to use the current date DateTime.Now and get all the data for the past 12 months from that. I am trying to avoid adding a calendar table to the database and do this just using LINQ.
Some months might not have any data but I still need a count of 0 for those.
For example. If my data contains
Date Count
12/2/2013, 4
10/1/2014, 1
11/5/2014, 6
The results should be, using the current date of 11/9/2014
11/2013, 0
12/1013, 4
1/2014, 0
2/2014, 0
3/2014, 0
4/2014, 0
5/2014, 0
6/2014, 0
7/2014, 0
8/2014, 0
9/2014, 0
10/2014, 1
11/2014, 6
I can't get it to work. I think it's how I'm using Range but I'm not sure.
TimeSpan ts = new TimeSpan(365, 0, 0, 0);
DateTime yearAgo = DateTime.Now.Subtract(ts);
var changesPerYearAndMonth =
from year in Enumerable.Range(yearAgo.Year, 1)
from month in Enumerable.Range(1, 12)
let key = new { Year = year, Month = month }
join revision in list on key
equals new { revision.LocalTimeStamp.Year,
revision.LocalTimeStamp.Month } into g
select new { GroupCriteria = key, Count = g.Count() };
I have modified the answer from this this link as a starting point.
Linq: group by year and month, and manage empty months
I just found this article that is the same question but unanswered
Linq - group by datetime for previous 12 months - include empty months
To get the past twelve months, use
var now = DateTime.Now;
var months = Enumerable.Range(-12, 12)
.Select(x => new {
year = now.AddMonths(x).Year,
month = now.AddMonths(x).Month });
To be safe you should first move 'now' to the start of the month to avoid any end-of-month effects with AddMonth.
var now = DateTime.Now;
now = now.Date.AddDays(1-now.Day);
Complete example:-
var list = new [] {
new { LocalTimeStamp = DateTime.Parse("12/2/2013"), count = 4},
new { LocalTimeStamp = DateTime.Parse("10/1/2014"), count = 1 },
new { LocalTimeStamp = DateTime.Parse("11/5/2014"), count = 6}
};
var now = DateTime.Now;
now = now.Date.AddDays(1-now.Day);
var months = Enumerable.Range(-12, 13)
.Select(x => new {
year = now.AddMonths(x).Year,
month = now.AddMonths(x).Month });
var changesPerYearAndMonth =
months.GroupJoin(list,
m => new {month = m.month, year = m.year},
revision => new { month = revision.LocalTimeStamp.Month,
year = revision.LocalTimeStamp.Year},
(p, g) => new {month = p.month, year = p.year,
count = g.Sum(a => a.count)});
foreach (var change in changesPerYearAndMonth)
{
Console.WriteLine(change.month + " " + change.year +" " + change.count);
}
You don't need a 3-way join, you just need to filter your data before grouping.
1) Query expression syntax
// since your list item type was not posted, anyway same access as your LocalTimeStamp property
list = new List<DateTime>();
DateTime aYearAgo = DateTime.Now.AddYears(-1);
var dateslastYear = from date in list
where date > aYearAgo
group date by new { date.Year, date.Month } into g
select new { GroupCriteria = g.Key, Count = g.Count() };
2) Chained
dateslastYear = list.Where (d=>d>aYearAgo)
.GroupBy (date=>new{date.Year, date.Month });
3) If you want grouping by year/month pairs, including records of not existent entries, and also omitting those pairs that are older than a year occurring with the joined Enumerable.Range call:
var thisYearPairs = from m in Enumerable.Range(1, DateTime.Now.Month)
select new { Year = DateTime.Now.Year, Month = m };
var lastYearPairs = from m in Enumerable.Range(DateTime.Now.Month, 12 - DateTime.Now.Month + 1)
select new { Year = DateTime.Now.Year - 1, Month = m };
var ymOuter = from ym in thisYearPairs.Union(lastYearPairs)
join l in list on new { ym.Year, ym.Month } equals new { l.Year, l.Month } into oj
from p in oj.DefaultIfEmpty()
select new { a = ym, b = p == null ? DateTime.MinValue : p };
var ymGroup = from ym in ymOuter
group ym by ym into g
select new { GroupCriteria = g.Key.a, Count = g.Key.b == DateTime.MinValue ? 0 : g.Count() };
You are taking the range for the 12 months of last year only but you actually want the last twelve months.
You can do this using a Enumerable.Range and the AddMonths method:
var changesPerYearAndMonth =
from month in Enumerable.Range(0, 12)
let key = new { Year = DateTime.Now.AddMonths(-month).Year, Month = DateTime.Now.AddMonths(-month).Month }
join revision in list on key
equals new
{
revision.LocalTimeStamp.Year,
revision.LocalTimeStamp.Month
} into g
select new { GroupCriteria = key, Count = g.Count() };
public int YearDiff(DateTime a, DateTime b)
{
return (int) Math.Floor((a.Year + a.Month / 100.0 + a.Day / 10000.0) - (b.Year + b.Month / 100.0 + b.Day / 10000.0));
}

Filter data from Xml according to date in C#

I need help filtering xml file according to dates , with this part of the code that i have it only prints out all average information according to user name and place
Runner run = new Runner();
string filePath = "runners.xml"; //path
XDocument xDoc = XDocument.Load(filePath);
string userSelect = name;
var averageAddDistancequery = xDoc.Descendants("User").Where(w => (string)w.Element("Name") == user).Select(s => new
{
add = s.Elements("Attempts").Where(w => (string)w.Element("Place").Value == "Paris").Select(t => t.Element("Distance").Value)
}).ToList();
if (averageAddDistancequery[0].add.Count() > 0)
{
var aa = averageAddDistancequery[0].add.Average(a => float.Parse(a));
run.averageDistance = aa.ToString();
}
else
{
// nothing
}
var averageAdd2Distancequery = xDoc.Descendants("User").Where(w => (string)w.Element("Name") == userSelector).Select(s => new
{
add = s.Elements("Attempts").Where(w => (string)w.Element("Place").Value == "Madrid").Select(t => t.Element("Distance").Value)
}).ToList();
if (averageAdd2Distancequery[0].add.Count() > 0)
{
var aa = averageAdd2DistanceSubquery[0].add.Average(a => float.Parse(a));
run.averageDistance2 = aa.ToString();
}
else
{
// nothing
}
xmlDoc.DocumentElement.SetAttribute("searching", user);
XmlNodeList tests = xmlDoc.SelectNodes("//User[Name =/*/#searching]/Attempts");
listBox1.Items.Clear();
listBox1.Items.Add("Runners Name: " + user);
listBox1.Items.Add("Overall Distance in Paris: " + run.averageAdd);
listBox1.Items.Add("Overall Distance in Madrid: " + run.averageSub);
For example if my xml file looks like this
Users>
<User>
<Name>David</Name>
<Attempts>
<Place>Paris</Place>
<Date>3/29/2012</Date>
<Distance>100</Distance>
</Attempts>
<Attempts>
<Place>Madrid</Place>
<Date>7/28/2012</Date>
<Distance>100</Distance>
</Attempts>
<Attempts>
<Place>Paris</Place>
<Date>8/19/2012</Date>
<Distance>60</Distance>
</Attempts>
<Attempts>
<Place>Madrid</Place>
<Date>9/29/2012</Date>
<Distance>200</Distance>
</Attempts>
</User>
<User>
<Name>Lenny</Name>
<Attempts>
<Place>Paris</Place>
<Date>9/29/2012</Date>
<Distance>130</Distance>
</Attempts>
</User>
</Users>
If i run the code for david it will print out something like this
User:David
Average Distance in Paris:// data
Average Distance in Madrid: // data
This is not what i want, what i want is to select any two dates lets from a textbox and display only the information between those two dates
For example if i chose david, from date 3/29/2012 to 8/29/2012
I would want and output something like this:
User: David
Average Distance in Paris from 3/29/2012 to 8/29/2012: //data
Average Distance in Madrid from 3/29/2012 to 8/29/2012: //data
Ive been trying for hours, i need help implementing this
Use LINQ to XML, assume in here two dates you select from TextBox:
var userElement = xDox.Descendants("User")
.SingleOrDefault(u => u.Element("Name").Value == "David");
if (userElement != null)
{
var result = userElement.Descendants("Attempts")
.Select(a => new
{
Place = a.Element("Place").Value,
Date = DateTime.Parse(a.Element("Date").Value),
Distance = int.Parse(a.Element("Distance").Value)
})
.Where(a => a.Date >= DateTime.Parse("3/29/2012")
&& a.Date <= DateTime.Parse("8/29/2012"))
.GroupBy(a => a.Place)
.Select(g => new {Place = g.Key, Avg = g.Average(x => x.Distance)});
}
You can do, what you need, with Linq to Xml:
XElement x = XElement.Load("In.xml");
IFormatProvider f = new System.Globalization.CultureInfo("en-US");
DateTime bdate = DateTime.Parse("3/29/2012", f);
DateTime edate = DateTime.Parse("8/29/2012", f);
string username = "David";
var info = x.Elements("User")
.Where(u => u.Element("Name").Value == username)
.Select(u => new
{
Name = u.Element("Name").Value, //user name
AverageAttempts = u.Elements("Attempts") //select user's attempts
.Where(a => //filter by dates
{
DateTime d = DateTime.Parse(a.Element("Date").Value, f);
return d >= bdate && d <= edate;
})
.GroupBy(a => a.Element("Place").Value) //group by place
.Select(g => new // create summary info by place
{
Place = g.Key, //place
BeginDate = g.Elements("Date")
.Select(d => DateTime.Parse(d.Value, f))
.Min(), //min date, i.e. first attempt
EndDate = g.Elements("Date")
.Select(d => DateTime.Parse(d.Value, f))
.Max(), //max date, i.e. last attempt
Distance = g.Elements("Distance")//average distance
.Average(d => decimal.Parse(d.Value))
})
})
.FirstOrDefault();
if(info!=null)
{
Console.WriteLine(info.Name);
foreach (var aa in info.AverageAttempts)
{
Console.WriteLine(string.Format("{0} [{1} - {2}]:\t{3}",
aa.Place,
aa.BeginDate,
aa.EndDate,
aa.Distance));
}
}
The output contains not the dates used to filter, but the actual min and max dates of the user attempts.
This code, of course, doesn't contain any validity checks on whether all the necessary xml tags present in the file, or whether values are valid dates and decimals...It's up to you to modify it under your certain needs.
You can use this Xml library that will enable to read the dates and sort by them.
XElement root = XElement.Load(file);
XElement david = root.XPathElement("//User[Name={0}]", "David");
XElement[] attempts = david
.XPath("Attempts[Date>={0} and Date<={1}]",
new DateTime(2012, 3, 29), new DateTime(2012, 8, 29))
.ToArray();

Categories