Crudrepository How to find by last date between? - java

My domain has and Date field updated, that I want to search by
#Column(name = "updated")
Date updated;
I have a Java Date object representing a day, that's passed in by my endpoint's controller.
Date day;
and a crudrepository representing my data
public interface DataRepository extends CrudRepository<Data, Long> {
List<Data> findByLastUpdatedInDate(Date date);
}
Obviously the above method doesn't work, but is there something similar? Or am I going to have to do a find between then manually search for the last entry?
Edit: Here's how I get day; dateString is passed in by the controller.
SimpleDateFormat dateFormatIn = new SimpleDateFormat("yyyy-MM-dd");
Date day = dateFormatIn.parse(dateString);

You're almost there. The slight tweak would be this if I read the documentation correctly:
Data data = dataRepository.findTopByUpdatedBetweenOrderByUpdatedDesc(start, stop);
Source: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.limit-query-result

You can annotatw your method with #Query annotation and write HQL query
#Query("select d from Data d where d.updated= :date")
List<Data> findByLastUpdatedInDate(#Param("date") Date date);

I'm hoping someone finds something more elegant, but for now what I'm using is
List<Data> findByUpdatedBetweenOrderByUpdatedDesc(Date start, Date stop);
And converting day with
Date start = new Date(day.getTime());
Date stop = new Date(day.getTime() + 86400000L);
to get my entry with
Data data = dataRepository.findByUpdatedBetweenOrderByUpdatedDesc(start, stop).get(0);

Related

Using JAVA to save data to Oracle table with TIMESTAMP WITH ZONED TIME column

I am trying to find a Java Time Type that can be persisted to a column of type TIMESTAMP WITH TIME ZONE in the Oracle DB. The Java type needs to have the Time Zone as part of it. Because of the way the application was written, the Java Calendar type was used (also, the Java Calendar type has Time Zone that is part of it)
TRIAL ONE:
I did try to use the Calendar directly (with no serializer) with this code:
dateStr was in a pattern of: "MM-dd-yyyy hh:mm:ss a"
ZoneLoc was for the timezone: ex: America/Chicago, US/Eastern, etc.
public Calendar convDateStrWithZoneTOCalendar(String dateStr,
String ZoneLoc) throws Exception {
String string = dateStr;
String pattern = this.getPattern();
Date date = new SimpleDateFormat(pattern).parse(string);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
TimeZone tz = TimeZone.getTimeZone(ZoneLoc);
calendar.setTimeZone( tz );
return calendar;
}
when using this, the correct Zone Location was not set. For example, I would try to set ZoneLoc to US/Hawaii and when data was saved to the DB, it would be something like
23-SEP-19 10.03.11.000000 AM -05:00 And (-05:00) does not represent US/Hawaii
TRIAL TWO
It is for this reason why the attribute-conversion route was tried. In this case, there is an attempt to convert Calendar to ZoneDateTime.
I had seen this in another message noting:
Add #Convert(converter=OracleZonedDateTimeSeriliazer.class) on top of
your createdOn attribute on ur Entity class.
But, as mentioned above, Calendar is being used as part of the entity and not ZonedDateTime
the way the entity class is defined now. Before (when using the ( convDateStrWithZoneTOCalendar above), the "#Convert" items were not present
#Entity
#Table(name = "LAWNCORRJOB", schema = "ORAAPPS", uniqueConstraints = #UniqueConstraint(columnNames = {
"TENANTID", "GENERATEDJOBNO" }))
public class Lawncorrjob implements java.io.Serializable {
private static final long serialVersionUID = -8207025830028821136L;
....
#Convert( converter = OracleCalendarZoneDateTimeSerializer.class, disableConversion = false )
private Calendar schedfirstdayts;
#Convert( converter = OracleCalendarZoneDateTimeSerializer.class, disableConversion = false )
private Calendar schedlastdayts;
...
}
the converter being used: converts Calendar to ZonedDateTime (under Oracle)
#Converter(autoApply = true)
public class OracleCalendarZoneDateTimeSerializer implements
AttributeConverter<Calendar, ZonedDateTime> {
#Override
public ZonedDateTime convertToDatabaseColumn(Calendar attribute) {
if (attribute == null)
return null;
// get the timezone
TimeZone tz = attribute.getTimeZone();
// use the timezone to specify the area location
// ex: For example, TimeZone.getTimeZone("GMT-8").getID() returns
// "GMT-08:00".
ZonedDateTime xzdt = ZonedDateTime.of(attribute.get(Calendar.YEAR),
attribute.get(Calendar.MONTH),
attribute.get(Calendar.DAY_OF_MONTH) + 1,
attribute.get(Calendar.HOUR_OF_DAY),
attribute.get(Calendar.MINUTE), attribute.get(Calendar.SECOND),
attribute.get(Calendar.MILLISECOND), ZoneId.of(tz.getID()));
return xzdt;
}
#Override
public Calendar convertToEntityAttribute(ZonedDateTime dbData) {
GregorianCalendar newcal = DateTimeUtils.toGregorianCalendar(dbData);
return newcal;
}
}
But, when executing this code, I get an error:
Error Message: Could not commit JPA transaction; nested exception is
javax.persistence.RollbackException: Error while committing the
transaction CAUSE : javax.persistence.RollbackException: Error while
committing the transaction",
So, is there any way I can fix either option to get this all working?
Any help, hints or advice is appreciated.
TIA

