001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.taglib;
017
018import org.opengion.hayabusa.common.HybsSystem;
019import org.opengion.hayabusa.common.HybsSystemException;
020import org.opengion.hayabusa.resource.CalendarData;
021import org.opengion.hayabusa.resource.CalendarFactory;
022import org.opengion.hayabusa.html.ViewStackTableParam;
023import org.opengion.fukurou.util.HybsDateUtil;                                          // 6.4.2.0 (2016/01/29)
024import org.opengion.fukurou.util.StringUtil;
025import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
026
027import static org.opengion.fukurou.util.StringUtil.nval ;
028
029import java.util.Calendar;
030import java.util.Date;
031import java.util.List;
032import java.util.ArrayList;
033import java.util.Locale ;
034import java.text.DateFormat;
035import java.text.SimpleDateFormat;
036
037/**
038 * ガントチャート用のヘッダー情報(日付け等)を出力するタグです。
039 *
040 * スライドバー式ガントチャートの表示時に、スライドバーの長さと日付とを関連付けるための
041 * ヘッダー情報(日付け等)を出力します。スライドバーと日付間隔は、zoom 属性によって、
042 * CSSファイルのフォントサイズと、JavaScript の内部配列に依存しています。
043 * また、このヘッダーでは、日付の休日情報を、カレンダテーブルを参照することで取得しています。
044 * calDB 属性への指定は、CalendarFactory で生成されるテーブル名(CalendarDataの実装クラス)
045 * を指定します。
046 *
047 * @og.formSample
048 * ●形式:<og:ganttHeader startDate="…" endDate="…" zoom="[…]" />
049 * ●body:なし
050 *
051 * ●Tag定義:
052 *   <og:ganttHeader
053 *       startDate          【TAG】表示開始日付けを設定します(yyyyMMdd または、yyyyMMddHHmm 形式)
054 *       endDate            【TAG】表示最終日を設定します(yyyyMMdd または、yyyyMMddHHmm 形式)
055 *       zoom               【TAG】ズーム変数(0~13,20~31,40~49)を設定します(初期値:2)
056 *       calDB              【TAG】DB検索するDBを指定します
057 *       arg1               【TAG】DB検索する場合の第1のキーを指定します
058 *       arg2               【TAG】DB検索する場合の第2のキーを指定します
059 *       arg3               【TAG】DB検索する場合の第3のキーを指定します
060 *       arg4               【TAG】DB検索する場合の第4のキーを指定します
061 *       daySpan            【TAG】1日の開始終了時間を24時間形式(HHmm-HHmm)で設定します(初期値:0700-2000)
062 *       breakTimes         【TAG】時間軸での休憩時間の開始-終了時刻をCSV形式で複数指定します(HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm形式、または、yyyyMMddHHmm-yyyyMMddHHmm形式)
063 *       breakTimeStyle     【TAG】時間軸での休憩時間の表示スタイルを設定します(初期値:top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;)
064 *       baseTimes          【TAG】時間軸でのベース時刻の開始時刻をCSV形式で複数指定します(HHmm形式、または、yyyyMMddHHmm形式)
065 *       baseTimeStyle      【TAG】時間軸でのベース時刻の表示スタイルを設定します(初期値:top:20px;background-color:transparent;border-left:2px dashed red;)
066 *       skipHoliday        【TAG】時間ガントで休日を表示する/しないを設定します (初期値:USE_GANTTHEADER_SKIP_HOLIDAY[=true])
067 *       useMultiClm        【TAG】時間ヘッダーの上段に日付を、下段の時間を表示します (初期値:USE_GANTTHEADER_MULTIPLE_COLUMN[=false])
068 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
069 *   />
070 *
071 * ●使用例
072 *    参照:jsp/GANTT06 フォルダ
073 *
074 *     <og:ganttHeader
075 *         startDate = "{@VIEW_DATE}"
076 *         endDate   = "{@DYMAX}"
077 *         zoom      = "{@VIEW_ZOOM}"
078 *         calDB     = "GF13"
079 *         arg1      = "{@CDJGS}"
080 *         arg2      = ""
081 *     /og:ganttHeader>
082 *
083 *     <og:ganttHeader
084 *         startDate  = "{@VIEW_DATE}"
085 *         endDate    = "{@DYMAX}"
086 *         daySpan    = "0700-2000"                               HHmm-HHmm 形式で1日の時間範囲を指定
087 *         breakTimes = "1200-1245,1645-1650,200508200700-1200;"  休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm形式、または、yyyyMMddHHmm-yyyyMMddHHmm形式です。
088 *         breakTimeStyle = "top:20px;background-color:yellow;"   休憩時間のスタイルに追加します。
089 *         zoom       = "20"
090 *     /og:ganttHeader>
091 *
092 * ●定義・解説
093 *   PL/SQL の VIEW_ZOOM メソッドを用いて、実際の日付けから画面表示ピクセルへ
094 *   変換する割合を求めます。これと、jsp\GANTT\image の ganttBGx.gif(x は ZOOM変数)
095 *   を対応付けて、日付けのヘッダーを求めます。
096 *   jsp\custom\custom.css の th.zoomx(x は ZOOM変数) により、日付けヘッダー文字の
097 *   表示間隔を制御していますので、これらの関係を正確に把握しておいて下さい。
098 *   日付けヘッダーは、イメージ変数を用いている関係上、固定の日数を加算して、
099 *   求めます。(週:7日, 半月:15日, 月:30日, 4半期:90日, 年:360日)
100 *
101 * ヘッダー部のカレンダに、calDB で指定された カレンダテーブルを使用出来ます。
102 * 使用する場合は、arg1(事業所コード等)~arg4(WCコード等) の属性を指定する事ができます。
103 * zoom="10"(週単位) を使用の週数の計算は、年初の最初の7日間が含まれる週を、第1週と数えます。
104 *
105 * zoom="20"(時)間 では、1日の時間範囲をdaySpanでHHmm-HHmm形式で指定します。
106 * 開始時刻は、内部で1時間単位に変換されます。8時30分~は、8時~になります。
107 * 終了時間は、その時間を「含みません」
108 * 開始終了は、startDate、endDateで指定しますが、yyyyMMdd または、yyyyMMddHHmm 形式とします。
109 * calDB で指定された カレンダテーブルを見て、休日の場合は、表示をスキップします。
110 * 休憩時間は、breakTimes で指定します。(HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、
111 * または、yyyyMMddHHmm-yyyyMMddHHmm形式)
112 * CSV形式で複数指定できます。日付指定がない場合は、毎日、日付指定がある場合は、
113 * その日のみ有効です。休憩時間は、日をまたぐ事は可能です。
114 * breakTimeStyle として、休憩時間の指定に追加するスタイル属性を追加します。
115 * 通常は、バックカラーと上からの位置です。ヘッダー表示は、1時間単位です。
116 * 初期値は、"top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" です。
117 *
118 * ベース時刻(baseTimes)は、HHmm形式、または、yyyyMMddHHmm形式で指定した箇所に、線を引きます。
119 * 例えば、検索した時刻を指定すると、現在時刻の箇所を示す線になります。
120 * また、業務自体の開始時刻や終了時刻の箇所を表すことも可能です。
121 * baseTimeStyle は、このベース時刻のスタイルを決めます。breakTimeStyle との違いは、
122 * 帯の幅を、このスタイルシートで指定していることです。
123 * 初期値は、top:20px;background-color:transparent;border-left:2px dashed red; です。
124 *
125 * zoom="21"(時)間 では、一時間のピクセルを"20"(時)の半分に変更します。
126 *
127 * useMultiClm  パラメータを設定すると、ガントヘッダーにおいて、2段組を使用するかどうかを、
128 * 指定できます。時間ヘッダーの上段に日付を、下段の時間軸の(h)の削除を行います。
129 * 日付は、表示開始時刻の上と、それの6時間ごとに表示します。
130 * 初期値は、システムリソースの USE_GANTTHEADER_MULTIPLE_COLUMN で指定します。
131 *
132 * システムリソースに USE_GANTTHEADER_MONTH_DATE パラメータを設定すると、
133 * ガントヘッダーにおいて、30日、90日、180日のヘッダー表示で、日付まで
134 * 表示するか、月のみ表示するかを指定します。
135 * ガントヘッダーの繰返し表示でバックグラウンドイメージは固定日なので、一月表示を
136 * 30日単位で表示していますが、先頭日付が 1日でないため、判りにくいと苦情がありました。
137 * そこで、30日、90日、180日のヘッダー表示時に、日付を表示しないようにするフラグです。
138 * 月表示は、その月が 20日以降の場合、翌月を表示します。
139 * 初期値は、互換性の為、false です。
140 *
141 * zoom 40(DAY),41(WEEK),42(MONTH) は、積み上げガント用のヘッダー処理を行います。
142 * 積み上げガントは、固定日処理ではなく、月単位に加算します。
143 *
144 * @og.rev 3.5.4.8 (2004/02/23) 新規作成
145 * @og.group 画面部品
146 *
147 * @version  4.0
148 * @author   Kazuhiko Hasegawa
149 * @since    JDK5.0,
150 */
151public class GanttHeaderTag extends CommonTagSupport {
152        /** このプログラムのVERSION文字列を設定します。   {@value} */
153        private static final String VERSION = "8.1.1.2 (2022/02/25)" ;
154        private static final long serialVersionUID = 811220220225L ;
155
156        // 5.6.2.3 (2013/03/22) 日付をセンターに表示させる場合の両端スペースの元ネタ
157        private static final String SPACE = "                                   " ;             // 日付(31日分)より多いスペース
158
159        // 5.6.5.0 (2013/06/07) 曜日データを配列で持っておきます。
160//      private static final String[] DAY_OF_WEEK_JA = { " ","日 ","月 ","火 ","水 ","木 ","金 ","土 " };      // 6.4.1.1 (2016/01/16) DAY_OF_WEEK_ja → DAY_OF_WEEK_JA  refactoring 8.1.1.2 (2022/02/25) Modify
161        private static final String[] DAY_OF_WEEK_JA = { " ","日","月","火","水","木","金","土" };
162        private static final int        TIME_PIXEL                      = 48;   // 3.8.1.1 (2005/11/21) 時間ヘッダー時の1時間のピクセル数
163        private static final int        MONTH_DATE_LIMITER      = 20;   // 当月 20 日以降は、翌月扱いとなる。
164        private static final boolean USE_MONTH_DATE     = HybsSystem.sysBool( "USE_GANTTHEADER_MONTH_DATE" );   // 3.8.5.2 (2006/06/09)
165
166//      private static final String BLUE_COLOR  = "<span style=\"color:Blue;\">" ;              // 8.1.1.2 (2022/02/25) Delete
167//      private static final String RED_COLOR   = "<span style=\"color:Red;\">" ;               // 8.1.1.2 (2022/02/25) Delete
168//      private static final String END_SPAN    = "</span>" ;                                                   // 8.1.1.2 (2022/02/25) Delete
169        private static final String TODAY_CLASS         = "gntToday" ;                                          // 5.6.2.3 (2013/03/22) 本日を示すクラス名
170        private static final String HOLIDAY_CLASS       = "gntHoliday" ;                                        // 5.6.2.3 (2013/03/22) 休日を示すクラス名
171        private static final String RANGE_CLASS         = "gntRange" ;                                          // 8.1.1.2 (2022/02/25) 本日を含むクラス名
172        // 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"/>" 止めを、">" に変更します)。
173//      private static final String BR                  = "<br/>" ;
174        private static final String BR                  = "<br>" ;                                                              // 7.0.1.0 (2018/10/15)
175
176        // 5.9.2.0 (2015/11/06) ヘッダー列幅の固定対応
177        private static final String DIV_ZOOMWEEK_START  = "<div class=\"zoomWeekBlock\">";                                      // 週の設定
178        private static final String DIV_ZOOMEVENCOLOR   = "<div class=\"zoomHeaderDiv evenColor\">";            // 奇数色の設定
179        private static final String DIV_ZOOMODDCOLOR    = "<div class=\"zoomHeaderDiv oddColor\">";                     // 偶数色の設定
180        private static final String DIV_ZOOMHEADER2             = "<div class=\"zoomHeaderDiv zoomHeaderDiv2\">";       // 列幅の設定
181        private static final String DIV_ZOOMWEEKDAY             = "<div class=\"zoomWeekDay\">";                                        // 日の設定
182        private static final String END_DIV                             = "</div>";
183
184        private static final boolean USE_MD_HEADER = HybsSystem.sysBool( "USE_MDHEADER_ONTIME" ); // 5.7.0.0 (2013/11/07)       // 6.4.1.1 (2016/01/16) useMdheader → USE_MD_HEADER  refactoring
185
186        private String  startDate       ;
187        private String  endDate         ;
188        private String  daySpan         = "0700-2000";  // 1日の時間範囲(HHmm-HHmm) 3.8.0.5 (2005/08/26)
189        private int             zoom            = 2;
190        private String  breakTimes      ;               // 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-HHmmyyyyMMdd形式です。
191        private String  breakTimeStyle  = "top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" ;   // 5.6.4.3 (2013/05/24) 初期値変更
192        private String  calDB           ;               // 3.6.0.0 (2004/09/17) DB検索するDBのキー
193        private String  arg1            ;               // 3.6.0.0 (2004/09/17) DB検索の第1キー(事業所コードなど)
194        private String  arg2            ;               // 3.6.0.0 (2004/09/17) DB検索の第2キー(WCコードなど)
195        private String  arg3            ;               // 3.6.0.0 (2004/09/17) DB検索の第3キー(事業所コードなど)
196        private String  arg4            ;               // 3.6.0.0 (2004/09/17) DB検索の第4キー(WCコードなど)
197        private boolean skipHoliday     = HybsSystem.sysBool( "USE_GANTTHEADER_SKIP_HOLIDAY" );         // 4.0.0.0 (2007/09/07) 休日をスキップするかどうか
198        private String  calStr          ;               // 5.5.4.0 (2012/07/02) 出勤日・休日のフラグ
199
200        private boolean useMultiClm     = HybsSystem.sysBool( "USE_GANTTHEADER_MULTIPLE_COLUMN" );      // 5.6.1.2 (2013/02/22)
201
202        private String  baseTimes       ;               // 5.6.1.2 (2013/02/22) ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式です。
203        private String  baseTimeStyle = "top:20px;background-color:transparent;border-left:2px dashed red;" ;           // 5.6.1.2 (2013/02/22) ベース時刻を赤線表示します。
204
205        /**
206         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
207         *
208         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
209         * @og.rev 3.6.0.0 (2004/09/17) zoom 3 の時の計算値を変更
210         * @og.rev 3.7.1.0 (2005/04/15) zoom 10 の追加
211         * @og.rev 3.8.1.6 (2006/04/25) zoom 21 の追加
212         * @og.rev 3.8.5.2 (2006/06/09) makeZoom メソッドの USE_MONTH_DATE パラメータ追加
213         * @og.rev 3.8.9.2 (2007/07/28) makeZoomTime メソッドの 時間間隔パラメータ追加
214         * @og.rev 5.5.4.0 (2012/07/02) ヘッダー属性情報の出力追加
215         * @og.rev 5.6.3.2 (2013/04/12) 曜日を出力する場合の段組みでは、全角スペースを使う(firefox対応)
216         *
217         * @return      後続処理の指示
218         */
219        @Override
220        public int doEndTag() {
221                debugPrint();           // 4.0.0 (2005/02/28)
222                if( startDate == null || endDate == null ||
223                         startDate.length() < 8 || endDate.length() < 8 ) {
224                                final String errMsg = "開始日と終了日は、どちらも yyyyMMdd 形式で、必須です。"
225                                                + " startDate=[" + startDate + "] endDate=[" + endDate + "]" ;
226                                throw new HybsSystemException( errMsg );
227                }
228
229                // 月単位の処理に30,60,90などの固定日を使用しているのは、ガントバーの長さが
230                // 日単位の固定長なので、長期間のガントを使用すると後ろの方でずれてくるため。
231                String header = "";
232                final String md = USE_MONTH_DATE ? "MM   " : "MM/dd";
233                switch( zoom ) {
234                        case  0: header = makeZoom( "MM/   "     ,"dd(EE)"     ,  1 ,false ) ; break;
235                        case  1: header = makeZoom( "MM/"        ,"dd "        ,  1 ,false ) ; break;
236                        case  2: header = makeZoom2( 1 ) ; break;
237                        case  3: header = makeZoom( "yyyy/  "    ,"MM/dd  "    ,  7 ,false ) ; break;
238                        case  4: header = makeZoom( "yyyy/  "    ,"MM/dd  "    , 14 ,false ) ; break;
239                        case  5: header = makeZoom( "yyyy/     " ,md + "     " , 30 ,USE_MONTH_DATE ) ; break;
240                        case  6: header = makeZoom( "yyyy/ "     ,md + " "     , 30 ,USE_MONTH_DATE ) ; break;
241                        case  7: header = makeZoom( "yyyy/     " ,md + "     " , 90 ,USE_MONTH_DATE ) ; break;
242                        case  8: header = makeZoom( "yyyy/     " ,md + "     " ,180 ,USE_MONTH_DATE ) ; break;
243                        case  9: header = makeZoom( "yyyy/ "     ,md + " "     ,180 ,USE_MONTH_DATE ) ; break;
244                        case 10: header = makeZoom( "ww'W'"      ,"'<span title=\"'MM/dd'\">'dd '</span>'" ,7 ,false ) ; break;
245        //              case 11: break; // 他物件予約済み
246        //              case 12: break; // 他物件予約済み
247                        case 13: header = makeZoom3( "yyyy/MM" , "dd"  ,"EE"  ,  1 ) ; break;           // 5.6.2.3 (2013/03/22) 月、曜日表示
248                        case 20: header = makeZoomTime( TIME_PIXEL  ,  1,true  ) ; break;       // 3.8.1.1 (2005/11/21)
249                        case 21: header = makeZoomTime( TIME_PIXEL/2,  1,false ) ; break;       // 3.8.1.6 (2006/04/25)
250                        case 22: header = makeZoomTime( TIME_PIXEL  ,  2,true  ) ; break;       // 3.8.9.2 (2007/07/28)
251                        case 23: header = makeZoomTime( TIME_PIXEL/2,  2,false ) ; break;       // 3.8.9.2 (2007/07/28)
252                        case 24: header = makeZoomTime( TIME_PIXEL  ,  4,true  ) ; break;       // 3.8.9.2 (2007/07/28)
253                        case 25: header = makeZoomTime( TIME_PIXEL/2,  4,false ) ; break;       // 3.8.9.2 (2007/07/28)
254                        case 26: header = makeZoomTime( TIME_PIXEL  ,  6,true  ) ; break;       // 3.8.9.2 (2007/07/28)
255                        case 27: header = makeZoomTime( TIME_PIXEL/2,  6,false ) ; break;       // 3.8.9.2 (2007/07/28)
256                        case 28: header = makeZoomTime( TIME_PIXEL  ,  8,true  ) ; break;       // 3.8.9.2 (2007/07/28)
257                        case 29: header = makeZoomTime( TIME_PIXEL/2,  8,false ) ; break;       // 3.8.9.2 (2007/07/28)
258                        case 30: header = makeZoomTime( TIME_PIXEL  , 12,true  ) ; break;       // 3.8.9.2 (2007/07/28)
259                        case 31: header = makeZoomTime( TIME_PIXEL/2, 12,false ) ; break;       // 3.8.9.2 (2007/07/28)
260                        // 5.6.1.2 (2013/02/22) 積み上げガント
261                        case 40: header = makeZoomStack( "MM/   "     ,"dd(EE)"     ,  1,false ) ; break;       // 5.6.1.2 (2013/02/22)
262                        case 41: header = makeZoomStack( "ww'W'   "   ,"MM/dd "     ,  7,false ) ; break;       // 5.6.1.2 (2013/02/22)
263                        case 42: header = makeZoomStack( "yyyy/     " ,"MM        " ,  1,true  ) ; break;       // 5.6.1.2 (2013/02/22)
264        //              case 43: break;         // 日単位ヘッダー予約済み
265        //                       ~
266        //              case 49: break;         // 日単位ヘッダー予約済み
267                        default: break;
268                }
269
270                jspPrint( header );
271                jspPrint(makeHeaderData()); // 5.5.4.0 (2012/07/02)
272                return EVAL_PAGE ;
273        }
274
275        /**
276         * タグリブオブジェクトをリリースします。
277         *
278         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
279         *
280         * @og.rev 3.6.0.0 (2004/09/17) 事業所コード cdjgs 属性を追加
281         * @og.rev 3.8.0.2 (2005/07/11) startTime,timePeriod,breakTimes 属性を追加
282         * @og.rev 3.8.0.5 (2005/08/26) daySpan,breakTimes,breakTimeStyle 属性を追加
283         * @og.rev 5.5.4.0 (2012/07/02) calStr追加
284         * @og.rev 5.6.1.2 (2013/02/22) baseTimes、baseTimeStyle追加,useMultiClm追加
285         */
286        @Override
287        protected void release2() {
288                super.release2();
289                startDate       = null;
290                endDate         = null;
291                daySpan         = "0700-2000";  // 開始時刻(HHmm-HHmm) 3.8.0.5 (2005/08/26)
292                zoom            = 2;
293                calDB           = null; // 3.6.0.0 (2004/09/17) DB検索するDBのキー
294                arg1            = null; // 3.6.0.0 (2004/09/17) DB検索の第1キー(事業所コードなど)
295                arg2            = null; // 3.6.0.0 (2004/09/17) DB検索の第2キー(WCコードなど)
296                arg3            = null; // 3.6.0.0 (2004/09/17) DB検索の第3キー
297                arg4            = null; // 3.6.0.0 (2004/09/17) DB検索の第4キー
298                breakTimes      = null;         // 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-HHmmyyyyMMdd形式です。
299                breakTimeStyle  = "top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;" ;
300                skipHoliday = HybsSystem.sysBool( "USE_GANTTHEADER_SKIP_HOLIDAY" ); // 4.0.0.0 (2007/09/10)
301                calStr          = null; // 5.5.4.0 (2012/07/02)
302                baseTimes               = null;                                                                         // 5.6.1.2 (2013/02/22) ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式です。
303                baseTimeStyle   = "top:20px;background-color:transparent;border-left:2px dashed red;" ;         // 5.6.1.2 (2013/02/22) ベース時刻を赤線表示します。
304                useMultiClm             = HybsSystem.sysBool( "USE_GANTTHEADER_MULTIPLE_COLUMN" );      // 5.6.1.2 (2013/02/22)
305        }
306
307        /**
308         * 上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
309         *
310         * @og.rev 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
311         * @og.rev 3.7.1.0 (2005/04/15) zoom == 10 週単位の場合の特殊処理を追加
312         * @og.rev 3.7.1.1 (2005/05/23) 本日は、青色で示します。
313         * @og.rev 3.8.5.2 (2006/06/09) makeZoom メソッドの USE_MONTH_DATE パラメータ追加
314         * @og.rev 5.5.4.0 (2012/07/02) カレンダーフラグ対応
315         * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
316         * @og.rev 5.6.5.0 (2013/06/07) 上段ヘッダーが MM の場合、週単位で月を表示し、色バーを使用します。
317         * @og.rev 5.7.2.0 (2014/01/10) 上段は、休日を出さないので、END_SPAN 不要
318         * @og.rev 5.9.2.0 (2015/11/06) ヘッダー列幅の固定対応
319         * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
320         * @og.rev 8.1.1.2 (2022/02/25) 本日と休日のCSSを直書きではなく、クラス名で対応します。
321         *
322         * @param       upper   上段の表示フォーマット
323         * @param       lower   下段の表示フォーマット
324         * @param       add     表示日付けの加算
325         * @param       useMonth        月表示 [true:月表示のみ(20日以降を翌月表示)/false:月日表示]
326         *
327         * @return  ヘッダー文字列
328         * @og.rtnNotNull
329         */
330        private String makeZoom( final String upper ,final String lower ,final int add, final boolean useMonth ) {
331                final boolean colBar = upper.startsWith( "MM" );                // 5.6.5.0 (2013/06/07) 色バー使用 true
332
333                final DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
334                final DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );
335
336                final Calendar str = HybsDateUtil.getCalendar( startDate );                     // 6.4.2.0 (2016/01/29)
337                final Calendar end = HybsDateUtil.getCalendar( endDate );                               // 6.4.2.0 (2016/01/29)
338
339                // zoom == 10 週単位の場合の特殊処理。
340                // 年の第一週を完全な一週間分(7日間)として、設定します。
341                if( zoom == 10 ) {
342                        str.setMinimalDaysInFirstWeek( 7 );
343                        format1.setCalendar( str );
344                        format2.setCalendar( str );
345                }
346
347                final StringBuilder buf1   = new StringBuilder( BUFFER_MIDDLE );
348                final StringBuilder buf2   = new StringBuilder( BUFFER_MIDDLE );
349                final StringBuilder bufcal = new StringBuilder( BUFFER_MIDDLE );                // 5.5.4.0 (2012/07/02) 休日判定用
350                final StringBuilder bufTdy1 = new StringBuilder( BUFFER_MIDDLE );               // 8.1.1.2 (2022/02/25) 上段の本日判定用
351                final StringBuilder bufTdy2 = new StringBuilder( BUFFER_MIDDLE );               // 8.1.1.2 (2022/02/25) 下段の本日判定用
352
353                // 5.6.5.0 (2013/06/07) 文字列の作成方法の統一。pre タグを最初に設定しておく。
354
355                // 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
356                final CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );
357
358//              boolean modifyFlag = false;                                                                                             // 8.1.1.2 (2022/02/25) Delete
359                // 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
360                int cnt  = 0;                                                                           // 5.6.5.0 (2013/06/07) 色バー対応
361                if( colBar ) {buf1.append( DIV_ZOOMWEEK_START ); }      // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応 spanをdivに変更し、1週間をdivで囲む。
362                boolean isFirst = true;                                                         // 5.6.5.0 (2013/06/07) 色バー対応で、最初だけ、月を表示する。
363
364                while( str.compareTo( end ) <= 0 ) {
365                        final boolean monday = Calendar.MONDAY == str.get( Calendar.DAY_OF_WEEK ) ;     // 5.6.5.0 (2013/06/07) 色バー対応
366                        if( colBar && monday ) {
367                                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応 週をdivで囲むため、buf1にbuf2を追加。
368                                buf1.append( buf2.toString() ).append( END_DIV );
369                                buf2.setLength( 0 );
370
371                                cnt++;
372                                isFirst = true;
373
374                                buf1.append( DIV_ZOOMWEEK_START ); // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
375                        }
376
377                        Date dt = str.getTime();
378                        // 3.8.5.2 (2006/06/09) useMonth フラグにより 月表示のみに変更します。
379                        // MONTH_DATE_LIMITER で指定の日以降は、翌月扱いとなる。
380                        if( useMonth && str.get( Calendar.DATE ) >= MONTH_DATE_LIMITER ) {
381                                final Calendar calPlus = (Calendar)str.clone();
382                                calPlus.set( Calendar.DATE , 1 );               // 1日にセットします。
383                                calPlus.add( Calendar.MONTH , 1 );              // 月を1ヶ月プラスします。
384                                dt = calPlus.getTime();
385                        }
386
387                        // 8.1.1.2 (2022/02/25) Delete
388//                      // 3.7.1.1 (2005/05/31) 本日は、青色で示します。
389//                      if( calData.isContainedToday( str,add ) ) {
390//                              buf2.append( BLUE_COLOR );
391//                              bufcal.append( '0' );   // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
392//                              modifyFlag = true;
393//                      }
394//
395//                      // 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
396//                      // modifyFlag が立っていない場合 を条件に追加します。
397//                      if( !modifyFlag && add == 1 && calData.isHoliday( str ) ) {
398//                              buf2.append( RED_COLOR );
399//                              bufcal.append( '1' );   // 5.5.4.0 (2012/07/02) 休日              // 6.0.2.5 (2014/10/31) char を append する。
400//                              modifyFlag = true;
401//                      }
402
403                        // 8.1.1.2 (2022/02/25) Modify
404                        // 休日と本日の処理を class属性化します。
405                        // 但し、枠単位が休日のとき
406                        // 1) 枠単位が本日のであれば、本日を示すクラス名を使用します。
407                        // 2) 枠単位に本日が含めれば、本日を含むクラス名を使用します。
408                        String tdyCls = null;
409                        bufTdy1.setLength( 0 );
410                        bufTdy2.setLength( 0 );
411                        // 休日判断を、事業所カレンダを使用
412                        if( add == 1 && calData.isHoliday( str ) ) {
413                                tdyCls = HOLIDAY_CLASS ;
414                                bufcal.append( '1' );                                                                                   // 休日
415                        }
416                        else {
417                                bufcal.append( '0' );                                                                                   // char を append する。
418                        }
419
420                        // 本日判断
421                        if( calData.isContainedToday( str,add ) ) {
422                                tdyCls = add == 1 ? TODAY_CLASS : RANGE_CLASS ;
423                        }
424
425                        if( tdyCls != null ) {
426                                bufTdy1.append( "<div class=\"" ).append( TODAY_CLASS ).append( "\">" );        // 上段の本日判定用
427                                bufTdy2.append( "<div class=\"" ).append( tdyCls ).append( "\">" );                     // 下段の本日判定用
428                        }
429
430                        // 5.6.5.0 (2013/06/07) 色バー対応。色バーで、かつ、先頭でなければ、スペースを出力
431                        if( colBar && !isFirst ) {
432                                buf1.append( SPACE.substring( 0,upper.length() ) );
433                        }
434                        else {
435                                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
436                                if( colBar ) {
437                                        if( cnt % 2 == 0)       { buf1.append( DIV_ZOOMEVENCOLOR ); }   // 奇数の色設定
438                                        else                            { buf1.append( DIV_ZOOMODDCOLOR ); }    // 偶数の色設定
439                                } else {
440                                        buf1.append( DIV_ZOOMHEADER2 );         // 色無しの設定
441                                }
442                                // ズーム変数=10:週
443                                if( tdyCls != null && upper.startsWith( "ww" ) ) { buf1.append( bufTdy1.toString() ); }                 // 8.1.1.2 (2022/02/25) 本日
444                                buf1.append( format1.format( dt ) );
445                                // ズーム変数=10:週
446                                if( tdyCls != null && upper.startsWith( "ww" )  ) { buf1.append( END_DIV ); }                                   // 8.1.1.2 (2022/02/25) 本日
447
448                                buf1.append( END_DIV );                                 // 5.9.2.0 (2015/11/06)
449                                isFirst = false;
450                        }
451                        buf2.append( DIV_ZOOMHEADER2 );                                                                         // 5.9.2.0 (2015/11/06)
452                        if( tdyCls != null ) { buf2.append( bufTdy2.toString() ); }                     // 8.1.1.2 (2022/02/25) 休日と本日
453                        buf2.append( format2.format( dt ) );
454                        if( tdyCls != null ) { buf2.append( END_DIV ); }                                        // 8.1.1.2 (2022/02/25) 休日と本日
455                        buf2.append( END_DIV );                                                                                         // 5.9.2.0 (2015/11/06)
456
457                        // 8.1.1.2 (2022/02/25) Delete
458//                      if( modifyFlag ) {
459//                              buf2.append( END_SPAN );
460//                              modifyFlag = false;
461//                      }
462//                      else{
463//                              bufcal.append( '0' );                                   // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
464//                      }
465                        str.add(Calendar.DATE, add);
466                }
467                calStr = bufcal.toString();                                             // 5.5.4.0 (2012/07/02)
468
469                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
470                if( colBar ) {
471                        buf1.append( buf2 ).append( END_DIV );
472                } else {
473                        buf1.append( BR ).append( buf2 );
474                }
475                buf2.setLength( 0 );
476
477                return buf1.toString();                                                 // 5.9.2.0 (2015/11/06)
478        }
479
480        /**
481         * zoom = 2 の場合のヘッダーを出力します。
482         * このヘッダーだけ特別なので、別メソッドを作成します。
483         *
484         * type=1 の場合
485         * [ 0   ・・・]&lt;br/&gt;[ 2   ・・・]&lt;br/&gt;[ /   ・・・]&lt;br/&gt;[0000 ・・・]&lt;br/&gt;[1234 ・・・]
486         *
487         * という月情報を毎週月曜日にヘッダーに出力します。(上記は、2月1日~2月4日まで)
488         *
489         * @og.rev 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
490         * @og.rev 3.6.0.7 (2004/11/06) 月の情報も出力します。
491         * @og.rev 3.7.1.1 (2005/05/23) 本日は、青色で示します。
492         * @og.rev 5.5.4.0 (2012/07/02) カレンダーフラグ対応
493         * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
494         * @og.rev 5.6.5.0 (2013/06/07) 日付欄の段組みを廃止し、色バーに変更します。
495         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
496         * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
497         * @og.rev 5.9.24.0 (2017/09/01) 当日、休日の色の不具合対応
498         * @og.rev 5.10.6.0 (2018/12/07) 火曜日が翌月の1日になる場合の、月表示不具合対応
499         * @og.rev 8.1.1.2 (2022/02/25) 本日と休日のCSSを直書きではなく、クラス名で対応します。
500         *
501         * @param       add     表示日付けの加算
502         *
503         * @return  ヘッダー文字列
504         * @og.rtnNotNull
505         */
506        private String makeZoom2( final int add ) {
507                final Calendar str = HybsDateUtil.getCalendar( startDate );                     // 6.4.2.0 (2016/01/29)
508                final Calendar end = HybsDateUtil.getCalendar( endDate );                               // 6.4.2.0 (2016/01/29)
509
510                final StringBuilder buf1   = new StringBuilder( BUFFER_MIDDLE );                // 月の1桁目
511                final StringBuilder buf4   = new StringBuilder( BUFFER_MIDDLE );                // 日の1桁目
512                final StringBuilder buf5   = new StringBuilder( BUFFER_MIDDLE );                // 日の2桁目
513                final StringBuilder bufcal = new StringBuilder( BUFFER_MIDDLE );                // 5.5.4.0 (2012/07/02) 休日判定用
514                final StringBuilder bufTdy = new StringBuilder( BUFFER_MIDDLE );                // 8.1.1.2 (2022/02/25) 本日判定用
515
516                // 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
517                final CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );
518
519//              boolean modifyFlag = false;                                                                                             // 8.1.1.2 (2022/02/25) Delete
520
521                // 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
522                int cnt  = 0;                                   // 5.6.5.0 (2013/06/07) 色バー対応
523                int hCnt = 0;                                   // 月欄は、3文字分
524                // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
525                buf1.append(DIV_ZOOMWEEK_START).append(DIV_ZOOMEVENCOLOR);
526
527                int mtPre=0;                                    // 5.10.6.0 (2018/12/07) mt保存用
528                while( str.compareTo( end ) <= 0 ) {
529                        final int mt = str.get( Calendar.MONTH ) + 1;
530                        final int dt = str.get( Calendar.DATE );
531                        final boolean monday = Calendar.MONDAY == str.get( Calendar.DAY_OF_WEEK );
532
533                        // 5.9.24.0 (2017/09/01) BLUE,REDの後ろに置いていた処理を移動(翌週の月曜にデータが出力されるので余分なデータが出ていた)
534                        if( monday ) {
535                                buf1.append( END_DIV ).append( buf4.toString() ).append( BR ).append( buf5.toString() ).append( END_DIV );
536                                buf4.setLength( 0 );
537                                buf5.setLength( 0 );
538
539                                cnt++;
540                                hCnt = 0;
541
542                                buf1.append( DIV_ZOOMWEEK_START );
543                                if( cnt % 2 == 0) { buf1.append( DIV_ZOOMEVENCOLOR ); }
544                                else                      { buf1.append( DIV_ZOOMODDCOLOR );  }
545                        }
546
547                        // 8.1.1.2 (2022/02/25) Delete
548//                      // 3.7.1.1 (2005/05/31) 本日は、青色で示します。
549//                      if( calData.isContainedToday( str,add ) ) {
550//                              buf4.append( BLUE_COLOR );
551//                              buf5.append( BLUE_COLOR );
552//                              bufcal.append('0');             // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
553//                              modifyFlag = true;
554//                      }
555//
556//                      // 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
557//                      // modifyFlag が立っていない場合 を条件に追加します。
558//                      if( !modifyFlag && add == 1 && calData.isHoliday( str ) ) {
559//                              buf4.append( RED_COLOR );
560//                              buf5.append( RED_COLOR );
561//                              bufcal.append('1');             // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
562//                              modifyFlag = true;
563//                      }
564
565                        // 8.1.1.2 (2022/02/25) Modify
566                        // 休日と本日の処理を class属性化します。
567                        String tdyCls = null;
568                        bufTdy.setLength( 0 );
569                        // 休日判断を、事業所カレンダを使用
570                        if( add == 1 && calData.isHoliday( str ) ) {
571                                tdyCls = HOLIDAY_CLASS ;
572                                bufcal.append( '1' );                                                                                   // 休日
573                        }
574                        else {
575                                bufcal.append( '0' );                                                                                   // char を append する。
576                        }
577
578                        // 本日判断
579                        if( calData.isContainedToday( str,add ) ) {
580                                tdyCls = add == 1 ? TODAY_CLASS : RANGE_CLASS ;
581                        }
582
583                        if( tdyCls != null ) {
584                                bufTdy.append( "<div class=\"" ).append( tdyCls ).append( "\">" );
585                        }
586
587                        // 5.6.5.0 (2013/06/07) 色バー対応
588                        // 6.0.2.5 (2014/10/31) char を append する。
589                        switch( hCnt++ ) {
590                                case 0 :
591                                        mtPre = mt; // 5.10.6.0
592                                        buf1.append( mt/10 ); break;            // 月の1文字目
593                                // 5.10.6.0 (2018/12/07) 火曜日の場合は、月曜日の月の2文字目を取得するように変更
594                                // case 1 :     buf1.append(  mt%10  ); break;          // 月の2文字目
595                                case 1 :                                                                                // 月曜日(前日)の月の2文字目
596                                        buf1.append(  mtPre%10  ); break;
597//                              case 0 :        buf1.append( mt/10 ); break;            // 月の1文字目
598//                              case 1 :        buf1.append( mt%10 ); break;            // 月の2文字目
599                                case 2 :        buf1.append(  '/'  ); break;            // 月の区切り文字
600                                default :       buf1.append(  ' '  ); break;            // 空欄
601                        }
602
603                        // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
604                        buf4.append( DIV_ZOOMHEADER2 );
605                        if( tdyCls != null ) { buf4.append( bufTdy.toString() ); }                      // 8.1.1.2 (2022/02/25) 休日と本日
606                        buf4.append( dt/10 );
607                        if( tdyCls != null ) { buf4.append( END_DIV ); }                                        // 8.1.1.2 (2022/02/25) 休日と本日
608                        buf4.append( END_DIV );
609
610                        buf5.append( DIV_ZOOMHEADER2 );
611                        if( tdyCls != null ) { buf5.append( bufTdy.toString() ); }                      // 8.1.1.2 (2022/02/25) 休日と本日
612                        buf5.append( dt%10 );
613                        if( tdyCls != null ) { buf5.append( END_DIV ); }                                        // 8.1.1.2 (2022/02/25) 休日と本日
614                        buf5.append( END_DIV );
615
616                        // 8.1.1.2 (2022/02/25) Delete
617//                      if( modifyFlag ) {
618//                              buf4.append( END_SPAN );
619//                              buf5.append( END_SPAN );
620//                              modifyFlag = false;
621//                      }
622//                      else{
623//                              bufcal.append('0');                             // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
624//                      }
625                        str.add(Calendar.DATE, add);
626                }
627                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
628                buf1.append(END_DIV).append( buf4.toString() ).append( BR ).append(buf5.toString()).append(END_DIV);
629                buf4.setLength( 0 );
630                buf5.setLength( 0 );
631
632                calStr = bufcal.toString();                             // 5.5.4.0 (2012/07/02)
633
634                return buf1.toString();                                 // 5.9.2.0 (2015/11/06)
635        }
636
637        /**
638         * ヘッダー、上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
639         * これは特殊で、ヘッダーに、年/月、上段は日、下段は、曜日を想定しています。
640         * ヘッダー部分は、月として横持で表示させます。
641         *
642         * @og.rev 5.6.2.3 (2013/03/22) 新規追加
643         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
644         * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
645         * @og.rev 8.1.1.2 (2022/02/25) 本日と休日のCSS指定方法を span から div に変更します。
646         *
647         * @param       header  年月のヘッダー部分
648         * @param       upper   上段の表示フォーマット(日)
649         * @param       lower   下段の表示フォーマット(曜日)
650         * @param       add             表示日付けの加算
651         *
652         * @return  ヘッダー文字列
653         * @og.rtnNotNull
654         */
655        private String makeZoom3( final String header ,final String upper ,final String lower ,final int add ) {
656                final DateFormat formatH = new SimpleDateFormat( header,Locale.JAPAN );
657                final DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
658                final DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );
659
660                final StringBuilder bufH   = new StringBuilder( BUFFER_MIDDLE );                // 年月のヘッダー部分(11Byte目から)
661                final StringBuilder buf1   = new StringBuilder( BUFFER_MIDDLE );                // 日(2桁)
662                final StringBuilder buf2   = new StringBuilder( BUFFER_MIDDLE );                // 曜日
663                final StringBuilder bufcal = new StringBuilder( BUFFER_MIDDLE );                // 5.5.4.0 (2012/07/02) 休日判定用
664                final StringBuilder bufTdy = new StringBuilder( BUFFER_MIDDLE );                // 8.1.1.2 (2022/02/25) 本日判定用
665
666                final Calendar str = HybsDateUtil.getCalendar( startDate );                             // 6.4.2.0 (2016/01/29)
667                final Calendar end = HybsDateUtil.getCalendar( endDate );                               // 6.4.2.0 (2016/01/29)
668
669                // 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
670                final CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );
671
672                final int       dtsu            = lower.length();                                               // 日付欄(下段)の文字数
673                int     dayCount        = 0;                                                                    // ヘッダー部の文字が入るかどうかの基準
674                int     mtCnt           = str.get( Calendar.MONTH ) + 1;                // 月をチェック(色設定用) 初期値は、開始時の月
675                String tmpH             = null;                                                                 // ヘッダー部のテンポラリ情報
676                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
677                bufH.append( DIV_ZOOMWEEK_START );
678
679                // 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
680                while( str.compareTo( end ) <= 0 ) {
681                        final Date dt = str.getTime();
682
683                        if( tmpH == null ) { tmpH = formatH.format( dt ); }     // 初期値。最初にセット
684
685                        // ここから一連の処理は、月表示ヘッダーの作成
686                        final int day = str.get( Calendar.DATE );                       // ヘッダー部の制御用に、日付が必要
687                        if( day == 1 && dayCount > 0 ) {
688                                makeHeaderYM( bufH , dayCount*dtsu , mtCnt++ , tmpH );          // このヘッダー出力は、ひと月前の情報
689
690                                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
691                                bufH.append( buf1 ).append(BR).append( buf2 ).append( "</div>" );
692                                buf1.setLength( 0 );
693                                buf2.setLength( 0 );
694                                bufH.append( DIV_ZOOMWEEK_START );
695
696                                dayCount = 0 ;
697                                tmpH     = formatH.format( dt );
698                        }
699                        dayCount ++ ;   //
700
701                        // 5.6.2.3 (2013/03/22) 休日、本日の処理を class属性化で、合成可能とします。
702                        String tdyCls = null;
703                        bufTdy.setLength( 0 );                                                                                          // 8.1.1.2 (2022/02/25) Add
704                        // 3.6.0.0 (2004/09/17) 休日判断を、事業所カレンダを使用
705//                      if( calData.isHoliday( str ) ) {                                                                        // 8.1.1.2 (2022/02/25) Modify
706                        if( add == 1 && calData.isHoliday( str ) ) {
707                                tdyCls = HOLIDAY_CLASS ;
708                                bufcal.append( '1' );                                                                                   // 5.5.4.0 (2012/07/02) 休日
709                        }
710                        else {
711                                bufcal.append( '0' );                                                                                   // 5.5.4.0 (2012/07/02)         // 6.0.2.5 (2014/10/31) char を append する。
712                        }
713
714                        // 本日判断
715                        if( calData.isContainedToday( str,add ) ) {
716//                              tdyCls = (tdyCls == null) ? TODAY_CLASS : tdyCls + " " + TODAY_CLASS ;  // 8.1.1.2 (2022/02/25) Modify
717                                tdyCls = add == 1 ? TODAY_CLASS : RANGE_CLASS ;
718                        }
719
720                        if( tdyCls != null ) {
721//                              buf1.append( "<span class=\"" ).append( tdyCls ).append( "\">" );       // 8.1.1.2 (2022/02/25) Delete
722//                              buf2.append( "<span class=\"" ).append( tdyCls ).append( "\">" );       // 8.1.1.2 (2022/02/25) Delete
723                                bufTdy.append( "<div class=\"" ).append( tdyCls ).append( "\">" );      // 8.1.1.2 (2022/02/25) Modify
724                        }
725
726                        // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
727                        buf1.append( DIV_ZOOMHEADER2 );
728                        if( tdyCls != null ) { buf1.append( bufTdy.toString() ); }                      // 8.1.1.2 (2022/02/25) 休日と本日
729                        buf1.append( format1.format( dt ) );
730                        if( tdyCls != null ) { buf1.append( END_DIV ); }                                        // 8.1.1.2 (2022/02/25) 休日と本日
731                        buf1.append( END_DIV );
732
733                        buf2.append( DIV_ZOOMHEADER2 );
734                        if( tdyCls != null ) { buf2.append( bufTdy.toString() ); }                      // 8.1.1.2 (2022/02/25) 休日と本日
735                        buf2.append( format2.format( dt ) );
736                        if( tdyCls != null ) { buf2.append( END_DIV ); }                                        // 8.1.1.2 (2022/02/25) 休日と本日
737                        buf2.append( END_DIV );
738
739                        // 8.1.1.2 (2022/02/25) Delete
740//                      if( tdyCls != null ) {
741//                              buf1.append( END_SPAN );
742//                              buf2.append( END_SPAN );
743//                      }
744                        str.add(Calendar.DATE, add);
745                }
746
747                // 処理の最後に、ヘッダーの出力は必要
748                makeHeaderYM( bufH , dayCount*dtsu , mtCnt , tmpH );
749
750                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
751                bufH.append( buf1 ).append( BR ).append( buf2 ).append( END_DIV );
752                buf1.setLength( 0 );
753                buf2.setLength( 0 );
754
755                calStr = bufcal.toString();             // 5.5.4.0 (2012/07/02)
756
757                return bufH.toString();                 // 5.9.2.0 (2015/11/06)
758        }
759
760        /**
761         * 時間軸での月ヘッダーデータを作成します。
762         *
763         * 月ヘッダーは、1日~月末までの日付の上段に、年月(yyyy/MM)表示のヘッダーを作成します。
764         * ヘッダーは、できるだけセンター表示になるように、前後にスペースを入れて調整します。
765         * ヘッダー表示領域が少ない場合、スペースのみになります。
766         * ヘッダーは月が偶数月か奇数月かで、背景色を切り替えることで、判りやすくします。
767         *
768         * @og.rev 5.6.2.3 (2013/03/22) 新規追加
769         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
770         *
771         * @param               bufH    ヘッダーを追記していくStringBuilder
772         * @param               dayCnt  日付欄の文字数カウント (日数*桁数(DTSU)、通常横持なら 2桁 となる)
773         * @param               mtCnt   月数に基づいた色の設定用の数字 (月の連番)
774         * @param               ymStr   ヘッダーに表示する年月文字列(yyyy/MM)
775         *
776         * @return  ヘッダーが追記された StringBuilder
777         * @og.rtnNotNull
778         */
779        private StringBuilder makeHeaderYM( final StringBuilder bufH , final int dayCnt , final int mtCnt , final String ymStr ) {
780                // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
781                // 奇数月と偶数月で色を変える。将来的に % 3 で判定すれば、3色で廻せる。
782                if( mtCnt % 2 == 0 )    { bufH.append( DIV_ZOOMEVENCOLOR ); }
783                else                                    { bufH.append( DIV_ZOOMODDCOLOR ); }
784
785                // 表示すべき文字列が、日付欄の幅よりも小さい場合、スペースのみとする。
786                if( dayCnt < ymStr.length() ) {
787                        bufH.append( SPACE.substring( 0,dayCnt ) );
788                }
789                // 大きい場合は、前後にスペースを入れて、センター配置
790                else {
791                        final int lcnt = (dayCnt-ymStr.length())/2 ;            // 左の個数。端数が切り捨てられる。
792                        final int rcnt = dayCnt-lcnt-ymStr.length();            // 右の個数。端数を考慮し、引き算のみで求める。
793
794                        bufH.append( SPACE.substring( 0,lcnt ) );
795                        bufH.append( ymStr );
796                        bufH.append( SPACE.substring( 0,rcnt ) );
797                }
798
799                bufH.append( END_DIV );                         // 5.9.2.0 (2015/11/06)
800
801                return bufH;
802        }
803
804        /**
805         * 時間軸でのヘッダー表示を行います。
806         *
807         * 時間軸の為、ヘッダーの上下段組は行いません。
808         * ヘッダーは、1時間単位に表示します。また、休憩時刻も求めています。
809         *
810         * @og.rev 3.8.0.5 (2005/08/26) 新規追加
811         * @og.rev 3.8.1.1 (2005/11/21) 日付title,範囲class,
812         * @og.rev 3.8.1.4 (2006/03/13) 日付表示、時刻単位(h)削除、2段組(USE_MULTI_CLM)
813         * @og.rev 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、2文字分(24ピクセル)化する。
814         * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
815         * @og.rev 4.0.0.0 (2007/09/03) 休日の場合でも表示されるように対応(システムリソースで切り替え)
816         * @og.rev 5.5.4.0 (2012/07/02) ガントの一日表示枠の計算を切り上げするようにする。カレンダーフラグ対応。
817         * @og.rev 5.6.1.2 (2013/02/22) ベース時刻を管理。 ym2int 廃止 ⇒ hm2int に変更。 USE_MULTI_CLM ⇒ useMultiClm 変更。
818         * @og.rev 5.6.4.3 (2013/05/24) ヘッダーずれ対応。"日" を2文字の、"日 " に修正。
819         * @og.rev 5.6.5.0 (2013/06/07) 色バーに変更します。
820         * @og.rev 5.6.7.0 (2013/11/03) 時間軸の上段ヘッダーに月日を表示
821         * @og.rev 6.0.2.4 (2014/10/17) daySpan の開始-終了の逆転時の加算は、setDaySpan( String ) メソッドで行います。
822         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
823         * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
824         * @og.rev 7.2.9.4 (2020/11/20) PMD:Useless parentheses.
825         * @og.rev 7.4.2.1 (2021/05/21) 24時間をオーバーした際に、00 時が含まれてしまう。
826         * @og.rev 8.1.1.2 (2022/02/25) 当日と休日を直書きではなく、クラス名で対応します。
827         *
828         * @param       hourOfPixcel    1時間あたりのピクセル数
829         * @param       step                    時間間隔の指定 (1:1時間間隔、2:2時間間隔・・・・)
830         * @param       useTani                 日や時間の単位表示 [true:行う/false:行わない]
831         *
832         * @return  ヘッダー文字列
833         * @og.rtnNotNull
834         */
835        private String makeZoomTime( final int hourOfPixcel,final int step,final boolean useTani ) {
836                final DateFormat format1 = new SimpleDateFormat( "yyyy/MM/dd(EE)",Locale.JAPAN );               // 5.6.5.0 (2013/06/07) 曜日を、tipsに出す。
837                final DateFormat format2 = new SimpleDateFormat( "MM/dd",Locale.JAPAN );                                // 5.7.0.0 (2013/11/03) 上段
838
839                final StringBuilder bufBT  = new StringBuilder( BUFFER_MIDDLE );                // 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)
840                final StringBuilder buf1   = new StringBuilder( BUFFER_MIDDLE );                // 下段の時刻データ
841                final StringBuilder bufH   = new StringBuilder( BUFFER_MIDDLE );                // 3.8.1.4 (2006/03/13) 段組みヘッダー
842                final StringBuilder bufcal = new StringBuilder( BUFFER_MIDDLE );                // 5.5.4.0 (2012/07/02) 休日判定用
843                final StringBuilder bufTdy = new StringBuilder( BUFFER_MIDDLE );                // 8.1.1.2 (2022/02/25) 本日判定用
844                final StringBuilder bufDY  = new StringBuilder( BUFFER_MIDDLE );                // 5.7.0.0 (2013/11/03) 上段用
845
846                String  lastTitle = null; // 5.7.0.0 (2013/11/03)
847                int             dayLength = 0; // 5.7.0.0 (2013/11/03)
848                int             base = 2;               // 5.7.0.0 (2013/11/03) 時間単位の標準桁数
849                if( useTani ){ base = 4;}
850
851                // daySpan      = "0700-2000";  // 開始時刻(HHmm-HHmm) 3.8.0.5 (2005/08/26)
852                // 分の小数計算を行います。加算は1時間(0100)単位です。
853                // 5.6.1.2 (2013/02/22)
854                final int ad = daySpan.indexOf( '-' );
855                final int startTime = hm2int( daySpan.substring( 0,ad ) ) ;
856                final int endTime   = hm2int( daySpan.substring( ad+1 ) ) ;
857
858                // 6.0.2.4 (2014/10/17) 逆転時の加算は、setDaySpan( String ) メソッドで行います。
859                // 開始時刻より終了時刻が同じか小さい場合は、翌日なので2400加算します。
860
861                // 休憩時間を管理する BreakTimes オブジェクトを作成します。
862                final BreakTimes breakTimeObj = new BreakTimes( hourOfPixcel/step,breakTimes,breakTimeStyle,startTime,endTime );
863
864                // 5.6.1.2 (2013/02/22) ベース時刻を管理する BreakTimes オブジェクトを作成します。(利用するクラスは同じ)
865                final BreakTimes baseTimeObj = new BreakTimes( hourOfPixcel/step,baseTimes,baseTimeStyle,startTime,endTime );
866
867                // 現在時刻を求めておきます。 現在時刻に5分加算しておきます。(余計なお世話?)
868                final Calendar rightNow = Calendar.getInstance();
869                rightNow.add( Calendar.MINUTE,5 );              // 5分 加算
870                final int now = rightNow.get( Calendar.HOUR_OF_DAY ) ;
871
872                // 3.8.5.0 (2006/02/06)
873                final boolean isDebug = isDebug();
874                if( isDebug ) {
875                        System.out.println( "startDate=" + startDate );
876                        System.out.println( "endDate  =" + endDate );
877                }
878
879                final Calendar str = HybsDateUtil.getCalendar( startDate );                     // 6.4.2.0 (2016/01/29)
880                final Calendar end = HybsDateUtil.getCalendar( endDate );                       // 6.4.2.0 (2016/01/29)
881
882                // 3.6.0.0 (2004/09/17) カレンダDB検索機能を追加
883                final CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );
884
885                // 1時間=hourOfPixcel(px) なので、1日分のピクセルを求めておく。(休憩時刻表示用)
886                final int dayOfPixel = (int)(hourOfPixcel * Math.ceil((endTime-startTime)/100.0/step) ); // 5.5.4.0 (2012/07/02) 切り上げ
887
888                // 休憩表示における画面上の表示日数。これが、左のバイアス値として1日分と乗算される。
889                int totalDay = 0;
890
891                // 1日分の表示範囲の開始時刻とデータの表示開始時刻との差(オフセット)ピクセル
892                final int offsetPixel = (int)(hourOfPixcel/step * (startTime - (int)(str.get( Calendar.HOUR_OF_DAY )*100 + str.get( Calendar.MINUTE )*10.0/6.0))/100.0 );
893
894                // 3.8.1.4 (2006/03/13) 時間単位(h)の表示有無を USE_MULTI_CLM と関係させます。
895                // 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、2文字分(24ピクセル)化する。
896                final String tani ;
897                if( useTani ) { tani = "h " ;   }               // 5.6.5.0 (2013/06/07) useMultiClm を無視します。
898                else {                  tani = "";                                                              }
899
900//              boolean modifyFlag = false;                                                                                             // 8.1.1.2 (2022/02/25) Delete
901                int cnt = 0;    // 3.8.1.1 (2005/11/21)
902                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
903                final StringBuilder bufSave = new StringBuilder( BUFFER_MIDDLE );
904
905                while( str.before( end ) ) {    // 終了時間は、「含まない」仕様
906                        if( isDebug ) { System.out.println( "Calendar str =" + str.getTime() ); }       // 3.8.5.0 (2006/02/06)
907
908                        // 5.6.5.0 (2013/06/07) 日付と曜日の対応
909                        final int day = str.get( Calendar.DATE );
910
911                        final String dayStr = String.format( "%02d", day )                                                      // 7.2.9.4 (2020/11/20)
912//                                                       + ( useTani ? DAY_OF_WEEK_JA[str.get( Calendar.DAY_OF_WEEK )] : "") ; // 8.1.1.2 (2022/02/25) Modify
913                                                         + ( useTani ? '(' + DAY_OF_WEEK_JA[str.get( Calendar.DAY_OF_WEEK )] + ')' : "") ;
914
915//                      final String dayStr = ( day >= 10 ? day : "0" + day )
916//                                                       + ( useTani ? DAY_OF_WEEK_JA[str.get( Calendar.DAY_OF_WEEK )] : "") ;
917
918                        // 5.5.4.0 (2012/07/02) この場合は枠単位ではなく、日単位で出力する
919                        // skipHolidayは無視して、範囲内の全てのカレンダーを出力
920                        if(calData.isHoliday( str )){
921                                bufcal.append('1');             // 6.0.2.5 (2014/10/31) char を append する。
922                        }
923                        else{
924                                bufcal.append('0');             // 6.0.2.5 (2014/10/31) char を append する。
925                        }
926
927                        // 休日判断を、事業所カレンダを使用:休日なら、日付を進める。
928                        if( calData.isHoliday( str ) && skipHoliday ) {
929                                if( isDebug ) { System.out.println( "Holiday =" + str.getTime() ); }    // 3.8.5.0 (2006/02/06)
930                                str.add(Calendar.DATE, 1);
931                                continue;
932                        }
933
934                        // 3.8.1.1 (2005/11/21) 日付のツールチップ表示
935                        final String ganttClass = "class=\"GNT_" + (cnt % 2) + " zoomHeaderDiv2\"";             // 5.9.2.0 (2015/11/06)
936
937                        final Date dt = str.getTime();
938                        String title = format1.format( dt );
939                        // 5.9.2.0 (2015/11/06) MODIFY
940                        buf1.append( "<div " ).append( ganttClass )
941                                .append( " title=\"" ).append( title ).append( "\">" );
942
943                        // 5.7.0.0 (2013/11/03) 上段
944                        if( lastTitle != null && dayLength > 0 ){                                       // 6.0.2.5 (2014/10/31) 非短絡論理の疑わしい使用
945                                makeHeaderMD(bufDY , dayLength*base , 0 , lastTitle);
946                                dayLength = 0;
947                        }
948                        lastTitle = format2.format( dt );
949
950                        if( isDebug ) { System.out.println( "title =" + title ); }      // 3.8.5.0 (2006/02/06)
951
952                        // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
953                        if( cnt > 0 ){
954                                bufSave.append( DIV_ZOOMWEEK_START );
955                                if( USE_MD_HEADER ){ // 5.7.0.0 (2013/11/03)月日を冗談に表示する
956                                        bufSave.append( bufDY );
957                                }
958                                bufSave.append( bufH );
959                                bufDY.setLength( 0 );
960                                bufH.setLength( 0 );
961                        }
962
963                        // 5.6.5.0 (2013/06/07) 色バー対応
964                        if( useMultiClm ) {
965                                // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
966                                if( cnt % 2 == 0 )      { bufH.append( DIV_ZOOMEVENCOLOR ); }           // 偶数の色
967                                else                            { bufH.append( DIV_ZOOMODDCOLOR ); }            // 奇数の色
968                        }
969                        cnt++;          // 5.6.5.0 (2013/06/07) 他の処理は、cnt++ を先にしているが、ここでは初期設定指定ない為、cnt++ を、処理の後で行う。
970
971                        // 本日判断
972                        final boolean isToday = calData.isContainedToday( str,1 );
973                        // 本日の処理を class属性化します。8.1.1.2 (2022/02/25) Add
974                        String tdyCls1 = null;
975                        if( isToday ) {
976                                tdyCls1 = TODAY_CLASS;
977                                bufH.append( "<div class=\"" ).append( tdyCls1 ).append( "\">" );
978                        }
979
980                        int tmHd = startTime/100 ;
981                        final int dayOut = tmHd;                // 3.8.1.4 (2006/03/13)
982                        boolean isTodayNow = false;             // 3.8.9.2 (2007/07/28) 時間ステップ対応
983
984                        for( int h=startTime; h<endTime; h+=100 ) {             // 加算は1時間単位
985                                if( isDebug ) { // 3.8.5.0 (2006/02/06)
986                                        System.out.println( "hour =" + h );
987                                        System.out.println( "tmHd =" + tmHd );
988                                }
989                                // 3.8.9.2 (2007/07/28) 時間ステップ対応
990                                // 8.1.1.2 (2022/02/25) Modify
991                                // 枠単位が 08h,12h で、現在時刻が 10h のとき、本日の現在時刻判断 12h 枠になる不具合対応
992//                              isTodayNow = isTodayNow || isToday && tmHd == now ;
993                                isTodayNow = isTodayNow || isToday && tmHd == now + ( dayOut - now ) % step ;
994                                if( ( dayOut - tmHd ) % step != 0 ) { tmHd++; continue; }
995
996                                dayLength++; // 5.7.0.0 (2013/11/03)
997
998                                if( tmHd >= 24 ) {
999//                                      tmHd = 0;
1000                                        tmHd = tmHd-24;                                 // 7.4.2.1 (2021/05/21) 24時間をオーバーした際に、00 時が含まれてしまう。
1001                                        // 3.8.1.1 (2005/11/21) 日付のツールチップを次の日に設定します。
1002                                        final Date dt2 = new Date( str.getTimeInMillis() + 24*3600*1000L );
1003                                        title = format1.format( dt2 );
1004                                        // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
1005                                        buf1.append( END_DIV ).append( "<div " ).append( ganttClass )
1006                                                .append( " title=\"" ).append( title ).append( "\">" );
1007                                }
1008
1009                                // 休日と本日の処理を class属性化します。
1010                                String tdyCls2 = null;                                                                                  // 8.1.1.2 (2022/02/25) Add
1011                                bufTdy.setLength( 0 );                                                                                  // 8.1.1.2 (2022/02/25) Add
1012                                // 本日の現在時刻判断
1013                                if( isTodayNow ) {
1014//                                      buf1.append( BLUE_COLOR );                                                                      // 8.1.1.2 (2022/02/25) Delete
1015//                                      bufH.append( BLUE_COLOR );                                                                      // 8.1.1.2 (2022/02/25) Delete
1016//                                      modifyFlag = true;                                                                                      // 8.1.1.2 (2022/02/25) Delete
1017                                        tdyCls2 = step == 1 ? TODAY_CLASS : RANGE_CLASS ;                       // 8.1.1.2 (2022/02/25) Add
1018                                        isTodayNow = false;                                                                                     // 初期化
1019                                }
1020                                // 4.0.0.0 休日判断
1021                                else if( calData.isHoliday( str ) && !skipHoliday ) {
1022//                                      buf1.append( RED_COLOR );                                                                       // 8.1.1.2 (2022/02/25) Delete
1023//                                      bufH.append( RED_COLOR );                                                                       // 8.1.1.2 (2022/02/25) Delete
1024//                                      modifyFlag = true;                                                                                      // 8.1.1.2 (2022/02/25) Delete
1025                                        tdyCls2 = HOLIDAY_CLASS ;                                                                       // 8.1.1.2 (2022/02/25) Add
1026                                }
1027
1028                                // 8.1.1.2 (2022/02/25) Add
1029                                if( tdyCls2 != null ) {
1030                                        bufTdy.append( "<div class=\"" ).append( tdyCls2 ).append( "\">" );
1031                                }
1032
1033                                // 実質表示日数(totalDay) * 1日分のピクセル(dayOfPixel) - オフセット(offsetPixel)
1034                                String bt = breakTimeObj.makeSpan( totalDay*dayOfPixel-offsetPixel,str,h,step );
1035                                if( bt != null ) { bufBT.append( bt ); }                // 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)
1036
1037                                // 5.6.1.2 (2013/02/22) ベース時刻のタグを出力します。
1038                                bt = baseTimeObj.makeSpan( totalDay*dayOfPixel-offsetPixel,str,h,step );
1039                                if( bt != null ) { bufBT.append( bt ); }                // 5.6.5.0 (2013/06/07) 休憩の管理(buf2 ⇒ bufBT 名称変更)
1040
1041                                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
1042                                buf1.append( DIV_ZOOMWEEKDAY );
1043                                if( tdyCls2 != null ) { buf1.append( bufTdy.toString() ); }             // 8.1.1.2 (2022/02/25) 休日と本日
1044                                // 時間当たりの文字数は、4文字: 文字列を詰める。
1045                                buf1.append( String.format( "%02d", tmHd ) ).append( tani );    // 7.2.9.4 (2020/11/20)
1046                                if( tdyCls2 != null ) { buf1.append( END_DIV ); }                               // 8.1.1.2 (2022/02/25) 休日と本日
1047                                buf1.append( END_DIV );
1048
1049//                              if( tmHd < 10 ) { buf1.append( '0' ); }         // 桁数あわせ
1050//                              buf1.append( tmHd ).append( tani )                      // 3.8.1.4 (2006/03/13)
1051//                                      .append( END_DIV );                                             // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
1052
1053                                // 3.8.1.4 (2006/03/13) 日付表示、時刻単位(h)削除、2段組(USE_MULTI_CLM)
1054                                // 3.8.1.6 (2006/04/25) 日や時間の単位表示を止め、2文字分(24ピクセル)化する。
1055                                if( useMultiClm ) {                                             // 5.6.1.2 (2013/02/22) useMultiClm 追加
1056                                        if( dayOut == tmHd ) {                          // 5.6.5.0 (2013/06/07) 色バー対応   // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
1057                                                bufH.append( dayStr );                  // 5.6.5.0 (2013/06/07) 先に日付+曜日の文字列を作成する。"日" を2文字の、"日 " に修正済み。
1058                                        }
1059                                        else {
1060                                                if( useTani ) { bufH.append( "    " ); }
1061                                                else {                  bufH.append( "  " );   }
1062                                        }
1063                                }
1064
1065                                // 8.1.1.2 (2022/02/25) Delete
1066//                              if( modifyFlag ) {
1067//                                      buf1.append( END_SPAN );
1068//                                      bufH.append( END_SPAN );
1069//                                      modifyFlag = false;
1070//                              }
1071                                tmHd++; // ヘッダーに記述する時刻
1072                        }
1073                        // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
1074                        if( useMultiClm ){ bufH.append( END_DIV ); }
1075                        if( tdyCls1 != null ) { bufH.append( END_DIV ); }                                       // 8.1.1.2 (2022/02/25) 本日
1076                        bufH.append( buf1.toString() ).append(END_DIV);
1077                        buf1.setLength( 0 );
1078
1079                        str.add( Calendar.DATE, 1 );
1080                        totalDay++ ;
1081                        if( useMultiClm ) { bufH.append(  END_DIV ); }  // 5.9.2.0 (2015/11/06)
1082                }
1083
1084                calStr = bufcal.toString();             // 5.5.4.0 (2012/07/02)
1085
1086                // 5.7.0.0 (2013/11/03) 最後の上段
1087                if( lastTitle != null && dayLength > 0 ){                                               // 6.1.0.0 (2014/12/26) findBugs
1088                        makeHeaderMD(bufDY , dayLength*base , 0 , lastTitle);
1089                        dayLength = 0;
1090                }
1091
1092                // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
1093                bufSave.append( DIV_ZOOMWEEK_START );
1094                if( USE_MD_HEADER ){                            // 5.7.0.0 (2013/11/03) 月日を上段に表示する
1095                        bufSave.append( bufDY );
1096                }
1097                bufSave.append( bufH );
1098                bufDY.setLength( 0 );
1099                bufH.setLength( 0 );
1100
1101                // 5.9.2.0 (2015/11/06) DEL ヘッダー列幅の固定対応
1102                return bufBT.append( bufSave ).toString();                      // 5.9.2.0 (2015/11/06)
1103        }
1104
1105        /**
1106         * 時間軸での日ヘッダーデータを作成します。
1107         *
1108         * ヘッダーは、時間表示の場合に上段にMM/ddを表示します。
1109         *
1110         * @og.rev 5.7.0.0 (2013/11/07) 新規追加
1111         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
1112         *
1113         * @param               bufH    ヘッダーを追記していくStringBuilder
1114         * @param               fillCnt 日付欄の文字数カウント (通常は2*時間数か、4*時間数のどちらか)
1115         * @param               mtCnt   月数に基づいた色の設定用の数字 (将来的な拡張用)
1116         * @param               mdStr   ヘッダーに表示する月日文字列(MM/dd)
1117         *
1118         * @return  ヘッダーが追記された StringBuilder
1119         * @og.rtnNotNull
1120         */
1121        private StringBuilder makeHeaderMD( final StringBuilder bufH , final int fillCnt , final int mtCnt ,  final String mdStr ) {
1122                // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
1123                if( mtCnt % 2 == 0 )    { bufH.append( DIV_ZOOMEVENCOLOR ); }   // 偶数の色
1124                else                                    { bufH.append( DIV_ZOOMODDCOLOR ); }    // 奇数の色
1125
1126                // 表示すべき文字列が、表示すべき幅よりも小さい場合、スペースのみとする。
1127                if( fillCnt < mdStr.length() ) {
1128                        bufH.append( StringUtil.stringXFill(" ",fillCnt) );
1129                }
1130                // 大きい場合は、前後にスペースを入れて、センター配置
1131                else {
1132                        bufH.append( StringUtil.stringXFill(mdStr,fillCnt) );
1133                }
1134
1135                bufH.append( END_DIV );                 // 5.9.2.0 (2015/11/06)
1136
1137                return bufH;
1138        }
1139
1140        /**
1141         * 上段・下段のフォーマットと、加算日に応じたヘッダー文字列を作成します。
1142         *
1143         * @og.rev 5.6.1.2 (2013/02/22) 新規作成
1144         * @og.rev 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
1145         * @og.rev 5.9.2.0 (2015/11/06) ヘッダ対応
1146         * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
1147         * @og.rev 8.1.1.2 (2022/02/25) 本日と休日のCSSを直書きではなく、クラス名で対応します。
1148         *
1149         * @param       upper           上段の表示フォーマット
1150         * @param       lower           下段の表示フォーマット
1151         * @param       add                     表示日付けの加算
1152         * @param       useMonth        月表示 [true:月表示のみ(20日以降を翌月表示)/false:月日表示]
1153         *
1154         * @return  ヘッダー文字列
1155         * @og.rtnNotNull
1156         */
1157        private String makeZoomStack( final String upper ,final String lower ,final int add, final boolean useMonth ) {
1158                final DateFormat format1 = new SimpleDateFormat( upper,Locale.JAPAN );
1159                final DateFormat format2 = new SimpleDateFormat( lower,Locale.JAPAN );
1160
1161                final DateFormat formatCal = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
1162
1163                // 5.5.8.3 (2012/11/17) スタック用にカレンダー枠の情報を保持(開始、休日判定、次枠開始)
1164                final ArrayList<String[]> calList = new ArrayList<>();                  // 個人的には Listを渡す方が好き
1165                String[] calArray = new String[3]; // 開始、休日判定、次枠開始
1166
1167                final Calendar str = HybsDateUtil.getCalendar( startDate );                     // 6.4.2.0 (2016/01/29)
1168                final Calendar end = HybsDateUtil.getCalendar( endDate );                       // 6.4.2.0 (2016/01/29)
1169
1170                // 週単位の場合の特殊処理。
1171                // 年の第一週を完全な一週間分(7日間)として、設定します。
1172                if( zoom == 41 ) {              // ViewStackTableParam.STACK_ZOOM_WEEK
1173                        str.setMinimalDaysInFirstWeek( 7 );
1174                        format1.setCalendar( str );
1175                        format2.setCalendar( str );
1176                }
1177
1178                if( useMonth ){
1179                        str.set(Calendar.DAY_OF_MONTH, 1);
1180                        startDate = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN ).format(str.getTime());
1181                }
1182
1183                final StringBuilder buf1    = new StringBuilder( BUFFER_MIDDLE );
1184                final StringBuilder buf2    = new StringBuilder( BUFFER_MIDDLE );
1185                final StringBuilder bufcal  = new StringBuilder( BUFFER_MIDDLE );
1186                final StringBuilder bufTdy1 = new StringBuilder( BUFFER_MIDDLE );               // 8.1.1.2 (2022/02/25) 上段の本日判定用
1187                final StringBuilder bufTdy2 = new StringBuilder( BUFFER_MIDDLE );               // 8.1.1.2 (2022/02/25) 下段の本日判定用
1188
1189                //  カレンダDB検索機能
1190                final CalendarData calData = CalendarFactory.getCalendarData( calDB,arg1,arg2,arg3,arg4 );
1191
1192//              boolean modifyFlag = false;                                                                                             // 8.1.1.2 (2022/02/25) Delete
1193                // 5.6.2.3 (2013/03/22) 日付の終了日は、「含む」に変更
1194                while( str.compareTo( end ) <= 0 ) {
1195                        Date dt = str.getTime();
1196                        calArray[0] = formatCal.format( dt ); // 5.5.8.3 (2012/11/17)
1197
1198                        // 8.1.1.2 (2022/02/25) Delete
1199//                      // 本日は、青色で示します。
1200//                      if( calData.isContainedToday( str,add ) ) {
1201//                              buf1.append( BLUE_COLOR );
1202//                              buf2.append( BLUE_COLOR );
1203//                              bufcal.append( '0' );           // 6.0.2.5 (2014/10/31) char を append する。
1204//                              calArray[1] = "0";                      // 5.5.8.3 (2012/11/17)
1205//                              modifyFlag = true;
1206//                      }
1207//
1208//                      // 休日判断を、事業所カレンダを使用
1209//                      // modifyFlag が立っていない場合 を条件に追加します。
1210//                      if( !modifyFlag && add == 1 && calData.isHoliday( str ) && !useMonth) {
1211//                              buf1.append( RED_COLOR );
1212//                              buf2.append( RED_COLOR );
1213//                              bufcal.append( '1' );   // 休日           // 6.0.2.5 (2014/10/31) char を append する。
1214//                              calArray[1] = "1";              // 5.5.8.3 (2012/11/17)
1215//                              modifyFlag = true;
1216//                      }
1217
1218                        // 8.1.1.2 (2022/02/25) Modify
1219                        // 休日と本日の処理を class属性化します。
1220                        String tdyCls1 = null;
1221                        String tdyCls2 = null;
1222                        bufTdy1.setLength( 0 );
1223                        bufTdy2.setLength( 0 );
1224                        // 休日判断を、事業所カレンダを使用
1225                        if( add == 1 && calData.isHoliday( str ) && !useMonth ) {
1226                                tdyCls1 = HOLIDAY_CLASS ;
1227                                tdyCls2 = HOLIDAY_CLASS ;
1228                                bufcal.append( '1' );                                                                                   // 休日
1229                                calArray[1] = "1";
1230                        }
1231                        else {
1232                                bufcal.append( '0' );                                                                                   // char を append する。
1233                                calArray[1] = "0";
1234                        }
1235
1236                        // 本日判断
1237                        if( calData.isContainedToday( str,add ) ) {
1238                                tdyCls1 = TODAY_CLASS ;
1239                                tdyCls2 = add == 1 ? TODAY_CLASS : RANGE_CLASS ;
1240                        }
1241
1242                        if( tdyCls1 != null ) {
1243                                bufTdy1.append( "<div class=\"" ).append( tdyCls1 ).append( "\">" );    // 上段の本日判定用
1244                                bufTdy2.append( "<div class=\"" ).append( tdyCls2 ).append( "\">" );    // 下段の本日判定用
1245                        }
1246
1247                        // 5.9.2.0 (2015/11/06) ADD ヘッダー列幅の固定対応
1248                        buf1.append( DIV_ZOOMHEADER2 );
1249                        if( tdyCls1 != null ) { buf1.append( bufTdy1.toString() ); }            // 8.1.1.2 (2022/02/25) 本日
1250                        buf1.append( format1.format( dt ) );
1251                        if( tdyCls1 != null ) { buf1.append( END_DIV ); }                                       // 8.1.1.2 (2022/02/25) 本日
1252                        buf1.append( END_DIV );
1253
1254                        buf2.append( DIV_ZOOMHEADER2 );
1255                        if( tdyCls2 != null ) { buf2.append( bufTdy2.toString() ); }            // 8.1.1.2 (2022/02/25) 休日と本日
1256                        buf2.append( format2.format( dt ) );
1257                        if( tdyCls2 != null ) { buf2.append( END_DIV ); }                                       // 8.1.1.2 (2022/02/25) 休日と本日
1258                        buf2.append( END_DIV );
1259
1260                        // 8.1.1.2 (2022/02/25) Delete
1261//                      if( modifyFlag ) {
1262//                              buf1.append( END_SPAN );
1263//                              buf2.append( END_SPAN );
1264//                              modifyFlag = false;
1265//                      }
1266//                      else{
1267//                              bufcal.append( '0' );           // 6.0.2.5 (2014/10/31) char を append する。
1268//                              calArray[1] = "0";                      // 5.5.8.3 (2012/11/17)
1269//                      }
1270
1271                        // カレンダーを進める
1272                        if( useMonth ){
1273                                str.add(Calendar.MONTH, add);
1274                        }
1275                        else{
1276                                str.add(Calendar.DATE, add);
1277                        }
1278
1279                        dt = str.getTime();
1280                        calArray[2] = formatCal.format( dt ); // 5.5.8.3 (2012/11/17)
1281                        calList.add( calArray.clone() );
1282                }
1283
1284                // スタックガント用の特別な処理。
1285                // 上位の ViewForm_HTMLStackedGanttTable クラスに対して、「開始、休日判定、次枠開始」リストを渡します。
1286                final ViewFormTag viewform = (ViewFormTag)findAncestorWithClass( this,ViewFormTag.class );
1287                viewform.setViewArrayList( calList );
1288
1289                calStr = bufcal.toString();
1290
1291                return buf1.toString() + BR + buf2.toString();                  // 5.9.2.0 (2015/11/06) MODIFY ヘッダー列幅の固定対応
1292        }
1293
1294        /**
1295         * ganttHeaderの属性情報をdisplay:noneで作成します。
1296         * ganttHeaderというタグで、id,class共にganttHeaderDataという名称で出力します。
1297         *
1298         * @og.rev 5.5.4.0 (2012/07/02) 新規作成
1299         * @og.rev 5.6.1.2 (2013/02/22) baseTimes 追加
1300         *
1301         * @return  ヘッダー情報の文字列
1302         * @og.rtnNotNull
1303         */
1304        private String makeHeaderData() {
1305
1306                final String tag = "<ganttHeader style='display:none' id='ganttHeaderData' class='ganttHeaderData' " ;
1307                final StringBuilder buf1 = new StringBuilder( BUFFER_MIDDLE );
1308
1309                buf1.append( CR )
1310                        .append( tag )
1311                        .append( "startDate='"          ).append( startDate             )
1312                        .append( "' endDate='"          ).append( endDate               )
1313                        .append( "' zoom='"                     ).append( zoom                  )
1314                        .append( "' daySpan='"          ).append( daySpan               )
1315                        .append( "' calDB='"            ).append( calStr                )
1316                        .append( "' breakTimes='"       ).append( breakTimes    )
1317                        .append( "' baseTimes='"        ).append( baseTimes             )               // 5.6.1.2 (2013/02/22) baseTimes 追加
1318                        .append( "' skipHoliday='"      ).append( skipHoliday   )
1319                        .append( "' useMultiClm='"      ).append( useMultiClm   )               // 5.6.1.2 (2013/02/22) useMultiClm 追加
1320                        .append( "' />" );              // XML なので、このまま。
1321
1322                return buf1.toString();
1323        }
1324
1325        /**
1326         * 【TAG】表示開始日付けを設定します(yyyyMMdd または、yyyyMMddHHmm 形式)。
1327         *
1328         * @og.tag
1329         * この値は、ヘッダーの先頭に表示する日付けを指定します。
1330         * 通常の日付ヘッダーの場合は、 yyyyMMdd 形式ですが、時間ヘッダーの場合は、
1331         * yyyyMMddHHmm 形式で指定します。
1332         *
1333         * @param       val 表示開始日付 (yyyyMMdd または、yyyyMMddHHmm形式)
1334         */
1335        public void setStartDate( final String val ) {
1336                startDate = nval( getRequestParameter( val ),startDate );
1337        }
1338
1339        /**
1340         * 【TAG】表示最終日を設定します(yyyyMMdd または、yyyyMMddHHmm 形式)。
1341         *
1342         * @og.tag
1343         * 表示開始日から終了日までを、zoom 変数の値に応じてヘッダーラベルを
1344         * 作成します。
1345         * 通常の日付ヘッダーの場合は、 yyyyMMdd 形式ですが、時間ヘッダーの場合は、
1346         * yyyyMMddHHmm 形式で指定します。
1347         *
1348         * @param       val 表示最終日 (yyyyMMdd または、yyyyMMddHHmm形式)
1349         */
1350        public void setEndDate( final String val ) {
1351                endDate = nval( getRequestParameter( val ),endDate );
1352        }
1353
1354        /**
1355         * 【TAG】1日の開始終了時間を24時間形式(HHmm-HHmm または HH-HH)で設定します(初期値:0700-2000)。
1356         *
1357         * @og.tag
1358         * この値は、1日の開始終了時間を指定します。
1359         * 開始時刻は、内部で1時間単位に変換されます。8時30分~は、8時~になります。
1360         * 終了時間は、その時間を「含みません」
1361         * 開始時刻より終了時刻が小さい場合は、翌日への日またぎとして計算します。
1362         * たとえば、夜勤等で、17:00-07:00 という指定が可能です。
1363         * 初期値は、朝の7:00から夜の20:00までです。(0700-2000)です。
1364         *
1365         * @og.rev 3.8.0.5 (2005/08/26) 本日は、青色で示します。
1366         * @og.rev 5.6.1.2 (2013/02/22) daySpan(時刻表示範囲)は、内部では1時間単位
1367         * @og.rev 6.0.2.4 (2014/10/17) 開始-終了が逆転している場合の処理をここで行う。
1368         *
1369         * @param       val 開始終了時間(HHmm-HHmm)形式
1370         */
1371        public void setDaySpan( final String val ) {
1372                daySpan = nval( getRequestParameter( val ),daySpan );
1373
1374                // 6.0.2.4 (2014/10/17) 開始-終了が逆転している場合の処理をここで行う。
1375                String st ;
1376                String ed ;
1377
1378                // 5.6.1.2 (2013/02/22) daySpan(時刻表示範囲)は、内部では1時間単位
1379                if( daySpan.length() == 5 && daySpan.charAt(2) == '-' ) {
1380                        st = daySpan.substring( 0,2 ) + "00" ;
1381                        ed = daySpan.substring( 3 )   + "00" ;
1382                }
1383                else if( daySpan.length() == 9 && daySpan.charAt(4) == '-' ) {
1384                        st = daySpan.substring( 0,2 ) + "00" ;
1385                        ed = daySpan.substring( 5 ) ;
1386                }
1387                else {
1388                        final String errMsg = "1日の開始終了時間は24時間制で(HHmm-HHmm または HH-HH)形式で指定してください。"
1389                                        + " value=[" + val + "]"
1390                                        + " daySpan=[" + daySpan + "]" ;                // 5.1.8.0 (2010/07/01) errMsg 修正
1391                        throw new HybsSystemException( errMsg );
1392                }
1393
1394                // 6.0.2.4 (2014/10/17) 開始時刻より終了時刻が同じか小さい場合は、翌日なので2400加算します。
1395                if( st.compareTo( ed ) >= 0 ) {                 // st >= ed
1396                        ed = String.valueOf( Integer.parseInt( ed ) + 2400 );
1397                }
1398
1399                daySpan = st + "-" + ed ;
1400        }
1401
1402        /**
1403         * 【TAG】ズーム変数(0~9,10,11,12,20~31,40~42)を設定します(初期値:2)。
1404         *
1405         * @og.tag
1406         * CSSファイルでの定義と、背景画像との関係で、作成します。
1407         * ズーム変数は、CSSファイルや、JavaScript、PL/SQLと連動して、日付間隔
1408         * あたりのピクセルを計算して、ヘッダーを作成しています。
1409         * また、現在の標準的なクライアントでの換算になる為、高解像度のディスプレイや
1410         * 特殊設定された環境では、表示間隔にずれが発生する可能性があります。
1411         *
1412         *    ZOOM  ラベル        日数ピクセル変換率          ヘッダ上      ヘッダ下    1文字(CSS)
1413         *  ========================================================================================
1414         *      0 : 1週間 日数 *  8 * 6       48    48px =  1日  [02/   ]      [23(EE)]       8px
1415         *      1 : 2週間 日数 *  8 * 3       24    24px =  1日  [02/]         [23 ]          8px
1416         *      2 : 1ヶ月 日数 *  12* 1       12    12px =  1日  [2]           [3]           12px
1417         *      3 : 2ヶ月 日数 *  8 * 7  /  7  8    56px =  7日  [2004/  ]     [02/03  ]      8px
1418         *      4 : 3ヶ月 日数 *  8 * 7  / 14  4    56px = 14日  [2004/  ]     [02/03  ]      8px
1419         *      5 : 4ヶ月 日数 *  9 * 10 / 30  3    90px = 30日  [2004/     ]  [02/03     ]   9px
1420         *      6 : 6ヶ月 日数 * 10 / 6  / 30  2    60px = 30日  [2004/ ]      [02/03 ]      10px
1421         *      7 : 1年   日数 *  9 / 10 / 90  1    90px = 90日  [2004/     ]  [02/03     ]   9px
1422         *      8 : 2年   日数 *  9 / 10 /180  0.5  90px =180日  [2004/     ]  [02/03     ]   9px
1423         *      9 : 3年   日数 * 10 / 6  /180  0.33 60px =180日  [2004/ ]      [02/03 ]      10px
1424         *     10 : 週単位 日数 *  8 / 3  /  7  3.43 24px =  7日  [19W]         [12 ]          8px
1425         *     11 : 予約済み(他物10件使用済み)
1426         *     12 : 予約済み(他物 8件使用済み)
1427         *     13 : 日(週) 日数 *  8 * 2       16    16px =  1日  [23]          [EE]           8px
1428         *  ========================================================================================
1429         *     20 :  1時間   時間 * 12 * 4        48 48px = 1時間 [02EE]        [07h ]        12px
1430         *     21 :  1時間2  時間 * 12 * 2        24 24px = 1時間 [02]          [07]          12px
1431         *     22 :  2時間   時間 * 12 * 4  /  2  24 48px = 2時間 [02EE]        [07h ]        12px
1432         *     23 :  2時間2  時間 * 12 * 2  /  2  12 24px = 2時間 [02]          [07]          12px
1433         *     24 :  4時間   時間 * 12 * 4  /  4  12 48px = 4時間 [02EE]        [07h ]        12px
1434         *     25 :  4時間2  時間 * 12 * 2  /  4   6 24px = 4時間 [02]          [07]          12px
1435         *     26 :  6時間   時間 * 12 * 4  /  6   8 48px = 6時間 [02EE]        [07h ]        12px
1436         *     27 :  6時間2  時間 * 12 * 2  /  6   4 24px = 6時間 [02]          [07]          12px
1437         *     28 :  8時間   時間 * 12 * 4  /  8   6 48px = 8時間 [02EE]        [07h ]        12px
1438         *     29 :  8時間2  時間 * 12 * 2  /  8   3 24px = 8時間 [02]          [07]          12px
1439         *     30 : 12時間   時間 * 12 * 4  / 12   4 48px =12時間 [02EE]        [07h ]        12px
1440         *     31 : 12時間2  時間 * 12 * 2  / 12   2 24px =12時間 [02]          [07]          12px
1441         *  ========================================================================================
1442         *     40 : 積上(日)                    48   48px =  1日  [02/   ]      [23(EE)]       8px
1443         *     41 : 積上(週)                    3.43 48px =  7日  [19W]         [12 ]          8px
1444         *     42 : 積上(月) 月数 * 1            1   90px = 30日  [2004/     ]  [02/03     ]   9px
1445         *     43 : 日単位ヘッダー予約済み
1446         *     ~
1447         *     49 : 日単位ヘッダー予約済み
1448         *
1449         * @og.rev 5.7.6.2 (2014/05/16) stackHeaderタグの互換機能として、DAY⇒40,WEEK⇒41,MONTH⇒42 対応する。
1450         *
1451         * @param       val ズーム変数(0~9,10,11,12,20~31,40~42)
1452         */
1453        public void setZoom( final String val ) {
1454                final String zm = nval( getRequestParameter( val ),null );
1455
1456                // 6.0.0.1 (2014/04/25) zoom の、DAY⇒40,WEEK⇒41,MONTH⇒42 対応
1457                if( ViewStackTableParam.STACK_ZOOM_DAY.equalsIgnoreCase( zm ) ) {
1458                        zoom = 40;
1459                } else if( ViewStackTableParam.STACK_ZOOM_WEEK.equalsIgnoreCase( zm ) ) {
1460                        zoom = 41;
1461                } else if( ViewStackTableParam.STACK_ZOOM_MONTH.equalsIgnoreCase( zm ) ) {
1462                        zoom = 42;
1463                }
1464                else {
1465                        zoom = nval( zm,zoom );
1466                }
1467
1468                if( zoom < 0 || 13 < zoom && zoom < 20 || 31 < zoom && zoom < 40 || 42 < zoom ) {       // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
1469                        final String errMsg = "ズーム変数は、(0~9,10,11,12,20~31,40~42)の範囲で指定してください。"
1470                                        + " zoom=[" + val + "]" ;
1471                        throw new HybsSystemException( errMsg );
1472                }
1473        }
1474
1475        /**
1476         * 【TAG】DB検索するDBを指定します。
1477         *
1478         * @og.tag
1479         * カレンダデータは、システムパラメータ の CalendarQuery_**** で
1480         * 指定する、CalendarQuery クラスの QUERY 文で、実際に取得します。
1481         * 上記の **** 部分に、ここで指定するキーワードを設定して置きます。
1482         * 通常は、データベースID (GE13, ZY01 など)を指定します。
1483         * このキーワードに対する実装クラスを、先のシステムパラメータ の
1484         * キーワード以下に記述しておきます。
1485         * {@og.doc03Link calDB CalendarQuery_****}
1486         *
1487         * @og.rev 3.6.0.0 (2004/09/17) DB検索するDBのキー
1488         *
1489         * @param       db      DB検索するデータベースID
1490         */
1491        public void setCalDB( final String db ) {
1492                calDB = nval( getRequestParameter( db ),calDB );
1493        }
1494
1495        /**
1496         * 【TAG】時間軸での休憩時間の開始-終了時刻をCSV形式で複数指定します。
1497         *
1498         * @og.tag
1499         * 休憩時間は、HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、
1500         * yyyyMMddHHmm-yyyyMMddHHmm形式で複数指定できます。
1501         * これは、開始-終了というハイフン形式でつなげます。
1502         * このセットを、カンマで複数指定できます。
1503         * 例えば、200508201200-1245,200508201300-1315 という感じです。
1504         * - の前後が、4桁の場合は、HHmm-HHmm 形式として、日付に関係なく、常にこの時分
1505         * で休憩が入るという認識をします。つまり、開始は、12桁か、4桁の日付形式、
1506         * 終了も、12桁か、4桁の日付形式になります。
1507         *
1508         * @og.rev 3.8.0.5 (2005/08/26) 新規追加
1509         * @og.rev 3.8.0.7 (2005/09/20) 日付またがり追加追加
1510         *
1511         * @param       times   休憩時間の開始-終了時刻(CSV形式)
1512         */
1513        public void setBreakTimes( final String times ) {
1514                breakTimes = nval( getRequestParameter( times ),null );
1515        }
1516
1517        /**
1518         * 【TAG】時間軸での休憩時間の表示スタイルを設定します
1519         *              (初期値:top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60;)。
1520         *
1521         * @og.tag
1522         * 通常は、ヘッダーのトップからの位置と、色です。
1523         * それ以外にも、スタイルシート属性(キー:値;) というセットを指定できます。
1524         * class="breakTime" を出力していますので、そちらを使用したい場合は、breakTimeStyleを無効化してください。
1525         * そうしないと、こちらは、直接 style属性で設定しているので、強いです。
1526         * 初期値は、top:20px;background-color:yellow;filter:alpha(opacity=60);opacity:0.60; です。
1527         * IE8以下のために、filter:alpha(opacity=60); しています。
1528         * 設定の後ろに、; を付ける様にしてください。
1529         *
1530         * @og.rev 3.8.0.5 (2005/08/26) 新規追加
1531         *
1532         * @param       style   休憩時間の表示スタイル
1533         */
1534        public void setBreakTimeStyle( final String style ) {
1535                breakTimeStyle = nval( getRequestParameter( style ),breakTimeStyle );
1536        }
1537
1538        /**
1539         * 【TAG】時間軸でのベース時刻の開始時刻をCSV形式で複数指定します。
1540         *
1541         * @og.tag
1542         * ベース時刻は、HHmm形式、または、yyyyMMddHHmm形式で複数指定できます。
1543         * このセットを、カンマで複数指定できます。
1544         * 例えば、1700,200508201300 という感じです。
1545         *
1546         * @og.rev 5.6.1.2 (2013/02/22) 新規追加
1547         *
1548         * @param       times   ベース時刻の開始時刻(CSV形式)
1549         */
1550        public void setBaseTimes( final String times ) {
1551                baseTimes = nval( getRequestParameter( times ),null );
1552        }
1553
1554        /**
1555         * 【TAG】時間軸でのベース時刻の表示スタイルを設定します。
1556         *
1557         * @og.tag
1558         * 通常は、ベース時刻の幅と、ヘッダーのトップからの位置と、色です。
1559         * それ以外にも、スタイルシート属性(キー:値;) というセットを指定できます。
1560         * 初期値は、top:20px;background-color:transparent;border-left:2px dashed red; です。
1561         * 設定の後ろに、; を付ける様にしてください。
1562         *
1563         * @og.rev 5.6.1.2 (2013/02/22) 新規追加
1564         *
1565         * @param       style   ベース時刻の表示スタイル
1566         */
1567        public void setBaseTimeStyle( final String style ) {
1568                baseTimeStyle = nval( getRequestParameter( style ),baseTimeStyle );
1569        }
1570
1571        /**
1572         * 【TAG】DB検索する場合の第1のキーを指定します。
1573         *
1574         * @og.tag
1575         * 例えば、GE13, ZY01 では、事業所コード(CDJGS)を設定します。
1576         * この値は、システムパラメータ の CalendarQuery_**** で
1577         * 指定する、CalendarQuery クラスの QUERY 文に依存します。
1578         * データベース定義の統一を望むところです。
1579         *
1580         * @og.rev 3.6.0.0 (2004/09/17) DB検索の第1キー(事業所コードなど)を追加
1581         *
1582         * @param       arg DB検索の第1キー(事業所コードなど)
1583         */
1584        public void setArg1( final String arg ) {
1585                arg1 = nval( getRequestParameter( arg ),arg1 );
1586        }
1587
1588        /**
1589         * 【TAG】DB検索する場合の第2のキーを指定します。
1590         *
1591         * @og.tag
1592         * 例えば、TP652 では、事業部コード(CDJGS) と 物件工程コード(CDKTEI)の2つの
1593         * キーで、カレンダを取得します。(+年月で、行を決定)
1594         * 引数が、2つまで対応しています
1595         * この値は、システムパラメータ の CalendarQuery_**** で
1596         * 指定する、CalendarQuery クラスの QUERY 文に依存します。
1597         * データベース定義の統一を望むところです。
1598         *
1599         * @og.rev 3.6.0.0 (2004/09/17) DB検索の第2キー(WCコードなど)を追加
1600         *
1601         * @param       arg DB検索の第2キー(WCコードなど)
1602         */
1603        public void setArg2( final String arg ) {
1604                arg2 = nval( getRequestParameter( arg ),arg2 );
1605        }
1606
1607        /**
1608         * 【TAG】DB検索する場合の第3のキーを指定します。
1609         *
1610         * @og.tag
1611         * この値は、システムパラメータ の CalendarQuery_**** で
1612         * 指定する、CalendarQuery クラスの QUERY 文に依存します。
1613         * データベース定義の統一を望むところです。
1614         *
1615         * @og.rev 3.6.0.0 (2004/09/17) DB検索の第3キーを追加
1616         *
1617         * @param       arg DB検索の第3キー
1618         */
1619        public void setArg3( final String arg ) {
1620                arg3 = nval( getRequestParameter( arg ),arg3 );
1621        }
1622
1623        /**
1624         * 【TAG】DB検索する場合の第4のキーを指定します。
1625         *
1626         * @og.tag
1627         * この値は、システムパラメータ の CalendarQuery_**** で
1628         * 指定する、CalendarQuery クラスの QUERY 文に依存します。
1629         * データベース定義の統一を望むところです。
1630         *
1631         * @og.rev 3.6.0.0 (2004/09/17) DB検索の第4キーを追加
1632         *
1633         * @param       arg DB検索の第4キー
1634         */
1635        public void setArg4( final String arg ) {
1636                arg4 = nval( getRequestParameter( arg ),arg4 );
1637        }
1638
1639        /**
1640         * 【TAG】時間ガントで休日をスキップするかどうかを設定します
1641         *              (初期値:USE_GANTTHEADER_SKIP_HOLIDAY[={@og.value SystemData#USE_GANTTHEADER_SKIP_HOLIDAY}])。
1642         *
1643         * @og.tag
1644         * この値をfalseにすると、時間ガントでも休日が赤色で表示
1645         * されるようになります。trueにした場合は、休日は表示されません。
1646         * (初期値:システム定数のUSE_GANTTHEADER_SKIP_HOLIDAY[={@og.value SystemData#USE_GANTTHEADER_SKIP_HOLIDAY}])。
1647         *
1648         * @og.rev 4.0.0.0 (2007/09/07) 新規作成
1649         *
1650         * @param       skipHol 休日をスキップするかどうか [true:スキップ(=非表示)/false:休日の赤色表示]
1651         * @see         org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_SKIP_HOLIDAY
1652         */
1653        public void setSkipHoliday( final String skipHol) {
1654                skipHoliday = nval( getRequestParameter( skipHol ),skipHoliday );
1655        }
1656
1657        /**
1658         * 【TAG】時間ガントで2段組を使用[true:する/false:しない]を設定します
1659         *              (初期値:USE_GANTTHEADER_MULTIPLE_COLUMN[={@og.value SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN}])。
1660         *
1661         * @og.tag
1662         * ガントヘッダーにおいて、時間ヘッダーの上段に日付を、下段の時間軸の(h)の削除を行います。
1663         * 日付は、表示開始時刻の上と、それの6時間ごとに表示します。
1664         * (初期値:システム定数のUSE_GANTTHEADER_MULTIPLE_COLUMN[={@og.value SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN}])。
1665         *
1666         * @og.rev 5.6.1.2 (2013/02/22) 新規作成
1667         *
1668         * @param       multiClm        2段組使用 [true:する/false:しない]
1669         * @see         org.opengion.hayabusa.common.SystemData#USE_GANTTHEADER_MULTIPLE_COLUMN
1670         */
1671        public void setUseMultiClm( final String multiClm ) {
1672                useMultiClm = nval( getRequestParameter( multiClm ),useMultiClm );
1673        }
1674
1675        /**
1676         * 日付、時刻の文字列を時間整数に変換します。
1677         *
1678         * 時間を扱う場合は、厄介なのは、時間と分の単位の違いです。
1679         * 分に換算してしまうと、時間の取得に60進数で扱う必要が出てきます。
1680         * そこで、単純に時間に換算するのではなく、1時間を100として、
1681         * 分を0から99までの整数に換算して計算しています。
1682         * これにより時間の足し算や引き算が可能になり、かつ、時間を求めるのに
1683         * 100で割るだけで求めることが可能になります。
1684         *
1685         * ここでは、引数に、HHmm 、 HHmmss 、yyyyMMddHHmm 、yyyyMMddHHmmss 、null が扱えます。
1686         * null の場合は、-1 を返します。
1687         * yyyyMMdd 部分は、無視されます。
1688         *
1689         * @og.rev 5.6.1.2 (2013/02/22) 日付、秒、null 対応
1690         *
1691         * @param       hhmm    時分の文字列
1692         *
1693         * @return 1時間を100として、分を0から99までの整数に換算した値
1694         */
1695        private static int hm2int( final String hhmm ) {
1696                int rtn = -1;
1697
1698                if( hhmm != null ) {
1699                        final int len = hhmm.length();
1700                        String hh = null;
1701                        String mm = null;
1702                        if( len == 4 || len == 6 ) {                    // HHmm 、HHmmss
1703                                hh = hhmm.substring( 0,2 );
1704                                mm = hhmm.substring( 2,4 );
1705                        }
1706                        else if( len == 12 || len == 14 ) {             // yyyyMMddHHmm 、yyyyMMddHHmmss
1707                                hh = hhmm.substring( 8,10 );
1708                                mm = hhmm.substring( 10,12 );
1709                        }
1710                        else {
1711                                final String errMsg = "指定できる時間形式は、HHmm 、HHmmss 、yyyyMMddHHmm 、yyyyMMddHHmmss です。"
1712                                                        + CR
1713                                                        + "hm2int=[" + hhmm + "]" ;
1714                                throw new HybsSystemException( errMsg );
1715                        }
1716                        rtn = (int)(Integer.parseInt( hh ) * 100 + Integer.parseInt( mm )*10.0/6.0 ) ;
1717                }
1718
1719                return rtn;
1720        }
1721
1722        /**
1723         * 休憩時間のデータを管理する内部クラスです。
1724         *
1725         * @og.rev 3.8.0.7 (2005/09/20) 内部クラス新規作成
1726         * @og.group 画面部品
1727         *
1728         * @version  4.0
1729         * @author      Kazuhiko Hasegawa
1730         * @since    JDK5.0,
1731         */
1732        private static final class BreakTimeData {
1733                private final String startDay   ;               // 開始日付。null の場合は、毎日
1734                private final int        startTime      ;               // 開始時刻のhm2int変換済み値
1735                private final int        timeSpan       ;               // 開始時刻と終了時刻の時間差(hm2int変換済み)
1736                private final String viewTime   ;               // ツールチップ表示用の文字列(HHmm-HHmm)
1737
1738                /**
1739                 * コンストラクター
1740                 *
1741                 * 開始日付(startDay)、開始時刻(startTime)、時間差(timeSpan)、表示ラベル(viewTime)
1742                 * を指定して、休憩時間のデータオブジェクトを構築します。
1743                 * 開始日付(startDay)は、null の場合は、毎日、つまり、定常的な休憩時刻として
1744                 * 認識します。日付が指定された場合は、その日のみの特別な休憩時間と認識します。
1745                 * 開始時刻は、hm2int変換済み値で、1時間が100となり、分は、10進数に変換されている
1746                 * 値として認識します。7:30 の場合は、750 という値になります。
1747                 * 開始時刻と終了時刻の時間差(timeSpan)も hm2int変換済み値です。
1748                 * 表示用の文字列(viewTime)は、休憩時間の HTML表記時の title 属性として
1749                 * 設定される為、マウスオーバー時のツールチップに現れます。
1750                 *
1751                 * @param       startDay        開始日付(yyyyMMdd形式) (nullの場合は、毎日)
1752                 * @param       startTime       開始時刻のhm2int変換済み値
1753                 * @param       timeSpan        開始時刻と終了時刻の時間差(hm2int変換済み)
1754                 * @param       viewTime        ツールチップ表示用の文字列(HHmm-HHmm)
1755                 */
1756                BreakTimeData( final String startDay,final int startTime,final int timeSpan,final String viewTime ) {
1757                        this.startDay   = startDay;
1758                        this.startTime  = startTime;
1759                        this.timeSpan   = timeSpan;
1760                        this.viewTime   = viewTime;
1761                }
1762
1763                /**
1764                 * 指定の日付と時刻が、この BreakTimeData の開始日時とマッチするかどうかをチェックします。
1765                 *
1766                 * 開始日時とマッチするとは、内部日付がマッチし、開始時刻が、指定の time の
1767                 * 1時間(+100)*stepの範囲に含まれている場合を指します。(true を返します。)
1768                 * 内部の日付(startDay)が null の場合は、毎日が対象となります。
1769                 * 開始時刻がマッチした場合は、timeSpan 分だけの幅を持った休憩時間を認識します。
1770                 * 境界条件の都合で、timeSpan == 0 の状態も存在しますが、これはマッチしないと判断します。
1771                 *
1772                 * @og.rev 3.8.1.1 (2005/11/21) timeSpan が 0 より大きい場合 条件追加
1773                 * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
1774                 *
1775                 * @param       inDay   日付文字列(yyyyMMdd形式)
1776                 * @param       time    休憩時間の開始時刻のhm2int変換済み値
1777                 * @param       step    時間間隔
1778                 * @return 含まれる(対象)場合は、true そうでない場合は、false
1779                 */
1780                /* default */ boolean startsWith( final String inDay,final int time,final int step ) {
1781                        return timeSpan > 0
1782                                         && time <= startTime
1783                                         && startTime < time+100*step
1784                                         && ( startDay == null || inDay.equals( startDay ) ) ;
1785                }
1786
1787                /**
1788                 * 休憩時間を表す SPANタグを作成します。
1789                 *
1790                 * 1時間=hourOfPixcel(px) で換算します。分は、すでに分数計算(hm2int)済み
1791                 *
1792                 * @og.rev 3.8.8.4 (2007/02/17) class="breaktime"  追加
1793                 * @og.rev 5.6.1.2 (2013/02/22) ベース時刻対応。width が 0 の場合は、2 をセット
1794                 *
1795                 * @param       offset  表示開始ピクセル数 (実質表示日数*1日分のピクセル-オフセット)
1796                 * @param       hourOfPixcel    1時間あたりのピクセル数
1797                 * @param       breakTimeStyle  休憩時間の指定に追加するスタイル属性
1798                 * @return 休憩時間を表す SPANタグ
1799                 * @og.rtnNotNull
1800                 */
1801                /* default */ String getBreakTime( final int offset,final int hourOfPixcel,final String breakTimeStyle ) {
1802                        final int left  = offset + (startTime*hourOfPixcel/100) ;
1803                        int width = timeSpan*hourOfPixcel/100 ;
1804                        if( width == 0 ) { width = 2; }         // 5.6.1.2 (2013/02/22) ベース時刻対応。width が 0 の場合は、2 をセット
1805
1806                        return "<span class=\"breaktime\" title=\"" + viewTime + "\""
1807                                        + " style=\"position:absolute;z-index:100;height:500000px;"
1808                                        + "left:"       + left  + "px;"
1809                                        + "width:"      + width + "px;"
1810                                        + breakTimeStyle        + "\" ></span>"
1811                                        + CR ;
1812                }
1813        }
1814
1815        /**
1816         * 休憩時間を管理する内部クラスです。
1817         *
1818         * 内部的に、休憩時間以外に、ベース時刻も処理できるようにします。
1819         * これは、終了時刻を指定されていない場合でも対応できるようにすることを意味します。
1820         * また、時間指定方法を、時分だけでなく、時分秒指定時でも処理できるようにします。(秒は無視)
1821         *
1822         * @og.rev 3.8.0.7 (2005/09/20) 内部クラスBreakTimeDataを使用するように修正
1823         * @og.rev 3.8.1.6 (2006/04/25) 変数の final 化
1824         * @og.rev 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
1825         *
1826         * @og.group 画面部品
1827         *
1828         * @version  4.0
1829         * @author      Kazuhiko Hasegawa
1830         * @since    JDK5.0,
1831         */
1832        private static final class BreakTimes {
1833                private final List<BreakTimeData>       timeList        = new ArrayList<>();
1834                private final int               hourOfPixcel    ; // 1時間あたりのピクセル数(例:TIME_PIXEL)
1835                private final String    breakTimeStyle  ; // 休憩時間の指定に追加するスタイル属性
1836                private final int               viewStartTime   ; // 数値化(hm2int)された表示開始時刻(例:0700)
1837                private final int               viewEndTime             ; // 数値化(hm2int)された表示終了時刻(例:2000)
1838
1839                /**
1840                 * コンストラクター
1841                 * 必要な情報を設定して、オブジェクトを構築します。
1842                 * 表示終了時刻は、表示開始時刻 >= 表示終了時刻 の場合、2400加算されている。
1843                 *
1844                 * @og.rev 3.8.0.7 (2005/09/20) breakTimesの日付またがり追加
1845                 * @og.rev 3.8.1.1 (2005/11/21) timeSpan の計算方法を見直し
1846                 * @og.rev 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
1847                 * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
1848                 *
1849                 * @param       hOfpx   1時間あたりのピクセル数
1850                 * @param       breakTimes      休憩時間(HHmm-HHmm形式、または、yyyyMMddHHmm-HHmm、または、yyyyMMddHHmm-yyyyMMddHHmm形式)
1851                 * @param       style   休憩時間の指定に追加するスタイル属性
1852                 * @param       vStartTime      数値化(hm2int)された表示開始時刻
1853                 * @param       vEndTime        数値化(hm2int)された表示終了時刻
1854                 */
1855                BreakTimes( final int hOfpx,final String breakTimes,final String style,
1856                                        final int vStartTime,final int vEndTime ) {
1857                        hourOfPixcel    = hOfpx;
1858                        breakTimeStyle  = ( style == null ) ? "" : style ;
1859                        viewStartTime   = vStartTime;
1860                        viewEndTime             = vEndTime;
1861                        final boolean time24    = viewEndTime > 2400 ;  // 3.8.1.1 (2005/11/21) 開始終了が逆転している場合 true
1862
1863                        // 3.8.1.1 (2005/11/21) timeSpan の計算方法を見直し
1864                        final DateFormat format = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
1865                        final String[] startEnds = StringUtil.csv2Array( breakTimes );
1866                        final int len = startEnds.length;
1867
1868                        String  startDay        ;               // null の場合は、毎日
1869                        String  endDay          ;               // 一時変数
1870                        int             startTime       ;               // 開始時刻のhm2int変換済み値
1871                        int             endTime         ;               // 終了時刻のhm2int変換済み値
1872                        int             timeSpan        ;               // 開始時刻と終了時刻の時間差(hm2int変換済み値)
1873                        String  viewTime        ;               // ツールチップ表示用の文字列(HH:mm-HH:mm)
1874
1875                        Calendar str ;
1876                        Calendar end ;
1877
1878                        for( int i=0; i<len; i++ ) {
1879                                final String startEnd = startEnds[i];
1880                                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
1881                                // null の場合は、カンマが連続したり、最後に余分に付いたケースなので、無視する。
1882                                if( startEnd == null ) {
1883                                        continue;
1884                                }
1885                                else {
1886                                        // startEnd     = "0700ss-2000ss";                                              // 開始-終了時刻(HHmm-HHmm)
1887                                        // startEnd     = "200508200700ss-2000ss";                              // 開始-終了時刻(yyyyMMddHHmm-HHmm)
1888                                        // startEnd     = "200508200700ss-200508212000ss";              // 開始-終了時刻(yyyyMMddHHmm-yyyyMMddHHmm)
1889
1890                                        // 5.6.1.2 (2013/02/22) breakTimesの処理方法の見直し
1891                                        final int idx = startEnd.indexOf( '-' );        // ハイフンを見つける。
1892                                        if( idx > 0 ) {
1893                                                final String st = startEnd.substring( 0,idx );
1894                                                final String ed = startEnd.substring( idx+1 );
1895
1896                                                startDay        = st.length() >= 8 ? st.substring( 0,8 ) : null ;               // 8ケタ以上で、yyyyMMdd 取得
1897                                                endDay          = ed.length() >= 8 ? ed.substring( 0,8 ) : null ;               // 8ケタ以上で、yyyyMMdd 取得
1898                                                startTime       = hm2int( st );
1899                                                endTime         = hm2int( ed );
1900                                        }
1901                                        // startEnd     = "0700ss";                                             // 開始時刻(HHmm)
1902                                        // startEnd     = "200508200700ss";                             // 開始時刻(yyyyMMddHHmm)
1903                                        // startEnd     = "200508200700ss";                             // 開始時刻(yyyyMMddHHmm)
1904                                        else {
1905                                                final String st = startEnd;
1906                                                startDay        = st.length() >= 8 ? st.substring( 0,8 ) : null ;               // 8ケタ以上で、yyyyMMdd 取得
1907                                                endDay          = null ;
1908                                                startTime       = hm2int( st );
1909                                                endTime         = startTime + 1;                                                                                // 差分を出すため、startTime に 1 だけ加算
1910                                        }
1911
1912                                        str = null;
1913                                        end = null;
1914                                        if( startDay != null ) { str = HybsDateUtil.getCalendar( startDay ); }                  // 6.4.2.0 (2016/01/29)
1915                                        if( endDay   != null ) { end = HybsDateUtil.getCalendar( endDay   ); }                  // 6.4.2.0 (2016/01/29)
1916
1917                                        // 表示終了時刻 が 2400 より大きい場合、表示開始時刻 >= 表示終了時刻 である。
1918                                        if( time24 ) {
1919                                                // 開始時刻 <  表示終了時刻 => 開始時刻に2400加算する。
1920                                                if( startTime < viewEndTime-2400 ) {
1921                                                        if( str != null ) {
1922                                                                str.add(Calendar.DATE, -1 );    // -1 日しておく
1923                                                                startDay = format.format( str.getTime() );
1924                                                        }
1925                                                        startTime += 2400;
1926                                                }
1927
1928                                                // 終了時刻 <= 表示終了時刻 => 終了時刻に2400加算する。
1929                                                if( endTime <= viewEndTime-2400 ) {
1930                                                        if( end != null ) {
1931                                                                end.add(Calendar.DATE, -1 );    // -1 日しておく
1932                                                                endDay = format.format( end.getTime() );
1933                                                        }
1934                                                        endTime += 2400;
1935                                                }
1936                                        }
1937
1938                                        // 3.8.1.1 (2005/11/21) 判定条件修正
1939                                        // 開始時刻 < 表示開始時刻 => 開始時刻に表示開始時刻をセット。
1940                                        if( startTime < viewStartTime ) { startTime = viewStartTime; }
1941
1942                                        // 開始時刻 > 表示終了時刻 => 開始時刻に表示終了時刻をセット。
1943                                        if( startTime > viewEndTime ) { startTime = viewEndTime; }
1944
1945                                        // 終了時刻 < 表示開始時刻 => 終了時刻に表示開始時刻をセット。
1946                                        if( endTime < viewStartTime ) { endTime = viewStartTime; }
1947
1948                                        // 終了時刻 > 表示終了時刻 => 終了時刻に表示終了時刻をセット。
1949                                        if( endTime > viewEndTime ) { endTime = viewEndTime; }
1950                                        timeSpan = endTime - startTime ;
1951                                        viewTime = startEnd ;
1952                                }
1953
1954                                // 終了日が入っていないか、開始日と終了日が同じ日の場合。
1955                                if( timeSpan >= 0 && ( endDay == null || startDay != null && startDay.equals( endDay ) ) ) {            // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
1956                                        timeSpan = endTime - startTime ;
1957                                        timeList.add( new BreakTimeData( startDay,startTime,timeSpan,viewTime ) );
1958                                }
1959                                else {
1960                                        // 終了日が入っていると複数日に分かれているので、分解する必要がある。
1961
1962                                        // 初日の timeSpan は、startTime から viewEndTime まで
1963                                        timeSpan = viewEndTime - startTime ;
1964                                        timeList.add( new BreakTimeData( startDay,startTime,timeSpan,viewTime ) );
1965
1966                                        // 最終日の timeSpan は、viewStartTime から endTime まで
1967                                        timeSpan = endTime - viewStartTime ;
1968                                        timeList.add( new BreakTimeData( endDay,viewStartTime,timeSpan,viewTime ) );
1969
1970                                        // 中日の timeSpan は、viewStartTime から viewEndTime まで
1971                                        timeSpan = viewEndTime - viewStartTime ;
1972                                        if( str != null && end != null ) {
1973                                                str.add(Calendar.DATE, 1 );             // +1 日しておく
1974                                                while( str.before( end ) ) {    // 終了時間は、「含まない」仕様
1975                                                        final Date dt = str.getTime();
1976                                                        final String tempStartDay = format.format( dt );
1977                                                        timeList.add( new BreakTimeData( tempStartDay,viewStartTime,timeSpan,viewTime ) );
1978                                                        str.add(Calendar.DATE, 1);
1979                                                }
1980                                        }
1981                                }
1982                        }
1983                }
1984
1985                /**
1986                 * その日のその時間の休憩時間を表す SPANタグ群(複数ありうる)を作成します。
1987                 *
1988                 * @og.rev 3.8.9.2 (2007/07/28) 時間間隔パラメータ追加
1989                 *
1990                 * @param       offset  表示開始ピクセル数(実質表示日数*1日分のピクセル-オフセット)
1991                 * @param       day             処理すべき日付のカレンダ
1992                 * @param       time    処理すべき時間
1993                 * @param       step    時間間隔
1994                 * @return その日のその時間の休憩時間を表す SPANタグ群(複数ありうる)
1995                 */
1996                /* default */ String makeSpan( final int offset,final Calendar day,final int time,final int step ) {
1997                        final DateFormat format1 = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
1998                        final String inDay = format1.format( day.getTime() );
1999
2000                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
2001                        final int size = timeList.size();
2002                        for( int i=0; i<size; i++ ) {
2003                                final BreakTimeData timeData = timeList.get(i);
2004                                if( timeData.startsWith( inDay,time,step ) ) {
2005                                        buf.append( timeData.getBreakTime( offset,hourOfPixcel,breakTimeStyle ) );
2006                                }
2007                        }
2008
2009                        String rtn = null;
2010
2011                        if( buf.length() > 0 ) { rtn = buf.toString(); }
2012                        return rtn;
2013                }
2014        }
2015
2016        /**
2017         * このオブジェクトの文字列表現を返します。
2018         * 基本的にデバッグ目的に使用します。
2019         *
2020         * @return このクラスの文字列表現
2021         * @og.rtnNotNull
2022         */
2023        @Override
2024        public String toString() {
2025                return ToString.title( this.getClass().getName() )
2026                                .println( "VERSION"                     ,VERSION                )
2027                                .println( "startDate"           ,startDate              )
2028                                .println( "endDate"                     ,endDate                )
2029                                .println( "daySpan"                     ,daySpan                )
2030                                .println( "zoom"                        ,zoom                   )
2031                                .println( "breakTimes"          ,breakTimes             )
2032                                .println( "breakTimeStyle"      ,breakTimeStyle )
2033                                .println( "baseTimes"           ,baseTimes              )               // 5.6.1.2 (2013/02/22) ベース時刻
2034                                .println( "baseTimeStyle"       ,baseTimeStyle  )               // 5.6.1.2 (2013/02/22) ベース時刻スタイル
2035                                .println( "calDB"                       ,calDB                  )
2036                                .println( "arg1"                        ,arg1                   )
2037                                .println( "arg2"                        ,arg2                   )
2038                                .println( "arg3"                        ,arg3                   )
2039                                .println( "arg4"                        ,arg4                   )
2040                                .println( "skipHoliday"         ,skipHoliday    )
2041                                .println( "TIME_PIXEL"          ,TIME_PIXEL     )
2042                                .println( "Other..."            ,getAttributes().getAttribute() )
2043                                .fixForm().toString() ;
2044        }
2045}