Two Datetimes, Calculate Duration

Two Datetimes, Calculate Duration

Two Datetimes, Calculate Duration

2つの日時, 経過時間の計算

Calculates the duration between Datetime-A and Datetime-B; like elapsed days (e.g. “1.38 d”), hours (e.g. “33.33 h”), minutes (e.g. “2000.00 min”) and/or time (e.g. “33:20”). A minus sign is given if Datetime-B is earlier than Datetime-A.

Auto Step icon
Configs for this Auto Step
StrConfA
A: Set Datetime (like “2022-12-31 00:00”) *#{EL}
StrConfB
B: Set Datetime (like “2023-01-01 09:20”) *#{EL}
SelectConfC
C: Select NUMERIC DATA for Elapsed Days (update)
SelectConfD
D: Select NUMERIC DATA for Elapsed Hours (update)
SelectConfE
E: Select NUMERIC DATA for Elapsed Minutes (update)
SelectConfF
F: Select STRING DATA for Elapsed Time h:mm (update)
Script (click to open)
// GraalJS Script (engine type: 2)

//////// START "main()" /////////////////////////////////////////////////////////////////

main();
function main(){

//// == Config Retrieving / 工程コンフィグの参照 ==

const strTimeA          = configs.get      ( "StrConfA" );     /// REQUIRED
  if( strTimeA        === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {A: String} is empty \n" );
  }
const strTimeB          = configs.get      ( "StrConfB" );     /// REQUIRED
  if( strTimeB        === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {B: String} is empty \n" );
  }
const numPocketDays     = configs.getObject( "SelectConfC" );  // NotRequired
const numPocketHours    = configs.getObject( "SelectConfD" );  // NotRequired
const numPocketMinutes  = configs.getObject( "SelectConfE" );  // NotRequired
const strPocketTime     = configs.getObject( "SelectConfF" );  // NotRequired



//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)



//// == Calculating / 演算 ==
const dateTimeA       = parseAsLocalDate ( strTimeA );
const dateTimeB       = parseAsLocalDate ( strTimeB );
const numMsecA        = dateTimeA.getTime();
const numMsecB        = dateTimeB.getTime();
const numMsecDuration = numMsecB - numMsecA;



//// == Data Updating / ワークフローデータへの代入 ==
if( numPocketDays !== null ){
  engine.setData ( numPocketDays,
    new java.math.BigDecimal( numMsecDuration /1000 /60 /60 /24 )
  );
}
if( numPocketHours !== null ){
  engine.setData ( numPocketHours,
    new java.math.BigDecimal( numMsecDuration /1000 /60 /60 )
  );
}
if( numPocketMinutes !== null ){
  engine.setData ( numPocketMinutes,
    new java.math.BigDecimal( numMsecDuration /1000 /60 )
  );
}
if( strPocketTime !== null ){
  let numPositiveIntM = Math.floor ( Math.abs ( ( numMsecDuration /1000 /60 ) ) );
  //  eg, 2000.00m -> 2000m,  -7.38m -> 7,  -67.38m -> 67
  let numH = Math.floor ( numPositiveIntM /60 );
  let numM = numPositiveIntM %60;
  if ( numMsecDuration < 0 ){
    engine.setData ( strPocketTime, '-' + numH + ":" + ( '0' + numM ).slice( -2 ) );
  }else{
    engine.setData ( strPocketTime,       numH + ":" + ( '0' + numM ).slice( -2 ) );
  }
}


} //////// END "main()" /////////////////////////////////////////////////////////////////


