Linq where clause compare only date value without time value - c#

var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true
&& x.DateTimeValueColumn <= DateTime.Now)
.Select(x => x);
Upper query is working correct.
But I want to check only date value only.
But upper query check date + time value.
In traditional mssql, I could write query like below.
SELECT * FROM dbo.tbl_MyTable
WHERE
CAST(CONVERT(CHAR(10), DateTimeValueColumn, 102) AS DATE) <=
CAST(CONVERT(CHAR(10),GETDATE(),102) AS DATE)
AND
Active = 1
So could anyone give me suggestion how could I check only date value in Linq.

There is also EntityFunctions.TruncateTime or DbFunctions.TruncateTime in EF 6.0 or later

Simple workaround to this problem to compare date part only
var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true &&
x.DateTimeValueColumn.Year == DateTime.Now.Year
&& x.DateTimeValueColumn.Month == DateTime.Now.Month
&& x.DateTimeValueColumn.Day == DateTime.Now.Day);
Because 'Date' datatype is not supported by linq to entity , where as Year, Month and Day are 'int' datatypes and are supported.

EDIT
To avoid this error : The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true)
.Select(x => x).ToList();
var filterdata = _My_ResetSet_Array
.Where(x=>DateTime.Compare(x.DateTimeValueColumn.Date, DateTime.Now.Date) <= 0 );
The second line is required because LINQ to Entity is not able to convert date property to sql query. So its better to first fetch the data and then apply the date filter.
EDIT
If you just want to compare the date value of the date time than make use of
DateTime.Date Property - Gets the date component of this instance.
Code for you
var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true
&& DateTime.Compare(x.DateTimeValueColumn.Date, DateTime.Now.Date) <= 0 )
.Select(x => x);
If its like that then use
DateTime.Compare Method - Compares two instances of DateTime and returns an integer that indicates whether the first instance is earlier than, the same as, or later than the second instance.
Code for you
var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true
&& DateTime.Compare(x.DateTimeValueColumn, DateTime.Now) <= 0 )
.Select(x => x);
Example
DateTime date1 = new DateTime(2009, 8, 1, 0, 0, 0);
DateTime date2 = new DateTime(2009, 8, 1, 12, 0, 0);
int result = DateTime.Compare(date1, date2);
string relationship;
if (result < 0)
relationship = "is earlier than";
else if (result == 0)
relationship = "is the same time as";
else
relationship = "is later than";

result = from r in result where (r.Reserchflag == true &&
(r.ResearchDate.Value.Date >= FromDate.Date &&
r.ResearchDate.Value.Date <= ToDate.Date)) select r;

&& x.DateTimeValueColumn <= DateTime.Now
This is supported so long as your schema is correct
&& x.DateTimeValueColumn.Value.Date <=DateTime.Now

In similar case I used the following code:
DateTime upperBound = DateTime.Today.AddDays(1); // If today is October 9, then upperBound is set to 2012-10-10 00:00:00
return var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true
&& x.DateTimeValueColumn < upperBound) // Accepts all dates earlier than October 10, time of day doesn't matter here
.Select(x => x);

Working code :
{
DataBaseEntity db = new DataBaseEntity (); //This is EF entity
string dateCheck="5/21/2018";
var list= db.tbl
.where(x=>(x.DOE.Value.Month
+"/"+x.DOE.Value.Day
+"/"+x.DOE.Value.Year)
.ToString()
.Contains(dateCheck))
}

