C# LINQ Datetime in a String Value - c#

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.

Related

ASP.NET MVC Filtering results by date returns 0 results

I am trying to filter the results of a database query by date. The user will input a date value as a string and then I use that string to compare to the date of every query result to try to find a match, however there is never a match, even when I know one exists.
Query and filtering:
var documents = from s in db.Documents
select s;
if (!String.IsNullOrEmpty(searchString))
{
documents = documents.Where(s => s.Order_Date.ToString().Contains(searchString) ||
s.Comment.Contains(searchString));
}
It should be noted that if the searchString is found in the Comment column, then it works fine. But again, there is never a match for date.
In the SQL table that the app connects to the column Order_Date is of date datatype (not datetime). However in the model Order_Date is a DateTime variable because as far as I'm aware C# does not have just date.
Here is an example of the problem:
Result
What am I doing wrong?
You are comparing 11/8/2004 with s.Order_Date.ToString(). This approach has several problems:
Maybe s.Order_Date contains 2004-08-11 but when you do s.Order_Date.ToString() it turns to month-day-year date format 8/11/2004 (instead day-month-year) and 8/11/2004 != 11/8/2004
What happens if user enters 11/08/2004 ? 11/08/2004 != 11/8/2004. User will don't understand why they are no results.
If you want to search by date the best solution is to use a date entry control. If for your UX is important to enter date in a text control instead a date control then you should to tokenize text and try to identify dates on text, convert to date and use a date to compare on linq expression.
DateTime? search_date_start = tokenize_and_extract_date_start(searchString)
DateTime? search_date_end = tokenize_and_extract_date_end(searchString)
String? search_comment = remove_dates_from_search_string(searchString)
documents =
documents
.Where(s =>
search_date_start == null ||
s.Order_Date >= search_date_start)
)
.Where(s =>
search_date_end == null ||
s.Order_Date <= search_date_end)
)
.Where(s =>
search_comment == null ||
s.Comment.Contains(search_comment)
);
I figured it out using Jonathan's comment. This is the simplest way to do it:
if (!String.IsNullOrEmpty(searchString))
{
try
{
var test = DateTime.Parse(searchString);
documents = documents.Where(s => s.Order_Date == test);
}
catch (FormatException e)
{
documents = documents.Where(s => s.Comment.Contains(searchString));
}
}

LINQ decimal value in query

I use:
Asp.net core
MongoDB Driver 2.4.2
I'm building a Mongo DB Linq query like hereunder:
This returns records as expected:
int.TryParse("1", out intVal);
query = query.Where(x => x.MyIntField == intVal);
This doesn't return any records while there are records that have MyDecimalField equal to 1.0:
decimal.TryParse("1.0", out decVal);
query = query.Where(x => x.MyDecimalField == decVal);
Does anybody have a clue why?
There can be two problems
First problem can be in your culture. Decimal separator in your culture is not . (maybe it is ,).
You can use decimal separator which your culture uses.
var parsed = decimal.TryParse("1,0", out decVal); // instead of "," use your culture decimal separator
if (parsed)
{
query = query.Where(x => x.MyDecimalField == decVal);
}
Or try to use InvariantCulture:
var parsed = decimal.TryParse("1.0", NumberStyles.Any, CultureInfo.InvariantCulture, out decVal);
if (parsed)
{
query = query.Where(x => x.MyDecimalField == decVal);
}
The second problem can be in parsing some text that cannot be parsed to decimal. If this text cannot be parsed then default value of decVal is 0 and filter by Where doesn't return values with MyDecimalField == 0.
You need to check if value is parsed and if it is then you can query some data.

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);

How to compare only date components from DateTime in EF?

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();

Categories

Resources