How to compare only date components from DateTime in EF? - c#

I am having two date values, one already stored in the database and the other selected by the user using DatePicker. The use case is to search for a particular date from the database.
The value previously entered in the database always has time component of 12:00:00, where as the date entered from picker has different time component.
I am interested in only the date components and would like to ignore the time component.
What are the ways to do this comparison in C#?
Also, how to do this in LINQ?
UPDATE:
On LINQ to Entities, the following works fine.
e => DateTime.Compare(e.FirstDate.Value, SecondDate) >= 0

Use the class EntityFunctions for trimming the time portion.
using System.Data.Objects;
var bla = (from log in context.Contacts
where EntityFunctions.TruncateTime(log.ModifiedDate) == EntityFunctions.TruncateTime(today.Date)
select log).FirstOrDefault();
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/84d4e18b-7545-419b-9826-53ff1a0e2a62/
UPDATE
As of EF 6.0 and later EntityFunctions is replaced by DbFunctions.

NOTE: at the time of writing this answer, the EF-relation was unclear (that was edited into the question after this was written). For correct approach with EF, check Mandeeps answer.
You can use the DateTime.Date property to perform a date-only comparison.
DateTime a = GetFirstDate();
DateTime b = GetSecondDate();
if (a.Date.Equals(b.Date))
{
// the dates are equal
}

I think this could help you.
I made an extension since I have to compare dates in repositories filled with EF data and so .Date was not an option since it is not implemented in LinqToEntities translation.
Here is the code:
/// <summary>
/// Check if two dates are same
/// </summary>
/// <typeparam name="TElement">Type</typeparam>
/// <param name="valueSelector">date field</param>
/// <param name="value">date compared</param>
/// <returns>bool</returns>
public Expression<Func<TElement, bool>> IsSameDate<TElement>(Expression<Func<TElement, DateTime>> valueSelector, DateTime value)
{
ParameterExpression p = valueSelector.Parameters.Single();
var antes = Expression.GreaterThanOrEqual(valueSelector.Body, Expression.Constant(value.Date, typeof(DateTime)));
var despues = Expression.LessThan(valueSelector.Body, Expression.Constant(value.AddDays(1).Date, typeof(DateTime)));
Expression body = Expression.And(antes, despues);
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
then you can use it in this way.
var today = DateTime.Now;
var todayPosts = from t in turnos.Where(IsSameDate<Turno>(t => t.MyDate, today))
select t);

If you use the Date property for DB Entities you will get exception:
"The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."
You can use something like this:
DateTime date = DateTime.Now.Date;
var result = from client in context.clients
where client.BirthDate >= date
&& client.BirthDate < date.AddDays(1)
select client;

To do it in LINQ to Entities, you have to use supported methods:
var year = someDate.Year;
var month = ...
var q = from r in Context.Records
where Microsoft.VisualBasic.DateAndTime.Year(r.SomeDate) == year
&& // month and day
Ugly, but it works, and it's done on the DB server.

Here's a different way to do it, but it's only useful if SecondDate is a variable you're passing in:
DateTime startDate = SecondDate.Date;
DateTime endDate = startDate.AddDays(1).AddTicks(-1);
...
e => e.FirstDate.Value >= startDate && e.FirstDate.Value <= endDate
I think that should work

You can also use this:
DbFunctions.DiffDays(date1, date2) == 0

you can use DbFunctions.TruncateTime() method for this.
e => DbFunctions.TruncateTime(e.FirstDate.Value) == DbFunctions.TruncateTime(SecondDate);

Just always compare the Date property of DateTime, instead of the full date time.
When you make your LINQ query, use date.Date in the query, ie:
var results = from c in collection
where c.Date == myDateTime.Date
select c;

This is how I do this.
DateTime date_time_to_compare = DateTime.Now;
//Compare only date parts
context.YourObject.FirstOrDefault(r =>
EntityFunctions.TruncateTime(r.date) == EntityFunctions.TruncateTime(date_to_compare));

//Note for Linq Users/Coders
This should give you the exact comparison for checking if a date falls within range when working with input from a user - date picker for example:
((DateTime)ri.RequestX.DateSatisfied).Date >= startdate.Date &&
((DateTime)ri.RequestX.DateSatisfied).Date <= enddate.Date
where startdate and enddate are values from a date picker.

Without time than try like this:
TimeSpan ts = new TimeSpan(23, 59, 59);
toDate = toDate.Add(ts);
List<AuditLog> resultLogs =
_dbContext.AuditLogs
.Where(al => al.Log_Date >= fromDate && al.Log_Date <= toDate)
.ToList();
return resultLogs;

