Cómo realizar operaciones de fecha en hibernación
Pregunta
Quiero realizar operaciones de tiempo de datos usando HQL hibernate.
Quiero sumar y restar dos fechas, así como restar 1 año o 1 mes de una fecha en particular.
¿Cómo es esto posible usando HQL en hibernación?
Solución
Ver ¿Realizando matemáticas de fecha / hora en HQL? por ejemplo.
Para usar sql personalizado, debe escribir un dialecto de hibernación propio y registrarse:
registerFunction("weekday",
new SQLFunctionTemplate(Hibernate.INTEGER, "to_char(?1,'D')") );
Otros consejos
Necesitas crear tu propio dialecto. Algo así como lo siguiente:
public class MyDialect extends MySQLInnoDBDialect{
public myDialect() {
super();
registerFunction("date_add_interval", new SQLFunctionTemplate(Hibernate.DATE, "date_add(?1, INTERVAL ?2 ?3)"));
}
}
En Hibernate / MySQL (al menos) Puede convertir ay desde una marca de tiempo Unix. Como la marca de tiempo de Unix es un número entero, puede agregarle un número entero de segundos.
FROM_UNIXTIME(UNIX_TIMESTAMP(date)+ (allowedTimeWindow*86400)) as deadline
Tiene limitaciones, pero es mucho más fácil que los enfoques anteriores.
Este es un problema abierto en Hibernate. A partir de Hibernate 3.3, no existe una forma estándar de manejar las comparaciones de fechas únicamente en HQL:
https://hibernate.atlassian.net/browse/HHH-2434
Hibernate 4.3 ofrece funciones para acceder a Fecha / Hora en HQL que son:
current_timestamp() , current_date() , current_time()
Las operaciones aritméticas pueden ser gestionadas por:
SECOND(...) , MINUTE(...) , HOUR(...) , DAY(...) , MONTH(...) , YEAR(...)
Descargo de responsabilidad: soy un novato en Java
Pude usar current_date() >= fromDate AND dateadd(day, -1, getdate()) <= toDate
en una declaración HQL contra un Sybase db en Hibernate 3.5.3, sin registrar ninguna función.
Muestra de uso de enfoque con dialecto para JPA + Hibernate 4.3.1 + MySQL 5
clase pública SampleMySQL5InnoDBDialect extiende org.hibernate.dialect.MySQL5InnoDBDialect {
public SampleMySQL5InnoDBDialect() {
super();
registerFunction("date_sub_days", new SQLFunctionTemplate(StandardBasicTypes.DATE, "date_sub(?1, interval ?2 day)"));
}
luego para su clase con anotación de mapeo:
@NamedQuery(name = "SampleEntity.getSampleEntitiesForGapOverlapCalculations", query = "from SampleEntity as se where "
+ "((se.toDate between :startDate and :endDate) or (date_sub_days(se.toDate, se.duration) between :startDate and :endDate)) order by se.toDate asc, se.duration desc")
SampleEntity tiene toDate campo de tipo java.sql.Date y duración campo entero (duración en días) y estamos calculando fromDate = toDate - duración y seleccionando todas las entidades que tienen fromDate o toDate dentro del intervalo [startDate, endDate] .
Hibernate4.3 proporciona funciones nativas para acceder a las fechas / marcas de tiempo y realizar operaciones aritmáticas en ellas
Aquí es el enlace a la documentación de qué expresiones se pueden usar en HQL. Pocos de los cuales estoy mencionando: Para acceder a la fecha / hora:
current_date(), current_time(), and current_timestamp()
Las operaciones aritméticas se pueden hacer siguiendo. Estas funciones toman el tiempo como entrada:
second(...), minute(...), hour(...), day(...), month(...), and year(...)
Uno puede obtener la diferencia absoluta de en HQL por
current_timestamp() - dateInstance
donde dateInstance puede tener definición
@Column(name = "updated_at")
@Temporal(TemporalType.TIMESTAMP)
private java.util.Date updatedAt;
El resultado es en 0.1 segundos. Entonces, para una diferencia absoluta de 1 segundo, la expresión anterior dará el resultado como 10.
Entonces una consulta se vería así:
select t from Table t where (current_timestamp() - updatedAt)>600
Usuarios de Postgres ...
registerFunction("dateadd", new SQLFunctionTemplate(StandardBasicTypes.DATE, "(?1 + INTERVAL ?2)"));
con uso de SQL como:
now() < dateadd(:mydate, '-1 day')