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