Search works on all fields except the date field - c#

I'd like to search data by date with format (dd/MM/yyyy) for example "20/01/2021". the search works on ADDRESS and NAME fields but not on the CREATE_DATE.
This is my code :
// search
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString().Contains(str)
));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}
This is the request :
http://localhost:6289/api/Customer?search=20/01/2021,hous
and this is the outputs of terms and test var :
and this is how the dates are saved , they dates are with datetime type

Your code actually works on my machine BUT only in case I use appropriate culture settings as #JustShadow pointed out.
Appropriate culture: which results a datetime.ToString() formating date in dd/MM/yyyy format.
For test purpose I used "es-ES" culture for example with the following code inside your if statement:
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES");
I suggest modifying your code according to this:
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
var originalCulture = Thread.CurrentThread.CurrentCulture;
try
{
// use any locale which results a datetime.ToString() output in dd/MM/yyyy format
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES"); ;
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString().Contains(str)));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
This will be enough if your input will have always dd/MM/yyyy format.
Edit:
You can try to use custom format string in ToString() call to achieve a working code as #bitapinches suggests. I think my solution performs better because there is no need to parse the custom format string in each comparison LINQ will execute. Here is the alternative for reference:
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString(#"dd\/MM\/yyyy").Contains(str)));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}

I think cast datatime to date ToString() you need to convert date format like "dd/MM/yyyy" which is the parameter (search=20/01/2021) in your url then Here [x.DATE_CREATE.ToString().Contains(str)] i would use "equals" be like [x.DATE_CREATE.ToString("dd/MM/yyyy").equals(str)] to be more specific on the query.

Related

MongoDB .NET Driver - Convert string to DateTime and for Filter Builder

var builder = Builders<ModelClass>.Filter;
var filter = builder.Where(x => x.Active);
if (fromDate.HasValue)
{
var date = fromDate.Value;
var subfilter = builder.Where(x => DateTime.Parse(x.EnrollmentDate) >= date);
filter &= subfilter;
}
Enrollment Date is saved as a string:
public string EnrollmentDate { get; set; }
, I need to filter docs within a set of date range, but how do I compare this? I need to filter like this.
I get
System.InvalidOperationException: Parse({document}{EnrollmentDate}) is not supported.
Error in subfilter line.
I think you need to achieve with MongoDB query as below:
{
"$expr": {
"$gte": [
{ "$toDate": "$EnrollmentDate" },
date
]
}
}
While I think it is not achievable with MongoDB .Net Driver LINQ syntax, you convert the query as BsonDocument:
var subfilter = new BsonDocument("$expr",
new BsonDocument("$gte",
new BsonArray {
new BsonDocument("$toDate", "$EnrollmentDate"),
date
}
)
);
filter &= subfilter;
You have problem here when you want to do DateTime.Parse()
Can you post format of your string EnrollmentDate? And your variable date , is it only Date or DateTime?
This one maybe can help you here
Also, try to use
var subfilter = builder.Gte(x=>x.Y, Z)

Convert string to MM/yyyy in c# to sort

I have seen previous questions which are related my query but couldn't figure out on how to resolve my issue.
I have a list "Sites" with one of the items as "Year". It is defined as string and is in the format "MM/yyyy". When I try to sort the list based on the year, I'm facing a small problem.
Data for "Year" is
01/2012
04/2012
01/2013
06/2012
When I sort the list by using orderby, the output I'm getting is
01/2012
01/2013
04/2012
06/2012
which is incorrect.
Cannot convert the string using Convert.ToDateTime as the string format doesn't contain day value. How should I go forward with this? How to implement DateTime.TryParseExact without changing the format of the string?
Note : The format should be the same and the list should be sorted.
you could try something like this without having to change the input this will give you the order that you like also look at the OrderByDescending property if you need it in a different sort order
var dateList = new List<string> { "01/2012", "04/2012", "01/2013", "06/2012" };
var orderedList = dateList.OrderBy(x => DateTime.Parse(x)).ToList();
You can still convert the string to a date within a LINQ statement, and the items will stay as strings.
var strings = new[]
{
"01/2012",
"04/2012",
"01/2013",
"06/2012"
};
var ordered = strings.OrderBy(s =>
{
var split = s.Split('/');
return new DateTime(int.Parse(split[1]), int.Parse(split[0]), 1);
});
Your last item will then be "01/2013".
As MethodMan showed in his answer, DateTime.Parse() will be able to parse a MM/yyyy formatted dated. However, if you need to perform anything that takes more than one line, this would be how you can do that. NB: This will not work in any query against a DbContext!
Implement System.IComparable interface:
public int CompareTo(object obj)
{
// Check null
if (obj == null)
return 1;
// Check types
if (this.GetType() != obj.GetType())
throw new ArgumentException("Cannot compare to different type.", "obj");
// Extract year and month
var year = int.Parse(this.Year.SubString(3, 4));
var month = int.Parse(this.Year.SubString(0, 2));
// Extract year and month to compare
var site = (Sites)obj;
var objyear = int.Parse(site.Year.SubString(3, 4));
var objmonth = int.Parse(site.Year.SubString(0, 2));
// Compare years first
if (year != objyear)
return year - objyear;
// Same year
// Compare months
return month - objmonth;
}
you also can create a new list with Dates converted to DateTime format and sort it after. It's a lot of lines but good for learning.
class Sites
{
public string Year { get; set; }
}
class MainClass
{
static void Main()
{
List<Sites> ListOfSites = new List<Sites>();
ListOfSites.Add(new Sites { Year = "01/2012" });
ListOfSites.Add(new Sites { Year = "04/2012" });
ListOfSites.Add(new Sites { Year = "01/2013" });
ListOfSites.Add(new Sites { Year = "06/2012" });
DateTime SiteYear;
List<DateTime> listWithDates = new List<DateTime>();
foreach (var item in ListOfSites)
{
if(DateTime.TryParse(item.Year, out SiteYear))
{
listWithDates.Add(SiteYear);
}
}
Display(SortAscending(listWithDates), "Sort Ascending");
}
static List<DateTime> SortAscending(List<DateTime> list)
{
list.Sort((a, b) => a.CompareTo(b));
return list;
}
static void Display(List<DateTime> list, string message)
{
Console.WriteLine(message);
foreach (var datetime in list)
{
Console.WriteLine(datetime);
}
Console.WriteLine();
}
}

Sort List by date values

I have the following list -
List<string> finalMessageContent
where
finalMessageContent[0] = "<div class="mHr" id="mFID">
<div id="postedDate">11/12/2015 11:12:16</div>
</div>" // etc etc
I am trying to sort the list by a particular value located in the entires - postedDate tag.
Firstly I have create an new object and then serialized it to make the html elements able to be parsed -
string[][] newfinalMessageContent = finalMessageContent.Select(x => new string[] { x }).ToArray();
string json = JsonConvert.SerializeObject(newfinalMessageContent);
JArray markerData = JArray.Parse(json);
And then used Linq to try and sort using OrderByDescending -
var items = markerData.OrderByDescending(x => x["postedDate"].ToString()).ToList();
However this is failing when trying to parse the entry with -
Accessed JArray values with invalid key value: "postedDate". Array position index expected.
Perhaps linq is not the way to go here however it seemed like the most optimised, where am I going wrong?
First, i would not use string methods, regex or a JSON-parser to parse HTML. I would use HtmlAgilityPack. Then you could provide such a method:
private static DateTime? ExtractPostedDate(string inputHtml, string controlID = "postedDate")
{
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(inputHtml);
HtmlNode div = doc.GetElementbyId(controlID);
DateTime? result = null;
DateTime value;
if (div != null && DateTime.TryParse(div.InnerText.Trim(), DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out value))
result = value;
return result;
}
and following LINQ query:
finalMessageContent = finalMessageContent
.Select(s => new { String = s, Date = ExtractPostedDate(s) })
.Where(x => x.Date.HasValue)
.OrderByDescending(x => x.Date.Value)
.Select(x => x.String)
.ToList();
Don't know if I get your question right.
But did you know that you can parse HTML with XPath?
foreach (var row in doc.DocumentNode.SelectNodes("//div[#id="postedDate"]"))
{
Console.WriteLine(row.InnerText);
}
this is just an example from the top of my head you might have to double-check the XPath query depending on your document. You can also consider converting it to array or parsing the date and do other transformations with it.
Like I said this is just from the top of my head. Or if the html is not so compley consider to extract the dates with an RegEx but this would be a topic for another question.
HTH
Json Serializer serializes JSON typed strings. Example here to json
To parse HTML I suggest using HtmlAgility https://htmlagilitypack.codeplex.com/
Like this:
HtmlAgilityPack.HtmlDocument htmlparsed = new HtmlAgilityPack.HtmlDocument();
htmlParsed.LoadHtml(finalMessageContent[0]);
List<HtmlNode> OrderedDivs = htmlParsed.DocumentNode.Descendants("div").
Where(a => a.Attributes.Any(af => af.Value == "postedDate")).
OrderByDescending(d => DateTime.Parse(d.InnerText)); //unsafe parsing

String was not recognized as a valid DateTime - Whats wrong?

I have been getting an annoying littler error and cannot for the life of me figure out why it is being cause. I have an xml file where i am storing data, as shown below.
- <EmployeeFinance>
<EmployeeEmploy_Id>5584</EmployeeEmploy_Id>
<EmpPersonal_Id>30358</EmpPersonal_Id>
<No_DaysWorked>30</No_DaysWorked>
<Date_Appointment>17/02/2012</Date_Appointment>
<Date_Employment>02/05/1984</Date_Employment>
<Date_Termination>01/01/0001</Date_Termination>
<Payperiod_StartDate>01/01/2013</Payperiod_StartDate>
<Payperiod_EndDate>31/01/2013</Payperiod_EndDate>
<BatchNumber>38</BatchNumber>
<PAYE_ToDate_Computed>0</PAYE_ToDate_Computed>
<Income_Tax_RateID>0</Income_Tax_RateID>
<NIS_RateID>0</NIS_RateID>
<NIS_weeks_worked>0</NIS_weeks_worked>
</EmployeeFinance>
If you look at the date nodes, Payperiod_StartDate,Payperiod_EndDate, Date_Appointment etc. They all have the same format. Now in my C# code, when i write my query to select from the xml file i get the String was not recognized as a valid DateTime error. WHen i comment out all the other dates and leave start_date, it works. They are the same format , i cant see what i am doing wrong. Please help me.
var context = new SSPModel.sspEntities();
XElement xelement = XElement.Load(GlobalClass.GlobalUrl);
XDocument doc = XDocument.Load(GlobalClass.GlobalUrl);
var query = from nm in xelement.Elements("EmployeeFinance")
select new EmployeeEmploy
{
Employee_Personal_InfoEmp_id = (int)nm.Element("EmpPersonal_Id"),
Substantive_designation = (int)nm.Element("Position_Id"),
Grade_Id = (int)nm.Element("Grade_Id"),
PositionTotal_PtBasic = (double)nm.Element("Sum_AllPosition"),//part of basic
GradeTotal_PtBasic = (double)nm.Element("Sum_AllGrade"), //part of basic
Housing_Allowance = (double)nm.Element("Housing"),
Base_Pay = (double)nm.Element("Base_Pay"),
startDate = (DateTime)nm.Element("Payperiod_StartDate"),
endDate = (DateTime)nm.Element("Payperiod_EndDate"),
Date_of_Appointment = (DateTime)nm.Element("Date_Appointment"),
Date_of_Employment = (DateTime)nm.Element("Date_Employment"),
Termination_date_actual = (DateTime)nm.Element("Date_Termination"),
Base_Pay_Currency = (string)nm.Element("Currency"),
Exchange_rate = (double)nm.Element("Exchange_Rate")
};
var x = query.ToList();
foreach (var xy in x) {
Debug.WriteLine(xy.endDate);
}
Because 17/02/2012 is not a valid date, however, 02/17/2012 is. The date will be parsed as mm/dd/yyyy. One option is to use DateTime.ParseExact to parse a date with the dd as the first set of numbers. e.g.
var startDate = DateTime.ParseExact("17/02/2012", "dd/MM/yyyy", null);
The debugger will show you that nm.Element("Payperiod_EndDate").ToString() gives you a string that includes the xml tags for that element. Try the following instead:
startDate = DateTime.ParseExact(nm.Element("Payperiod_EndDate").Value, "dd/MM/yyyy", null)

DateTime Parse Based on Search Function

I have a search function which includes dates also. The problem that i have is this:
when you add 2 dates in the search function for example:
2013-04-10 and 2013-04-11 it displays just for 2013-04-10 until 23:59 or if i search the same date
2013-04-10 and 2013-04-10 it doesn't find any hit.
the code is this:
Func<string, string> emptyToNull = s => String.IsNullOrWhiteSpace(s) ? null : s.Trim();
var from = emptyToNull(input.CreditApplicationSearchFromDate);
var to = emptyToNull(input.CreditApplicationSearchToDate);
from = from ?? DateTime.Today.ToString("yyyy-MM-dd");
to = to ?? DateTime.Today.ToString("yyyy-MM-dd");
And i was thinking to do like this:
Func<string, string> emptyToNull = s => String.IsNullOrWhiteSpace(s) ? null : s.Trim();
var from = emptyToNull(input.CreditApplicationSearchFromDate);
var to = emptyToNull(input.CreditApplicationSearchToDate);
from = from ?? new DateTime().ToString("yyyy-MM-dd HH:mm");
to = to ?? new DateTime().ToString("yyyy-MM-dd HH:mm");
but is not good and i don't know how to do to display when i search for example
2013-04-10 and 2013-04-10 to find the hits for all day
You need to specify the start and end hours of the whole day, or better yet - the very start of the next day:
from = from ?? DateTime.Now.Date.ToString("yyyy-MM-dd");
to = to ?? new DateTime.Now.Date.AddDays(1).ToString("yyyy-MM-dd");
Note the use of Now.Date giving you the current date without a time component (new DateTime() will not compile, so I don't really know where you got that piece of code from).

Categories