Postgresql - Looping based on timestamp - postgresql-11

i am working on a scenario where need to run a particular code block for 5 mins.
I tried various options but no luck till now.
Could you please guide me.
Attaching the half-baked block:
DO
$do$
DECLARE
i int;
startTime TIMESTAMP;
endTime TIMESTAMP;
BEGIN
i := 1;
startTime := now();
endTime := now() + (1 * interval '5 minute');
RAISE NOTICE 'City Name:(%)(%)',statement_timestamp(),now() + (1 * interval '5 minute');
WHILE statement_timestamp() < endTime LOOP
RAISE NOTICE 'City Name:(%)(%)(%)',endTime,now(), statement_timestamp();
-- example:
--create table if not exists test12345(id int,start_dt TIMESTAMP,end_dt TIMESTAMP);
insert into test12345
select i,startTime,endTime;
--RAISE NOTICE startTime;
RAISE NOTICE 'City Name:(%)', statement_timestamp();
--startTime := statement_timestamp();
END LOOP;
END;
$do$;
thanks in advance.

Related

Is it possible call a procedure using strings?

I need to call a lot of procedures with incrementing names. Is it possible to generate the name of a procedure in a string and then call it using that string? Python has its own exec method which would be ideal but I'd be fine if I could dynamically pick the name of a function.
Edit:
To elaborate on what this is for, I have to write a performance test that repeats procedures of multiple codeunits. Depending on the parameters given, I could have 100 codeunits containing 30 procedures each, so to call all of them I currently have to explicitly call each and every one of them.
startTime := Time();
progressDialog.Update(1,'Proc0A');
for i := 1 to 1000 do begin
Set0_No0.Proc0A(1);
progressDialog.Update(2,i);
end;
timeElapsed := Time() - startTime;
if timeElapsed = 0 then begin
timeElapsed := 1;
end;
baseTime := timeElapsed;
FinishTest(timeElapsed, baseTime, 0, false, false, 1, 1, 1000);
startTime := Time();
progressDialog.Update(1,'Proc0B');
for i := 1 to 1000 do begin
Set0_No0.Proc0B(1);
progressDialog.Update(2,i);
end;
timeElapsed := Time() - startTime;
if timeElapsed = 0 then begin
timeElapsed := 1;
end;
FinishTest(timeElapsed, baseTime, 0, true, false, 1, 1, 1000);
Instead, I'd like it to work like this:
procedure CallMethod(setNo:Integer; codeunitNo:Integer; procedureNo:Integer; type:Code[5]; repetitions:Integer)
begin
for i := 1 to repetitions do begin
Exec('Set%1_No%2.Proc%3%4(1)',setNo,codeunitNo,procedureNo,type);
Set0_No0.Proc0A(1);
progressDialog.Update(2,i);
end;
end;
The feature you require is not available in AL.
There are however a couple of options you could consider:
Using a combination of enums, interfaces and codeunits you can remove a lot of boilerplate code.
Using a script (e.g. PowerShell) you could parse all your source files, find the codeunits and their procedures and then generate a new codeunit that invokes each procedure.

Adding seconds to time variable

*data final;
set final;
duration = redate-ondate;
dudays = floor(duration/86400);
duhrs = floor((duration-(dudays*86400))/3600);
dumins = floor((duration-(dudays*86400+duhrs*3600))/60);
****************Set up new variable duration**************;
attrib dur length=$11.;
if ae_term ne 'None' and dudays ne . then
dur = left(put(dudays,z2.))||':'||left(put(duhrs,z2.))||':'||left(put(dumins,z2.));
else dur = '';
run;*
I have this code but need to calculate seconds and concatenate to dur as I have an adverse event that is less than a minute so won't display. What's the most efficient way to do this?
You can calculate the remaining seconds and then append to your time string like this:
dusec = duration-(dudays*86400+duhrs*3600+dumins*60);
if ae_term ne 'None' and dudays ne . then
dur = left(put(dudays,z2.))||':'||left(put(duhrs,z2.))||':'||left(put(dumins,z2.)||':'||left(put(dusec,z2.)));
One note - using put(dudays,z2.) assumes your duration is never more than 99 days.
Ok, this should simplify things somewhat:
dudays = FLOOR(duration/86400);
duhrs = FLOOR(MOD(duration,86400)/3600);
dumins = FLOOR(MOD(duration,3600)/60);
dusec = MOD(duration,60);
The difference between two datetime values is a number of seconds (so it is also a datetime value). You can use the DATEPART() and TIMEPART() function to divide into the number of days and seconds since midnight. The TOD11.2 format will display seconds in HH:MM:SS.mm style.
length dur $20;
if n(redate,ondate)=2 and ae_term not in (' ','None') then do;
duration = redate-ondate;
dur = catx(':',datepart(duration),put(timepart(duration),tod11.2));
end;

Classic report, dynamic display with PL / SQL content

