Hello I am currently trying to array.find all the dates before the current date. I have tried both using the datetime.now as well as creating a seperate variable for current date in my struct but i keep getting "Cannot implicitly convert type 'Assignment_3.Program.Hire' to 'System.DateTime". I'm sure the solution is quite simple but as a novice it does escape from me. If you need any more of the code I will be happy to provide
struct Hire
{
public int CustomerNo;
public int DVDNo;
public DateTime HireDate;
public int NoNights;
public DateTime CurrentDate = DateTime.Now;
}
DateTime result = Array.Find(hiredetails, Hire => Hire.HireDate <= Hire.CurrentDate);
Array.Find<T> returns the element matching the criteria. In you case since it is an array of Hire type, it will return element of type Hire, which you cannot assign to DateTime. You can do:
List<DateTime> allDates = hiredetails.Where(hire=> hire.HireDate <= hire.CurrentDate)
.Select(r=> r.HireDate)
.ToList();
You can also return IEnumerable<DateTime> and exclude ToList() from the above statement.
Not really sure if you need this but instead of keeping the current date inside the object you can have that in your local variable and pass that in your query like:
DateTime currentDate = DateTime.Now;
List<DateTime> allDates = hiredetails.Where(hire=> hire.HireDate <= currentDate)
.Select(r=> r.HireDate)
.ToList();
Do not store current date in a structure, use local variable instead, solution would look like:
var currentDate = DateTime.Now;
var result = hiredetails.Select(h => h.HireDate).Where(d => d <= currentDate);
Related
I am a beginner in c # and I can not find the solution for my problem.
I am creating a personal project that allows me to send reminders, I have a date list and I need to do tasks between two specific dates in real life.
I found how to get the next date from today's date but I can't find how to get the previous one
Here is my sample code
void calc_x_date()
{
List<string> x_dates = new List<string>();
x_dates.Add("10/01/2017");
x_dates.Add("14/02/2017");
x_dates.Add("14/03/2017");
x_dates.Add("11/04/2017");
x_dates.Add("09/05/2017");
x_dates.Add("13/06/2017");
x_dates.Add("04/07/2017");
x_dates.Add("08/08/2017");
x_dates.Add("12/09/2017");
x_dates.Add("10/10/2017");
x_dates.Add("14/11/2017");
x_dates.Add("12/12/2017");
var allDates = x_dates.Select(DateTime.Parse).OrderBy(d => d).ToList();
var todayDate = DateTime.Today;
var nextDate = todayDate >= allDates.Last()
? allDates.Last()
: todayDate <= allDates.First()
? allDates.First()
: allDates.First(d => d >= todayDate);
string NextDate = nextDate.ToString(); // the closest next date from today
//string PreviousDate = // the closest previous date from today
}
Could someone explain me how to find my previous date please ?
Thanks in advance
I'd suggest using List<T>.BinarySearch: that will find the index of the date. If the index is 0 or more, then the exact date was found. If it's negative, then taking ~index will get you the index where the date would have been inserted.
Once you've got that information, it's easy to find the value at the previous index or the next index - but you should consider all the cases of:
Today is before all dates
Today is after all dates
Today is a date between the first and last date in the list, but isn't in the list
Today is equal to the first date
Today is equal to the last date
Today is equal to a date in the list which isn't the first or last date
As asides:
I would strongly encourage you to get in the habit of following .NET naming conventions as early as possible
I'd encourage you not to use strings to represent dates unless you really need to
If you're doing a lot of date/time work, you may find my Noda Time library easier to use correctly than DateTime
Here is a Linq approach
List<string> x_dates = new List<string>();
x_dates.Add("10/01/2017");
x_dates.Add("14/02/2017");
x_dates.Add("14/03/2017");
x_dates.Add("11/04/2017");
x_dates.Add("09/05/2017");
x_dates.Add("13/06/2017");
x_dates.Add("04/07/2017");
x_dates.Add("08/08/2017");
x_dates.Add("12/09/2017");
x_dates.Add("10/10/2017");
x_dates.Add("14/11/2017");
x_dates.Add("12/12/2017");
DateTime today = DateTime.Today;
IEnumerable<DateTime> dt_dates = x_dates.Select(DateTime.Parse);
DateTime prev = dt_dates.Where(x => x < today)
.OrderByDescending(x => x)
.First();
DateTime next = dt_dates.Where(x => x > today)
.OrderBy(x => x)
.First();
alternative solution
DateTime prev = dt_dates.Where(x => x < today).Max();
DateTime next = dt_dates.Where(x => x > today).Min();
Storing dates in string format works. It is however incredibly difficult to do date comparisons. You have to first cast it to numbers, handle the exceptions, etc.
C# has a DateTime object. You can store dates in this and ignore the time. DateTime objects can be compared using the < and > operators.
If you create a class with a start date and an end date, store these objects in a list(of tasks), would that solve your problem? You can also add a text of the task in a string to said object.
I would like to get dates between two dates. Instead of expected 9 different dates, I get 875287 and run out of memory. What would be the problem with the code below?
StartDate value is 01/04/2016 00:00:00
EndDate value is 10/04/2016 00:00:00
var selectedDates = new List<DateTime?>();
for (var date = StartDate; date <= EndDate; date.Value.AddDays(1))
{
selectedDates.Add(date);
}
You aren't assigning the value of date.Value.AddDays(1) to anything, so it ends up in an infinite loop. You'd need to change your code so that date is set to the result of AddDays.
for (var date = StartDate; date <= EndDate; date = date.AddDays(1))
{
selectedDates.Add(date);
}
LINQ solution (let's generate selectedDates):
var selectedDates = Enumerable
.Range(0, int.MaxValue)
.Select(index => new DateTime?(StartDate.AddDays(index)))
.TakeWhile(date => date <= EndDate)
.ToList();
As far as I can see, since AddDays method returns a new instance of a DateTime, it does not change the current instance since DateTime is immutable.
Looks like your date is DateTime?, you can change this part as;
for (var date = StartDate; date <= EndDate; date = date.Value.AddDays(1))
{
selectedDates.Add(date);
}
As usr pointed, this might be affected on DST. You might wanna check Dmitry's answer as well.
A shorter notation using Linq's Range method uses the ability to already figure out the number of days using the TimeSpan.Days property after subtracting start from end.
Assuming the start is before end you'd end up with:
DateTime StartDate = new DateTime(1979, 10, 4);
DateTime EndDate = new DateTime(2016, 10, 4);
var dates = Enumerable.Range(0, (EndDate - StartDate).Days + 1)
.Select(day => StartDate.AddDays(day))
If you need it to be Nullable, add:
.Cast<DateTime?>()
If you need this to be a List, add:
.ToList()
It's probably quite a bit more efficient than the other LINQ based solution.
Decided to change it up with a do/while
var selectedDates = new List<DateTime?>();
DateTime? StartDate = DateTime.Parse("01/04/2016 00:00:00");
DateTime? EndDate = DateTime.Parse("10/04/2016 00:00:00");
do
{
selectedDates.Add(StartDate);
StartDate = StartDate.Value.AddDays(1);
}while(StartDate < EndDate);
The user enters two parameters in the url which are the start date and end date and they are entered in the format yyyyMMddhhmm as a string. I'm attempting to take these strings and turn them into dates so I can query my database.
[ResponseType(typeof(Detail))]
public IHttpActionResult GetDetail(string StartDate, string EndDate)
{
DateTime StartDateTime;
DateTime EndDateTime;
StartDateTime = new DateTime();
EndDateTime = new DateTime();
StartDateTime = DateTime.ParseExact(StartDate, "yyyyMMddhhmm", null);
EndDateTime = DateTime.ParseExact(EndDate, "yyyyMMddhhmm", null);
var detail = from a in db.Details where (a.callDate >= StartDateTime && a.callDate <= EndDateTime) select a;
var Response = new DetailResponse() { status = true, calls = detail };
return Ok(response);
}
However I get the error that >= can't be used in datetime and strings.
EDIT:
For the sake of one of the answer I'm including a model class I'm using to display the data.
DetailResponse.cs
public class DetailResponse
{
public bool status { get; set; }
public string statusMessage { get; set; }
public IQueryable<Detail> calls { get; set; }
}
Probably this is happening, because callDate is a string. So you can't compare a string with a datetime. The solution to this problem is to have the same type. That being said I would convert a.callDate to a DateTime.
However, I think that it would be better you change the data type of callDate in the database level. Undoubtedly, this is a personal opinion. So you don't have to follow it. Doing so your code will not need any change.
Now, in terms of code the solution I suggested above is the following:
var allDetails = db.Details.AsEnumerable();
var details = from detail in details
let callDate = DateTime.ParseExact(detail.callDate, "yyyyMMddhhmm", null)
where callDate >= StartDateTime
&& callDate <= EndDateTime
select detail;
Update
As we concluded in comments, we had to call the AsEnumerable, in order the above query to work. Why is this needed?
Borrowing Jon Skeet's words from Reimplementing Linq to Objects: Part 36 – AsEnumerable
Now it’s not entirely uncommon to want to perform some aspects of the
query in the database, and then a bit more manipulation in .NET –
particularly if there are aspects you basically can’t implement in
LINQ to SQL (or whatever provider you’re using). For example, you may
want to build a particular in-memory representation which isn’t really
amenable to the provider’s model.
The DateTime.ParseExact cannot be translated properly in a database method.
Your comparison is failing because the date in your database is of type string, try doing like this:
[ResponseType(typeof(Detail))]
public IHttpActionResult GetDetail(string StartDate, string EndDate)
{
DateTime StartDateTime = DateTime.ParseExact(StartDate, "yyyyMMddhhmm", null);
DateTime EndDateTime = DateTime.ParseExact(EndDate, "yyyyMMddhhmm", null);
var detail = from a in db.Details where (DateTime.ParseExact(a.callDate, "yyyyMMddhhmm", null) >= StartDateTime &&
DateTime.ParseExact(a.callDate, "yyyyMMddhhmm", null) <= EndDateTime) select a;
}
However you are probably best off chaning the type of your callDate to a date instead of a string.
What does your schema look like? is callDate a string? you may need to convert callDate to a DateTime before you can do the comparison.
var detail = from a in db.Details where (Convert.ToDateTime(a.callDate) >= StartDateTime && Convert.ToDateTime(a.callDate) <= EndDateTime) select a;
As has already been said, you can't compare a string to a DateTime, however, given that the date format is
yyyyMMddhhmm
(ie. year month day hour minute) where the values are all numeric and go from least varying -> most varying you will be safe doing a string comparison:
var detail = from a in db.Details where (a.callDate >= StartDate && a.callDate <= EndDate) select a;
This is because "201601010101" is less than "201612312359" when comparing strings (in the same way that "a" is less than "b").
This will save you converting the data to DateTime.
Having said that, by doing the conversion you are validating the data and can show an error if it's not in the right format.
I have two textboxes and a button, both textbox have calender attach to them. I want to store the dates which are between the first textbox and second textbox in a list, I am invoking following method on button click.
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> datelist = new List<DateTime>();
for (StartDate = Convert.ToDateTime(txtFromDate.Text); StartDate < Convert.ToDateTime(txtTillDate.Text); StartDate.AddDays(1))
{
datelist.Add(StartDate);
}
}
But I am getting error after storing the first date in the list: Exception of type 'System.OutOfMemoryException' was thrown.
I think my loop is running endlessly, any help will be appreciated.
DateTime.AddDays() does not change the datetime you must assign its return value. Like
StartDate = StartDate.AddDays(1)
It is indeed an infinite loop. You're stating that if the start date is less than the end date, add start date to the list. It'll keep doing this for infinity as start date should always (in theory) be less than the end date. The add days function isn't assigned to a variable so it never gets added to the start date.
Also another piece of advice with .Net datetime is to use the in-built compare function.
DateTime Compare function
Hope that helps!
Try this:
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> dateList = new List<DateTime>();
DateTime currentDate = StartDate;
while(currentDate <= EndDate)
{
dateList.Add(currentDate);
currentDate.AddDays(1);
}
}
use this
for (int i =0; i<(EndDate-StartDate).Days; i++)
{
datelist.Add(StartDate.AddDays(i));
}
you might want to try linq:
Enumerable.Range(0, (int)endDate.Subtract(startDate).TotalDays)
.Select(d => startDate.AddDays(d))
.ToList()
DateTime.ToLocalTime is not supported in Linq to EF.
What's the alternative? I am running out of idea.
Instead of using .ToLocalTime() inside your Linq query, use the opposite conversion outside of the query on the parameters.
var dateUniversal = dateParam.ToUniversalTime();
var query = myTable.Where( t => t.DateTime > dateUniversal );
I used a combination of Extensions plus relying on the value passed from the front-end of my app to be in LocalTime. So, If I had two date times.. like.. a start date and end date parameter for a report, I'd put them up there.. let the user submit in LocalTime.. then on the back end part of my Controller.. I'd use the sdate and edate variables in my Linq to Entities Query. The static extension methods I threw into a static helper class. Sorry that I'm over a year late. : )
DateTime sdate = CalcHelper.AbsoluteStart(model.StartDate);
DateTime edate = CalcHelper.AbsoluteEnd(model.EndDate);
public static DateTime AbsoluteStart(this DateTime dateTime)
{
return dateTime.Date.ToUniversalTime();
}
public static DateTime AbsoluteEnd(this DateTime dateTime)
{
return AbsoluteStart(dateTime).AddDays(1).AddTicks(-1).ToUniversalTime();
}
if you get the timezone offset from the server you might be able to use EntityFunctions to apply the offset in your linq query
var offset = TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes;
var result = db.Dates.Where(a =>
EntityFunctions.DiffDays(EntityFunctions.AddMinutes(a.Date, offset), DateTime.Now) == 0);
You can try like this:
var promotions = _promotionService.GetAll(
x => (DbFunctions.TruncateTime(x.CreatedDate.Value) >= viewModel.GTXFromDate.Date)
&& (DbFunctions.TruncateTime(x.CreatedDate.Value) <= viewModel.GTXToDate.Date));
As a rule, you should store dates and times in UTC in your database.
Convert any local date/times to UTC in your code before you store them in the database.
Similarly, if you need to show local time from the UTC in the database, then convert it in code after the database fetch.
Convert DateTime to String for comparison, for example:
const string DATE_FORMAT = "yyyy/MM/dd";
var query = sampleTable.Where(x => x.DateTime.ToString(DATE_FORMAT) > DateTime.Now.ToString(DATE_FORMAT));
Found the solution on this question
public partial class Person {
partial void OnLoaded() {
this._BirthDate = DateTime.SpecifyKind(this._BirthDate, DateTimeKind.Utc);
}
}