java cucumber pass date as string error - cucumber-junit

Java - cucumber
I am new to writing cucumber test, getting error on given method signature can some one help pls ?
following is my feature file entry
#txn
Feature: ORP
Scenario Outline: Save a ORP
Given when i pass start date <start date> and end date <end date>
When the user saves a ORP
Then the PROP is saved
Examples:
| start date | end date |
| 1-1-2016 | 1-1-2017 |
and step file as following signature to get given start and end date
#Given ("^when i pass start date (.+) and end date (.+)$")
public void processOPR(String, start, String end){...}
when i run my test i get the following error
Exception
#Given("^when i pass start date (\\d+)-(\\d+)-(\\d+) and end date (\\d+)-(\\d+)-(\\d+)$")
public void when_i_pass_start_date_and_end_date(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
I want to pass date "1/1/2016" in one variable not in 3 different variables.

found solution as following
#Given ("^when i pass start date (.+) and end date (.+)$")
public void processOPR(#Format("dd-MM-yyyy")Date start, #Format("dd-MM-yyyy") Date end){...}

Related

JPA Query using between and Instant not working

I'm trying to make a query to retrieve some data which has been created between two dates (represented as Instant).
Here below an extract from the Entity I'm using:
#Entity
public class HistoricalData {
#Id
#GeneratedValue
private Long id;
#Column
private String name;
#CreationTimestamp
private Instant timestamp;
#Column
private Double price;
}
And the query I've written to retrieve the data between the two Instants;
#Query("select h from HistoricalData h where h.timestamp between :timestampStart and :timestampEnd and upper(name) = upper(:name)")
List<HistoricalData> findHistoricalDataBetween(#NonNull Instant timestampStart, #NonNull Instant timestampEnd, #NonNull String name);
Which produces this SQL query:
select historical0_.id as id1_5_, historical0_.price as price2_5_, historical0_.timestamp as timestam3_5_ from historical_data historical0_ where (historical0_.timestamp between ? and ?) and upper(historical0_.name)=upper(?)
Also I wrote the "hibernate JPA" query just to try but no success:
List<HistoricalData> findHistoricalDataByTimestampAfterAndTimestampBeforeAndName(#NonNull Instant timestampStart, #NonNull Instant timestampEnd, #NonNull String name);
Keep in mind that all the above queries compile correctly and do not throw any exception, they just retrieve nothing from the database
The database I'm using is a latest version of MariaDB and the connector version is the 2.7.2
Also the SpringBoot version I'm using is the 2.5.3
Here is DDL from the table definition (automatically generated from Hibernate):
create table historical_data
(
id bigint not null primary key,
price double null,
timestamp datetime not null,
name varchar not null
);
An this is how the timestamp looks like in the database:
Even though records between those two Instants are present in the database I'm still getting nothing as a result from the query.
Looks like the reason is a time zone.
MySQL driver uses incorrect time zone transformations, using a default local time zone in place of a connection time zone (or vice versa).
Just debug this query inside MySQL driver to have fun and figure out what happens.
You can add parameters to the database URL to see which actual values are passed for the prepare statement
jdbc:mysql://<DATABASE_URL>?logger=com.mysql.cj.log.Slf4JLogger&profileSQL=true

Spring data reactive repository - r2dbc not working

The query is getting executed but not getting any result.
router :- api/v1/service/appt/usr/{usr_id}
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
public Mono<ServerResponse> retrieveProjectsByUsr(ServerRequest request) {
final String userIdStr = request.pathVariable(USER_ID_PARAM);
final Optional<String> stDateStr = request.queryParam("stDate");
final Optional<String> endDateStr = request.queryParam("endDate");
final LocalDateTime stDate = LocalDateTime.parse(stDateStr.get(), DATE_TIME_FORMATTER);
final LocalDateTime endDate = LocalDateTime.parse(endDateStr.get(), DATE_TIME_FORMATTER);
long userId = Long.parseLong(userIdStr);
return secContext.retrieveUser().flatMap(usr -> {
Flux<Appt> appts = projectRepository.findApptsBetween(stDate, endDate, userId, usr.getOrgId());
return ServerResponse.ok().contentType(APPLICATION_JSON).body(appts, Project.class);
});
}
Repository code,
#Repository
public interface ApptRepository extends ReactiveCrudRepository<Appt, Long> {
#Query("select * from appt where usr_id = :usrId and org_id = :orgId and start_time BETWEEN :stDate and :endDate")
Flux<Appt> findApptsBetween(LocalDateTime stDate, LocalDateTime endDate, long usrId, int orgId);
}
Query from the log,
Executing SQL statement [select * from appt where usr_id = :usrId and org_id = :orgId and start_time BETWEEN :stDate and :endDate]
Data in project table,
Postman request,
http://localhost:9090/api/v1/service/appt/usr/2?stDate=2021-01-24 03:20&endDate=2021-03-25 05:23
Not sure what is wrong with this. It doesn't return the record.
The problem here is that reactive code needs to be subscibed to, to start execution. The following statement only describes what should happen:
Flux<Appt> appts = projectRepository.findApptsBetween(stDate, endDate, userId, usr.getOrgId());
To initate execution one needs to add .subscribe() operator to the reactive call. But here you dont't want that because that will start execution in a different context/thread and you won't be able to return the value to the outer method. This is why one should write reactive code as chain of reactive calls.
(Note: controller methods and router functions have an implicit .subscribe() at the end of your code so you don't need to add it)
You could rewite this code to something like this:
return secContext.retrieveUser().flatMap(usr ->
projectRepository.findApptsBetween(stDate, endDate, userId, usr.getOrgId())
.collectList()
.map(appts -> ServerResponse.ok().contentType(APPLICATION_JSON).body(appts, Project.class));
The following code works. Answer was modified from the above posts.
return secContext.retrieveUser()
.flatMap(usr -> apptRepository.findApptsBetween(userId, usr.getOrgId(), stDate, endDate).collectList()
.flatMap(appts -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(appts)));

Query from database with date range in .Net Core

I receive a MySql database and one table inside it have a Date column in string format, now I need to build a .Net core server with Pomelo and EF Core and requirement is my server can query data from that table in a range of date, but because Date column of that table is in string format so I don't know how to query it, please help.
Thank you!
You are going to have to get that string into a date in order to query it.
I would probably add a new datetime column to the table and then create a simple console app that reads in each string date, try to parse this as a datetime and save it to the new datetime column.
Then you should see how many rows have valid datetimes and correct the others
Finally, you can then query using Entity Framework
how to convert a string to date in mysql?
As was told here
You can Query string to date
SELECT STR_TO_DATE(yourdatefield, '%m/%d/%Y')
FROM yourtable
With database schema change
If you can (i.e. are allowed) to change the schema of the table in question, then just add a new datetime or date column, copy the data over from the old column to the new one, and drop the column:
ALTER TABLE `YourTable` ADD COLUMN `NewDateColumn` date NOT NULL;
UPDATE `YourTable` SET `NewDateColumn` = STR_TO_DATE(`OldDateColumn`,'%Y-%m-%d');
ALTER TABLE `YourTable` DROP COLUMN `OldDateColumn`;
You can run these statements just using MySQLWorkbench or the commmand line tool. Of course you first test them with a local copy, to see that everything works fine.
With value converter
If you cannot change the schema of the table, then you can still query date ranges from the database, as long as the date strings in the database are in a string format, that sorts alphabetically (e.g. YYYY-MM-DD). In that case, you can just use a value converter in your actual app code and don't need to alter the database at all:
public class SomeModel
{
public int SomeModelId {get; set;}
public DateTime YourDateProperty {get; set;} // <-- the type you want to use in .NET
}
public class Context : DbContext
{
public virtual DbSet<SomeModel> SomeModels { get; set; }
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeModel>(
entity =>
{
entity.Property(e => e.YourDateProperty)
.HasColumnType("varchar(255)") // <-- the type it has in the database table
.HasConversion(
v => v.ToString(#"yyyy\-MM\-dd"),
v => DateTime.Parse(v, CultureInfo.InvariantCulture));
});
}
}
// Here is how a sample query in your app would look like:
var query = context.SomeModels
.Where(m => m.YourDateProperty >= new DateTime(2020, 9, 1) &&
m.YourDateProperty < new DateTime(2020, 9, 10))
.ToList();

spring JPA java.sql.Date is accepting invalid Dates

I am writing rest apis for my project to create, retrieve and modify values to my database.
The model has an sql.Date field which while doing POST request if I give date as for example 2018-01-35(yyyy-MM-dd), it is auto converting to 2018-02-04.
I want to avoid this so that it can tell me that the given date is invalid.
I searched in SO and tried this approach,
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dob;
but this did nothing, so then I tried another method
#JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd")
but this only checks for format like if i give value as just "1993", it gives error but does not check for "1993-01-35".
I also tried,
public static boolean dateChecker(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.setTime(date);
try{
calendar.getTime();
}catch(Exception e)
{
System.out.println(e.getMessage());
return false;
}
return true;
}
But when I debug it, this method is already getting "1993-01-35" as "1993-02-04".
The model is,
#JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd")
private Date dob;
This is my POST method,
#RequestMapping(value = "/patient",method = RequestMethod.POST,consumes = "application/json")
public ResponseEntity<?> createPatient(#RequestBody Patient patient)
{
if(patient.getPatientId()!=null)
{
Patient patient1 = patientRepository.findOne(patient.getPatientId());
if(patient1!=null)
{
return new ResponseEntity("Patient for the given patient Id already exists.",HttpStatus.BAD_REQUEST);
}
}
System.out.println(patient.getDob());//Here I am getting 1993-02-04 when i give date as 1993-01-35
Please help me solve this.
Try util.date package for date.
You could try doing something like this if the calendar.setLenient isn't working for you.
I just added some random number for the day for testing.
int day = 21;
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(Calendar.MONTH, Calendar.JANUARY);
if(day <= gmtCal.getActualMaximum(Calendar.DAY_OF_MONTH)){
gmtCal.set(1993, Calendar.JANUARY, day );
System.out.println(gmtCal.get(Calendar.YEAR));
System.out.println(gmtCal.get(Calendar.MONTH));
System.out.println(gmtCal.get(Calendar.DAY_OF_MONTH));
System.out.println(gmtCal.getTime());
}
else{
System.out.println("Out of bounds");
}
The First thing you would have to do is to set the month for the calendar and then do a test on the day that was entered. If it passes then then you can set the whole date and if not print out an error.
Note: when using Calendar.get, the year and day will be printed out correctly. However, the month will start at zero. So in this example the dot gets print out:
1993 (year)
0 (month)
21 (day).
Also the the sysout for getTime() will print out some extra information that you might not need.
I used this post as a reference, it might give you some extra help: Detect invalid date on Calendar.set()
I hope this helps you. Let me know if this needs tweeking

Weird behaviour encountered using java.sql.TimeStamp and a mysql database

The weird behavior is that a java.sql.Timestamp that I create using the System.currentTimeMillis() method, is stored in my MySQL database as 1970-01-01 01:00:00.
The two timestamps I am creating are to mark the beginning and end of a monitoring task I am trying to perform, what follows are excepts from the code where the behavior occurs
final long startTime = System.currentTimeMillis();
while(numberOfTimeStepsPassed < numTimeStep) {
/*
* Code in here
*/
}
final long endTime = System.currentTimeMillis();
return mysqlConnection.insertDataInformation(matrixOfRawData, name,Long.toString(startTime),
Long.toString(endTime), Integer.toString(numTimeStep),
Integer.toString(matrixOfRawData[0].length), owner,
type);
And here is the code used for inserting the time stamps and other data into the MySQL database
public String insertDataInformation(final double [][] matrix,
final String ... params) {
getConnection(lookUpName);
String id = "";
PreparedStatement dataInformationInsert = null;
try {
dataInformationInsert =
databaseConnection.prepareStatement(DATA_INFORMATION_PREPARED_STATEMENT);
id = DatabaseUtils.createUniqueId();
int stepsMonitored = Integer.parseInt(params[STEPS_MONITORED]);
int numberOfMarkets = Integer.parseInt(params[NUMBER_OF_MARKETS]);
dataInformationInsert.setNString(ID_INDEX, id);
dataInformationInsert.setNString(NAME_INDEX, params[0]);
dataInformationInsert.setTimestamp(START_INDEX, new Timestamp(Long.parseLong(params[START_INDEX])));
dataInformationInsert.setTimestamp(END_INDEX, new Timestamp(Long.parseLong(params[END_INDEX])));
dataInformationInsert.setInt(STEPS_INDEX, stepsMonitored);
dataInformationInsert.setInt(MARKETS_INDEX, numberOfMarkets);
dataInformationInsert.setNString(OWNER_INDEX, params[OWNER]);
dataInformationInsert.setNString(TYPE_INDEX, params[TYPE]);
dataInformationInsert.executeUpdate();
insertRawMatrix(matrix, id, Integer.toString(stepsMonitored), Integer.toString(numberOfMarkets));
} catch (SQLException sqple) {
// TODO Auto-generated catch block
sqple.printStackTrace();
System.out.println(sqple.getSQLState());
} finally {
close(dataInformationInsert);
dataInformationInsert = null;
close(databaseConnection);
}
return id;
}
The important lines of code are :
dataInformationInsert.setTimestamp(START_INDEX, new Timestamp(Long.parseLong(params[START_INDEX])));
dataInformationInsert.setTimestamp(END_INDEX, new Timestamp(Long.parseLong(params[END_INDEX])));
The JavaDocs on the TimeStamp ( http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/Timestamp.html ) says that it takes in time in milliseconds since 1st January 1970 and a simple print test confirms this.
What I am looking for is:
A reason for this behavior when trying to store timestamps in a MySQL database through java.sql.Timestamp?
Any solutions to this behavior?
Any possible alternatives?
Any possible improvements?
EDIT:
Been asked to include what START_INDEX and END_INDEX are:
private static final int END_INDEX = 4;
private static final int START_INDEX = 3;
Apologises for not putting them in the original post.
Okay, look at your call:
insertDataInformation(matrixOfRawData, name, Long.toString(startTime),
Long.toString(endTime), Integer.toString(numTimeStep),
Integer.toString(matrixOfRawData[0].length), owner,
type);
So params will have values:
0: name
1: start time
2: end time
3: numTimeStep
4: matrixOfRowData[0].length
5: owner
6: type
Then you're doing:
dataInformationInsert.setTimestamp(START_INDEX,
new Timestamp(Long.parseLong(params[START_INDEX])));
... where START_INDEX is 3.
So you're using the value corresponding to numTimeStep as the value for the timestamp... I suspect you don't want to do that.
I would strongly advise you to create a simple object type (possibly a nested type in the same class) to let you pass these parameters in a strongly typed, simple to get right fashion. The string conversion and the access by index are both unwarranted, and can easily give rise to errors.