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     */
016    package org.opengion.hayabusa.resource;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    
021    import java.util.Calendar;
022    import java.util.Map;
023    import java.util.SortedMap;
024    import java.util.TreeMap ;
025    import java.util.BitSet ;
026    
027    /**
028     * 事業æ‰?CDJGS) 毎ã?休日カレンãƒ?ƒ‡ータオブジェクトですã?
029     *
030     * カレンãƒ?ƒ‡ータは、指定ã?事業æ‰?�«関して、すべての休日æƒ??を持ってã�?�¾すã?
031     * å…??カレンãƒ?ƒ†ーブル(GE13)の ?‘日(DY1)?ž31日(DY31)までの日付けæ¬?�«対してã€?
032     * 休日日付けの 年月日 に対する、休日かどã�?�‹を判断できるã�?�‘のæƒ??を保持しますã?
033     * 具体的には、休日の年月日に対する List を持つことになりますã?
034     * こã?クラスは、パãƒ?‚±ージプライベã?トになってã�?�¾すã?こã?オブジェクトを作æ?するのはã€?
035     * CalendarFactory#getCalendarData( String ) で行いますã?引数は、事業æ‰?‚³ーãƒ?cdjgs)ですã?
036     * こã?カレンãƒ?‚ªブジェクトを使用するには、事業æ‰?‚«レンãƒ?ƒ†ーブル(GE13) を使用する
037     * ことを許可しておくå¿?¦�がありますã?
038     * 許可は、シスãƒ?ƒ パラメータ の USE_CALENDAR_DATABASE 属æ?ã‚?true に
039     * 設定しまã�?初期値は、互換性優先ã? false ですã?)
040     * こã?、カレンãƒ?ƒ†ーブルは、GE13 固定ですã?他ã?ãƒ??ブルを使用する場合ã?ã€?
041     * ビュー等を作æ?するå¿?¦�がありますã?
042     * カレンãƒ?ƒ†ーブル はã€??常 DEFAULT DBIDを使用しますが、RESOURCE_CALENDAR_DBID
043     * を設定することで、他ã?ãƒ??タベã?スから読み取ることが可能になりますã?
044     *
045     * @og.rev 3.6.0.0 (2004/09/17) 新規作æ?
046     * @og.group リソース管ç�?
047     *
048     * @version  4.0
049     * @author   Kazuhiko Hasegawa
050     * @since    JDK5.0,
051     */
052    class CalendarDBData implements CalendarData {
053            private final SortedMap<String,BitSet> ymMap  = new TreeMap<String,BitSet>() ;      // 休日日付けãƒ??タを年月をキーに持ちますã?
054    //      private final Calendar today = Calendar.getInstance();  // 3.8.8.6 (2007/04/20) å»?­¢
055    
056            /**
057             * コンストラクタ
058             *
059             * 配å?æ–?­—å?のãƒ??タをå?に、CalendarDBDataオブジェクトを構築しますã?
060             * こã?コンストラクタは、他ã?パッケージから呼び出せなã�?‚ˆã�?�«ã€?
061             * パッケージプライベã?トにしておきますã?
062             * 年月データはã€??続であるå¿?¦�がありますã?
063             * 途中に抜けがあるかどã�?�‹のチェãƒ?‚¯を行いますã?
064             *
065             * @param       data    ãƒ??タベã?ス検索ãƒ??タ
066             * @param       isFlat  縦持ち(false)か横持ち(true)の区別
067             */
068            CalendarDBData( final String[][] data,final boolean isFlat ) {
069                    if( isFlat ) {
070                            callFlatTable( data );
071                    }
072                    else {
073                            callVerticalTable( data );
074                    }
075    
076                    // 3.7.1.1 (2005/05/31)
077    //              today.set( Calendar.HOUR_OF_DAY ,12 );  // 昼にセãƒ?ƒˆ
078    //              today.set( Calendar.MINUTE ,0 );
079    //              today.set( Calendar.SECOND ,0 );
080            }
081    
082            /**
083             * 横持ち(フラãƒ?ƒˆ)配å?æ–?­—å?のãƒ??タをå?に、日付情報を構築しますã?
084             * 年月データはã€??続であるå¿?¦�がありますã?
085             * 途中に抜けがあるかどã�?�‹のチェãƒ?‚¯を行いますã?
086             *
087             * @og.rev 3.8.8.0 (2007/12/22) 休日がå?くなã�??合でもã?日付設定するã?
088             *
089             * @param data String[][]
090             *                     [0]:年æœ?YYYYMM) 200406 とã�?�†形å¼?
091             *                     [1]?ž[31] 1日??1日のãƒ??タ
092             *                           0:平日 / そã?ä»?休日
093             */
094            private void callFlatTable( final String[][] data ) {
095                    for( int ym=0; ym<data.length; ym++ ) {
096                            String yyyymm = data[ym][0] ;
097                            if( yyyymm.length() != 6 ) {
098                                    String errMsg = "年æœ?YYYYMM)は、YYYYMM(例ï¼?00406) とã�?�†形式でæŒ?®šして下さã�??"
099                                                            + " YYYYMM [" + yyyymm + "]" ;
100                                    throw new HybsSystemException( errMsg );
101                            }
102    
103                            Calendar month = HybsSystem.getCalendar( yyyymm + "01" );       // 当月
104                            int lastDay = month.getActualMaximum( Calendar.DAY_OF_MONTH );  // 月末日
105    
106                            BitSet ymData = new BitSet( lastDay+1 );
107                            for( int d=1; d<=lastDay; d++ ) {
108                                    if( ! "0".equals( data[ym][d] ) ) {
109                                            // 日付けのビットを立てますã?
110                                            ymData.set( d );
111                                    }
112                            }
113    
114                            // 日付けのキーがありã?休日設定があれば、有効月とみなしã?セãƒ?ƒˆしますã?
115                            // 3.8.8.0 (2007/12/22) 休日がå?くなã�??合でもã?日付設定するã?
116                            ymMap.put( yyyymm,ymData );
117                    }
118            }
119    
120            /**
121             * 縦持ち(バã?ãƒ?‚£カル)配å?æ–?­—å?のãƒ??タをå?に、日付情報を構築しますã?
122             * 年月データはã€??続であるå¿?¦�がありますã?
123             * 途中に抜けがあるかどã�?�‹のチェãƒ?‚¯を行いますã?
124             *
125             * @og.rev 3.8.8.0 (2007/12/22) 休日がå?くなã�??合でもã?日付設定するã?
126             *
127             * @param data String[][]
128             *                     [0]:年æœ?YYYYMMDD) 20040601 とã�?�†形å¼?
129             *                     [1] 0:平日 / そã?ä»?休日
130             */
131            private void callVerticalTable( final String[][] data ) {
132                    String bk_yyyymm = null;
133                    BitSet ymData = null;
134                    for( int ymd=0; ymd<data.length; ymd++ ) {
135                            if( data[ymd][0].length() != 8 ) {
136                                    String errMsg = "年月日(YYYYMMDD)は、YYYYMMDD(例ï¼?0040601) とã�?�†形式でæŒ?®šして下さã�??"
137                                                            + " YYYYMMDD [" + data[ymd][0] + "]" ;
138                                    throw new HybsSystemException( errMsg );
139                            }
140    
141                            String yyyymm = data[ymd][0].substring( 0,6 ) ;
142                            if( ! yyyymm.equals( bk_yyyymm ) ) {    // 月ã?ブレイク
143                                    // 日付けのキーがありã?休日設定があれば、有効月とみなしã?セãƒ?ƒˆしますã?
144                                    // 3.8.8.0 (2007/12/22) 休日がå?くなã�??合でもã?日付設定するã?
145                                    if( ymData != null && bk_yyyymm != null ) {
146                                            ymMap.put( bk_yyyymm,ymData );
147                                    }
148                                    bk_yyyymm = yyyymm;
149    
150                                    Calendar month = HybsSystem.getCalendar( yyyymm + "01" );       // 当月
151                                    int lastDay = month.getActualMaximum( Calendar.DAY_OF_MONTH );  // 月末日
152    
153                                    ymData = new BitSet( lastDay+1 );
154                            }
155    
156                            if( ! "0".equals( data[ymd][1] ) ) {
157                                    // 日付けのビットを立てますã?
158                                    int dt = Integer.parseInt( data[ymd][0].substring( 6 ) );
159                                    ymData.set( dt );
160                            }
161                    }
162                    // 日付けのキーがありã?休日設定があれば、有効月とみなしã?セãƒ?ƒˆしますã?
163                    // 3.8.8.0 (2007/12/22) 休日がå?くなã�??合でもã?日付設定するã?
164                    if( ymData != null && bk_yyyymm != null ) {
165                            ymMap.put( bk_yyyymm,ymData );
166                    }
167            }
168    
169            /**
170             * æŒ?®šã?日付けがã?休日かどã�?�‹を返しますã?
171             * æŒ?®šã?日付けがã?ãƒ??タベã?スに設定されてã�?�ªã�??合ã?、すべて休日ã‚?
172             * 返すことで、存在しなã�?º‹を示しますã?
173             *
174             * @param  day Calendar æŒ?®šã?日付け
175             *
176             * @return      休日?štrue それ以外:false
177             *
178             */
179            public boolean isHoliday( final Calendar day ) {
180                    String yyyymm = cal2YM( day );
181                    BitSet ymData = ymMap.get( yyyymm );
182    
183                    if( ymData != null ) {
184                            return ymData.get( day.get( Calendar.DATE ) );
185                    }
186                    else {
187                            return true;    // DB 上に登録されてã�?�ªã�??合ã?、すべて休日とするã€?
188                    }
189            }
190    
191            /**
192             * æŒ?®šã?日付けから、ç¯?›²の間に、本日を含ã‚?�‹どã�?�‹を返しますã?
193             * æŒ?®šã?日付けがã?キャãƒ?‚·ュしてã�?‚‹ãƒ??タのæœ?¤§とæœ?°�ã?間に
194             * 存在しなã�??合ã?、常に false になりますã?
195             * 判定ã?、年月日のé ?›®のみで比è¼?�—、時åˆ?§’ã?無視しますã?
196             *
197             * @og.rev 3.7.1.1 (2005/05/31) 新規追åŠ?
198             * @og.rev 3.8.8.6 (2007/04/20) today を毎回求めますã?(キャãƒ?‚·ュ対ç­?
199             *
200             * @param  day Calendar æŒ?®šã?開始日付け
201             * @param       scope   ç¯?›²の日数
202             *
203             * @return      本日?štrue それ以外:false
204             */
205            public boolean isContainedToday( final Calendar day,final int scope ) {
206                    final boolean rtnFlag;
207    
208                    Calendar today = Calendar.getInstance();
209                    today.set( Calendar.HOUR_OF_DAY ,12 );  // 昼にセãƒ?ƒˆ
210                    today.set( Calendar.MINUTE ,0 );
211                    today.set( Calendar.SECOND ,0 );
212    
213                    if( scope == 1 ) {
214                            // false の確çŽ??高い方から、比è¼?�—ますã?
215                            rtnFlag = day.get( Calendar.DATE )  == today.get( Calendar.DATE  ) &&
216                                                    day.get( Calendar.MONTH ) == today.get( Calendar.MONTH ) &&
217                                                    day.get( Calendar.YEAR )  == today.get( Calendar.YEAR  ) ;
218                    }
219                    else {
220                            Calendar next = (Calendar)day.clone();
221                            next.add( Calendar.DATE,scope );
222                            rtnFlag = day.before( today ) && next.after( today ) ;
223                    }
224                    return rtnFlag ;
225            }
226    
227            /**
228             * æŒ?®šã?開始ã?終äº?—¥の期間に、平日(稼働日)が何日あるか求めますã?
229             * 調査月が、データベã?ス上に存在してã�?�ªã�??合ã?、エラーとしますã?
230             * 開始と終äº?�Œ同じ日の場合ã?ã€?¼‘を返しますã?
231             *
232             * @param  start Calendar 開始日付け(稼働日に含めまã�?
233             * @param  end   Calendar 終äº?—¥付け(稼働日に含めまã�?
234             *
235             * @return      稼働日数
236             *
237             */
238            public int getKadoubisu( final Calendar start,final Calendar end ) {
239    
240                    String stYM = cal2YM( start );
241                    String edYM = cal2YM( end );
242    
243                    SortedMap<String,BitSet> subMap = ymMap.subMap( stYM,edYM+"\0" ) ;        // 終äº?‚­ーはそã?ままでは含まれなã�?�Ÿめã?
244    
245                    @SuppressWarnings("rawtypes")
246                    Map.Entry[] entrys = (subMap.entrySet()).toArray( new Map.Entry[subMap.size()] );
247    
248                    int holidaySu = 0;
249                    for( int i=0; i<entrys.length; i++ ) {
250                            String ym = (String)entrys[i].getKey();
251                            BitSet bt ;
252                            if( stYM.equals( ym ) ) {
253                                    bt = ((BitSet)entrys[i].getValue()).get( start.get( Calendar.DATE ),31 );
254                            }
255                            else if( edYM.equals( ym ) ) {
256                                    bt = ((BitSet)entrys[i].getValue()).get( 1,end.get( Calendar.DATE )+1 );
257                            }
258                            else {
259                                    bt = (BitSet)entrys[i].getValue();
260                            }
261                            holidaySu += bt.cardinality() ;
262                    }
263    
264                    long diff = start.getTimeInMillis() - end.getTimeInMillis() ;
265                    int dayCount = (int)(diff/(1000*60*60*24)) + 1; // end も含ã‚??で?‹1å¿?¦?
266    
267                    return dayCount - holidaySu ;
268            }
269    
270            /**
271             * æŒ?®šã?開始日に平日のみ期間を加算して求められる日付けを返しますã?
272             * これは、実稼働日計算に使用しますã?
273             * 例えば、start=20040810 , span=5 で、休日がなければã€?0,11,12,13,14 となりã?
274             * 20040815 を返しますã?
275             * æŒ?®šã?日付けã‚??期間åŠ?®—後ã?日付けがã?キャãƒ?‚·ュしてã�?‚‹ãƒ??タの
276             * æœ?¤§とæœ?°�ã?間に存在しなã�??合ã?、エラーとしますã?
277             *
278             * @param  start Calendar   開始日付け(YYYYMMDD 形å¼?
279             * @param       span    稼動期é–?
280             *
281             * @return Calendar 開始日から稼動期間をåŠ?®—した日付け(当日を含ã‚?
282             *
283             */
284            public Calendar getAfterDay( final Calendar start,final int span ) {
285                    Calendar today = (Calendar)(start.clone());
286                    int suSpan = span ;
287                    while( suSpan > 0 ) {
288                            if( ! isHoliday( today ) ) { suSpan--; }
289                            today.add(Calendar.DATE, 1);            // 日にちをé?めるã€?
290                    }
291                    return today ;
292            }
293    
294            /**
295             * カレンãƒ?‚ªブジェクトよりã?年月を YYYYMM 形式にした æ–?­—å?を返しますã?
296             *
297             * @return  カレンãƒ??YYYYMM æ–?­—å?
298             */
299            private String cal2YM( final Calendar cal ) {
300                    return String.valueOf(
301                                            cal.get( Calendar.YEAR ) * 100 +
302                                            cal.get( Calendar.MONTH ) + 1 );
303            }
304    
305            /**
306             * オブジェクトã?識別子として?Œ詳細なカレンãƒ?ƒ…報を返しますã?
307             *
308             * @return  詳細なカレンãƒ?ƒ…報
309             */
310            public String toString() {
311                    StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
312                    rtn.append( "CLASS   : ").append( getClass().getName() ).append( HybsSystem.CR );       // クラスå�?
313    
314                    @SuppressWarnings("rawtypes")
315                    Map.Entry[] entrys = (ymMap.entrySet()).toArray( new Map.Entry[ymMap.size()] );
316    
317                    for( int i=0; i<entrys.length; i++ ) {
318                            String yyyymm = (String)entrys[i].getKey();
319    
320                            rtn.append( yyyymm );
321                            rtn.append( ":" );
322                            rtn.append( (BitSet)entrys[i].getValue() );
323                            rtn.append( HybsSystem.CR );
324                    }
325    
326                    return rtn.toString();
327            }
328    }