You can user below link to compare 2 dates without time :
private bool DateGreaterOrEqual(DateTime dt1, DateTime dt2)
{
return DateTime.Compare(dt1.Date, dt2.Date) >= 0;
}
private bool DateLessOrEqual(DateTime dt1, DateTime dt2)
{
return DateTime.Compare(dt1.Date, dt2.Date) <= 0;
}
the Compare function return 3 different values: -1 0 1 which means dt1>dt2, dt1=dt2, dt1

Try this... It works fine to compare Date properties between two DateTimes type:
PS. It is a stopgap solution and a really bad practice, should never be used when you know that the database can bring thousands of records...
query = query.ToList()
.Where(x => x.FirstDate.Date == SecondDate.Date)
.AsQueryable();

I have resolved error using EfCore FromSqlRaw method.
var sql =
$"select * from \"ProgressBooks\" where date(\"Date\") = date('{today.Date.ToString("yyyy-MM-dd")}') and \"GroupId\" = {groupId}";
var todayProgressBook = _context.ProgressBooks.FromSqlRaw(sql).FirstOrDefault();

Related

C# LINQ Datetime in a String Value

I have a database with a string column that indicates a datetime value with this format: yyyyMMdd.
For example the value 20160908 indicate the 08 of Semptember 2016.
I have two datetimepicker for filter dateFrom and dateTo value. I take the datetime value in my datepicker textbox with this simply code:
DateTime dataFromSel = Convert.ToDateTime(txtDatFrom.Text);
DateTime dataToSel = Convert.ToDateTime(txtDatTo.Text);
My query is:
var query = from c in snd.WineOWines.OrderByDescending(x => x.DDT_DATA)
select new
{
c.ID,
c.VABRMA,
c.VABNCL,
c.DDT_DATA,
};
If I have a datetime filter i add this code:
if (txtDatDa.Text != "")
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
int dataDa = Convert.ToInt32(dataDaSel);
query = query.Where(x => int.Parse(x.DDT_DATA) >= dataDa);
}
The problem is that i can't to list the query before the filter because i have a lot of rows and if i use this query i can't do an int.parse in the LINQ statement.
How can i write a LINQ statement that select the row in my DB with datetime between from and to, if the value in the column is a string?For now my query works fine, but i need a where clause for this problem.
Thanks to all
If dates have the same format you do not need to cast them to int.
You should be able to compare stings and remove the cast...
if (!string.IsNullOrEmpty(txtDatDa.Text))
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
var res = query.Where(x => string.Compare(dataDaSel, x.Name) <= 0);
}
Linq to SQL supports string.Compare(string, string) as described here
https://social.msdn.microsoft.com/Forums/en-US/98180ae0-4ccd-4ecd-89d5-576a04169219/linq-to-entities-with-string-comparison?forum=adodotnetentityframework
You don't have to put int.Parse, you can do a direct string comparison it is going to work ok. Neither you have to convert your dataDaSel into integer.
if (txtDatDa.Text != "")
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
query = query.Where(x => x.DDT_DATA >= dataDaSel);
}
E.g.
"20120201" >= "20120201" // true
"20120101" >= "20120201" // false
"20120301" >= "20120201" // true
As long as you keep format as yyyyMMdd it is going to work ok even with string.

date part equality in LinqTo Entities