How to reject 3-digit time in request in Spring Boot?

I am a newbie to Java. I was getting date and time in the following format in json,
{
"appointmentDate":"2017-05-30",
"appointmentTime":"23:30:00"
}
In the request, I was doing this,
#NotNull(message = "appointmentDate is required")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date appointmentDate;
#NotNull(message = "appointmentTime is required")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
private String appointmentTime;
In the above request class, I was using Date class for getting date and considering time as String.
Then in service class, I am trying to convert string object into date object, then search in the table to find the list of appointments in the table.
// convert into string
String dateString = null;
SimpleDateFormat sdfr = new SimpleDateFormat("yyyy-MM-dd");
dateString = sdfr.format( appointmentDate );
String dt = dateString + " " + appointmenTime;
Date startDateAndTime = null;
try {
//startDateAndTime = yyyyMMddFormat.parse(yyyyMMddFormat.format(dt));
startDateAndTime = new SimpleDateFormat(Constants.DATEANDTIME).parse(dt);
} catch (ParseException e) {
throw new IllegalArgumentException("Illegal date format");
}
but the issue I am facing is, even when i entered the wrong date it giving me output. No parse exception is thrown on the error in the date.
{
"appointmentDate":"20171-05-30",
"appointmentTime":"231:30:00"
}
this is my constants
public static final String DATEANDTIME = "yyyy-MM-dd HH:mm:ss";
and this is my repository query,
#Query(value = "select COUNT(a.doctorId) from Appointment a WHERE a.doctorId = :doctorId AND a.scheduleFromTime = :appointmentDateTime")
Long findAppointmentExists(#Param("doctorId") Long doctorId,
#Param("appointmentDateTime") Date appointmentDateTime);
Allow me to suggest you use the modern classes LocalDate and LocalTime for your date and time. Then it’s straightforward to do for example
if (appointmentDate.isAfter(LocalDate.now().plusYears(5)) {
throw new IllegalArgumentException("Too far into the future");
}
This will catch the 5-digit year and many other errors in the year value. Please set an appropriate limit yourself. You may similarly forbid dates in the past, maybe with a stricter limit. For the time this will be built-in since LocalTime only accepts times up to 23:59:59.999999999.
To combine both into one object
LocalDateTime startDateAndTime = LocalDateTime.of(appointmentDate, appointmentTime);
I have entered the code snippets off the top of my head, there could be a typo or two. If you cannot fix, please revert.
I haven’t got recent experience with Spring Boot. There’s more on using the modern Java date and time classes with Spring Boot and Jackson in this question: JSON Java 8 LocalDateTime format in Spring Boot. And no doubt still more in other places.
The first date format in your code is pointless, it is just converting to a Date(which was failing when I tried) and then immediately converting back to String anyway.
I've taken out the unnecessary lines from your example and posted my "working" example below.
String dt = appointmentDate + " " + appointmentTime;
Date startDateAndTime = null;
try
{
startDateAndTime = new SimpleDateFormat(Constants.DATEANDTIME).parse(dt);
} catch (ParseException e)
{
throw new IllegalArgumentException("Illegal date format");
}
System.out.println(startDateAndTime);
This tends to happen a lot when something is not working and you keep throwing code at it until you get entirely stuck. It's good to step back sometimes and try to work out what you are actually trying to achieve and then take another crack at it.

How to match system date with the date from database mysql

I have a database named work created using mysql in which a table named register is created. It contain a column renewdate. I accessed the table from java swing like this
conn=ConnectionDB.conn();
Date d=sysdate();
String sql="select renewdate from register";
try
{
ps=conn.prepareStatement(sql);
ResultSet rs=ps.executeQuery();
Date dates;
while(rs.next())
{
dates = rs.getDate("renewdate");
System.out.println(dates);
if(dates==d)
{
SendMailTLS.sendMail();
}
}
}
My problem is to send an email when renewdate equals system date. I generate current date using function sysdate() and assigned it to d. Also assigned renewdate in table to dates using dates = rs.getDate("renewdate").
My problem is I can not match up both d and dates and thus can not sent email. Could you help me how to match d and dates.
I tried while(rs.next()) all the dates from table register is obtained. But can not match with d using if(dates==d). Also I tried if(rs.next()), but it only fetch first renewdate from table. So how could i check all the values of renewdate and match with the current date to sent message
Just change a query string to
// NOW() in mysql will get the current date and time. So here you get only renewdates matched with current date and time
String sql="select renewdate from register where renewdate = NOW()";
// If you want to compare only with date not time, then go with
String sql="select renewdate from register where renewdate = CURDATE()";
There is no need for this if(dates == d) in your above code. Send mail as soon you have next element in your while condition.
Nice code! So:
Save the value of date into strings like:
Date d=sysdate();
String strDate1 = d.toString();
String strDate2 = rs.getDate("renewdate").toString;
Then compare it like:
strDate1.equals(strDate2);
as Strings contain references to "words", not the "words" themself, the == opereator would do something else;
Couly you please send us your whole code for this app anyway, as it would be a nice peace of work to learn from?
If you want to do it in code, here is a way:-
Convert date fetched from database into java.util.Date object using below code (assuming date is stored in GMT):
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
Date dateInDB = formatter.parse(dates);
Then, you can simply use java.util.Date equals method to compare d with dateInDB.
If you want to ignore time portion while comparing two dates, call below method (that sets time portion to 00:00:00) for each date and use returned date in equals method:
public static Date getZeroTimeDate(Date dateWithTime) {
Date res = dateWithTime;
Calendar calendar = Calendar.getInstance();
calendar.setTime( dateWithTime );
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
res = calendar.getTime();
return res;
}
This way it does not uses any deprecated method too.
Hope this helps!

Oracle function returns date but no time when called via JPQL

I have an Oracle function which accepts amongst other things, a date as parameter, and returns a date. The function is like this:
FUNCTION my_func(par1 IN DATE, par2 IN NUMERIC) RETURN DATE AS
ret_val DATE;
BEGIN
....
END;
I need to call this function in my Java application, and am currently doing so with JPQL. The code is for a web application running on JBoss 5, and looks like this:
Query q = entityMng.createNativeQuery("SELECT MY_FUNC(?1,?2) FROM DUAL");
java.util.Date now = new Date();
long param2 = 110L;
q.setParameter(1, now);
q.setParameter(2, param2);
java.sql.Date retSql = null;
Object obj = q.getSingleResult();
if (obj != null) {
retSql = (java.sql.Date) obj;
}
After executing the code the retSql variable contains the correct date but has a time = 00.00.000. I obtain the same behaviour even when using java.util.Date as opposed to java.sql.Date, as the type for retSql.
While investigating this problem I cam across this SO post How to convert correctly an Oracle Date field into java.util.Date through JPA, but I don't understand how to use "addScalar" in my case.
Any help would be appreciated, thanks in advance.
Try returning a TIMESTAMP in your function, not a DATE. DATE is now only a date in Oracle, and TIMESTAMP is suppose to be used for date/time. There is a backward compatibility flag you can set in JDBC to control this.
What JPA provider are you using? EclipseLink should be handling this automatically.
What about using XMLAdapter;
public class DateAdapter extends XmlAdapter {
// the desired format
private String pattern = "yyyy-MM-dd HH:mm:ss";
/*few more formats http://www.xyzws.com/javafaq/how-to-use-simpledateformat-class-formating-parsing-date-and-time/142 */
public String marshal(Date date) throws Exception {
return new SimpleDateFormat(pattern).format(date);
}
public Date unmarshal(String dateString) throws Exception {
return new SimpleDateFormat(pattern).parse(dateString);
}
And then adding it to your Entity; for example
private java.util.Date originDate;
#XmlJavaTypeAdapter(DateAdapter.class)
#Column(name = "ORIGIN_DATE", nullable = true)
#XmlElement(namespace = "my-namespace")
public Date getOriginDate() {
return this.originDate;
}
Here is a tutorial that I used to learned about this;
http://weblogs.java.net/blog/kohsuke/archive/2005/04/xmladapter_in_j.html

Problem with String to Date Conversion

I am trying to convert date in String format to sql date and based on that query database to get the result.
Date in string format is :2011-08-11 09:16:00.0
So I am converting it to sql date by using the method:
public static convertStringToSqlDate(String dateString){
DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date parsedUtilDate = formater.parse(dateString);
java.sql.Date sqlDate= new java.sql.Date(parsedUtilDate.getTime());
return sqlDate;
}
The resulting date is :2011-08-11
but while doing the query I am not getting desired output
The complete code is
def startDate = params. startDate
def endDate = params. endDate
def formattedTripStartDate =Trip.convertStringToSqlDate(startDate);
def formattedTripEndDate =Trip.convertStringToSqlDte(endDate);
def listOfContracts = Rule.findAll("FROM Rule WHERE name LIKE ? AND client_id = ? AND STR_TO_DATE(contract_begins,'%Y-%m-%d')<= ? AND STR_TO_DATE(contract_terminates,'%Y-%m-%d')>= ?",["%"+q_param+"%",clientId,formattedTripStartDate,formattedTripEndDate] )
Where am I going wrong?
In database the contract_begins is stored as :2011-08-23 00:00:00
Contract domain Class is
class Contract extends Rule {
Date contractBegins
Date contractTerminates
int runningDays
Double contractValue
Double estimatedRevenue
Double actualRevenue
static constraints = {
contractBegins(nullable:true)
contractTerminates(nullable:true)
runningDays(nullable:true)
contractValue(nullable:true)
estimatedRevenue(nullable:true)
actualRevenue(nullable:true)
}
}
Date object didn't format by itself, it return only date and time value. you can get the formatted by only Format supported class in string format like SimpleDateFormat, DateFormat etc.
Why do you want to use a findAll query, and not a criteria. Something like this should do it:
def startDate = params.startDate
def endDate = params.endDate
def tripStartDate=Trip.convertStringToSqlDate(startDate);
def eripEndDate=Trip.convertStringToSqlDte(endDate);
def c = Contract.createCriteria()
def results = c.list {
like("name", "%${q_param}%")
eq("client_id", clientId)
ge('contract_begins', tripStartDate)
le('contract_terminates','tripEndDate)
}
It's much cleaner and you don't have to worry about how the SQL looks like!
Take a deep dive into http://grails.org/doc/latest/ref/Domain%20Classes/createCriteria.html and http://grails.org/doc/latest/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.4.2 Criteria where you can find much more information.
Also consider making your code even nicer by adding the criteria into the Domain Class named queries: http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html

Categories