Try this,
var _My_ResetSet_Array = _DB
.tbl_MyTable
.Where(x => x.Active == true
&& x.DateTimeValueColumn <= DateTime.Now)
.Select(x => x.DateTimeValueColumn)
.AsEnumerable()
.select(p=>p.DateTimeValueColumn.value.toString("YYYY-MMM-dd");

Do not simplify the code to avoid "linq translation error":
The test consist between a date with time at 0:0:0 and the same date with time at 23:59:59
iFilter.MyDate1 = DateTime.Today; // or DateTime.MinValue
// GET
var tempQuery = ctx.MyTable.AsQueryable();
if (iFilter.MyDate1 != DateTime.MinValue)
{
TimeSpan temp24h = new TimeSpan(23,59,59);
DateTime tempEndMyDate1 = iFilter.MyDate1.Add(temp24h);
// DO not change the code below, you need 2 date variables...
tempQuery = tempQuery.Where(w => w.MyDate2 >= iFilter.MyDate1
&& w.MyDate2 <= tempEndMyDate1);
}
List<MyTable> returnObject = tempQuery.ToList();

Use mydate.Date to work with the date part of the DateTime class only.

Related

Count row only by date without time using Entity Framework

Check the CountEmailChart carefully. Here I am taking input of DateTime which is fully formatted date with time. But the problem is I want to compare only the date, not time, on Entity Framework below to count number of rows. Can anyone tell me how I can do this?
Controller code:
public int CountEmailChart(DateTime date, int campaignID)
{
int count = dbcontext.CampaignEmails
.Count(x => x.DateSigned == date && x.CampaignID == campaignID);
return count;
}
Karan's answer is correct but resulting query won't use an index for DateSigned. If a such index exist (or combined index for CampaignID and DateSigned columns) you may prefer this approach:
var startDate = date.Date;
var endDate = date.Date.AddDay(1);
int count = dbcontext.CampaignEmails.Count(x => x.CampaignID == campaignID && x.DateSigned >= startDate && x.DateSigned < endDate);
Try like this. .Date property on DateTime object will return only Date part.
If you are using Entity Framework 6 then.
date = date.Date;
int count = dbcontext.CampaignEmails.Count(x => DbFunctions.TruncateTime(x.DateSigned) == date.Date && x.CampaignID == campaignID);
Else
date = date.Date;
int count = dbcontext.CampaignEmails.Count(x => EntityFunctions.TruncateTime(x.DateSigned) == date.Date && x.CampaignID == campaignID);

Get List of Records between two times C# Linq To Entities

In my application, I am wanting to fill a list with records from the database that match specific conditions:
public ActionResult SelectYearGraph(int year)
{
var lstAllSummaries = db.Summaries.ToList();
var lstMonths =
lstAllSummaries.Where(x => x.FlightDay.Year == year)
.Select(x => x.TestDay.Month)
.Distinct()
.OrderBy(x => x)
.ToList();
List<string> lstMonthNames = new List<string>();
List<int> lstCountSummaries = new List<int>();
List<int> lstCountDailySummariesDifferentTime = new List<int>();
var tsSix = new TimeSpan(6, 0, 0);
var tsTen = new TimeSpan(22, 0, 0);
foreach (var item in lstMonths)
{
var monthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(item);
lstMonthNames.Add(monthName);
foreach (var item in lstMonths)
{
var monthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(item);
lstMonthNames.Add(monthName);
lstCountDailySummaries.Add(lstAllSummaries.Count(x => x.FlightDay.Month == item && x.FlightDay.Year == year
&& (x.FlightDay.TimeOfDay >= tsSix && x.FlightDay.TimeOfDay <= tsTen)
&& !x.deleted));
lstCountDailySummariesDifferentTime.Add(lstAllSummaries.Count(x => x.FlightDay.Month == item && x.FlightDay.Year == year
&& (x.FlightDay.TimeOfDay > tsTen || x.FlightDay.TimeOfDay < tsSix)
&& !x.deleted));
}
}
... // more down here but not relevant to question
}
When I run this, I get a runtime error:
The specified type member 'TimeOfDay' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
I have tried Date and Time Canonical Functions for LINQ-to-Entities, but I am receiving the same error.
How do I get all records between 6am and 10pm?
You don't need TimeOfDay just reading Hour, Minute, Second of your DateTime will give you the same result in your case.
the TimeOfDay property returns a TimeSpan value that represents a DateTime value's time component.
So just change your code to:
...
&& (DbFunctions.CreateTime(x.TestDay.Hour, x.TestDay.Minute,x.TestDay.Second) > DbFunctions.CreateTime(6,0,0)
&& (DbFunctions.CreateTime(x.TestDay.Hour, x.TestDay.Minute, x.TestDay.Second) < DbFunctions.CreateTime(22,0,0))
...
The problem with looking for times which cross midnight is that whereas a time can be both after 6am AND before 10pm the same is not true for after 10pm AND before 6am.
You'll need to change your AND to an OR
...
&& (
(DbFunctions.CreateTime(x.TestDay.Hour, x.TestDay.Minute,x.TestDay.Second) > DbFunctions.CreateTime(22,0,0)
|| (DbFunctions.CreateTime(x.TestDay.Hour, x.TestDay.Minute, x.TestDay.Second) < DbFunctions.CreateTime(6,0,0))
)
...
var query = from x in db.Summaries
let time = DbFunctions.CreateTime(x.TestDay.Hour, x.TestDay.Minute, x.TestDay.Second)
where x.FlightDay.Year == year
&& !x.deleted
&& (time < DbFunctions.CreateTime(6, 0, 0))
&& (time > DbFunctions.CreateTime(22, 0, 0))
group x by x.FlightDay.Month into summaries
let month = summaries.Key
select new
{
Month = month,
Count = summaries.Count(),
DifferentCount = (from d in db.DailySummaries
let timed = DbFunctions.CreateTime(d.TestDay.Hour, d.TestDay.Minute, d.TestDay.Second)
where d.FlightDay.Year == year && d.FlightDay.Month == month
&& !d.deleted
&& (timed < DbFunctions.CreateTime(6, 0, 0))
&& (timed > DbFunctions.CreateTime(22, 0, 0))
select d).Count(),
};

Entity framework filtering data by time

I am so sorry from the question, but I can not take a period from a DateTime. for exemple: If I have date "10.10.2016 7:00", 10.10.2016 10:00", I need to take only the rows with the time between "6:00" and "8:00". Next is my code by return an error : "can not use TimeOfDay ",help me please
ds.TrafficJamMorning = (from row in orderQuery
where row.AcceptedTime.TimeOfDay >= new TimeSpan(6, 30, 0) &&
row.AcceptedTime.TimeOfDay <= new TimeSpan(9, 30, 0)
group row by row.AcceptedTime.Date
into grp
select new TrafficJamPeriodInfo
{
CurrentDateTime = grp.Key,
ReceptionCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Reception),
InternetCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Internet),
ExchangeSystemCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.ExchangeSystem)
}).ToList();
TimeOfDay Is not supported by the linq provider and it does not know how to parse it into sql. Use instead DbFunctions.CreateTime:
Also instantiate the timespans before the linq query so you do not instantiate a new object every time
var startTime = new TimeSpan(6, 30, 0);
var endTime = new TimeSpan(9, 30, 0);
var result = (from row in orderQuery
let time = DbFunctions.CreateTime(row.AcceptedTime.Hour, row.AcceptedTime.Minute, row.AcceptedTime.Second)
where time >= startTime &&
time <= endTime
group row by DbFunctions.TruncateTime(row.AcceptedTime) into grp
select new TrafficJamPeriodInfo
{
CurrentDateTime = grp.Key,
ReceptionCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Reception),
InternetCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Internet),
ExchangeSystemCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.ExchangeSystem)
}).ToList();
Looking again at the question - If all you want to check is that it is between 2 hours then use the Hour property (This won't be nice to write if you want to check for example Hour and Minues and in that case I'd go for my first suggestion):
var result = (from row in orderQuery
where row.AcceptedTime.Hour >= 6
row.AcceptedTime.Hour < 8
group row by DbFunctions.TruncateTime(row.AcceptedTime) into grp
select new TrafficJamPeriodInfo
{
CurrentDateTime = grp.Key,
ReceptionCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Reception),
InternetCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Internet),
ExchangeSystemCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.ExchangeSystem)
}).ToList();
I use the following where clause on my IQueryable:
var query = dbContext.GetAllItems().AsQueryable();
//... other filters
if(MusBeBetween6and8){
query = query.Where(item => item.AcceptedTime.Hour > 6 && item.AcceptedTime.Hour < 8);
}
//... other filters
return query.ToList();
Hope it helps. This also works for Oracle + Odac.
ds.TrafficJamMorning = (from row in orderQuery
where
DbFunctions.DiffMinutes( DbFunctions.TruncateTime(row.AcceptedTime), row.AcceptedTime) >= 6 * 60 + 30 &&
DbFunctions.DiffMinutes( DbFunctions.TruncateTime(row.AcceptedTime), row.AcceptedTime) <= 9 * 60 + 30
group row by DbFunctions.TruncateTime(row.AcceptedTime)
into grp
select new TrafficJamPeriodInfo
{
CurrentDateTime = grp.Key,
ReceptionCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Reception),
InternetCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.Internet),
ExchangeSystemCount = grp.Count(r => r.OrderOriginId == (int)OrderOrigin.ExchangeSystem)
}).ToList();
I had a similar problem.
You can compare the date parts instead.
where row.Year > s.Year && r.Month > s.Month && row.Day > s.Day