In APEX I created a page and here a region. The region reports a classic report. I have selected "PL/SQL function body that returns an SQL query" as the source. Here I have also deposited the following code
declare
l_date_string varchar2(32000);
l_date_diff number(4);
x NUMBER := 0;
l_script varchar2(32000);
l_script_pivot varchar2(32000);
new_date varchar(256);
begin
l_date_diff:=TO_DATE(:P2066_DATE_UNTIL, 'dd.mm.yyyy') - TO_DATE(:P2066_DATE_FROM, 'dd.mm.yyyy') ;
While X < l_date_diff+1 Loop
new_date := to_char(TO_DATE(:P2066_DATE_FROM, 'dd.mm.yyyy')+X,'dd.mm.yyyy');
l_date_string := l_date_string || ',''' || new_date || '''';
X := X + 1;
End Loop;
l_date_string := substr(l_date_string,2);
l_script := 'Select * from
(Select
pkey,
to_char(createdformat,''dd.mm.yyyy'') business_date,
regexp_substr(statistics, ''business_\w*'') business_statistics
from
gss.business_data
where
statistics like ''%business_%''
and createdformat between :P2066_DATE_FROM and :P2066_DATE_UNTIL
) ';
l_script_pivot := l_script || ' pivot(
count(pkey)
for business_date
in ('||l_date_string||'))';
sys.htp.p('<li>' || l_script_pivot || ' </li>' );
return l_script_pivot;
end;
The first column, Business_Statistis, is always displayed, the date in the subsequent columns should be displayed dynamically - depending on the selection of the period.
I also spent the respective code according to the time period selection and knew it successfully as a classic report with an SQL query. That's working.
How can I now dynamically update the classic report with a PL / SQL action. That means that depending on the result, the Classic Report is always displayed?
I once selected to use Generic Number of Columns in parallel, with a number of 365. Then he shows me the columns, but the column heading is not the date but Col2, Col3, Col4 and so on
There are a few ways to solve this issue.
Option 1: If you're happy to use "Generic Number of Columns", then select PL/SQL as your "Headings Type". Then define your headings with PL/SQL e.g.
DECLARE
v_heading varchar2(2000);
l_date_diff number(4);
BEGIN
v_headings := 'business_statistics';
l_date_diff:=TO_DATE(:P2066_DATE_UNTIL, 'dd.mm.yyyy') - TO_DATE(:P2066_DATE_FROM, 'dd.mm.yyyy') ;
WHILE X < l_date_diff+1 LOOP
new_date := to_char(TO_DATE(:P2066_DATE_FROM, 'dd.mm.yyyy')+X,'dd.mm.yyyy');
v_headings := v_headings ||':' || new_date ;
X := X + 1;
END LOOP;
END;
Option 2: I assume you are using "PL/SQL function body that returns an SQL query" to get around the "in clause" of the pivot? Another way to fix this is to define your pivot clause as a page item. E.g. P2066_PIVOT_CLAUSE. You can then set the pivot clause with a before header process. Then you can use standard SQL in your report.
i.e.
SELECT * FROM
(SELECT pkey,
to_char(createdformat,'dd.mm.yyyy') business_date,
regexp_substr(statistics, 'business_\w*') business_statistics
FROM
gss.business_data
WHERE
statistics like '%business_%'
AND createdformat BETWEEN :P2066_DATE_FROM AND :P2066_DATE_UNTIL)
PIVOT (COUNT(pkey)FOR business_date in (&P2066_PIVOT_CLAUSE.))

Get time difference between two times in swift 3

I have 2 variables where I get 2 times from datePicker and I need to save on a variable the difference between them.
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HHmm"
time2 = timeFormatter.date(from: timeFormatter.string(from: datePicker.date))!
I have tried to get the timeIntervalSince1970 from both of them and them substract them and get the difference on milliseconds which I will turn back to hours and minutes, but I get a very big number which doesn't corresponds to the actual time.
let dateTest = time2.timeIntervalSince1970 - time1.timeIntervalSince1970
Then I have tried using time2.timeIntervalSince(date: time1), but again the result milliseconds are much much more than the actual time.
How I can get the correct time difference between 2 times and have the result as hours and minutes in format "0823" for 8 hours and 23 minutes?
The recommended way to do any date math is Calendar and DateComponents
let difference = Calendar.current.dateComponents([.hour, .minute], from: time1, to: time2)
let formattedString = String(format: "%02ld%02ld", difference.hour!, difference.minute!)
print(formattedString)
The format %02ld adds the padding zero.
If you need a standard format with a colon between hours and minutes DateComponentsFormatter() could be a more convenient way
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute]
print(formatter.string(from: time1, to: time2)!)
TimeInterval measures seconds, not milliseconds:
let date1 = Date()
let date2 = Date(timeIntervalSinceNow: 12600) // 3:30
let diff = Int(date2.timeIntervalSince1970 - date1.timeIntervalSince1970)
let hours = diff / 3600
let minutes = (diff - hours * 3600) / 60
To get duration in seconds between two time intervals, this can be used -
let time1 = Date(timeIntervalSince1970: startTime)
let time2 = Date(timeIntervalSince1970: endTime)
let difference = Calendar.current.dateComponents([.second], from: time1, to: time2)
let duration = difference.second
Now you can do it in swift 5 this way,
func getDateDiff(start: Date, end: Date) -> Int {
let calendar = Calendar.current
let dateComponents = calendar.dateComponents([Calendar.Component.second], from: start, to: end)
let seconds = dateComponents.second
return Int(seconds!)
}

How to remove weekdays in duration data type NAV

How can i remove weekdays in the data type duration in CAL ?
for example:
duration := datetime2 - datetime1
But duration do contains Saturdays and Sundays. How can i remove them ?
Simple answer: you can not.
But you can use the Date virtual table. Something like this:
Date.SETRANGE("Period Type", Date."Period Type"::Date);
Date.SETFILTER("Period Start", '%1..%2', DT2DATE(datetime1), DT2DATE(datetime2));
Date.SETRANGE("Period No.", 1, 5); // only days 1 - 5 = weekdays
EXIT(Date.COUNT); // returns number of days
You can then convert the number of days to a duration with a simple multiplication. A Duration is nothing more than the number of milliseconds.
1 hour = 3600000ms.
Therefore:
MESSAGE('%1', NoOfDays);
dur := NoOfDays * 24 * 3600 * 1000;
MESSAGE('%1', dur);