I have a IQueryable<Journey> that i collect from my entity model. I want to use this to get a new set of IQueryable<Journey> but only within a specific date interval from 2 textboxes on my webpage.
A Journey has Journey.DateFrom and Journey.DateTo which are strings ("YYYYMMDD").
I thought i would do something like this:
(journeys is IQueryable<Journey>)
if (tb_DateFrom.Text != ""){
journeys = from j in journeys
where Convert.ToInt32(j.DateTo) >= Convert.ToInt32(tb_DateFrom.Text)
select j;
}
if (tb_DateTo.Text != ""){
journeys = from j in journeys
where Convert.ToInt32(j.DateFrom) <= Convert.ToInt32(tb_DateTo.Text)
select j;
}
But i get error saying that linq doesnt know how to do Convert.ToInt32, neither does it know how to do int.parse or datetime.parse. What works is to use IEnumerable<Journey> instead of IQueryable<Journey> but that is so slow that the website crash since the data im comparing is quite huge.
How can i work this out, is the only answer to get the format in db to datetime?
Please help :)
I'd try this:
if (tb_DateFrom.Text != "") {
journeys = from j in journeys
where j.DateTo.CompareTo(tb_DateFrom.Text) >= 0
select j;
}
if (tb_DateTo.Text != "") {
journeys = from j in journeys
where j.DateFrom.CompareTo(tb_DateTo.Text) <= 0
select j;
}
Why don't you convert textbox values to datetime and then compare the dates in the where clause, instead of converting to int
DateTime? dateFrom = null, dateTo = null;
if(!String.IsNullOrWhiteSpace(tb_DateFrom.Text))
dateFrom = DateTime.ParseExact(tb_DateFrom.Text, "yyyyMMdd", null);
if (!String.IsNullOrWhiteSpace(tb_DateTo.Text))
dateTo = DateTime.ParseExact(tb_DateTo.Text, "yyyyMMdd", null);
if (dateFrom.HasValue)
journeys = journeys.Where(j => j.DateFrom >= dateFrom.Value);
if (dateTo.HasValue)
journeys = journeys.Where(j => j.DateTo <= dateTo.Value);
private DateTime getDate(string yyyyMmDd, DateTime defaultValue)
{
DateTime ret = DateTime.MinValue;
if (!DateTime.TryParse(yyyyMmDd, out ret))
return defaultValue;
return ret;
}
var to = DateTime.Parse(tb_DateTo.Text);
var from = DateTime.Parse(tb_DateFrom.Text);
journeys.Where(j=> getDate(j.DateFrom, DateTime.MaxValue) <= from && getDate(j.DateTo, DateTime.MinValue) >= to);
As the string format you have sorts in the same order as the dates they represent, I don't see why you have to convert their data format at all. Just do (untested):
journeys = from j in journeys
where j.DateTo >= tb_DateFrom.Text && j.DateFrom >= tb_DateTo.Text
select j;
Update, after Joakim's comment, still just using the sort order of the strings:
journeys = from j in journeys
where j.DateTo.CompareTo(tb_DateFrom.Text) >= 0 &&
j.DateFrom.CompareTo(tb_DateTo.Text) <= 0
select j;
(Det borde väl fungera, Joakim?)
Oops, I missed the accepted answer, but I'll still leave my first edit...
Related
I have a string which has short month name in it.\
string month = "Jun";
I need to get month in digit from this month name.
Say i do this:
int monthInDigit = getMonth(month);
monthInDigit <-- 6
How can i achieve this. If you cant get my question pleases comment i will explain it proprly.
Thanxx in advance
int monthInDigit = DateTime.ParseExact(month, "MMM", CultureInfo.InvariantCulture).Month;
You can parse it to a DateTime first:
DateTime dt = DateTime.ParseExact("Jun", "MMM", CultureInfo.InvariantCulture);
int month = dt.Month;
if(month < 6)
{
// do something...
}
another way :
string [] arr= {jun, fab,...};
public int getMonth(string month){
for(int i = 0 ; i< arr.length ; i++){
if(string[i].Contains(month) || month.Contains(arr[i]))
return i+1;
}
return -1;// if month is invalid , return -1
}
I have a function which takes two DateTime parameters and I have to add separate offsets to these date. I know that DateTime has a AddDays function to add days to a date and it throws an exception if DateTime is less than MinValue or greater than MaxValue.
Now I want to do a safe check whether adding/subtracting the following number of days to a DateTime can cause over/under flow or not.
safeStartDate = (startDate == DateTime.MinValue || startDate == DateTime.MaxValue) ? startDate : startDate.AddDays(startDateOffset);
safeEndDate = (endDate == DateTime.MaxValue || endDate == DateTime.MinValue) ? endDate : endDate.AddDays(enDateOffset);
By doing this, I am making it one level exception free but date can be DateTime.Max - 1 and while trying to add offset it throws an exception. I am looking a better way that whether the final values over/under flows without doing the actual calculation, in order to prevent exception.
If catch is not called very often you can do:
try
{
safeDate = dt.AddDays(days);
}
catch (ArgumentOutOfRangeException)
{
safeDate = date;
}
Alternatively,
var maxDays = (DateTime.MaxValue - dt).TotalDays;
safeDate = (days <= maxDays) ? dt.AddDays(days) : dt;
Or if there are negative days:
var maxDays = (DateTime.MaxValue - dt).TotalDays;
var minDays = (DateTime.MinValue - dt).TotalDays;
return (minDays <= days && days <= maxDays) ? dt.AddDays(days) : dt;
Or just use the method from Rawling's answer: CanAddDays(dt, days) ? dt.AddDays(days) : dt
The try/catch version is about 25% faster if you don't catch and about 1000x slower if you do. So, if you expected to catch more than about 1 time in every 5000 uses, then use the second version.
You can use the following to check whether you can add a given number of days to a given DateTime without causing an overflow:
bool CanAddDays(DateTime dt, int days)
{
double maxDaysToAdd = (DateTime.MaxValue - dt).TotalDays;
double minDaysToAdd = (DateTime.MinValue - dt).TotalDays;
return days <= maxDaysToAdd && days >= minDaysToAdd;
}
You might consider the following method:
private static DateTime AddDays(DateTime dateTime, int days)
{
var daysTimeSpanTicks = (new TimeSpan(days, 0, 0, 0)).Ticks;
return (days >= 0) ?
(DateTime.MaxValue.Ticks < dateTime.Ticks + daysTimeSpanTicks) ? dateTime : dateTime.AddDays(days) :
(dateTime.Ticks + daysTimeSpanTicks < 0) ? dateTime : dateTime.AddDays(days);
}
A sample usage is:
DateTime date = DateTime.MinValue;
DateTime safe = AddDays(date, -100);
I guess you are looking for something like this
DateTime Now = DateTime.Now;
DateTime Max = DateTime.MaxValue;
Max.Subtract(Now);
int DaysToAdd = 1000;//or something else
if (Max.Day > DaysToAdd) Now.AddDays(DaysToAdd);//add
can anyone help me with the formatting of the following?
if(system.datetime.now > 20:00:00 AND < 23:59:59)
NewDateTime = (system.datetime.now + 1 day) + time as 00:01:00
ie if the sysdate meets the criteria, make NewDateTime = Sysdate + 1 day, with the time as 00:01:00
thanks
You shouldn't be dealing with formatting at all here. I suspect you want something like:
TimeSpan earliest = new TimeSpan(20, 0, 0);
TimeSpan latest = new TimeSpan(23, 59, 59);
DateTime now = DateTime.Now;
TimeSpan currentTime = now.TimeOfDay;
if (currentTime > earliest && currentTime < latest)
{
DateTime newDateTime = now.Date.AddDays(1).AddHours(1);
}
One important point here is that I'm only taking DateTime.Now once, rather than every time we're interested in "the current time". That leads to better consistency.
I'd also question your "latest" part - do you really want the behaviour to be different at 23:59:59.5? Don't you really mean "any time after 8pm"? And possibly that should be inclusive, too? That would lead to:
// Probably make this a static readonly field
TimeSpan earliest = new TimeSpan(20, 0, 0);
DateTime now = DateTime.Now;
TimeSpan currentTime = now.TimeOfDay;
if (currentTime >= earliest)
{
DateTime newDateTime = now.Date.AddDays(1).AddHours(1);
}
DateTime now = DateTime.Now;
DateTime newDateTime;
if (now.Hours >= 20)
{
newDateTime = now.Date.AddDays(1).AddHours(1);
}
Roughly this is what I think you want:
CurrentTime=DateTime.Now;
if(CurrentTime.GetHour()>19)
{
NewDateTime=CurrentTime.AddDays(1);
NewDateTime.SetHour(1);
NewDateTime.SetMinute(0);
NewDateTime.SetSecond(0);
}
I think you can do that - if not you can calculate the time based on the current time
NewDateTime.AddHours(-CurrentTime.Hour-1)
NewDateTime.AddMinutes(-CurrentTime.Minute);
Your code is not valid in many aspects:
if(system.datetime.now > 20:00:00 AND < 23:59:59)
In C#, there is no "between" operator, so you need two comparisons plus the AND:
if(system.datetime.now > 20:00:00 AND system.datetime.now < 23:59:59)
It is && (for or, it is ||)
if(system.datetime.now > 20:00:00 && system.datetime.now < 23:59:59)
Note that && and || have short-circuit behaviour, that is, if the left operand of && if false, the right operand is not evaluated. Same for ||, except that if the left hand operand is true, the right hand operand is not evaluated.
C# does not have time literals. Now it depends on what exactly you want to compare. Do you intend to see whether it is 20 o'clock already? Then do (note that DateTime.Now also contains today's date, DateTime.Today is the beginning of the current day):
if(system.datetime.now > system.datetime.today.addHours (20)
&& system.datetime.now < system.datetime.today.addDays (1))
C# source code is case sensitive, so
if(System.DateTime.Now > System.Datetime.Today.AddHours (20)
&& System.DateTime.Now < System.DateTime.Today.AddDays (1))
You could also work with TimeSpans, which comes in handy when you also want to specify minutes and seconds (assume 20:15 for example):
if(System.DateTime.Now > System.Datetime.Today.Add (new TimeSpan(20,15,0))
&& System.DateTime.Now < System.DateTime.Today.AddDays (1))
I'd advise to use a named value, though:
var tomorrow = System.DateTime.Today.AddDays(1);
var quincyTime = today.Add (new TimeSpan (20,15,0));
if(System.DateTime.Now > quincyTime && System.DateTime.Now < tomorrow)
Further, which is important, Now gives you (roughly) the moment when you call it. So if you have multiple invocations of Now, store it so it doesn't change throughout the execution of your function:
var now = System.DateTime.Now;
var today = System.DateTime.Today;
var quincyTime = today.Add (new TimeSpan (20,15,0));
var tomorrow = today.AddDays(1);
if(now > quincyTime && now < tomorrow)
The observing reader might recognize that not even Today might be save if this program runs in a nuclear power plant at midnight. There is cure:
var now = System.DateTime.Now;
var today = now.Date;
Also note that the if-body is either a single statement, e.g.
if(now > quincyTime && now < tomorrow)
; // empty statement
if(now > quincyTime && now < tomorrow)
foobar();
or a whole "block":
if(now > quincyTime && now < tomorrow)
{
} // empty block
if(now > quincyTime && now < tomorrow)
{
foobar();
frob();
}
Btw, if you meant "at least"/"at max" instead of "later"/"sooner", use <= and >=:
if(now >= quincyTime && now <= tomorrow) {...}
how do I used date on searching using Linq. I think I'm missing something on the declaration
string searchName = Request.Form["PersonName"];
DateTime searchDateFrom = Request.Form["ReceivedDateFrom"];
DateTime searchDateTo = Request.Form["ReceivedDateTo"];
var Results = (from va in _db.myTable
where ((va.PersonName.Contains(searchName)
&& (va.ApplicationReceivedDate > searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo)
select va).ToList();
HttpRequest.Form is a NameValueCollection, where you can get strings in it by int/string indexer. That is, Request.Form["ReceivedDateFrom"] returns a string, you can't assign it to a variable whose type is DateTime without any convert. You can try DateTime.ParseExact method to convert the string to a DateTime. But if you can't guarantee the string has a correct format, you can use a TryParse method.
Might be a typo, but you need to cast searchDateFrom / searchDateTo to a DateTime and you have two extra open brackets in your linq statement
I'd also recommand using a cleaner indentation, it's easier to follow and count the brackets and stuff.
string searchName = Request.Form["PersonName"];
DateTime searchDateFrom = Request.Form["ReceivedDateFrom"];
DateTime searchDateTo = Request.Form["ReceivedDateTo"];
var Results = (from va in _db.myTable
where va.PersonName.Contains(searchName)
&& (va.ApplicationReceivedDate > searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo)
select va).ToList();
This is when I setup a unit test to see what's going on.
Check your brackets and casting from string to datetime:
[TestMethod]
public void TestMethod1()
{
List<myTable> myTables = new List<myTable>();
for (int month = 1; month < 10; month++)
{
for (int day = 1; day < 20; day++)
{
myTables.Add(new myTable { PersonName = "Person " + month.ToString() + " " + day.ToString(), ApplicationReceivedDate = new DateTime(2011, month, day) });
}
}
string searchName = "Person";
DateTime searchDateFrom = Convert.ToDateTime("2011-01-02");
DateTime searchDateTo = Convert.ToDateTime("2011-01-03");
var Results = (from va in myTables
where va.PersonName.Contains(searchName)
&& va.ApplicationReceivedDate >= searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo
select va);
Assert.AreEqual(Results.Count(), 1);
}
public class myTable
{
public string PersonName { get; set; }
public DateTime ApplicationReceivedDate { get; set; }
}
Also check the search from & to.
I have a date and I need to populate a drop-down with the months/years between that date and today. For instance, if that date is 10/14/2010 then the drop-down should contain October 2010, November 2010, December 2010, January 2011.
The way I'm thinking of doing this is to pass that date to a function, loop from today backwards step 1 month while adding each month to a collection until we reach that date and finally return a collection of strings. Then, populate the drop-down control on page load. Finally, use some ajax with a page method to parse back the string and trigger a partial page reload.
I'm just wondering if there's an easy way to do it.
Thanks.
Maybe you can try this:
static IEnumerable<DateTime> monthsBetween(DateTime startDate, DateTime endDate)
{
return Enumerable.Range(0, (endDate.Year - startDate.Year) * 12 + (endDate.Month - startDate.Month + 1))
.Select(m => new DateTime(startDate.Year, startDate.Month, 1).AddMonths(m));
}
This will not give you the result in the exact format that you want, but you get the drift. :)
You can do something like this which is pretty much what you described except counting forward:
private string[] FillDropDownWithDates(DateTime dt)
{
DateTime dtnow = DateTime.Now;
List<string> values = new List<string>();
if ( (dt <= dtnow))
{
values.Add(String.Format("{0:y}", dt));
}
while ( (dt = dt.AddMonths(1)) <= dtnow || ( dt.Month == dtnow.Month && dt.Year == dtnow.Year) )
{
values.Add(String.Format("{0:y}", dt)); // "March, 2008" YearMonth
}
return values.ToArray();
}
public static List<string> GetMonths(DateTime StartDate)
{
List<string> MonthList = new List<string>();
DateTime ThisMonth = DateTime.Now.Date;
while (ThisMonth.Date > StartDate.Date)
{
MonthList.Add(ThisMonth.ToString("MMMM") + " " + ThisMonth.Year.ToString());
ThisMonth = ThisMonth.AddMonths(-1);
}
return MonthList;
}
For Year,
public static IEnumerable<int> Range (int start, int count)
{
int end = start + count;
for (int i = start; i < end; i++)
yield return i;
}
var startYear = 2000;
YearDropDownList.ItemsSource= Enumerable.Range(startYear, 2050 - startYear + 1);
For Month,
An enumerable list with .ToString("MMMM") format.
This is how I got a 12 month/year. Hope the code helps.
public IEnumerable<SelectListItem> Additional12Months {
get
{
return Enumerable.Range(12, 12).Select(i => new SelectListItem { Value = DateTime.Now.AddMonths(-(i)).ToShortDateString(), Text = DateTime.Now.AddMonths(-(i)).ToString("MMM-yyyy") }).ToList();
}
}