NIFI: Generating dates between two dates using ExecuteScript processor - groovy

I am currently trying to get list of all dates in a flowfile between the two dates specified using ExecuteScript. But I am somehow getting empty attribute.
Following is my Groovy code of ExecuteScript for the specified startdate and enddate variable specified:
flowFile = session.get();
if(!flowFile)
return;
DATE_FORMAT = 'dd-MM-yyyy';
startDate = Date.parse(DATE_FORMAT, flowFile.getAttribute("startdate"));
endDate = Date.parse(DATE_FORMAT, flowFile.getAttribute("enddate"));
allDates = "";
Calendar calendar = Calendar.getInstance();
Set allDates = new LinkedHashSet();
numbers = TimeUnit.MILLISECONDS.toDays(Math.abs(endDate - startDate))
for (int i = 1; i <= numbers; i++) {
calendar.setTime( startDate );
calendar.add( Calendar.DATE, i );
}
days.each {
day -> allDates = allDates + day + "\n";
}
flowFile = session.putAttribute(flowFile,"allDates", allDates );
session.transfer(flowFile,REL_SUCCESS)
On my outgoing queue I find the attribute allDates is empty String
What is going wrong with my code?

you have some problems in your code
for example the variable allDates declared twice i two different scopes:
global (without type or def)
allDates = "";
and local (with type)
Set allDates = new LinkedHashSet();
after that it's hard to predict which one is used
and actually code could be easier in groovy:
def DATE_FORMAT = 'dd-MM-yyyy';
def startDate = Date.parse(DATE_FORMAT, '01-11-1970');
def endDate = Date.parse(DATE_FORMAT, '09-11-1970');
def allDates = ""
for (def d = startDate; d<=endDate; d++){
allDates+=d.format(DATE_FORMAT)+"\n"
}
println allDates
note that this is runable code so you can use groovyconsole or any IDE to debug it before integrating into nifi
of cause you have to wrap it with flow file handling before using in nifi

Related

Calculate difference between 2 date-time in soapui

I'm using SoapUI free version. I have a REST response that returns date-time like this
<startTime>2018-02-22T17:10:00-05:00</startTime>
<endTime>2018-02-22T18:05:00-05:00</endTime>
How do I calculate the difference between them (in minutes) using groovy test step?
//Assuming string teased out of response, if not you need to extract the value to a string....
def startString = '<startTime>2018-02-22T17:10:00-05:00</startTime>';
def endString = '<endTime>2018-02-22T18:05:00-05:00</endTime>';
// If you have the tags, ditch them.
startString = startString.replace("<startTime>", "");
startString = startString.replace("</startTime>", "");
endString = endString.replace('<endTime>', '');
endString = endString.replace('</endTime>', '');
log.info("Now just strings... ${startString} - ${endString}");
// Convert strings to dates...
def convertedStartDate = Date.parse("yyyy-MM-dd'T'HH:mm:ssX",startString);
def convertedEndDate = Date.parse("yyyy-MM-dd'T'HH:mm:ssX",endString);
log.info("Now dates... ${convertedStartDate} - ${convertedEndDate}");
//Use time category to tease out the values of interest...
use(groovy.time.TimeCategory) {
def duration = convertedEndDate - convertedStartDate
log.info( "Days: ${duration.days}, Hours: ${duration.hours}, Minutes: ${duration.minutes}, Seconds: ${duration.seconds}, etc.")
}

How to use Groovy script in soapUi to loop multiple time

I am new to SoapUi. I am exploring on how multiple request in soapUi is done using groovy script.
below is the example that im trying to do, based on example that i found through "googling"
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.model.testsuite.*;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner
import java.util.Random
import com.eviware.soapui.model.testsuite.TestRunner.Status
// Define your testCase pointer
//def testcase = testRunner.testCase.testSuite.project.testSuites["TestSuite - User Management REST API"].getTestCaseByName ("Authenticate User")
def counterUser = testRunner.testCase.testSuite.getPropertyValue( "counter" )
int value = counterUser.toInteger()
String tester = ""
30.times {
value = value + 1
tester = "tester " + value.toString()
testRunner.testCase.testSuite.setPropertyValue( "userName", tester )
testRunner.runTestStepByName("POST - createUser - Create a User")
}
testRunner.testCase.testSuite.setPropertyValue( "counter", value.toString() )
I want to create a 30 users which start from Tester1...tester2.....tester30.
Is it possible to do this way? I keep getting an error such as NullPointerException at this line
int value = counterUser.toInteger()
I got what you say.
That is because, initially there is no value for counter which results to null and you are applying toInteger() over it.
Just change:
From:
int value = counterUser.toInteger()
To:
int value = counterUser?.toInteger() ?: 0

