日付, N営業日後の算出 (Date, Calc after N Business Days)
任意日付のN営業日後を計算します。Nがマイナスの場合、N営業日前を計算します。あらかじめ祝祭日の設定が必要です。会社オリジナルの休日を追加することも可能です。
Configs
- A1: 全ての祝祭日(会社休日含む)を各行にセットしてください (例 “2021/12/25,クリスマス” )#{EL}
- B1: 定休日となる曜日と曜日表記を各行にセットしてください (例 “0,日曜日” )#{EL}
- B2: 例外的に営業する定休日を各行にセットしてください (例 “2022/4/1” )#{EL}
- C1: 計算起点となる日付もしくは日時をセットしてください (例 “2022-04-29” ) *#{EL}
- C2: 加算する日数をセットしてください (例 “3” “-2” ) *#{EL}
- D1: 算出された日付が格納される日付型データ項目を選択してください (更新) *
- D2: 非営業日とみなされた日付と名称が格納される文字列型データ項目を選択してください (更新)
Script (click to open)
// GraalJS Script (engine type: 2)
//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){
//// == Config Retrieving / 工程コンフィグの参照 ==
const strHolidays = configs.get( "StrConfA1" ); // NotRequired ///////////
if( strHolidays === "" ){
engine.log( " AutomatedTask ConfigWarning:" +
" Config {A1: Holidays} is empty" );
}
let arr2dHolidays = parseTwoColOfCsv( strHolidays );
const strClosedDays = configs.get( "StrConfB1" ); // NotRequired ///////////
if( strClosedDays === "" ){
engine.log( " AutomatedTask ConfigWarning:" +
" Config {B1: Closed DaysOfWeek} is empty" );
}
let arr2dClosedDays = parseTwoColOfCsv( strClosedDays );
const strOpenDespiteWeekends = configs.get( "StrConfB2" ); // NotRequired ///////////
let arrOpenDespiteWeekends = strOpenDespiteWeekends.split("\n");
const strTarget = configs.get( "StrConfC1" ); /// REQUIRED /////////////
if( strTarget === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {C1: Date or Datetime} is empty \n" );
}
let dateTarget = parseDateAsMidnight( strTarget ); // the first of the date
const strToAdd = configs.get( "StrConfC2" ); /// REQUIRED /////////////
let numToAdd = parseInt( strToAdd );
if( isNaN( numToAdd ) ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {C2} is not an integer \n" );
}
const datePocketOutput = configs.getObject( "SelectConfD1" ); /// REQUIRED ///////////
const strPocketNonbiz = configs.getObject( "SelectConfD2" ); // NotRequired ///////////
//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)
//// == Calculating / 演算 ==
if( numToAdd === 0 ){
engine.log( " AutomatedTask ConfigWarning:" +
" Config {C2} is Zero, Not calculated" );
engine.setData( datePocketOutput, new java.sql.Date( dateTarget.getTime() ) );
return;
}
Date.prototype.toBpmsYMD = function() {
var dd = this.getDate(); var mm = this.getMonth() + 1; // getMonth() is zero-based
return [ this.getFullYear(), (mm>9 ? '' : '0') + mm, (dd>9 ? '' : '0') + dd ].join('-');
};
let n = 0;
let strNonbiz = "";
while( n !== numToAdd ){
if( numToAdd < 0 ){ dateTarget.setDate( dateTarget.getDate() - 1 ); }
if( numToAdd > 0 ){ dateTarget.setDate( dateTarget.getDate() + 1 ); }
engine.log( " AutomatedTask RuntimeLog:" +
" DayOfWeek of " + dateTarget.toBpmsYMD() + " (Sun=0,Mon=1): " + dateTarget.getDay() );
let strOutput = "";
for( let i = 0; i < arr2dHolidays.length; i++ ){
let dateTmp = parseDateAsMidnight( arr2dHolidays[i][0] ); // the first of the date, "00:00"
if( dateTmp.getTime() === dateTarget.getTime() ){
strOutput = arr2dHolidays[i][1];
break;
}
}
if( strOutput !== "" ){
engine.log( " AutomatedTask RuntimeLog:" +
" Holiday" );
}else{
engine.log( " AutomatedTask RuntimeLog:" +
" Not holiday" );
for( let i = 0; i < arr2dClosedDays.length; i++ ){
if( arr2dClosedDays[i][0] === dateTarget.getDay() + "" ){ // Matches Closing Day
engine.log( " AutomatedTask RuntimeLog: " +
arr2dClosedDays[i][1] );
let boolOpen = false;
if( strOpenDespiteWeekends !== "" ){
for( let j = 0; j < arrOpenDespiteWeekends.length; j++ ){
let dateTmp = parseDateAsMidnight( arrOpenDespiteWeekends[j] );
if( dateTmp.getTime() === dateTarget.getTime() ){
boolOpen = true;
break;
}
}
}
if( ! boolOpen ){
strOutput = arr2dClosedDays[i][1];
}else{
engine.log( " AutomatedTask RuntimeLog:" +
" but be Open despite " + arr2dClosedDays[i][1] );
}
break;
}
}
}
if( numToAdd < 0 ){
if( strOutput === "" ){
n = n - 1;
}else{
strNonbiz += dateTarget.toBpmsYMD() + "\t" + strOutput + "\n";
}
}
if( numToAdd > 0 ){
if( strOutput === "" ){
n = n + 1;
}else{
strNonbiz += dateTarget.toBpmsYMD() + "\t" + strOutput + "\n";
}
}
} // end of while
if( strNonbiz !== "" ){
strNonbiz = strNonbiz.slice( 0, -1 ); // delete last "\n"
}
//// == Data Updating / ワークフローデータへの代入 ==
engine.setData( datePocketOutput, new java.sql.Date( dateTarget.getTime() ) );
if( strPocketNonbiz !== null ){
engine.setData( strPocketNonbiz, strNonbiz );
}
} //////// END "main()" /////////////////////////////////////////////////////////////////
function parseDateAsMidnight( str ) { // Transform date from String to Date
if( str === "" ){
throw new Error( "\n AutomatedTask ParseDateError:" +
" String is empty \n" );
}
var arrNumParts = str.match( /\d+/g );
if( arrNumParts === null ){
throw new Error( "\n AutomatedTask ParseDateError:" +
" No numeric characters in: " + str + "\n" );
}
if( arrNumParts.length < 3){
throw new Error( "\n AutomatedTask ParseDateError:" +
" 3 Parts of numeric characters are needed in: " + str + "\n" );
}
return new Date( parseInt(arrNumParts[0], 10),
parseInt(arrNumParts[1], 10) - 1,
parseInt(arrNumParts[2], 10) ); // months are 0-based
// Note: new Date("2014-11-10") // Mon Nov 10 2014 09:00:00 GMT+0900 (JST)
// Note: new Date(2014, 10, 10) // Mon Nov 10 2014 00:00:00 GMT+0900 (JST)
}
// Parses CSV string and Creates a 2D array.
function parseTwoColOfCsv( strCsv ){
const arrCsv = strCsv.split("\n");
let arr2d = [];
for( let i = 0; i < arrCsv.length; i++ ){
if( arrCsv[i] === "" ){ continue; } // Skip blank lines
let arrTmp = [];
let arrCells = arrCsv[i].split(",");
for( let j = 0; j < arrCells.length; j++ ){
arrTmp[0] = arrCells[0];
arrTmp[1] = arrCells[1];
// Refer to only the first two columns of CSV.
}
arr2d.push( arrTmp );
}
return arr2d;
}
/*
Notes:
- When the process reaches the automated task, N business days after the DATE data is automatically calculated.
- `YYYY-MM-DD` (date type format), `YYYY/MM/DD`, etc.
- `YYYY-MM-DD hh:mm` (datetime data format) can also be regarded as the starting date.
- If it corresponds to "A1. Holiday list" of the config value, the name of the holiday is stored.
- You need to list all the holidays of all years.
- It is also possible to add "company-defined holidays" to the holiday list.
- The CSV file in the Cabinet Office "About National Holidays" is useful. (JAPAN)
- https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
- https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
- 2022/1/1,New Year's Day 2022/1/10,Coming-of-Age Day 2022/2/11,National Foundation Day 2022/2/23,Emperor's Birthday
- If the config value "B1. Regular closing days" is applicable, the day name is stored.
- However, if it corresponds to "a day that is not closed specially", an empty string will be stored.
- Set the regular holidays with a number from 0-6. (Sunday-Saturday: 0-6)
- If it falls on a national holiday, it will not be judged whether it is a regular closing day.
- The starting date is not subject to holiday judgment.
APPENDIX:
- Refers to only the first two columns of CSV.
- No error will occur even if the memo is written in the third column.
- (1st row, 2nd row, remarks memo)
- No problem if the data is for holidays of about 50 years (about 1000 lines).
- If you set a large number of "A1. Holiday list" that exceeds 10,000 lines, an error may occur.
Notes-ja:
- 案件が自動処理工程に到達した際、日付データのN営業日後が自動計算されます。
- `YYYY-MM-DD` (日付型データの書式) や `YYYY/MM/DD` など
- `YYYY-MM-DD hh:mm` (日時型データの書式) も起点日と見なすことが可能です。
- コンフィグ値の「A1.祝祭日リスト」に該当する場合に、祝祭日の名前が格納されます。
- 全ての年の全ての祝祭日をリストアップする必要があります。(実務上必要とされる範囲)
- 祝祭日リストに「会社が定めた休日」を追加することも可能です。
- 内閣府「国民の祝日について」にあるCSVファイルが有用です。
- https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
- https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
- 2022/1/1,元日 2022/1/10,成人の日 2022/2/11,建国記念の日 2022/2/23,天皇誕生日
- コンフィグ値「B1.定休日(休業する曜日)」に該当する場合に、曜日名が格納されます。
- ただし「特別に休業としない日」に該当した場合には、空文字が格納されます。
- 定休曜日は 0-6 の数字で設定します。(Sunday - Saturday : 0 - 6)
- 祝祭日に該当する場合、定休日判定は行われません。
- 起点日は祝日判定の対象にはなりません。
APPENDIX-ja:
- CSV設定は、先頭の2列だけが参照されます。
- 3列目にメモが記載されていてもエラーにはなりません
- (1列目,2列目,備考メモ)
- 50年程度の祝祭日データ(1000行程度)であれば問題ありません。
- 1万行を超えるような大量の「A1.祝祭日リスト」を設定するとエラーとなる場合があります。
*/
Download
- date-calc-after-n-business-days-2021.xml
- date-calc-after-n-business-days-2023.xml
- 2023-08-21 (C) Questetra, Inc. (MIT License)
- for “GraalJS standard (engine-type 3)” on v15.0 or above
2021-10-04 (C) Questetra, Inc. (MIT License)
https://support.questetra.com/ja/addons/date-calc-after-n-business-days-2021/
Addonファイルのインポートは Professional でのみご利用いただけます。
自由改変可能な JavaScript (ECMAScript) コードです。いかなる保証もありません。
Notes
- 案件が自動処理工程に到達した際、日付データのN営業日後が自動計算されます。
YYYY-MM-DD
(日付型データの書式) やYYYY/MM/DD
などYYYY-MM-DD hh:mm
(日時型データの書式) も起点日と見なすことが可能です。
- コンフィグ値の「A1.祝祭日リスト」に該当する場合に、祝祭日の名前が格納されます。
- 全ての年の全ての祝祭日をリストアップする必要があります。(実務上必要とされる範囲)
- 祝祭日リストに「会社が定めた休日」を追加することも可能です。
- 内閣府「国民の祝日について」にあるCSVファイルが有用です。
- https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
- https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
- 2022/1/1,元日 2022/1/10,成人の日 2022/2/11,建国記念の日 2022/2/23,天皇誕生日
- 全ての年の全ての祝祭日をリストアップする必要があります。(実務上必要とされる範囲)
- コンフィグ値「B1.定休日(休業する曜日)」に該当する場合に、曜日名が格納されます。
- ただし「特別に休業としない日」に該当した場合には、空文字が格納されます。
- 定休曜日は 0-6 の数字で設定します。(Sunday – Saturday : 0 – 6)
- 祝祭日に該当する場合、定休日判定は行われません。
- 起点日は祝日判定の対象にはなりません
Capture


Appendix
- CSV設定は、先頭の2列だけが参照されます。
- 3列目にメモが記載されていてもエラーにはなりません
- (1列目,2列目,備考メモ)
- 50年程度の祝祭日データ(1000行程度)であれば問題ありません。
- 1万行を超えるような大量の「A1.祝祭日リスト」を設定するとエラーとなる場合があります。