From the MSDN site
The Date property, which returns a DateTime value that represents a date without its time component
Well this method
public List<int> GetSymbolIdsFromProjectionsForDate(DateTime testDate)
{
var date = testDate.Date;
var db = _projContext;
List<int> symbList;
using (db)
{
symbList =
db.CommodityProjections.Where(e => DbFunctions.TruncateTime(e.ProjectionDate) == date)
.Select(e => e.CommoditySymbolId)
.ToList();
}
return symbList;
}
The list count is always zero. So while debugging, I see that the date variable is actually NOT just the date component of a datetime as it shows
Date = {11/14/2015 12:00:00 AM}
WTF So how does one compare dates using SQL Server. (I just migrated from MySql, where this was easier IMHO)
Just use DbFunctions.TruncateTime on both dates.
.Where(e => DbFunctions.TruncateTime(e.ProjectionDate) == DbFunctions.TruncateTime(testDate)

Assigning Querystring variable with Linq

I have a date variable named start that is passed in a query-string. Using linq I need to test on another page if another date variable named StartDate equals the date variable passed in the url.
I'm attempting to do something like:
test = client.GetEventInstances().Where(e => e.StartDate == start);
I can then filter by events with a StartDate that is equal to my start var sent in the url
You need to convert your string date to DateTime:-
DateTime startDate = DateTime.Parse(start);
test = client.GetEventInstances().Where(e => e.StartDate.Date == startDate.Date);
Obviously you will have to check whether date was parsed or not.
You should use DateTime.TryParse()
DateTime startDateTime;
if (DateTime.TryParse(start, out startDateTime))
client.GetEventInstances().Where(e => e.StartDate.Date == startDateTime.Date);
else
/* query can't be parsed, do whatever you need to do */

Linq - between dates query

I am trying to convert the following sql query as a linq query, however I keep experiencing an error -
Operator '<=' cannot be applied to operands of type 'string' and 'System.DateTime'.
SQL Query:
select top 3 Deal, [property], [event], [Date] from [dbo]. [Database_CRE_Events]
where (convert(datetime,[Date],103) between '01-May-2015' and '15-May-2015') and [property] is not NULL
order by convert(datetime,[Date],103) desc
I believe this is happening because c.Date is a string field from the entity database. I have tried converting the date values to string and datetime to get the following to work, but I keep getting an operand error.
LINQ Query:
DateTime dat = DateTime.Now.AddDays(-10);
string preWeek = dat.ToString("dd-MMM-yyyy");
DateTime dtt = DateTime.Now;
string today = dat.ToString("dd-MMM-yyyy");
var data = db.Database_CRE_Events.Where(c => c.Date <= Convert.ToDateTime(preWeek) && c.property != null)
.Select(x => new Loan() { Name = x.Deal, loan = x.property, evnt = x.Event })
.ToList().Take(3);
return data;
Is it possible to convert the original sql query to a linq query as c.Date being a string parameter?
Thank you for any further assistance.
The problem is that you're introducing strings into the mix for no reason at all. Unless you have to convert a DateTime to or from a string, don't do it.
Your query should be as simple as:
DateTime preWeek = DateTime.Today.AddDays(-10);
var data = db.Database_CRE_Events
.Where(c => c.Date <= preWeek && c.property != null)
.Select(x => new Loan() { Name = x.Deal, loan = x.property, evnt = x.Event })
.ToList()
.Take(3);
return data;
If c.Date is actually a string, you should fix your database so that it isn't a string. It's meant to be a date, so represent it as a date! If you absolutely have to keep it as a string, you should at least use a sortable format, such as yyyy-MM-dd. At that point you could use CompareTo - but it's horrible :(
If the format is dd-MMM-yyyy (as it sounds) you could try performing the parse in the LINQ query, still passing in a DateTime but parsing each value in the database:
.Where(c =>
DateTime.ParseExact(c.Date, "dd-MMM-yyyy", CultureInfo.InvariantCulture) <= preWeek
&& c.property != null)
... but I wouldn't be surprised if that fails. You may want to add a view in SQL which gives a more appropriate version of the data. Fundamentally, if you have to work with a broken schema (in this case using the wrong type and making a poor decision about how to format the data within that type) then you should expect pain. Pass this pain up to managers in order to prioritize changing the schema...
Notes:
You're fetching all the data, and then just taking the first three elements. That's a bad idea. Switch round the calls to ToList and Take after addressing the next bullet...
"First three elements" is only meaningful with ordering. Use OrderBy to specify an ordering
You're not currently using today, so I removed it
If you're only interested in a date, use DateTime.Today
You should carefully consider time zones, both in your database and in your calling code. This is currently using the system default time zone - is that what you want?

Compare a Part of the date using linq

I need to compare, using LINQ, a date string "2010-06-11" with a field value in the database "2013-07-25 14:33:58.070", but only the year-month-day part.
I tried this:
updateDate = "2010-06-11";
_adRepository.Query.Where(p => p.DateModified.ToString("YYYYMMDD") <= updateDate).FirstOrDefault();
but it's not working, any ideas?
Thanks.
One of the problems not mentioned earlier is that the test data you're using will always fail to return a value. "2013-07-25" will never be less than "2010-06-11".
That being said, your code really should be converting the updateDate variable into a date time and doing the comparison against that rather than converting the DateModifed field in the table. Otherwise the conversion is applied against all of the records in the database. The code I would use is:
var updateDateString = "2010-06-11";
DateTime updateDate;
if (DateTime.TryParse(updateDateString, out updateDate))
{
_adRepository.Query.Where(p => p.DateModified <= updateDate).FirstOrDefault();
}
else
{
// throw an exception or something
}
This should work:
_adRepository.Query.Where(p => p.DateModified.Day <= DateTime.Parse(updateDate).Day);
It might have some issues with parse, but I can't remember proper format for it.
Date format is incorrect. You want "yyyyMMdd". But this is trying to get linq to do a string compare. If you are using EF it probably won't work.
Convert UpdateDate to a DateTime instead and use that in your query.
from q in _adRepository.Query
where DateTime.Compare(updateDate.Date, DateTime.Parse(q.DateModified).Date) <= 0
select q
try this:
DateTime updateDate = DateTime.Today;
_adRepository.Query.Where(p => p.DateModified.Date <= updateDate).FirstOrDefault()
This works in LinqPad
DateTime[] update = new DateTime[]{ new DateTime(2014,01,01), new DateTime(2014,01,29), new DateTime(2014,01,22)};
var selected = update.Where(x => x.Date <= new DateTime(2014,01,22).Date);

Categories

Resources