I have a list of data that have datetimeoffset? as a column inside. I want to get specific data that has the month I want but don't know how. Below are those code I have tried.
This return me with error of No overload for method 'Tostring' which is weird since I can pass datetimeoffset? and use it in other function but if I do it directly inside where I get it, I can't use it.
int d = DateTime.Now.Month;
string f = d.ToString();
var s = _dbContext.Documents.FirstOrDefault(x => x.ApplyDate.ToString("MM") == f);
return Json(s);
This return null
int d = DateTime.Now.Month;
string f = d.ToString();
var s = _dbContext.Documents.FirstOrDefault(x => x.ApplyDate.Value.ToString("MM") == f);
return Json(s);
You can retrieve the month of a nullable datetimeoffset like this:
DateTimeOffset? dt;
dt?.Value.Month;
However, I really wonder if EF will be able to translate this:
x => x.ApplyDate?.Month == f
into a SQL expression. I presume that it will fallback to in-memory filtering.
Next to that, even if EF is able to translate this into a SQL expression, it won't be optimal as indexes that might be defined on that column will not be used.
Therefore, I'd suggest to rewrite your LINQ expression to something like this:
x :> x.ApplyDate != null && x.ApplyDate >= new DateTimeOffset(someDate.Year, someDate.Month, 1) && x.ApplyDate <= new DateTimeOffset(someDate.Year, someDate.Month, daysInMonth)
(Given you want to retrieve the data that belong to a specific month in a specific year. If you want to retrieve records that belong to a certain month, regardless the year, I see no other option)
DateTimeOffset? is Nullable type therefore is has no overload of ToString(string format) like DateTimeOffset has.
to get get the month value from your DateTimeOffset? you can
x.ApplyDate.Value.ToString("MM")
x.ApplyDate.Value.Month
please consider that you might want to check if ApplyDate.Value is null before obtaining its Month property
Your code above shows DateTime, not DateTimeOffSet.
DateTimeOffSet is Struct, and if you have a nullable value, you need to check the value first and then get the month from the value part
DateTimeOffSet myNullableDateTime = someValue...//
Option 1:
// notice I added value below
myNullableDateTime.HasValue? "?Month="+myNullableDateTime.EscapeDataString(myNullableDateTime.Value.ToString()):"")
Option 2:
if(myNullableDateTime.HasValue)
{
var Month = myNullableDateTime.Month
TimeSpan difference = DateTimeOffset.Now.Subtract(myNullableDateTime.Value);
// convert the difference to what you need and get Month
}
I have not compiled it, but it should get you the answer or pretty close.
Related
I am using the method below to find a list of objects (from a sharepoint list) between a date range using a LINQ query. It is working fine but takes a lot of time, can it be optimized?
public System.Collections.Generic.List<ItineraryModel> FilterDashboard(string StartDate, string EndDate ,ClientContext clientContext, SharePointContext spContext)
{
var src = this.SpHelper.getAllListData(clientContext).ToList<ItineraryModel>();
System.Collections.Generic.List<ItineraryModel> source2 = src.Where(delegate (ItineraryModel x)
{
if (!(System.Convert.ToDateTime(x.StartDate).Date > System.Convert.ToDateTime(EndDate).Date))
{
return !(System.Convert.ToDateTime(x.EndDate).Date < System.Convert.ToDateTime(StartDate).Date);
}
return false;
}).ToList<ItineraryModel>();
return source2.Distinct<ItineraryModel>().ToList<ItineraryModel>();
}
If src has 1000 elements, how many times will you convert StartDate from string to a DateTime. Wouldn't it be more efficient if you would only do this once?
Furthermore, you return a List. Are you sure that all your callers will need the complete list? Could it be that some callers only want to know whether there are any elements? of maybe they want only the first element, or do first 24 elements to display on a screen. In other words: wouldn't it be more efficient to return an IEnumerable instead of a List.
If you create a LINQ like function, always consider to return an IEnumerable instead of a List, especially if you don't need the List to create your function.
Now you forgot to tell us the return value of GetAllListData.But let's assume that GetAllListData returns an IEnumerable sequence of ItenaryModels.
Apparently every ItenaryModel has at least a StartDate and an EndDate. You don't want all ItenaryModels, you only want those ItenaryModels that started in the interval of input parameters startDate and endDate, or in other words where property StartDate >= input parameter startDate and property EndDate <= input parameter endDate.
IEnumerable<ItenaryModel> FilterDashboard(string textStartDate, string textEndDate, ...)
{
// TODO: check for non-null textStartDate, textEndDate
// convert the input dates to DateTime:
DateTime startDate = DateTime.Parse(textStartDate);
DateTime endDate = Datetime.Parse(textEndDate);
// TODO: decide what to do if dates can't be parsed
// TODO: decide what to do if startDate > endDate?
IEnumerable<ItenaryModel> itenaryModels = this.SpHelper.getAllListData(clientContext);
// the easiest is a foreach, alternatively use a LINQ where.
foreach (var itenaryModel in itenaryModels)
{
DateTime itenaryStartDate = DateTime.Parse(itenaryModel.StartDate.Date);
DateTime itenaryEndDate = DateTime.Parse(itenaryMode.EndDate.Date);
// TODO: decide what to do if can't be parsed
if (startDate <= itenaryStartDate && itenaryEndDate <= endDate)
{
// put this itenaryModel in the returned enumeration
yield return itenaryModel;
}
}
}
Alternatively you could use a LINQ where. This is not faster!
DateTime startDate = DateTime.Parse(textStartDate);
DateTime endDate = Datetime.Parse(textEndDate);
IEnumerable<ItenaryModel> itenaryModels = this.SpHelper.getAllListData(clientContext);
return itenaryModels.Where(itenaryModel =>
startDate <= DateTime.Parse(itenaryModel.StartDate.Date) &&
DateTime.Parse(itenaryModel.EndDate.Date) <= endDate);
You are loading the list items into the memory as a whole, then search for it. #Harald Coppoolse has given all possible answers about LINQ.
As an alternative approach, you can utilize CAML queries for that. You are using SPHelper whose internals are alien to me. But you can use old school SharePoint CAML queries for performance.
I have a date value that I want to strip the time from. I want the return type to be a date type since I want to order the list of date I have. having a list to string representing Date does not return a correct order.
I know that DateTime always returns the date with the time. What are my options here? How can I better my code and have a list of items of Date type without the time?
Edit: I would like to have the date only. nothing after that. Something like 8/7/2016 not 8/7/2016 00:00:00 or anything after date. and in a date object.
Here is my code:
using (var db = new MyModel.Context())
{
var cert = (
from tr in db.uspTranscripts(personId)
from a in db.PersonTranscripts.Where(x => x.UPID == personId)
from b in db.LU_CreditType.Where(x => x.ID == a.CreditTypeID)
select new CertViewModel
{
ActivityTitle = tr.ActivityTitle,
Score = tr.Score,
Status = tr.Status,
CompletionDate = tr.CompletionDate,
CretitTypeName = b.ShortName,
CompletedDateSorted = a.HK_CreatedOn
}).OrderByDescending(x => x.CompletedDateSorted).ToList();
List<CertViewModel> certlist = cert;
foreach (var item in certlist)
{
string itemWithoutHour = item.CompletionDate.Value.ToShortDateString();
var itemConverted = DateTime.ParseExact(itemWithoutHour, "M/d/yyyy", null);
item.CompletionDate = itemConverted;
}
return certificateslist.GroupBy(x => x.ActivityTitle).Select(e => e.First()).ToList();
}
For any given DateTime object, you can reference its Date property to strip out the time values:
var withTime = DateTime.Now; // 8/7/2016 22:11:43
var withoutTime = withTime.Date; // 8/7/2016 00:00:00
The .NET framework does not have a date-only object.
It may be worth understanding how the DateTime structure works. Internally, it stores an offset in ticks (1 tick = 100 nanoseconds) since 1/01/0001 12:00 am in a single 64-bit unsigned integer. (1 tick = 100 nanoseconds)
The DateTime structure then provides many useful methods and properties for dealing with dates and times, such as adding some days to an existing date, or calculating the difference of two times. One useful property is Date, which rounds a DateTime object down to the nearest day (12:00 am).
Dates, times and dates-with-times are all very similar, the main difference is how you format them, a date-with-time where you omit the time is just a date.
What David has suggested is that you work with the DateTime structure internally, strip any times using the Date property, sort on the DateTime, compare them and modify them as DateTime objects.
Only convert them to a string when they need to be displayed, at which point you can use methods such as ToShortDateString() or ToString(string format) to display only the date.
I need to filter my nullable datetime by day month and year.
I currently trying to do it by using string comparisons. I have this in where statement in linq:
DOB.ToString().StartsWith("2/25/19") || DOB == null
But its not working. I know its because the server doesnt store the date like that, but Im unsure as to how it is storing it, and how can I retrieve it and do the comparison.
I REALLY need this to happen on the database. I cant get everything and filter in the server.
I just want linq to filter dates by day, month, and year
Any help or pointers are appreciated.
You could try something like this (updated to include optional date components):
int? month = 2;
int? day = 25;
int? century = 19; // actual century minus one
// other LINQ here
.Where(x => x.DOB == null
|| ((month == null || x.DOB.Month = month)
&& (day == null || x.DOB.Day = day)
&& (century == null || x.DOB.Year / 100 == century)));
try this:
context.Entities.Where(e => e.Date != null && e.Date.Day == 15)
you can use DateTime.Day, DateTime.Month, DateTime.Year and the logical operators && and || to filter as you see fit. You must however check for nullity first or you may end up with NullExceptions
If you want to filter by day, month, year, use the example code below:
DateTime dateTime = DateTime.Now;
Console.WriteLine(dateTime.Day);
Console.WriteLine(dateTime.Month);
Console.WriteLine(dateTime.Year);
You can get those value from DateTime object. Then, you can apply filter on it.
After reading the comment, I got your point.
For example, you enter a string like this:
string search = "2/25/2015";
Now, you want to extract the value of the string to perform filter, right? Simply do:
string[] values = search.Split('/');
Then, the values would be [2, 25, 2015]. First element is month, second is day, third is year, that depends on how you define the format.
I would like to query the db for items with a date greater than or equal to a given date.
The date in the db is a datetime and records time.
If the user enters the search string "1/30/2014", they expect entries that occurred at any time on that date to be returned. However, anything that has a time after 12 am is not returned.
I know I could simply add a day to the search string, but is there a more appropriate way?
if (form["closedend"] != "")
{
DateTime d = DateTime.Parse(form["closedend"]);
traces = traces.Where(s => s.date_Closed >= d);
}
You can use the Date property to truncate the time part:
traces = traces.Where(s => s.date_Closed.Date <= d.Date);
On this way you'd include this day since both DateTimes are midnight.
Update if you use LINQ to Entities DateTime.Date is not supported, you could use this solution: Using DateTime in LINQ to Entities
.Where(s => EntityFunctions.TruncateTime(s.date_Closed) <= EntityFunctions.TruncateTime(d))
You said
with a date greater than or equal to a given date
but in your code you write
s.date_Closed <= d
I think you must change <= by >= to obtain dates greater or equal to d, now you're getting dates less or equal to d.
For this example you don't need neccessary any other dll. You can implement other function, which return bool, f.e:
public bool MyFunction(DateTime s)
{
DateTime d = DateTime.Parse(Your constructor);
return (s.date_Closed >= d);
}
var query = from obj in traces
where MyFunction(obj.date_Closed.Date)
select obj;
or:
var query = traces.Where(p => MyFunction(p.data_Closed.Date));
You can use DbFunctions.TruncateTime(StartDateTime) To remove the time from datetime.
if (form["closedend"] != "")
{
DateTime d = DateTime.Parse(form["closedend"]);
traces = traces.Where(s => DbFunctions.TruncateTime(s.date_Closed) >= DbFunctions.TruncateTime(d));
}
I have a table with a couple of columns called Key and Value.
One of the Keys is called RequestedOn and the value is a timestamp saved as a string.
Now in my linq query I would like to compare this timestamp, for example
var startDate = DateTime.Now.AddDays(-7);
var endDate = DateTime.Now;
var query = (from ep in db.ExtendedProperties
where
ep.Key == "RequestedOn" && ep.Value >= startDate && ep.Value <= endDate
select ep).ToList();
Now I know I cannot compare ep.Value (string) against startDate or endDate, and I cannot convert ep.Value to a DateTime as it couldn't make sense. Any ideas on a solution?
Thanks in advance?
if its saved as string you must parse it to DateTime and then compare
You can either:
Convert the DateTime to string
Convert the string to DateTime
Write a method that compares the 2 directly
Something else
Using LINQ for something that does not have a type and contains different data is not a good option. The whole point of LINQ is to have types.
That being said one solution to your problem is to save the date in a format that is comparable as string such as 201405231801 (being 23.05.2014 18:01) and just compare strings.
Of course you care about timezones and daylight saving time you are guaranteed to get it wrong.
If you save your strings right you can actually do a comparison:
For example: '20131201125959': year, month, date, hours, minutes, seconds.