function parseAsLocalDate ( str ){ // strDateOrDatetime
  //
  // Searches a Date-or-Datetime String for YYYY, MM, DD, hh:mm in that order and
  //  returns JavaScript `Date` object.
  // Any format is forcibly recognized as LOCAL DATETIME. -- UNIQUE --
  // Supports "ISO 8601 format", "BPMS date format", "BPMS datetime format", etc,,,
  //
  // String "2022-12-31 23:59"          (Questetra BPMS datetime format)
  // ⇒ Date 2022-12-31T23:59:00+XX:00
  // String "2022-12-31 23:59:59"       (SQL Time format)
  // ⇒ Date 2022-12-31T23:59:00+XX:00
  // String "2022-12-31T23:59:59.999Z"  (ISO 8601 format)
  // ⇒ Date 2022-12-31T23:59:00+XX:00   // UNIQUE: Timezone not evaluated
  // String "2022-12-31"                (Questetra BPMS date format) 
  // ⇒ Date 2022-12-31T00:00:00+XX:00   // UNIQUE: not UTC
  // String "2022/12/31"                (Windows date-ja format)
  // ⇒ Date 2022-12-31T00:00:00+XX:00   // UNIQUE: not UTC
  // String "2022年12月31日"            (日本語/Japanese)
  // ⇒ Date 2022-12-31T00:00:00+XX:00
  //
  // String "20221231"
  // ⇒ Date 2022-12-31T00:00:00+XX:00   // UNIQUE: not UTC
  // String "20221231T235959Z"          (ISO 8601 format)
  // ⇒ Date 2022-12-31T23:59:00+XX:00   // UNIQUE: Timezone not evaluated
  // String "20221231T2359"
  // ⇒ Date 2022-12-31T23:59:00+XX:00

  if( str === "" ){
    throw new Error( "\n AutomatedTask ParseDateError:" +
                     " String is empty \n" );
  }
  const arrNumParts = str.match( /\d+/g );
  if( arrNumParts === null ){
    throw new Error( "\n AutomatedTask ParseDateError:" +
                     " No numeric characters in: " + str + "\n" );
  }

  /// function default
  let numYear    = 0; // limit in QBPMS: 1900 to 2100 (asof 2022-12)
  let indexMonth = 0;
  let numDay     = 0;
  let numHours   = 0;
  let numMinutes = 0;

  /// case: startsWith YYYYMMDD
  if( arrNumParts[0].length === 8 ){
    numYear      = parseInt( arrNumParts[0].slice( 0, 4 ), 10 );
    indexMonth   = parseInt( arrNumParts[0].slice( 4, 6 ), 10 ) - 1;
    numDay       = parseInt( arrNumParts[0].slice( 6, 8 ), 10 );
    if( arrNumParts.length > 1 ){ // "20221231T2359"
      numHours   = parseInt( arrNumParts[1].slice( 0, 2 ), 10 );
      numMinutes = parseInt( arrNumParts[1].slice( 2, 4 ), 10 );
    }

  /// case: not startsWith YYYYMMDD, like "2022-12-31 23:59"
  }else{
    if( arrNumParts.length < 3){
      throw new Error( "\n AutomatedTask ParseDateError:" +
                       " 3 Parts of numeric characters are needed in: " + str + "\n" );
    }
    numYear      = parseInt( arrNumParts[0], 10 );
    indexMonth   = parseInt( arrNumParts[1], 10 ) - 1;
    numDay       = parseInt( arrNumParts[2], 10 );
    if( arrNumParts.length > 4){
      numHours   = parseInt( arrNumParts[3], 10 );
      numMinutes = parseInt( arrNumParts[4], 10 );
    }
  }

  /// return JavaScript `Date` object
  return new Date( numYear, indexMonth, numDay, numHours, numMinutes );
}



