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.util.Arrays; 019import java.util.Calendar; 020import java.util.Date; 021import java.util.Locale; 022import java.util.Map; 023import java.util.HashMap; 024import java.text.DateFormat; 025import java.text.SimpleDateFormat; 026import java.text.ParseException; 027 028/** 029 * HybsDateUtil.java は、共通的に使用される Date,Calender関連メソッドを集約した、staticメソッドのみで構成されるクラスです。 030 * 031 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 032 * 033 * @og.group ユーティリティ 034 * 035 * @version 5.5 036 * @author Kazuhiko Hasegawa 037 * @since JDK7.0, 038 */ 039public final class HybsDateUtil { 040 041 /** システム依存の改行記号をセットします。 */ 042 private static final String CR = System.getProperty("line.separator"); 043 044 /** 各種フォーマットを簡易的に表した文字列 */ 045 private static final Map<String,String> DATE_FORMAT = new HashMap<String,String>(); 046 static { 047 DATE_FORMAT.put( "YMD" ,"yyyyMMdd" ); 048 DATE_FORMAT.put( "Y2MD" ,"yyMMdd" ); 049 DATE_FORMAT.put( "YM" ,"yyyyMM" ); 050 DATE_FORMAT.put( "MD" ,"MMdd" ); // 5.5.5.2 (2012/08/18) 051 DATE_FORMAT.put( "HMS" ,"HHmmss" ); 052 DATE_FORMAT.put( "YMDHMS" ,"yyyyMMddHHmmss" ); 053 DATE_FORMAT.put( "EEE" ,"EEE" ); 054 DATE_FORMAT.put( "YMDF" ,"yyyy/MM/dd" ); 055 DATE_FORMAT.put( "Y2MDF" ,"yy/MM/dd" ); 056 DATE_FORMAT.put( "YMF" ,"yyyy/MM" ); 057 DATE_FORMAT.put( "HMSF" ,"HH:mm:ss" ); 058 DATE_FORMAT.put( "YMDHMSF" ,"yyyy/MM/dd HH:mm:ss" ); 059 DATE_FORMAT.put( "MDF" ,"MM/dd" ); // 5.5.0.2 (2012/03/09) 和暦 060 DATE_FORMAT.put( "MDEF" ,"MM/dd(EEE)" ); // 5.5.0.2 (2012/03/09) 和暦 061 DATE_FORMAT.put( "MD2F" ,"MM月dd日" ); // 5.5.5.2 (2012/08/18) 和暦 062 DATE_FORMAT.put( "GYMDF" ,"GGGGyyyy年MM月dd日" ); // 5.5.0.2 (2012/03/09) 和暦 063 DATE_FORMAT.put( "G2YMDF" ,"Gyyyy/MM/dd" ); // 5.5.0.2 (2012/03/09) 和暦 064 DATE_FORMAT.put( "GYMF" ,"GGGGyyyy年MM月" ); // 5.5.0.2 (2012/03/09) 和暦 065 DATE_FORMAT.put( "GYF" ,"GGGGyyyy" ); // 5.5.0.2 (2012/03/09) 和暦 066 } 067 068 /** 069 * デフォルトコンストラクターをprivateにして、 070 * オブジェクトの生成をさせないようにする。 071 * 072 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 073 * 074 */ 075 private HybsDateUtil() {} 076 077 /** 078 * 現在日付、時刻を指定のフォーマットで文字列に変換して返します。 079 * 出力フォーマットは、"yyyy/MM/dd HH:mm:ss" 固定です。 080 * 081 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 082 * 083 * @return 現在日付、時刻 ( 例 2012/09/05 18:10:24 ) 084 */ 085 public static final String getDate() { 086 DateFormat formatter = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss",Locale.JAPAN ); 087 return formatter.format(new Date()); 088 } 089 090 /** 091 * 現在時刻を指定のフォーマットで文字列に変換して返します。 092 * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。 093 * 変換時のロケーションは、Locale.JAPAN です。 094 * 現在時刻は、new Date() で求めます。 095 * 096 * @param form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss.SSS" ) 097 * 098 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 099 * 100 * @return 現在日付、時刻 101 * @see java.text.SimpleDateFormat 102 */ 103 public static final String getDate( final String form ) { 104 DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN ); 105 return formatter.format( new Date() ); 106 } 107 108 /** 109 * 指定時刻を指定のフォーマットで文字列に変換して返します。 110 * フォーマットの指定方法は、java.text.SimpleDateFormat の指定方法と同一です。 111 * 変換時のロケーションは、Locale.JAPAN です。 112 * 指定時刻は、new Date( time ) で求めます。 113 * 114 * @param time 指定のカレントタイムのロング値 115 * @param form フォーム文字列 ( 例 "yyyy/MM/dd HH:mm:ss.SSS" ) 116 * 117 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 118 * 119 * @return 現在日付、時刻( 例 2001/04/17 15:48:22 ) 120 */ 121 public static final String getDate( final long time,final String form ) { 122 DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN ); 123 return formatter.format( new Date( time ) ); 124 } 125 126 /** 127 * 指定の文字列から、以下の文字を削除した文字列を返します。 128 * '/' , '-' , ' ' , ':' の数字以外の文字を含むフォーマットされた 129 * 日付文字列を、日付データだけに変換する場合に利用することを想定しています。 130 * よって、マイナス記号や、小数点、コンマなども削除されます。 131 * このメソッドでは、日付としての整合性や桁チェックは行いません。 132 * 133 * 引数が、null の場合は、ゼロ文字列に、変換します。 134 * 135 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 136 * @og.rev 5.5.8.3 (2012/11/17) 数字のみ返す仕様だったが、対象以外の文字入力はそのまま返すよう変更 137 * 138 * @param value 任意の文字列(例:2001/04/17 15:48:22) 139 * 140 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 141 */ 142 public static final String parseNumber( final String value ) { 143 if( value == null ) { return ""; } 144 145 StringBuilder buf = new StringBuilder(); 146 for( int i=0; i<value.length(); i++ ) { 147 char ch = value.charAt(i); 148// if( ch >= '0' && ch <= '9' ) { buf.append( ch ); } 149 if( ch == '/' || ch == '-' || ch == ' ' || ch == ':'){} // 5.5.8.3 (2012/11/17) 何もしない 150 else { 151 buf.append( ch ); 152 } 153 } 154 155 return buf.toString(); 156 } 157 158 /** 159 * 指定の文字列から、yyyy-mm-dd hh:mm:ss[.f...] 形式の文字列を作成します。 160 * これは、java.sql.Timestamp オブジェクトを文字列から作成するに当たり、 161 * Timestamp の文字列形式にしなければならないためです。 162 * 桁数は、8桁 または、14桁以外の場合は、変換エラーとします。 163 * 164 * @og.rev 5.5.8.5 (2012/11/27) 新規作成 165 * 166 * @param value 任意の文字列(例:20010417 or 20010417154822) 167 * 168 * @return Timestampの文字列形式(例:2001-04-17 00:00:00 or 2001-04-17 15:48:22) 169 */ 170 public static final String parseTimestamp( final String value ) { 171 if( value == null || ( value.length() != 8 && value.length() != 14 ) ) { 172 String errMsg = "日付文字列に、不正な値が指定されました。8桁 または、14桁で指定してください。" 173 + " value=[" + value + "]" ; 174 throw new RuntimeException( errMsg ); 175 } 176 177 StringBuilder buf = new StringBuilder(); 178 buf.append( value.substring( 0,4 ) ).append( "-" ); 179 buf.append( value.substring( 4,6 ) ).append( "-" ); 180 buf.append( value.substring( 6,8 ) ).append( " " ); 181 if( value.length() == 8 ) { 182 buf.append( "00:00:00" ); 183 } 184 else { 185 buf.append( value.substring( 8,10 ) ).append( ":" ); 186 buf.append( value.substring( 10,12 ) ).append( ":" ); 187 buf.append( value.substring( 12,14 ) ); 188 } 189 190 return buf.toString(); 191 } 192 193 /** 194 * 日付文字列の桁数の整合性を取ります。 195 * これは、内部で、parseNumber(String) 処理により、不要なフォーマット記号を削除します。 196 * ここでは、基本的には、6文字(yyyyMM)、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss) 197 * の日付文字列を作成することを想定していますが、指定の桁数以外は、エラーになります。 198 * 199 * 引数が、null ⇒ 桁数に無関係に、空文字列を返す。 200 * 引数の桁数が一致 ⇒ その値を返す。 201 * 引数の桁数が不一致 ⇒ エラー 202 * ただし、引数の最大長は、14ケタに制限しています。 203 * 204 * このメソッドでは、日付として成立しているかどうか(99999999など)は判定していません。 205 * 206 * @og.rev 5.6.6.0 (2013/07/05) メソッドの内容を移す。 207 * 208 * @param value 任意の日付け文字列 209 * @param size 変換したい桁数 210 * 211 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 212 */ 213 public static final String parseDate( final String value , final int size ) { 214 return parseDate( value , size , size ); // 最小と最大を同じ値にする。 215 } 216 217 /** 218 * 日付文字列の桁数の整合性を取ります。 219 * これは、内部で、parseNumber(String) 処理により、不要なフォーマット記号を削除します。 220 * ここでは、基本的には、6文字(yyyyMM)、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss) 221 * の日付文字列を作成することを想定していますが、それ以外の桁数でも下記のルールに従って 222 * 処理されます。 223 * 224 * 引数が、null ⇒ 桁数に無関係に、空文字列を返す。 225 * 引数の桁数が範囲内 ⇒ 以下の処理を実行する。 226 * 引数の桁数を同じ ⇒ そのまま返す。 227 * 引数の桁数より大きい ⇒ 余をカットして、引数の最大長にそろえる。 228 * 引数の桁数に足りない ⇒ "20000101000000" の文字列の部分文字列を結合させて、引数の最大長にそろえる。 229 * ただし、引数の最大長は、14ケタに制限しています。 230 * 231 * このメソッドでは、日付として成立しているかどうか(99999999など)は判定していません。 232 * 233 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 234 * @og.rev 5.6.1.1 (2013/02/08) 桁数チェック導入。6桁以下だとエラーにする。 235 * @og.rev 5.6.6.0 (2013/07/05) 桁数チェックの最小-最大指定 236 * 237 * @param value 任意の日付け文字列 238 * @param minSize 変換したい桁数の最小値 239 * @param maxSize 変換したい桁数の最大値 240 * 241 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 242 */ 243// public static final String parseDate( final String value , final int size ) { 244 public static final String parseDate( final String value , final int minSize , final int maxSize ) { 245 if( value == null ) { return ""; } 246 247 String rtn = parseNumber( value ); 248 249 // 引数の最大長は、14ケタに制限しています。 250 if( maxSize > 14 ) { 251 String errMsg = "日付登録に許可できる最大桁数は、14ケタです。" 252 + " maxSize=[" + maxSize + "]" ; 253 throw new RuntimeException( errMsg ); 254 } 255 256// int maxSize = ( size > 14 ) ? 14 : size ; // 先に最大サイズを求めておく 257 int len = rtn.length() ; 258 259 if( len == maxSize ) { rtn = value; } 260// else if( len > maxSize ) { rtn = rtn.substring( 0,maxSize ); } 261 // 5.6.1.1 (2013/02/08) 桁数チェック導入。6桁以下だとエラーにする。 262// else if( len < 6 ) { 263 // 5.6.6.0 (2013/07/05) 桁数チェックの最小-最大指定で、範囲外はエラー 264 else if( len < minSize || len > maxSize ) { 265 String errMsg = "日付文字列に、不正な値が指定されました。最小[" 266 + minSize + "] から、最大[" + maxSize + "]の範囲で指定してください。" 267 + " value=[" + value + "]" ; 268 throw new RuntimeException( errMsg ); 269 } 270 else { 271 rtn = rtn + "20000101000000".substring( len,maxSize ) ; // 中間文字列を加える。 272 } 273 274 return rtn ; 275 } 276 277 /** 278 * 日付文字列の厳密な整合性チェックを行います。 279 * ここで指定できるのは、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss)のどちらかの 280 * 数字だけの日付文字列であり、それが、日付として正しいかどうかのチェックを行います。 281 * 正しければ、true を、間違っていれば、false を返します。 282 * ここでは、20120230(2月30日)などの日付や、20120101235960 なども false になります。 283 * 引数が、null および、空文字列の場合も、false を返しますので、避けたい場合は、事前に 284 * 判定しておいてください。 285 * 286 * 内部処理としては、DateFormat で、setLenient( false ) を設定することで、 287 * 日付/時刻解析を厳密に解析するにして、ParseException が発生しないかどうか判定しています。 288 * 289 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 290 * 291 * @param value 数字だけで構成される日付け文字列 292 * 293 * @return true:日付として正しい場合/false:日付として間違っている場合 294 */ 295 public static final boolean isStrict( final String value ) { 296 if( value == null || ( value.length() != 8 && value.length() != 14 ) ) { return false; } 297 298 // 日付の厳密なチェック 299 String form = (value.length() == 8) ? "yyyyMMdd" : "yyyyMMddHHmmss" ; 300 DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN ); 301 formatter.setLenient( false ); // 日付/時刻解析を厳密に行う(false=厳密) 302 303 boolean flag ; 304 try { 305 formatter.parse( value ); 306 flag = true; 307 } 308 catch( ParseException ex ) { 309 flag = false; 310 } 311 312 return flag; 313 } 314 315 /** 316 * 日付関係の情報を簡易的に処理します。 317 * 318 * CC引数の加減算パラメータは、0 です。 319 * 320 * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため、旧メソッドを再現しておきます。 321 * 322 * @param key フォーマットの予約語 323 * @param prmA 基準となる日付(nullの場合は、処理時刻) 324 * @param prmB 処理コマンド 325 * 326 * @return メッセージ情報 327 * @see #getDateFormat( String , String ,String , int ) 328 */ 329 public static final String getDateFormat( final String key ,final String prmA ,final String prmB ) { 330 return getDateFormat( key,prmA,prmB,0 ); 331 } 332 333 /** 334 * 日付関係の情報を簡易的に処理します。 335 * 336 * 第一引数 "XXXX" は、日付処理を行うフォーマットの予約語になっています。 337 * ・YMD :8文字の4-2-2年月日データ(yyyyMMdd)を扱います。 338 * ・Y2MD :6文字の2-2-2年月日データ(yyMMdd)を扱います。 339 * ・YM :6文字の4-2年月データ(yyyyMM)を扱います。 340 * ・HMS :6文字の2-2-2時分秒データ(HHmmss)を扱います。 341 * ・YMDHMS :14文字の4-2-2-2-2-2年月日時分秒データ(yyyyMMddHHmmss)を扱います。 342 * ・EEE :曜日をデフォルトロケールで表示します。 343 * 344 * F付きは、フォーマットされた日付を返します。 345 * ・YMDF :10文字の日付表現(yyyy/MM/dd)を扱います。 346 * ・Y2MDF :8文字の日付表現(yy/MM/dd)を扱います。 347 * ・YMF :7文字の日付表現(yyyy/MM)を扱います。 348 * ・HMSF :8文字の時刻表現(HH:mm:ss)を扱います。 349 * ・YMDHMSF:19文字の日付表現(yyyy/MM/dd HH:mm:ss)を扱います。 350 * ・MDF :5文字の月日表現(MM/dd)を扱います。 351 * ・MDEF :5文字+曜日の月日表現(MM/dd(EEE))を扱います。 352 * ・MD2F :和暦の月日表現(MM月dd日)を扱います。(5.5.5.2 追加) 353 * ・GYMDF :和暦の年月日表現(GGGGyyyy年MM月dd日)を扱います。 354 * ・G2YMDF :和暦の日付表現(Gyyyy/MM/dd)を扱います。 355 * ・GYMF :和暦の年月表現(GGGGyyyy年MM月)を扱います。 356 * ・GYF :和暦の年表現(GGGGyyyy)を扱います。 357 * 358 * なお、上記以外のフォーマットを指定する場合は、XXXX部分に直接記述できます。(5.5.5.2 追加) 359 * ただし、基本的には、自由フォーマットは、エラーチェックがない為、使わないでください。 360 * 361 * 第二引数 AA は、基準となる日付を、yyyyMMdd形式で指定します。nullの場合は、現在時刻を使用します。 362 * 指定できる日付は、yyyyMMdd形式を推奨しますが、'/' , '-' , ' ' , ':' を削除して使います。 363 * 6桁の場合は、yyyyMM + 01 とし、8ケタの場合は、yyyyMMdd とし、14ケタ以上の場合は、前半14文字を 364 * yyyyMMddHHmmss として処理します。それ以外の桁数の場合は、エラーになります。 365 * たとえば、"2012/09/05 16:52:36" のようなフォーマットデータの場合、'/' , '-' , ' ' , ':' を削除して 366 * "20120905165236" に変換後、日付オブジェクトに変換されます。 367 * 368 * 第三引数 BB は、日付についての加減算処理を行うためのコマンドを指定します。 369 * nullの場合は、なにも加減算処理を行いません。 370 * ・SD :当月の最初の日付にセットします。(当月1日)。CC引数は、-N:N月前、0:当月(=SD)、N:N月後、-1:BSD と同じ、1:ASD と同じ 371 * ・ED :当月の最後の日付にセットします。(当月月末)。CC引数は、-N:N月前、0:当月(=ED)、N:N月後、-1:BED と同じ、1:AED と同じ 372 * ・SW :日付処理の週初め(月曜日)にセットします。日付は当日より前に移動します。CC引数は、-N:N週前、0:今週(=SW)、N:N週後 373 * ・EW :日付処理の週末(日曜日)にセットします。日付は当日より後ろに移動します。CC引数は、-N:N週前、0:今週(=EW)、N:N週後 374 * ・H1 〜 HXXX :時を指定の分だけ進めます。H1なら1時間後、H24 なら24時間後(5.5.5.6 (2012/08/31) 追加) 375 * ・D1 〜 DXXX :日を指定の分だけ進めます。D1なら翌日、D200 なら200日後 376 * ・M1 〜 MXXX :月を指定の分だけ進めます。M1なら翌月、M6 なら半年後 377 * ・BSD :(有閑)先月の最初の日付にセットします。(先月1日)(5.5.5.2 追加)。SD -1 と同等 378 * ・BED :(有閑)先月の最後の日付にセットします。(先月月末)(5.5.5.2 追加)。ED -1 と同等 379 * ・ASD :(有閑)翌月の最初の日付にセットします。(翌月1日)(5.5.5.2 追加)。SD 1 と同等 380 * ・AED :(有閑)翌月の最後の日付にセットします。(翌月月末)(5.5.5.2 追加)。ED 1 と同等 381 * 382 * CC 引数は、特別な処理で、BB 引数に対して、加算、減算のための数字を指定できます。(5.7.4.1 (2014/03/14) 追加) 383 * 従来は、BB 引数が、"H" , "D" , "M" の 1文字パラメータの場合のみ利用可能でした。 384 * 385 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 386 * @og.rev 5.6.1.1 (2013/02/08) prmB処理を、calendarCalc メソッドへ移動 387 * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張 388 * 389 * @param key フォーマットの予約語 390 * @param prmA 基準となる日付(nullの場合は、処理時刻) 391 * @param prmB 処理コマンド 392 * @param intC 加減算処理を行うための数字。0 は、BB引数の従来計算のまま。 393 * 394 * @return メッセージ情報 395 * @see #getDateFormat( String , String ,String ) 396 * @see #getCalendar( String ) AA 引数 からカレンダオブジェクトを作成します。 397 * @see #calendarCalc( Calendar , String , int ) BB 引数、CC 引数を元に、日付計算します。 398 */ 399 public static final String getDateFormat( final String key ,final String prmA ,final String prmB ,final int intC ) { 400 401 // prmA が null の場合は、そのまま、現在時刻が使われます。 402 Calendar now = getCalendar( prmA ); 403 404 // 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離。 405// calendarCalc( now,prmB ); 406 calendarCalc( now,prmB,intC ); // 5.7.4.1 (2014/03/14) CC 引数を拡張 407 408 String format = DATE_FORMAT.get( key ); 409 if( format == null ) { 410 // DATE_FORMAT に存在しないフォーマットを指定しても、エラーにしません。 411 // ただし、後処理でフォーマットエラーになる可能性は残ります。 412 format = key; // 5.5.5.2 (2012/08/18) 自由フォーマット指定 413 } 414 415 //5.5.0.2 先頭Gの場合は和暦なのでformatterのLocaleを変更する 416 DateFormat formatter = null; 417 if( key.indexOf('G') == 0 ){ 418 formatter = new SimpleDateFormat( format, new Locale("ja","JP","JP")); 419 } 420 else{ 421 formatter = new SimpleDateFormat( format,Locale.JAPAN ); 422 } 423 424 return formatter.format( now.getTime() ); 425 } 426 427 /** 428 * 開始前設定値、または 終了後設定値の文字列から、オプション文字列を合成します。 429 * 基準となる日付に計算した結果を反映させます。 430 * 431 * CC引数の加減算パラメータは、0 です。 432 * 433 * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため、旧メソッドを再現しておきます。 434 * 435 * @param now 基準となる日付(Calendarオブジェクト) 436 * @param prmB 処理コマンド 437 */ 438 public static final void calendarCalc( final Calendar now,final String prmB ) { 439 calendarCalc( now,prmB,0 ); 440 } 441 442 /** 443 * 開始前設定値、または 終了後設定値の文字列から、オプション文字列を合成します。 444 * 基準となる日付に計算した結果を反映させます。 445 * 446 * prmB は、日付についての加減算処理を行うためのコマンドを指定します。 447 * ・SD :当月の最初の日付にセットします。(当月1日)。CC引数は、-N:N月前、0:当月(=SD)、N:N月後、-1:BSD と同じ、1:ASD と同じ 448 * ・ED :当月の最後の日付にセットします。(当月月末)。CC引数は、-N:N月前、0:当月(=ED)、N:N月後、-1:BED と同じ、1:AED と同じ 449 * ・SW :日付処理の週初め(月曜日)にセットします。日付は当日より前に移動します。CC引数は、-N:N週前、0:今週(=SW)、N:N週後 450 * ・EW :日付処理の週末(日曜日)にセットします。日付は当日より後ろに移動します。CC引数は、-N:N週前、0:今週(=EW)、N:N週後 451 * ・H1 〜 HXXX :時を指定の分だけ進めます。H1なら1時間後、H24 なら24時間後(5.5.5.6 (2012/08/31) 追加) 452 * ・D1 〜 DXXX :日を指定の分だけ進めます。D1なら翌日、D200 なら200日後 453 * ・M1 〜 MXXX :月を指定の分だけ進めます。M1なら翌月、M6 なら半年後 454 * ・BSD :先月の最初の日付にセットします。(先月1日)(5.5.5.2 追加)。SD-1 と同等 455 * ・BED :先月の最後の日付にセットします。(先月月末)(5.5.5.2 追加)。ED-1 と同等 456 * ・ASD :翌月の最初の日付にセットします。(翌月1日)(5.5.5.2 追加)。SD1 と同等 457 * ・AED :翌月の最後の日付にセットします。(翌月月末)(5.5.5.2 追加)。ED1 と同等 458 * ・数字:日を指定の分だけ進めます。D1 〜 DXXX の簡略系 459 * 460 * CC 引数は、特別な処理で、BB 引数に対して、加算、減算のための数字を指定できます。(5.7.4.1 (2014/03/14) 追加) 461 * HXXX,DXXX,MXXX 形式に、CC 引数を付けた場合は、XXX にさらに加算されます。 462 * prmB に、数字を使用した場合、(コマンドでない場合)にも、CC 引数は、加算されます。 463 * 464 * @og.rev 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離。 465 * @og.rev 5.7.4.1 (2014/03/14) H1 〜 HXXX :時を指定の分だけ進める処理が実装されていなかった。 466 * @og.rev 5.7.4.1 (2014/03/14) CC 引数追加 467 * 468 * @param now 基準となる日付(Calendarオブジェクト) 469 * @param prmB 処理コマンド 470 * @param intC 加減算処理を行うための数字。0 は、BB引数の従来計算のまま。 471 */ 472 public static final void calendarCalc( final Calendar now , final String prmB , final int intC ) { 473 474 // 基準は、intC == 0 の場合 475 if( prmB != null ) { 476 if( "SD".equals( prmB ) ) { // (当月1日) 477 if( intC != 0 ) { now.add( Calendar.MONTH,intC ); } // 5.7.4.1 (2014/03/14) CC 引数追加 478 now.set( Calendar.DATE,1 ); 479 } 480 else if( "ED".equals( prmB ) ) { // (当月月末) 481 if( intC != 0 ) { now.add( Calendar.MONTH,intC ); } // 5.7.4.1 (2014/03/14) CC 引数追加 482 now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 483 } 484 else if( "BSD".equals( prmB ) ) { // (先月1日) 485 // 5.7.4.1 (2014/03/14) CC 引数追加 486 now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,1 ); 487// now.roll( Calendar.MONTH,false ); now.set( Calendar.DATE,1 ); 488 } 489 else if( "BED".equals( prmB ) ) { // (先月月末) 490 // 5.7.4.1 (2014/03/14) CC 引数追加 491 now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 492// now.roll( Calendar.MONTH,false ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 493 } 494 else if( "ASD".equals( prmB ) ) { // (翌月1日) 495 // 5.7.4.1 (2014/03/14) CC 引数追加 496 now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,1 ); 497// now.roll( Calendar.MONTH,true ); now.set( Calendar.DATE,1 ); 498 } 499 else if( "AED".equals( prmB ) ) { // (翌月月末) 500 // 5.7.4.1 (2014/03/14) CC 引数追加 501 now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 502// now.roll( Calendar.MONTH,true ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 503 } 504 else if( "SW".equals( prmB ) ) { // 週初め(月曜日)セット 505 // 5.7.4.1 (2014/03/14) CC 引数追加 506 if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); } // まず、基準の日付を週単位で加減算する。 507 508 // 日付型文字列入力データの開始日を月曜日にセットします。 509 // SUNDAY=1 , MONDAY=2 になります。月曜日との差だけ、前に戻します。 510 // 指定日が日曜日の場合は、月曜日まで戻します。 511 512 int shu = now.get( Calendar.DAY_OF_WEEK ) - Calendar.MONDAY ; 513 514 if( shu > 0 ) { now.add( Calendar.DATE, -shu ); } 515 else if( shu < 0 ) { now.add( Calendar.DATE, -6 ); } 516 } 517 else if( "EW".equals( prmB ) ) { // 週末(日曜日)にセット 518 // 5.7.4.1 (2014/03/14) CC 引数追加 519 if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); } // まず、基準の日付を週単位で加減算する。 520 521 // 日付型文字列入力データの終了日を日曜日にセットします。 522 // SUNDAY=1 , MONDAY=2 になります。日曜日になるように、先に進めます。 523 int shu = now.get( Calendar.DAY_OF_WEEK ) ; 524 if( shu != Calendar.SUNDAY ) { now.add( Calendar.DATE, 8-shu ); } 525 } 526 // 5.7.4.1 (2014/03/14) H1 〜 HXXX :時を指定の分だけ進める処理が実装されていなかった。 527// else if( prmB.startsWith( "H" ) && prmB.length() > 1 ) { 528 else if( prmB.startsWith( "H" ) ) { 529// int hour = Integer.parseInt( prmB.substring( 1 ) ); 530 int hour = intC ; 531 if( prmB.length() > 1 ) { hour += Integer.parseInt( prmB.substring( 1 ) ); } 532 now.add( Calendar.HOUR_OF_DAY , hour ); 533 } 534// else if( prmB.startsWith( "D" ) && prmB.length() > 1 ) { 535 else if( prmB.startsWith( "D" ) ) { 536// int day = Integer.parseInt( prmB.substring( 1 ) ); 537 int day = intC ; 538 if( prmB.length() > 1 ) { day += Integer.parseInt( prmB.substring( 1 ) ); } 539 now.add( Calendar.DATE, day ); 540 } 541// else if( prmB.startsWith( "M" ) && prmB.length() > 1 ) { 542 else if( prmB.startsWith( "M" ) ) { 543// int month = Integer.parseInt( prmB.substring( 1 ) ); 544 int month = intC ; 545 if( prmB.length() > 1 ) { month += Integer.parseInt( prmB.substring( 1 ) ); } 546 now.add( Calendar.MONTH , month ); 547 } 548 else { 549 // 上記のパターン以外は、数字(加減算する日数)なので、変換できなければ、フォーマットエラー 550 try { 551// int day = Integer.parseInt( prmB ); 552 int day = Integer.parseInt( prmB ) + intC ; // 5.7.4.1 (2014/03/14) CC 引数追加 553 now.add( Calendar.DATE, day ); 554 } 555 catch( NumberFormatException ex ) { 556 String errMsg = "日付変数パラメータに、不正な値が指定されました。以下の中から指定しなおしてください。" 557 + "指定可能:[SD,ED,BSD,BED,ASD,AED,SW,EW,H1〜HXXX,D1〜DXXX,M1〜MXXX]" 558 + " prmB=[" + prmB + "]" ; 559 throw new RuntimeException( errMsg,ex ); 560 } 561 } 562 } 563 } 564 565 /** 566 * 指定の引数の日付け文字列より、カレンダオブジェクトを作成します。 567 * 引数は、数字以外の文字を削除した状態に変換後、処理に回します。 568 * 不要な文字を削除した状態で、8文字以上になるように指定してください。 569 * 例外的に、6文字の場合は、yyyyMM01 とみなして、"01" 文字列を付与します。 570 * 引数に null を指定すると、現在時刻のカレンダを返します。 571 * それ以外のデータで、8ケタ以下の場合は、RuntimeException が発生します。 572 * 8ケタ以上14ケタ未満の場合は、8ケタ分を、年月日に分離したカレンダ 573 * オブジェクトを作成します。14ケタ以上で初めて、時分秒を含むカレンダ 574 * を作成します。 575 * 576 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 577 * @og.rev 5.5.8.2 (2012/11/09) value の判定に、null と ゼロ文字列を判定する。 578 * 579 * @param value 日付け文字列 580 * 581 * @return カレンダオブジェクト(引数がnullの場合は、現在時刻) 582 */ 583 public static final Calendar getCalendar( final String value ) { 584 Calendar cal = Calendar.getInstance(); 585 586// if( value == null ) { return cal; } 587 if( value == null || value.isEmpty() ) { return cal; } // 5.5.8.2 (2012/11/09) null と ゼロ文字列を判定する。 588 589 // 日付表記に不要な文字を削除します。 590 String dateStr = parseNumber( value ) ; 591 592 if( dateStr.length() == 6 ) { dateStr = dateStr + "01"; } // yyyyMM01 形式に無理やり合わせる。 593 else if( dateStr.length() < 8 ) { 594 String errMsg = "日付指定パラメータに、不正な値が指定されました。value=[" + value + "]" ; 595 throw new RuntimeException( errMsg ); 596 } 597 598 cal.clear(); // 日付文字列が存在するので、カレンダをリセット 599 600 int year = Integer.parseInt( dateStr.substring( 0,4 ) ); 601 int month = Integer.parseInt( dateStr.substring( 4,6 ) ) - 1; 602 int date = Integer.parseInt( dateStr.substring( 6,8 ) ); 603 604 int hour=0, minute=0, second=0; 605 if( dateStr.length() >= 14 ) { 606 hour = Integer.parseInt( dateStr.substring( 8,10 ) ); 607 minute = Integer.parseInt( dateStr.substring( 10,12 ) ); 608 second = Integer.parseInt( dateStr.substring( 12,14 ) ); 609 } 610 611 cal.set( year,month,date,hour,minute,second ); 612 613 return cal; 614 } 615 616 /** 617 * 指定の引数の日付け文字列(yyyyMMdd)より、日付を加算して返します。 618 * マイナスを与えると、減算します。 619 * 日付以上の精度の文字列を渡しても、日付のみの計算となります。 620 * 結果は、引数の日付フォーマットとは全く別で、yyyyMMdd の8文字形式になります。 621 * 引数に null を渡すと、実行時の日付をベースとして処理します。 622 * 623 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 624 * 625 * @param baseDate 日付け文字列(yyyyMMdd) 626 * @param plus 加算する日数(過去にするにはマイナス値を指定する) 627 * 628 * @return 結果の日付(yyyyMMdd) 629 */ 630 public static final String getDatePlus( final String baseDate,final int plus ) { 631 Calendar cal = getCalendar( baseDate ); 632 cal.add( Calendar.DATE,plus ); 633 634 return getDate( cal.getTimeInMillis() , "yyyyMMdd" ); 635 } 636 637 /** 638 * 現在の月に、指定の月数をプラスした日付文字列を返します。 639 * 日付文字列のフォーマットは、"yyyyMM" です。 640 * 指定する月数にマイナスを指定すると、減算できます。 641 * 642 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 643 * 644 * @param baseDate 日付け文字列(yyyyMM) 645 * @param plus 加算する月数(過去にするにはマイナス値を指定する) 646 * 647 * @return 指定の月数をプラスした日付文字列(yyyyMM) 648 */ 649 public static final String getMonthPlus( final String baseDate,final int plus ) { 650 Calendar cal = getCalendar( baseDate ); 651 cal.set( Calendar.DATE, 1 ); // 当月の 1 日に設定 652 cal.add( Calendar.MONTH , plus ); 653 654 return getDate( cal.getTimeInMillis() , "yyyyMM" ); 655 } 656 657 /** 658 * 指定の引数の日付け文字列(yyyyMMdd、yyyyMMddHHmmss)に、日付を加算して返します。 659 * マイナスを与えると、減算します。 660 * 661 * 指定する日付には、単位を付与することが可能です。 662 * 単位は、yyyyMMddHHmmss 形式の1文字を指定します。大文字、小文字も識別します。 663 * plus="5M" とすれば、5か月、plus="5d" とすれば、5日 追加します。 664 * plus に単位を付けない場合は、tani に指定の単位を使います。 665 * plus そのものが、null か、isEmpty の場合は、加算は、1 になります。 666 * 667 * baseDate 文字列を日付文字列に変換後、Calendar で計算し、結果を、format 形式に変換します。 668 * 引数に null を渡すと、実行時の日付をベースとして処理します。 669 * 670 * @og.rev 5.6.1.0 (2013/02/01) 新規作成 671 * 672 * @param baseDate 日付け文字列(yyyyMMdd、yyyyMMddHHmmss 形式の日付文字列) 673 * @param plus 加算する日数(日付単位を含む。単位は、y,M,d,H,m,s の文字で、大文字小文字の区別があります) 674 * @param defTani 日付単位が未指定の場合の初期単位('y','M','d','H','m','s' のどれか) 675 * @param format 返す日付文字列のフォーマット(yyyyMMdd、yyyyMMddHHmmss) 676 * 677 * @return 結果の日付(yyyyMMdd) 678 * @throws NumberFormatException 加算する日数の単位が('y','M','d','H','m','s')以外の場合。 679 */ 680 public static final String getDatePlus( final String baseDate,final String plus,final int defTani,final String format ) { 681 682 int addSu = 1; // 初期値(plus が null や Empty の場合は、+1となる) 683 int tani = defTani; 684 685 if( plus != null && !plus.isEmpty() ) { 686 boolean flag = true; // 日付単位を持っているかどうか。持っている場合は、true 687 char ch = plus.charAt( plus.length()-1 ); // 最後の一文字を取得(単位か、数字本体) 688 switch( ch ) { 689 case 'y' : tani = Calendar.YEAR; break ; 690 case 'M' : tani = Calendar.MONTH; break ; 691 case 'd' : tani = Calendar.DATE; break ; 692 case 'H' : tani = Calendar.HOUR_OF_DAY; break ; 693 case 'm' : tani = Calendar.MINUTE; break ; 694 case 's' : tani = Calendar.SECOND; break ; 695 default : flag = false; break ; // 日付単位を持っていない。 696 } 697 if( flag ) { 698 addSu = Integer.parseInt( plus.substring( 0,plus.length()-1 ) ); // 日付単位 あり 699 } 700 else { 701 addSu = Integer.parseInt( plus ) ; // 日付単位 なし 702 } 703 } 704 705 Calendar cal = getCalendar( baseDate ); 706 cal.add( tani,addSu ); 707 708 return getDate( cal.getTimeInMillis() , format ); 709 } 710}