Select entity using between two offset times - spring

In my entity I have two values openTime and closeTime both of the type OffsetTime, now I want to retrieve the entity where the current time is between the openTime and closeTime, but the problem I now have what if openTime = '23:00:00' and closeTime = '05:00:00', meaning that the entity is open at evening and during night.
I have the following query:
SELECT s FROM ShopArticle s LEFT JOIN FETCH s.openTimes t WHERE t.openTime < :time AND t.day = :day`
where :time is of type OffsetTime and :day of type DayOfWeek. I can't change openTime to DateTime or sth else, so how do I do this?

Without the over-night problem the important part of the where clause should look like this
WHERE t.openTime <= :time
AND :time <= t.closeTime
With the over-night issue you'd need something like
WHERE (
t.openTime <= :time
AND :time <= t.closeTime
AND t.day = :day
)
OR (
(
(t.openTime <= :time AND t.day = :day)
OR
(:time <= t.closeTime AND t.day = :day -1)
)
AND t.openTime > t.closeTime
)
You can't do date calculations in JPQL though, so :day -1 won't work.
Since you seem to use Spring Data JPA, you can solve that problem with a SpEL expression. How to do that exactly depends on how you pass :day to the query. If it is actually a date-like value, this question and it's answers might be helpful: How do I do date manipulation in SpEL?
Unfortunately JPQL doesn't really have ways to do date calculations, which would come in handy, because you'd have to do something like this:

Related

How can I dynamically filter for dates using mongodb?

I have the following in postgresql:
where("booking.started_at + (interval '1 min' * booking.duration) <= ?", Time.zone.now)
However, I don't know how to express it in mongo. I've seen some posts suggesting to use date ranges, something like:
db.bookings.find({"started_at": {"$gte": started_at_value, "$lt": ?}})
Basically, I'd like to find all the bookings that are started, this means (pseudocode) : started_at <= current_time <= started_at + duration . I don't know how to specify the end range of the query. Any pointers?

Linq DateTime comparison not working

I have the following code:
DateTime timeStamp = Convert.ToDateTime(Request.QueryString["TimeStamp"]);
var result = (from rs in db.VRec
where
rs.TimeStamp == timeStamp &&
rs.Fixure == wFixture
select rs).ToList();
The result shows 0 even though the correct timeStamp is passed.
If I remove the part where I do the TimeStamp comparison:
rs.TimeStamp == timeStamp
The code works fine.
Any idea on why the datetime comparison may not be working?
DateTime has a pretty fine resolution - likely you are comparing timestamps that only differ in milliseconds, which will fail. You probably want something like:
DateTime now = DateTime.Now;
DateTime then = now.Add(TimeSpan.FromMilliseconds(1));
const int EPSILON_MS = 10;
if(now.Subtract(then).TotalMilliseconds < EPSILON_MS)
{
Console.WriteLine("More or less equal!");
}
Linq converts DateTime arguments to DateTime2 in the sql query executed.
That is, when you do the comparison the actual sql executed will compare a DateTime to a DateTime2. This comparison will "cast" the DateTime to a DateTime2 and the millisecond part will be expanded to a greater resolution (in an odd way in my opinion, please enlighten me).
Try to execute the following sql:
declare #d1 datetime = '2016-08-24 06:53:01.383'
declare #d2 datetime2 = '2016-08-24 06:53:01.383'
declare #d3 datetime2 = #d1
select #d1 as 'd1', #d2 'd2', #d3 'converted'
select (case when (#d1 = #d2) then 'True' else 'False' end) as 'Equal',
(case when (#d1 > #d2) then 'True' else 'False' end) as 'd1 greatest'
From the question, I do not know if you want to compare the date with time or only the date part. If you only want to compare date then following would work
var result = (from rs in db.VRec
where
rs.TimeStamp.Date == timeStamp.Date &&
rs.Fixure == wFixture
select rs).ToList();
Since you are using some reference to db, it gives me a feeling that you are fetching your records from database (which ORM you are using is not obvious from the question or tags). Assuming that you are using Entity framework the above query will fail with exception that .Date has no direct translation to sql. If so you can rewrite the query as following to make it work.
var result = (from rs in db.VRec
where
rs.TimeStamp.Day == timeStamp.Day &&
rs.TimeStamp.Month == timeStamp.Month &&
rs.TimeStamp.Year == timeStamp.Year &&
rs.Fixure == wFixture
select rs).ToList();
The benefit of this approach is that you can compare properties to arbitrary deep level i.e you can compare Hours, Minutes,Seconds etc. in your query. The second query is tested in Entity framework 5.

Linq - Getting calendar events that have Start and Length properties

My application has a built-in calendaring system and the database schema for them looks like this:
CalendarItem( CalendarItemId bigint, Start datetime, Length int, Blargh nvarchar(MAX) )
Start is the UTC datetime value when the event starts, and Length is the length of the event in seconds. An all-day event starts at 0000h and has a length of 86400.
I'm using Linq with Entity Framework, and I want to find events that fall within a date range. It's easy to find events that start between two datetimes, but I don't know how to find events that also end between two datetimes.
Here's my current code:
public IEnumerable<CalendarItem> GetCalendarItems(DateTime from, DateTime to) {
var events = from c in db.CalendarItems
where c.Start >= from && c.Start <= to
orderby c.Start
select c;
return events;
}
If I were using T-SQL, I would need to use DATEADD to add Length seconds to Start to give an End datetime, which would then work, but I don't think I can do this in Linq. What can I do?
EDITED with ToList() function included:
If I'm reading this correctly, you would want:
var events = (from c in db.CalendarItems
where c.Start >= from && c.Start <= to
orderby c.Start
select c).ToList();
events = events.Where(e => e.Start.AddSeconds(Length) <= to);
return events;
This will then give you the events that started and ended during the specified date range.
For more information about DateTime.AddSeconds(), just visit this link.
You will need to call ToList() first before you can use the DateTime.AddSeconds function. Otherwise the compiler will complain that it cannot find the AddSeconds function since your LINQ queries will be translated to SQL and SQL does not contain this DateTime.AddSeconds function.
var events = (from c in db.CalendarItems
where c.Start >= from && c.Start <= to
orderby c.Start
select c).ToList();
events = events.Where(e => e.Start.AddSeconds(Length) <= to);
return events;
EDIT: Corrected my logic, the answer is now identical to IronMan84's.
I evaluated the .ToList approaches, but they're inefficient because after modifying it to return events that occur (regardless of whether or not they started or ended within) a time period it fetches many irrelevant results from the database.
I also looked at the SqlFunctions methods, but they aren't present in EF1.0.
I ended up using a Sproc with a strongly-typed import on my Entity Context. It's not perfect, but it's better than the alternatives.
When the project is upgraded to .NET4 eventually, I'll switch to SqlFunctions. Thanks for all of the advice anyway!

Date comparison in Rails 3.2

Stage:
I have this model:
Promo(id: integer, start_date: datetime, end_date: datetime)
I want to know which current promotions.
May be our query should be like:
SELECT * FROM promos WHERE now BETWEEN start_date AND end_date;
Question:
How should I make it in Ruby?
Which is the correct way?
Thank you.
Rails is intelligent. If you retrieve a date/time, it will converted to DateTime object.
On contrary, passing DateTime object to the where clause (for Rails 3.x), it will correctly build the where clause.
String passed to where clause will be passed to the SQL where clause. If you pass an array,
second and later elements will be replaced with '?' character in the first element.
So, for your case:
Promo.where(["? between start_date and end_date", DateTime.now])
works. I verified on my Rails model(Position) which happen to have start_date and end_date, and works correctly:
[1] pry(main)> Position.where(["? between start_date and end_date", DateTime.now]).count
=> 2914
It's on Rails 3.2.8 with PostgreSQL.
Yes, you can use comparison operators to compare dates e.g.:
irb(main):018:0> yesterday = Date.new(2009,6,13)
=> #<Date: 4909991/2,0,2299161>
irb(main):019:0> Date.today > yesterday
=> true
But are you trying to compare a date to a datetime?
If that's the case, you'll want to convert the datetime to a date then do the comparison.
or
Date.parse('2010-11-01') < Date.today
will return true if '2010-11-01' has already passed
I hope this helps.
Haven't tested this, but try something like:
currentTime = Time.now()
Promo.find(
:all,
:conditions => ['start_date < ? AND end_date > ?', currentTime, currentTime]
)
You might need to use the Date class if the Time class doesn't work

compare the dates with linq

I have this code:
i.SpesaVitto = db.TDP_NotaSpeseSezB.Where(p => p.GiornoFine == null &&
((DateTime)p.Giorno).Date == ((DateTime)i.Data).Date &&
p.MissioneID == missioneID).Sum(p => p.Costo);
If i launch it i obtain this error:
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
how can i compare the datetimes field without the hours part
thanks
Well this is certainly not the most efficient way to do it, but you can try something like:
i.SpesaVitto = db.TDP_NotaSpeseSezB.Where(p => p.GiornoFine == null &&
(new DateTime((p.Giorno as DateTime).Year, (p.Giorno as DateTime).Month, (p.Giorno as DateTime).Day) == (new DateTime((i.Data as DateTime).Year, (i.Data as DateTime).Month, (i.Data as DateTime).Day) &&
p.MissioneID == missioneID).Sum(p => p.Costo);
Depending on the requirements I would probably implement something cleaner and faster but it would depend on how the dates are stored in your database.
Check out this question it looks like the syntax error may be in your SQL, not in your LINQ. The asker in that question had written:
SQL ------
Select
EmployeeNameColumn
From
EmployeeTable
WHERE StartDateColumn.Date <= GETDATE() //Today
SQL ------
When they should have written:
SQL ------
Select
EmployeeNameColumn
From
EmployeeTable
WHERE StartDateColumn <= GETDATE() //Today
SQL -
solution for your problem will be the "SqlFunctions class and DateDiff" http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.aspx

Resources