/*
Notes:
- When the process reaches the automated step, the "Two Datetimes" will be automatically evaluated.
    - If "A: Process start time" and "B:`#{#now}`", the elapsed time to this step will be calculated.
- This automatic process evaluates both "2022-12-31" and "2022-12-31 00:00" as local time.
    - On JST platform (+9), both are interpreted as "2022-12-30T15:00:00Z" (2022-12-31T00:00:00+09:00).
    - Even if in ISO 8601 format with time zone, it is still evaluated as local time.
    - https://support.questetra.com/addons/converter-date-or-datetime-string-to-workflow-datetime-2022/
- Datetime-A or Datetime-B can be set in various formats.
    - Fixed config
        - `2022-12-31 00:00`.
        - `2022-12-31 00:00`
        - `2022-12-31` (= `2022-12-31 00:00`)
        - `2022-12-31` (= `2022-12-31 00:00`)
    - Dynamic config (Referring to process data)
        - `#{#q_TimeOfBirth}`
            - (Fixed time)
        - `#{#q_LastDayOfFiscalYear} 18:00`
            - (DATE data + Fixed time)
        - `#{#q_BirthDay}`
            - (If only DATE is set, assumed to be 00:00.)
        - `#{#q_OrderReceivedTime.addMonths(1).getLastTimeInMonth().getFirstTimeInDate().addHours(7)}`
            - 7:00 AM of the last day of the month following the "Order Received Time".
        - `#{processInstanceStartDatetime}` (process start time)
        - `#{#now}` (token arrival time)
    - R2272: Output of Strings via EL syntax https://questetra.zendesk.com/hc/en-us/articles/360024292872-R2272
        - R2271: Output of Date and Datetime Data via EL syntax https://questetra.zendesk.com/hc/en-us/articles/360024292672-R2271

Notes (ja):
- 案件(トークン)がこの自動工程に到達した際、「2つの時刻」が評価されます。
    - たとえば「A:プロセス開始日時」「B:`#{#now}`」とセットすれば、自動工程までの所用時間が算出されます。
- この自動工程では "2022-12-31" も "2022-12-31 00:00" もローカルタイムとして評価します。UNIQUE
    - JST基盤(+9)の場合、どちらも "2022-12-30T15:00:00Z" (2022-12-31T00:00:00+09:00) と解釈されます。
    - 仮にタイムゾーンが記載された ISO 8601 形式であっても、ローカルタイムとして評価されます。
    - https://support.questetra.com/ja/addons/converter-date-or-datetime-string-to-workflow-datetime-2022/
- 様々な書式で「日時A・日時B」をセットできます。
    - 固定的な設定
        - `2022-12-31 00:00`
        - `2022/12/31 00:00`
        - `2022-12-31` (= `2022-12-31 00:00`)
        - `2022年12月31日` (= `2022-12-31 00:00`)
        - `20221231 235959` (= `2022-12-31 23:59`)
    - 動的な設定(プロセスデータ等を参照する設定)
        - `#{#q_TimeOfBirth}`
            - (Fixed time)
        - `#{#q_LastDayOfFiscalYear} 18:00`
            - (DATE data + Fixed time)
        - `#{#q_BirthDay}`
            - (If only DATE is set, assumed to be 00:00.)
        - `#{#q_OrderReceivedTime.addMonths(1).getLastTimeInMonth().getFirstTimeInDate().addHours(7)}`
            - DATETIME "受注時刻" の翌月の末日の朝7時
        - `#{processInstanceStartDatetime}` (プロセス開始日時)
        - `#{#now}` (トークンがこの自動工程に到達した時刻)
    - R2272: EL式による文字列としての出力(データ設定式) https://questetra.zendesk.com/hc/ja/articles/360024292872-R2272
        - └ R2271: EL式による日付日時としての出力(データ設定式) https://questetra.zendesk.com/hc/ja/articles/360024292672-R2271
*/

Download

warning Freely modifiable JavaScript (ECMAScript) code. No warranty of any kind.
(Installing Addon Auto-Steps are available only on the Professional edition.)

Notes

  • When the process reaches the automated step, the “Two Datetimes” will be automatically evaluated.
    • If “A: Process start time” and “B:#{#now}“, the elapsed time to this step will be calculated.
  • This automated step evaluates both “2022-12-31” and “2022-12-31 00:00” as local time.

Capture

Calculates the duration between Datetime-A and Datetime-B; like elapsed days (e.g. "1.38 d"), hours (e.g. "33.33 h"), minutes (e.g. "2000.00 min") and/or time (e.g. "33:20"). A minus sign is given if Datetime-B is earlier than Datetime-A.

Appendix

  • Datetime-A or Datetime-B can be set in various formats.
    • Fixed config
      • 2022-12-31 00:00.
      • 2022-12-31 00:00
      • 2022-12-31 (= 2022-12-31 00:00)
      • 2022-12-31 (= 2022-12-31 00:00)
    • Dynamic config (Referring to process data)
      • #{#q_TimeOfBirth}
        • (Fixed time)
      • #{#q_LastDayOfFiscalYear} 18:00
        • (DATE data + Fixed time)
      • #{#q_BirthDay}
        • (If only DATE is set, assumed to be 00:00.)
      • #{#q_OrderReceivedTime.addMonths(1).getLastTimeInMonth().getFirstTimeInDate().addHours(7)}
        • 7:00 AM of the last day of the month following the “Order Received Time”.
      • #{processInstanceStartDatetime} (process start time)
      • #{#now} (token arrival time)
    • R2272: Output of Strings via EL syntax

See Also

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top

Discover more from Questetra Support

Subscribe now to keep reading and get access to the full archive.

Continue reading