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.fukurou.util;
017
018import java.io.FileInputStream;
019import java.io.FileOutputStream;
020
021// import java.util.Date;
022// import java.util.Locale;
023// import java.text.DateFormat;
024// import java.text.SimpleDateFormat;
025
026/**
027 * DateSet.java は、入力ファイルの日付,時刻キーワードを実行時の日時で変換して,出力します。
028 *
029 * 変換には,$(yyyy)の形式で指定し,カッコの文字列は,java.text.SimpleDateFormat で使用する,
030 * 時刻フォーマット構文を用います。
031 * また、引数に keys,vals を渡すことで、$(KEY1) 文字列を VAL1 文字列と置き換えます。
032 *
033 *  サンプルファイル
034 *  $(yyyy/MM/dd)        年/月/日を表します。
035 *  $(yy)                年だけを2桁で表します。
036 *  $(MM)                月を2桁 (02,03など)で表します。
037 *  $(dd)                日を2桁 (02,03など)で表します。
038 *  $(HH:mm:ss)          時:分:秒を表します。
039 *  $(MMMMMMMM)          月をフルスペルで表します。
040 *  $(MMM)               月を3桁固定(Mar,Aplなど)で表します。
041 *  $(EEEEEEEE)          曜日をフルスペルで表します。
042 *  $(EEE)               曜日を3桁固定(Sun,Monなど)で表します。
043 *
044 *   時刻フォーマット構文
045 *
046 *   記号     意味                    表示                例
047 *   ------   -------                 ------------        -------
048 *   G        年号                    (テキスト)          AD
049 *   y        年                      (数値)              1996
050 *   M        月                      (テキスト & 数値)  July & 07
051 *   d        日                      (数値)              10
052 *   h        午前/午後の時 (1~12)    (数値)              12
053 *   H        一日における時 (0~23)   (数値)              0
054 *   m        分                      (数値)              30
055 *   s        秒                      (数値)              55
056 *   S        ミリ秒                  (数値)              978
057 *   E        曜日                    (テキスト)          火曜日
058 *   D        年における日            (数値)              189
059 *   F        月における曜日          (数値)              2 (7月の第2水曜日)
060 *   w        年における週            (数値)              27
061 *   W        月における週            (数値)              2
062 *   a        午前/午後               (テキスト)          PM
063 *   k        一日における時 (1~24)   (数値)              24
064 *   K        午前/午後の時 (0~11)    (数値)              0
065 *   z        時間帯                  (テキスト)          PDT
066 *   '        テキスト用エスケープ
067 *   ''       単一引用符                                  '
068 *
069 *  パターン文字のカウントによって、そのフォーマットが決まります。
070 *  (テキスト): 4以上: フル形式を使用します。4以下: 短いまたは省力された形式があれば、それを使用します。
071 *
072 *  (数値): 最小桁数。これより短い数値は、この桁数までゼロが追加されます。年には特別な処理があります。
073 *  つまり、'y'のカウントが2なら、年は2桁に短縮されます。
074 *
075 *  (テキスト & 数値): 3以上ならテキストを、それ以外なら数値を使用します。
076 *
077 *  パターンの文字が['a'..'z']と['A'..'Z']の範囲になければ、その文字は引用テキストとして扱われます。
078 *  たとえば、':'、'.'、' '、'#'、'@'などの文字は、単一引用符に囲まれていなくても、
079 *  結果の時刻テキストに使用されます。
080 *
081 *  無効なパターン文字がパターンに入っていると、フォーマットや解析で例外がスローされます。
082 *
083 *  USロケールを使った例:
084 *
085 *   フォーマットパターン                   結果
086 *   --------------------                   ----
087 *   "yyyy.MM.dd G 'at' hh:mm:ss z"    ⇒  1996.07.10 AD at 15:08:56 PDT
088 *   "EEE, MMM d, ''yy"                ⇒  Wed, July 10, '96
089 *   "h:mm a"                          ⇒  12:08 PM
090 *   "hh 'o''''clock' a, zzzz"         ⇒  12 o'clock PM, Pacific Daylight Time
091 *   "K:mm a, z"                       ⇒  0:00 PM, PST
092 *   "yyyyy.MMMMM.dd GGG hh:mm aaa"    ⇒  1996.July.10 AD 12:08 PM
093 *
094 * @version  0.9.0  1999/03/09
095 * @author   Kazuhiko Hasegawa
096 * @since    JDK1.1,
097 */
098public class DateSet {
099        private String[] keys = null;
100        private String[] vals = null;
101
102        /**
103         * フォーマット解析時に置き換える キーと値の配列を設定します。
104         *
105         * $(KEY1) 文字列を VAL1 文字列と置き換える処理を行います。これにより日付以外の
106         * 文字列を置き換える処理を実行できます。
107         *
108         * @param       inkeys  置き換え元キー配列
109         * @param       invals  置き換え元値配列
110         */
111        public void setKeysVals( final String[] inkeys, final String[] invals ) {
112                if( inkeys != null && invals != null && inkeys.length == invals.length ) {
113                        int size = inkeys.length ;
114                        keys = new String[size];
115                        vals = new String[size];
116                        System.arraycopy( inkeys,0,keys,0,size );
117                        System.arraycopy( invals,0,vals,0,size );
118                }
119        }
120
121        /**
122         * 現在日付、時刻をフォーマット指定個所に埋め込みます。
123         * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
124         *
125         * @param       inByte  変換元バイト配列
126         *
127         * @return      変換後のバイト配列
128         */
129        public byte[] change( final byte[] inByte ) {
130                byte[] outByte = new byte[ inByte.length+100 ];
131                int add = 0;
132                for( int i=0; i<inByte.length; i++) {
133                        if( inByte[i] == '$' && i<inByte.length-1 && inByte[i+1] == '(' ) {
134                                int j = 0;
135                                while( inByte[i+j+2] != ')') { j++; }
136//                              String str = changeForm( new String( inByte,i+2,j ) );
137//                              byte[] byteDate = str.getBytes() ;
138                                String str = changeForm( new String( inByte,i+2,j,StringUtil.DEFAULT_CHARSET ) );       // 5.5.2.6 (2012/05/25) findbugs対応
139                                byte[] byteDate = str.getBytes( StringUtil.DEFAULT_CHARSET ) ;                                          // 5.5.2.6 (2012/05/25) findbugs対応
140                                for( int k = 0; k<byteDate.length; k++) {
141                                        outByte[add] = byteDate[k];
142                                        add++;
143                                }
144                                i += j+2;
145                        }
146                        else {
147                                outByte[add] = inByte[i];
148                                add++;
149                        }
150                }
151                byte[] rtnByte = new byte[ add ];
152                System.arraycopy( outByte,0,rtnByte,0,add );
153                return rtnByte;
154        }
155
156        /**
157         * keys,vals の変換、および、現在日付、時刻のフォーマット変換を行います。
158         *
159         * 先に、keys,vals の変換を行います。form が、keys にマッチすれば、vals を
160         * 返します。最後までマッチしなければ、時刻のフォーマット変換を行います。
161         * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
162         *
163         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
164         *
165         * @param       form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss" )
166         *
167         * @return      フォーマット変換結果
168         */
169        public String changeForm( final String form ) {
170                if( keys != null ) {
171                        for( int i=0; i<keys.length; i++ ) {
172                                if( form.equals( keys[i] ) ) {
173                                        return vals[i];
174                                }
175                        }
176                }
177
178//              DateFormat formatter = new SimpleDateFormat( form, Locale.JAPAN );
179//              return formatter.format(new Date());
180
181                return HybsDateUtil.getDate( form );
182        }
183
184        /**
185         * keys,vals の変換、および、現在日付、時刻のフォーマット変換を行います。
186         *
187         * 先に、keys,vals の変換を行います。form が、keys にマッチすれば、vals を
188         * 返します。最後までマッチしなければ、時刻のフォーマット変換を行います。
189         * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
190         *
191         * @param       form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss" )
192         *
193         * @return      フォーマット変換結果
194         */
195        public String changeString( final String form ) {
196                StringBuilder buf = new StringBuilder( 200 );
197                int bkst = 0;
198                int st = form.indexOf( "$(" );
199                while( st >= 0 ) {
200                        buf.append( form.substring( bkst,st ) );
201                        int ed = form.indexOf( ")",st+2 );
202                        buf.append( changeForm( form.substring( st+2,ed ) ) );
203                        bkst = ed + 1;
204                        st = form.indexOf( "$(",bkst );
205                }
206                buf.append( form.substring( bkst ) );
207
208                return buf.toString();
209        }
210
211        /**
212         * 現在日付、時刻をフォーマットを指定して、所得します。
213         * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
214         *
215         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するため、削除。
216         *
217         * @param       form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss" )
218         *
219         * @return      現在日付、時刻
220         */
221//      public static String getDate( final String form ) {
222//              DateFormat formatter = new SimpleDateFormat( form, Locale.JAPAN );
223//              return formatter.format(new Date());
224//      }
225
226        /**
227         * 入力ファイルの時刻フォーマットを変換して出力ファイルに書き込みます。
228         *
229         * 引数に &lt;key1&gt; &lt;val1&gt; のペア情報を渡すことが可能です。
230         * 先に、keys,vals の変換を行います。form が、keys にマッチすれば、vals を
231         * 返します。最後までマッチしなければ、時刻のフォーマット変換を行います。
232         * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。
233         * フォーム文字列例 (  "yyyy/MM/dd HH:mm:ss" )
234         *
235         * @param       args 引数配列( 入力ファイル 出力ファイル キー1 値1 ・・・
236         * @throws Throwable なんらかのエラーが発生した場合。
237         */
238        public static void main( final String[] args ) throws Throwable {
239                if( args.length > 2 && ( args.length % 2 != 0 ) ) {
240//                      LogWriter.log("Usage: java DateSet <inputFile> <outputFile> [<key1> <val1> ・・・]" );
241                        System.err.println( "Usage: java DateSet <inputFile> <outputFile> [<key1> <val1> ・・・]" );
242                        return ;
243                }
244
245                String[] keys = new String[ (args.length-2)/2 ];
246                String[] vals = new String[ (args.length-2)/2 ];
247                for( int i=1; i<=keys.length; i++ ) {
248                        keys[i-1] = args[i*2];
249                        vals[i-1] = args[i*2+1];
250                }
251
252                FileInputStream filein = new FileInputStream( args[0] );
253                byte[] byteIn = new byte[ filein.available() ];
254                int len = filein.read( byteIn );
255                if( len != byteIn.length ) {
256                        String errMsg = "読み取りファイルのデータが切り捨てられました。" +
257                                                        "File=" + args[0] + " Length=" + len  + " Input=" + byteIn.length ;
258//                      LogWriter.log( errMsg );
259                        System.err.println( errMsg );
260                }
261                filein.close();
262
263                DateSet dateSet = new DateSet();
264                dateSet.setKeysVals( keys,vals );
265                byte[] byteout = dateSet.change( byteIn );
266
267                FileOutputStream fileout = new FileOutputStream( args[1] );
268                fileout.write( byteout );
269                fileout.close();
270        }
271}