Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Builtin functions

Usable as an expression anywhere, e.g. &Username = USERID(). Most take zero arguments with a fixed return type; Val() is the exception (see its own entry).

FunctionReturnDescription
USERID()char(10)IBM i user profile running this program. No arguments.
PGNAME()char(10)Object name of this same program — a compile-time constant, not a runtime lookup. No arguments.
TODAY()dateCurrent system date. No arguments.
TIME()char(8)Current system time formatted "HH:MM:SS" (8 characters). No arguments.
Val(&CharVariable)same as the assignment’s destinationParses a char value into a Number, using the destination of the assignment’s precision/scale — unlike other builtins, it has no fixed return type. Only valid directly as &NumberVariable = Val(&CharExpr); using it anywhere else (nested in another expression, as a Do/Call argument, etc.) is an error.
CurrentInput()char(30)See @Source: Event and Screen.
Cursor(&variable)conditionTrue when the cursor is on the control bound to &variable (an Input or a visible DataGridView column). Use it as a direct condition: If Cursor(&Codigo), without = 1. Same scope as CurrentInput(). Errors: E00336, E00337, E00338. See @Source: Event and Screen.
String(&NumberVariable, integerDigits[, decimalDigits][, fill])char(integerDigits [+ decimalDigits])Converts a Number to a fixed-width char, e.g. to concatenate it in a Message(...) (which only accepts text). integerDigits/decimalDigits must be integer literals (compile-time constants): the result width is integerDigits + decimalDigits, with no decimal separator. decimalDigits is optional (default 0). fill is optional: a literal text of exactly one character (E00341 otherwise). Without fill, leading zeros of the integer part are replaced by spaces; with "0" the zeros are kept; with any other character (e.g. "*") that character is used. The units digit of the integer part is always shown: String(0, 5) gives " 0". Negative numbers show the - sign, which takes one of the requested width positions (the result still measures integerDigits + decimalDigits): with "0" fill it replaces the first character (String(-2, 5, "0") = -0002); without fill it sits right next to the first digit (String(-15, 6) = -15); with another fill character, likewise (String(-15, 6, "*") = ***-15). If the number uses all positions, the sign replaces the most significant digit, so for negatives request one extra position in integerDigits. Positives and zero are unchanged. Forms: String(n, 5), String(n, 5, 2), String(n, 5, "0"), String(n, 5, 2, "0"), String(n, 5, "*"). Errors: E00206, E00207, E00208, E00341.
Int(expression)NumberReturns the integer part of a number: truncates toward zero, does not round (Int(10 / 3) is 3). Takes exactly 1 argument of type Number (E00342 if the count is not 1; E00343 if it is not numeric). If the argument is a variable or field of known type, the result is Number(argument's integer digits, 0); with a compound expression (e.g. &a / &b) the type is not restricted and it can be stored in any Number (RPG truncates on assignment). It translates to %dec(expr : 30 : 0).
SubString(&Variable, start, length)char(length)Trims a fixed-width chunk out of a char value (variable or literal) so it fits into a smaller variable — e.g. &Short40 = SubString(&Long120, 1, 40). Without this, directly assigning a wider char to a narrower one is a compile-time error. start/length must be integer literals. When the source size is known at compile time, start + length - 1 exceeding it is also a compile-time error.
Trim(&Variable)same as the argument (char/varchar)Removes blanks from both left and right. A single argument.
LTrim(&Variable)same as the argumentRemoves blanks from the left. A single argument.
RTrim(&Variable)same as the argumentRemoves blanks from the right. A single argument.
Upper(&Variable)same as the argumentConverts a char/varchar to uppercase, including accented letters. A single argument (otherwise error E00225); on a type other than char/varchar it gives E00226. Translated to %upper. See Upper and Lower release requirement.
Lower(&Variable)same as the argumentConverts a char/varchar to lowercase, including accented letters. Same rules as Upper. Translated to %lower.
Length(&Variable)numberSize of a char/varchar value: for varchar, the actual runtime content length; for char, its declared fixed length. A single argument.
IndexOf(needle, &haystack)numberSearches for needle inside haystack and returns the raw position found (1-based if found, 0 if not), with no conversion applied. Exactly two arguments (text to search for, text to search in).
Round(expression, decimals)number(30, decimals)Rounds expression half-adjust (half rounds up, RPG %dech) to decimals. decimals must be an integer literal between 0 and 29 (a compile-time constant: it defines the scale of the result). The whole expression is evaluated before rounding, so a division is not truncated first. The first argument must be Number. Errors: E00328 (argument count), E00329 (decimals not a literal or out of range), E00330 (first argument not numeric).
Replace(text, search, new)varcharReplaces all occurrences of search with new, without overlapping (%scanrpl). The result is a varchar with the length of the source text: if the replacement is longer, assigning it to a smaller variable truncates it. Blanks in search count (as in IndexOf): use Trim() if needed.
Contains(text, search)conditionTrue if text contains search. Used as a condition (If, While, And, Or), not assigned to a variable. Same blank handling as IndexOf.
StartsWith(text, search)conditionTrue if text starts with search. Same rules as Contains.
EndsWith(text, search)conditionTrue if text ends with search. Same rules as Contains; translated to %scanr, which requires IBM i 7.4 or later. For a char with trailing blanks use EndsWith(Trim(&Text), "end").
PadLeft(text, width[, fill])char(width)Right-aligns, filling on the left. width is an integer literal between 1 and 32766; fill is a literal of one character (a space by default). Ignores trailing blanks of the text; if the text is longer than width, it is cut on the left.
PadRight(text, width[, fill])char(width)Left-aligns, filling on the right. Same rules as PadLeft; if the text is longer than width, it is cut on the right.
Translate(text, from, to)same as textChanges each character of from to the one at the same position in to (%xlate).
Abs(n)numberAbsolute value (%abs).
Sqrt(n)numberSquare root (%sqrt).
Mod(a, b)numberRemainder of the integer division (%rem). Requires operands without decimals (E00362; use Int() to truncate). The result has the sign of the dividend: Mod(17, 5) is 2 and Mod(-17, 5) is -2.
ErrorCode()number(5)Status of the caught error (%status), e.g. 102 for a division by zero. No arguments. Only inside a Catch (E00366 outside). See Try / Catch.
ErrorMessage()char(80)Message text of the caught error (PSDS subfield, positions 91-170). No arguments. Only inside a Catch (E00366 outside). Apply Trim() to remove trailing blanks.
Check(text, characters)numberPosition (1-based) of the first character of text that is not in characters; 0 if all are. Trailing blanks of a char do not count (they are padding). Maps to %check.
Concat(text1, text2)varcharJoins two texts (RPG +). Each operand keeps its own blanks.
Div(number, divisor)numberInteger quotient, truncated toward zero (Div(-7, 2) is -3). Maps to %div.
Min(number1, number2)numberThe smaller of two numbers. Maps to %min.
Max(number1, number2)numberThe larger of two numbers. Maps to %max.
DateTimeToTimestamp(date, time)timestampJoins a date and a time into a timestamp (the time has no microseconds, so they are 000000). Maps to a text conversion with %timestamp.

Upper and Lower release requirement

Upper and Lower are translated to the RPG BIFs %upper and %lower, which depend on the IBM i release:

  • IBM i 7.5: available natively.
  • IBM i 7.3 and 7.4: only with the April 2021 PTFs. Compiler: SI76100 (7.3) or SI76101 (7.4). In addition, the runtime PTF SI76098 (7.3) or SI76099 (7.4) must be installed on every system where the program runs; without it, the program fails with MCH4437.
  • IBM i 7.2 and earlier: not available.

Date, time and timestamp

Year/Month/Days/Hour/Minute/Second are polymorphic: they accept date/time/timestamp as appropriate (Year/Month/Days with date or timestamp; Hour/Minute/Second with time or timestamp) — there’s no need for a different name per type.

format (where it applies) is always optional: if omitted, it falls back to the value configured in @GeneratorConfig (Date Format/Time Format/Timestamp Format); if there’s no configuration either, the system default format is used.

FunctionReturnDescription
Year(&Variable)number(4)Year of a date/timestamp.
Month(&Variable)number(2)Month of a date/timestamp.
Days(&Variable)number(2)Day of the month of a date/timestamp.
Hour(&Variable)number(2)Hour of a time/timestamp.
Minute(&Variable)number(2)Minute of a time/timestamp.
Second(&Variable)number(2)Second of a time/timestamp.
DateDiff(&Date1, &Date2, Unit)numberDifference between two dates, in Days/Months/Years (bare word, not a string). Positive when Date1 is later than Date2, negative otherwise.
TimeDiff(&Time1, &Time2, Unit)numberSame as DateDiff, over time, with Hours/Minutes/Seconds.
TimestampDiff(&Ts1, &Ts2, Unit)numberSame as DateDiff, over timestamp, with all 6 units enabled: Seconds/Minutes/Hours/Days/Months/Years.
DateAdd(&Date, amount, Unit)dateAdds (or subtracts, if amount is negative) days/months/years to a date. amount can be any number expression (not just a literal).
TimeAdd(&Time, amount, Unit)timeSame as DateAdd, over time, with Hours/Minutes/Seconds.
TimestampAdd(&Ts, amount, Unit)timestampSame as DateAdd, over timestamp, with all 6 units.
IsDate(value[, format])number(1)Validates whether value (char/varchar/number) is a valid date in format (optional — one of Iso/Usa/Eur/Jis/Mdy/Dmy/Ymd/Jul, or a text pattern; see Date format patterns). Returns 1/0 (WARP has no boolean type). Not a pure expression — that’s why, just like Val(), it’s only valid directly as &NumberVariable = IsDate(...).
IsTime(value[, format])number(1)Same as IsDate, over time (format one of Hms/Iso/Usa/Eur/Jis).
IsTimestamp(value[, format])number(1)Same as IsDate, over timestamp (format one of Iso/Usa/Eur/Jis). Iso is the recommended, most widely compatible format.
StringToDate(string[, format])dateConverts char/varchar to date. format also accepts a text pattern.
NumberToDate(number[, format])dateConverts number to date — same format rules as StringToDate (including text patterns).
StringToTime(string[, format])timeConverts char/varchar to time.
StringToTimestamp(string[, format])timestampConverts char/varchar to timestamp.
DateToString(&Date[, format])char(10)Converts date to text — same format rules. With a text pattern it returns a char as long as the pattern (maximum 10).
TimeToString(&Time[, format])char(8)Converts time to text.
TimestampToString(&Ts[, format])char(26)Converts timestamp to text (26 = ISO width with microseconds).
Now()timestampCurrent system timestamp. No arguments.

Date format patterns

In StringToDate, NumberToDate, IsDate and DateToString, the second format argument accepts, besides the single keywords (Iso, Usa, Eur, Jis, Mdy, Dmy, Ymd, Jul), a literal text pattern with YYYY (4-digit year), MM and DD. Each must appear exactly once, in any order, with or without separators, and is case-insensitive. Examples: "YYYYMMDD", "DDMMYYYY", "DD/MM/YYYY", "YYYY-MM-DD", "MM.DD.YYYY".

  • Resolved at compile time: the RPG extracts year, month and day with %subst at fixed positions and reads them as *iso.
  • char/varchar: the value must be exactly as long as the pattern. A shorter varchar fails at runtime.
  • NumberToDate/IsDate with number: the number is converted to text with leading zeros (%editc(n : 'X')) and the pattern separators do not count (a number has none). The number must have as many digits as the pattern (e.g. number(8) for "DDMMYYYY").
  • DateToString: returns a char as long as the pattern (maximum 10); e.g. "YYYYMMDD" gives char(8).
  • 2-digit years (YY), repeated or missing fields, and letters other than Y/M/D are not allowed: E00253 is reported.
&Date = StringToDate(&DateText, "DD/MM/YYYY")
&Date2 = NumberToDate(&Number, "DDMMYYYY")   // &Number: number(8)
&IsValid = IsDate(&Number, "YYYYMMDD")
&Text = DateToString(&Date, "YYYYMMDD")      // char(8)

Text and calculation: Replace, Contains, Pad, Translate, Abs, Sqrt, Mod

  • Contains, StartsWith and EndsWith are conditions: write them directly in If, While, And or Or, like Cursor.
  • Replace, Contains, StartsWith, EndsWith and Translate treat blanks in the arguments as part of the text. For a char with trailing blanks, apply Trim() before comparing.
  • PadLeft and PadRight always return a char of the given width; width and fill must be literals (E00361 otherwise).
  • Wrong argument count (E00358), non-text argument (E00359) and non-numeric argument (E00360) are reported with the function name.
  • Sqrt of a negative number and Mod with a zero divisor are RPG runtime errors (status 00101 and 00102) that abort the program until Try/Catch exists.
&Clean = Replace(&Text, "-", " ")
If Contains(&Text, "world")
    Message("Contains the word", Info)
EndIf
If StartsWith(&Code, "AB") And EndsWith(Trim(&Code), "99")
    Message("Valid code", Info)
EndIf
&Code5 = PadLeft(&Number, 5, "0")     // "00042"
&Label = PadRight(&Name, 20)          // left-aligned, 20 characters
&Upper = Translate(&Text, "abc", "ABC")
&Rest = Mod(17, 5)                    // 2
&Absolute = Abs(&Difference)
&Root = Sqrt(&Area)

Examples

&Username = USERID()
&Program = PGNAME()
&Today = TODAY()
&CurrentTime = TIME()

&Quantity = Val(&QuantityText)

Message("Total: " + String(&Total, 9, 2), Info)

&PerPart = Int(&Total / &Parts)             // integer part: 100 / 3 -> 33
&Text1 = String(&Row, 5)                    // "    7"  (spaces)
&Text2 = String(&Row, 5, "0")               // "00007"  (zeros)
&Text3 = String(&Row, 5, "*")               // "****7"
&Text4 = String(&Amount, 6, 2, "0")         // 6 integer + 2 decimal digits, zero-filled

&Short = SubString(&Long, 1, 40)
&Clean = Trim(&WithSpaces)
&Code = Upper(Trim(&Input))
&Text = Lower(&Text)
&Size = Length(&Description)
&Pos = IndexOf("@", &Email)
&Amount = Round(&Total / &ExchangeRate, 2)
&New = Replace(&Text, "a", "b")
&Code5 = PadLeft(&Number, 5, "0")
&Rest = Mod(&Total, 7)

&DueDate = DateAdd(&Today, 30, Days)
&DaysUntilDue = DateDiff(&DueDate, &Today, Days)
&IsValidDate = IsDate(&DateText, Dmy)

&Now = Now()
&HoursElapsed = TimestampDiff(&Now, &Start, Hours)

Int and String with fill

Breaking change in String. Previously, String(n, integerDigits) padded with leading zeros. Now, by default, those zeros are replaced by spaces. To keep the old behavior, pass the fill: String(n, 5, "0").

Equivalents in generated RPG:

FormRPG
String(n, 5) (spaces)%editw(%dec(n : total : dec) : ' 0')
String(n, 5, "0") (zeros)%editc(%dec(n : total : dec) : 'X')
String(n, 5, "*") (other character)%xlate(' ' : '*' : %editw(...))

Sign of negative numbers

String shows the - sign of negative numbers. The sign takes one of the requested width positions, so the result still measures integerDigits + decimalDigits:

CallResult
String(-2, 5, "0")-0002
String(-15, 6) -15
String(-15, 6, "*")***-15

If the number uses all positions, the sign replaces the most significant digit; for negatives, request one extra position in integerDigits. Positives and zero are unchanged. Decimals still have no decimal point (12.00 with 2 decimals gives 1200). For this, the generated RPG includes a helper procedure WarpStrSign (once per program).

Int translates to %dec(expr : 30 : 0). Full example: example/programs/PNUM01.warp.