Linq - Dynamic Condition

I have the following query :-
I want to add one more condition which is dynamic, so if user passes DATEOFBIRTH it should be e.DateOfBirth <= date.
var data = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date)
.Select(e => e)
.ToList();
How to condition dynamically?
You can use reflection to solve this problem but there is another idea that may helps you:
var criteria = new Dictionary<string, Func<Employee, bool>>();
var date = DateTime.Now; //or any other value
//Initialize your criterias
criteria.Add("DATEOFBIRTH", e => e.DateOfBirth <= date);
criteria.Add("DateOfJoining", e => e.DateOfJoining <= date);
var selectedValue = "DATEOFBIRTH";
var data = ctx.Employee.Where(e => e.Id == id &&
e.Category == Category &&
criteria[selectedValue](e)).ToList();
So if you change the selectedValue the output will be based on corresponding criteria you are looking for.
From your comment:
If the DateOfBirth is choosen, there where condition should be appended
by one more condition e.DateOfBirth <= date.. if user chooses
DateOfAnniversary then it should be e.DateOfAnniversary <= date
Then you could use:
var data = ctx.Employee
.Where(e => e.Id == Id && e.Category == Category && e.DateOfJoining <= date);
Now, assuming that filterbyDateOfBirth and filterbyDateOfAnniversary are bools:
if(filterbyDateOfBirth)
data = data.Where(e => e.DateOfBirth <= date);
if(filterbyDateOfAnniversary)
data = data.Where(e => e.DateOfAnniversary <= date);
var list = data.ToList();
Due to LINQ's deferred execution the database is queried just once at ToList.
Sounds like you're trying to do the following:
var employees = ctx.Employee.Where(e => e.Id == Id
&& e.Category == Category
&& e.DateOfJoining <= date);
if (!string.IsNullOrWhiteSpace(DATEOFBIRTH))
{
employees = employees.Where(e => e.DateOfBirth <= DATEOFBIRTH);
}
var data = employees.ToList();
You could also do the following, which is more concise, but since it looks like you are querying a database here, I would prefer the above approach since it doesn't include anything unnecessary in the query.
var data = ctx.Employee.Where(e => e.Id == Id &&
e.Category == Category &&
e.DateOfJoining <= date &&
(string.IsNullOrWhiteSpace(DATEOFBIRTH) ||
e.DateOfBirth <= DATEOFBIRTH))
.ToList();