Convert time in milliseconds to date format (YYYY-MM-DD) in Groovy

Is there a function to convert time in milliseconds to date format (YYYY-MM-DD) in Groovy?
I have a Groovy script which needs to compare to date values as follows:
for(i in order_lineitems)
{
if(i.startDate==order_submit_date)
{
matchedIds1 += i.salesOrderLineitemId+',';
}
}
Here i.startDate has time in milliseconds of the date format yyyy-mm-dd whereas order_submit_date has the time in milliseconds in the date format yyyy-MM-dd HH:mm:ss. I need to convert order_submit_date into this format yyyy-mm-dd within the if block itself.
I am new to the Groovy script and I need help here.
There was a small mistake in my code. I corrected it.
The if block should be as follows if (i.startDate == order_submit_date) and both are long values represented in millis.
Now I need to make sure the condition is right i.e. start date is equal to order submit date.
Here what is happening is :
i.startDate has the value 1452105000000 (Thu Jan 07 2016 00:00:00) which is been stored in the DB when a Sales Order is created
and order_submit_date has the value 1452158393097 (Thu Jan 07 2016 14:49:53) which is being genertaed on the flow when a user submits the Sales order for approvals in the UI.
Now since order_sbmit_date has both date and time the long value is different and am unable to satisfy the condition.
Hence now i have a question as to wether there a function in groovy which would convert my order_submit_date long value to Date(yyyy-mm-dd) format and then compare both the values so as to satisfy the if block.
You can compare your dates in millis like this:
Notice that solutions depend on timezone.
Groovy option:
def compare(def m1, def m2) {
def dateInMillis1 = new Date(m1)
def dateInMillis2 = new Date(m2)
dateInMillis1.clearTime() == dateInMillis2.clearTime()
}
Java option 1:
boolean compare1(long millis1, long millis2) {
Date dateFromMillis = new Date(millis1);
Date dateFromMillis2 = new Date(millis2);
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD");
sdf.format(dateFromMillis).equals(sdf.format(dateFromMillis2));
}
or you can use Calendar:
Java option 2:
boolean compare2(long m1, long m2) {
Calendar calendar1 = Calendar.getInstance();
calendar1.setTimeInMillis(m1);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(m2);
return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) &&
calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH) &&
calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH);
}
Your question is not clear that whether your dates are in string format or in milliseconds (long).
If dates are in string format like "2015-10-31"
You can use SimpleDateFormat for this.
import java.text.SimpleDateFormat
...
SimpleDateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd")
SimpleDateFormat dateTimeParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
for (i in order_lineitems) {
if (dateParser.parse(i.startDate) >= dateTimeParser.parse(order_submit_date)) {
matchedIds1 += i.salesOrderLineitemId+',';
}
}
If dates are in milliseconds:
for (i in order_lineitems) {
if (new Date(i.startDate.toString().toLong()) >= new Date(order_submit_date.toString().toLong())) {
matchedIds1 += i.salesOrderLineitemId+',';
}
}
Note: Capital Y and small y (similarly for m & h) matterns in terms of formatting so please be clear about the usage.
Actual Answer to the Question:
You don't need any of the above solution instead you can simply use the clearTime() method on the date like below:
for (i in order_lineitems) {
if (new Date(i.startDate) >= new Date(order_submit_date).clearTime()) {
matchedIds1 += i.salesOrderLineitemId+',';
}
}
The clearTime() method will simply remove the time part from your date i.e. will convert Thu Jan 07 2016 14:49:53 to Thu Jan 07 2016 00:00:00`
What are type for i.startDate and order_submit_date java.util.Date? or String?
And do you want use i.startDate and order_submit_date only to do compare?
-- updated --
ok, then maybe like folowing?
import java.text.SimpleDateFormat
String startDate = "2016-01-20"
String order_submit_date = "2016-01-20 12:34:56"
SimpleDateFormat formatDateWithTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd")
if (formatDate.parse(startDate) >= formatDateWithTime.parse(order_submit_date)) {
println "hehe"
} else {
println "hoho"
}
SimpleDateFormat#parse() returns java.util.Date.
Also you can compare with these.
You can also write like follows!
import java.text.SimpleDateFormat
SimpleDateFormat formatDateWithTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd")
def matchedIds1 = order_lineitems.findAll {
formatDate.parse(it.startDate) >= formatDateWithTime.parse(order_submit_date)
}.join(",")
Long(type) version
def matchedIds1 = order_lineitems.findAll {
new Date(it.startDate).clearTime() == new Date(order_submit_date).clearTime()
}.join(",")
Long(type) without clearTime version
String format = "yyyy-MM-dd 00:00:00"
SimpleDateFormat fillByZero = new SimpleDateFormat(format)
def matchedIds1 = order_lineitems.findAll {
Date a = new Date(it.startDate)
Date b = new Date(order_submit_date)
fillByZero.parse(a.format(format)) == fillByZero.parse(b.format(format))
}.join(",")

Optimize Groovy code

I am fairly new to the Groovy/Grails arena. I recently modified some code to add the following block.
result.processed.each{
def queueEntry = QueueEntry.findById(it.id)<<<START ADD>>>
Set dates = new HashSet<Long>()
def children = QueueEntry.findAllByParent(queueEntry)
for(QueueEntry qe : children){
def f = new GregorianCalendar()
f.setTimeInMillis(DateUtils.getClearedTime(qe.entryTimestamp))
def l = new GregorianCalendar()
l.setTimeInMillis(DateUtils.getClearedTime(qe.exitTimestamp))
while(f < l){
if(f.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY && f.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY){//only add weekdays
dates.add(f.time.time)
}
def xx = new GregorianCalendar()
xx.setTimeInMillis(f.time.next().time)
f = xx
}
dates.add(l.time.time)
} <<<STOP ADD>>>
Set outsideDays = it.numberOfDaysOutsideCVB
Set days = DateUtils.businessDaysBetweenDates(it.entryTimestamp, it.exitTimestamp)
days.removeAll(outsideDays)
days.removeAll(dates)
turnTimes << days.size()
}
The application is now crawling. I am obviously doing something wrong. When this is run for small data-sets it will complete slowly. On larger sets it doesn't finish. Prior to this change it was completing.
You can start with the lines of the below changes.
// Proposed
import static java.util.Calendar.*
// Query for all the children upfront instead of hitting
// database twice on each iteration.
// You can also avoid N + 1 situation if children is fetched eagerly
def allChildren = QueueEntry.where {
id in (result.processed*.id as List<Long>)
}.children.list()
def turnTimes = result.processed.collect { entry ->
allChildren.findAll { it.parent.id == entry.id }.collect { child ->
Set dates = []
new Date( child.entryTimeStamp ).upto( new Date( child.exitTimestamp ) ) {
if ( !( it[DAY_OF_WEEK] in [ SUNDAY, SATURDAY ] ) ) {
dates << it.time
}
}
Set outsideDays = child.numberOfDaysOutsideCVB
Set days =
DateUtils.businessDaysBetweenDates(
child.entryTimestamp,
child.exitTimestamp
)
( days - outsideDays - dates )?.size() ?: 0
}
}
Assumptions:
QueueEntry hasMany children
entryTimestamp/exitTimestamp is java.sql.Timestamp
entryTimestamp/exitTimestamp are not null and entryTimestamp comes before exitTimestamp.
As Burt suggested this question best fits in codereview.stackexchange.com

Why can't I directly assign to object properties using multiple return values from a method?

Based on this question I've coded the following which throws a compilation time error:
Here is the code:
43. Currency currency = new Currency()
44. (currency.rate_one, currency.time_one) = getDateAndRate()
My method with two return values:
def getDateAndRate(){
Date date = new Date()
double rate = getRate();
return [rate, date]
}
Error thrown
expecting '}', found ',' # line 44, column 26.
(currency.rate_one, currency.time_one) = getDateAndRate()
^
Try this instead
def (rate, time) = getDateAndRate()
currency.rate_one = rate
currency.time_one = time
There is a trick I learned only recently myself and that is to combine multiple assignment and with:
with (currency) {
(rate_one, time_one) = getDateAndTime()
}

Resources