C# Linq Where Date Between 2 Dates

I'm trying to get my linq statement to get me all records between two dates, and I'm not quite sure what I need to change to get it to work: (a.Start >= startDate && endDate)
var appointmentNoShow =
from a in appointments
from p in properties
from c in clients
where a.Id == p.OID && (a.Start.Date >= startDate.Date && endDate)
Just change it to
var appointmentNoShow = from a in appointments
from p in properties
from c in clients
where a.Id == p.OID &&
(a.Start.Date >= startDate.Date && a.Start.Date <= endDate)
var appointmentNoShow = from a in appointments
from p in properties
from c in clients
where a.Id == p.OID
where a.Start.Date >= startDate.Date
where a.Start.Date <= endDate.Date
var QueryNew = _context.Appointments.Include(x => x.Employee).Include(x => x.city).Where(x => x.CreatedOn >= FromDate).Where(x => x.CreatedOn <= ToDate).Where(x => x.IsActive == true).ToList();
So you are scrolling down because the Answers do not work:
This works like magic (but they say it has efficiency issues for big data, And you do not care just like me)
1- Data Type in Database is "datetime" and "nullable" in my case.
Example data format in DB is like:
2018-11-06 15:33:43.640
An in C# when converted to string is like:
2019-01-03 4:45:16 PM
So the format is :
yyyy/MM/dd hh:mm:ss tt
2- So you need to prepare your datetime variables in the proper format first:
Example 1
yourDate.ToString("yyyy/MM/dd hh:mm:ss tt")
Example 2 - Datetime range for the last 30 days
DateTime dateStart = DateTime.Now.AddDays(-30);
DateTime dateEnd = DateTime.Now.AddDays(1).AddTicks(-1);
3- Finally the linq query you lost your day trying to find (Requires EF 6)
using System.Data.Entity;
_dbContext.Shipments.Where(s => (DbFunctions.TruncateTime(s.Created_at.Value) >= dateStart && DbFunctions.TruncateTime(s.Created_at.Value) <= dateEnd)).Count();
To take time comparison into account as well :
(DbFunctions.CreateDateTime(s.Created_at.Value.Year, s.Created_at.Value.Month, s.Created_at.Value.Day, s.Created_at.Value.Hour, s.Created_at.Value.Minute, s.Created_at.Value.Second) >= dateStart && DbFunctions.CreateDateTime(s.Created_at.Value.Year, s.Created_at.Value.Month, s.Created_at.Value.Day, s.Created_at.Value.Hour, s.Created_at.Value.Minute, s.Created_at.Value.Second) <= dateEnd)
Note the following method mentioned on other stackoverflow questions and answers will not work correctly:
....
&&
(
s.Created_at.Value.Day >= dateStart.Day && s.Created_at.Value.Day <= dateEnd.Day &&
s.Created_at.Value.Month >= dateStart.Month && s.Created_at.Value.Month <= dateEnd.Month &&
s.Created_at.Value.Year >= dateStart.Year && s.Created_at.Value.Year <= dateEnd.Year
)).count();
if the start day was in this month for example and the end day is on the next month, the query will return false and no results, for example:
DatabaseCreatedAtItemThatWeWant = 2018/12/05
startDate = 2018/12/01
EndDate = 2019/01/04
the query will always search for days between 01 and 04 without taking the "month" into account, so "s.Created_at.Value.Day <= dateEnd.Day" will fail
And in case you have really big data you would execute Native SQL Query rather than linq
...
... where Shipments.Created_at BETWEEN CAST(#Created_at_from as datetime) AND CAST(#Created_at_to as datetime))
....
Thanks
If someone interested to know how to work with 2 list and between dates
var newList = firstList.Where(s => secondList.Any(secL => s.Start > secL.RangeFrom && s.End < secL.RangeTo))
public List<tbltask> gettaskssdata(int? c, int? userid, string a, string StartDate, string EndDate, int? ProjectID, int? statusid)
{
List<tbltask> tbtask = new List<tbltask>();
DateTime sdate = (StartDate != "") ? Convert.ToDateTime(StartDate).Date : new DateTime();
DateTime edate = (EndDate != "") ? Convert.ToDateTime(EndDate).Date : new DateTime();
tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).
Where(x => x.tblproject.company_id == c
&& (ProjectID == 0 || ProjectID == x.tblproject.ProjectId)
&& (statusid == 0 || statusid == x.tblstatu.StatusId)
&& (a == "" || (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)))
&& ((StartDate == "" && EndDate == "") || ((x.StartDate >= sdate && x.EndDate <= edate)))).ToList();
return tbtask;
}
this my query for search records based on searchdata and between start to end date
If you have date interval filter condition and you need to select all records which falls partly into this filter range. Assumption: records has ValidFrom and ValidTo property.
DateTime intervalDateFrom = new DateTime(1990, 01, 01);
DateTime intervalDateTo = new DateTime(2000, 01, 01);
var itemsFiltered = allItems.Where(x=>
(x.ValidFrom >= intervalDateFrom && x.ValidFrom <= intervalDateTo) ||
(x.ValidTo >= intervalDateFrom && x.ValidTo <= intervalDateTo) ||
(intervalDateFrom >= x.ValidFrom && intervalDateFrom <= x.ValidTo) ||
(intervalDateTo >= x.ValidFrom && intervalDateTo <= x.ValidTo)
);
I had a problem getting this to work.
I had two dates in a db line and I need to add them to a list for yesterday, today and tomorrow.
this is my solution:
var yesterday = DateTime.Today.AddDays(-1);
var today = DateTime.Today;
var tomorrow = DateTime.Today.AddDays(1);
var vm = new Model()
{
Yesterday = _context.Table.Where(x => x.From <= yesterday && x.To >= yesterday).ToList(),
Today = _context.Table.Where(x => x.From <= today & x.To >= today).ToList(),
Tomorrow = _context.Table.Where(x => x.From <= tomorrow & x.To >= tomorrow).ToList()
};
You can use DbFunctions.TruncateTime(StartDateTime) To remove the time from datetime
var appointmentNoShow =
from a in appointments
from p in properties
from c in clients
where a.Id == p.OID && (DbFunctions.TruncateTime(a.Start) >= DbFunctions.TruncateTime(startDate) && endDate)

Categories

Resources