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 org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 019import java.util.Calendar; 020import java.util.Locale; 021import java.util.Map; 022import java.util.HashMap; 023import java.text.DateFormat; 024import java.text.SimpleDateFormat; 025import java.text.ParseException; 026 027import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29) 028import static org.opengion.fukurou.system.HybsConst.BUFFER_SMALL; // 6.1.0.0 (2014/12/26) refactoring 029 030/** 031 * HybsDateUtil.java は、共通的に使用される Date,Calender関連メソッドを集約した、staticメソッドのみで構成されるクラスです。 032 * 033 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 034 * 035 * @og.group ユーティリティ 036 * 037 * @version 5.5 038 * @author Kazuhiko Hasegawa 039 * @since JDK7.0, 040 */ 041public final class HybsDateUtil { 042 043 /** 各種フォーマットを簡易的に表した文字列 */ 044 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 045 private static final Map<String,String> DATE_FORMAT = new HashMap<>(); 046 static { 047 DATE_FORMAT.put( "Y4" ,"yyyy" ); // 6.9.2.1 (2018/03/12) 048 DATE_FORMAT.put( "YMD" ,"yyyyMMdd" ); 049 DATE_FORMAT.put( "Y2MD" ,"yyMMdd" ); 050 DATE_FORMAT.put( "YM" ,"yyyyMM" ); 051 DATE_FORMAT.put( "MD" ,"MMdd" ); // 5.5.5.2 (2012/08/18) 052 DATE_FORMAT.put( "HMS" ,"HHmmss" ); 053 DATE_FORMAT.put( "HM" ,"HHmm" ); // 6.7.4.1 (2017/02/17) 054 DATE_FORMAT.put( "YMDHMS" ,"yyyyMMddHHmmss" ); 055 DATE_FORMAT.put( "EEE" ,"EEE" ); 056 DATE_FORMAT.put( "YMDF" ,"yyyy/MM/dd" ); 057 DATE_FORMAT.put( "Y2MDF" ,"yy/MM/dd" ); 058 DATE_FORMAT.put( "YMF" ,"yyyy/MM" ); 059 DATE_FORMAT.put( "HMSF" ,"HH:mm:ss" ); 060 DATE_FORMAT.put( "HMF" ,"HH:mm" ); // 6.7.4.1 (2017/02/17) 061 DATE_FORMAT.put( "YMDHMSF" ,"yyyy/MM/dd HH:mm:ss" ); 062 DATE_FORMAT.put( "MDF" ,"MM/dd" ); // 5.5.0.2 (2012/03/09) 和暦 063 DATE_FORMAT.put( "MDEF" ,"MM/dd(EEE)" ); // 5.5.0.2 (2012/03/09) 和暦 064 DATE_FORMAT.put( "MD2F" ,"MM月dd日" ); // 5.5.5.2 (2012/08/18) 和暦 065 DATE_FORMAT.put( "GYMDF" ,"GGGGyyyy年MM月dd日" ); // 5.5.0.2 (2012/03/09) 和暦 066 DATE_FORMAT.put( "G2YMDF" ,"Gyyyy/MM/dd" ); // 5.5.0.2 (2012/03/09) 和暦 067 DATE_FORMAT.put( "GYMF" ,"GGGGyyyy年MM月" ); // 5.5.0.2 (2012/03/09) 和暦 068 DATE_FORMAT.put( "GYF" ,"GGGGyyyy" ); // 5.5.0.2 (2012/03/09) 和暦 069 } 070 071 /** 072 * デフォルトコンストラクターをprivateにして、 073 * オブジェクトの生成をさせないようにする。 074 * 075 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 076 * 077 */ 078 private HybsDateUtil() {} 079 080 /** 081 * 指定の文字列から、以下の文字を削除した文字列を返します。 082 * '/' , '-' , ' ' , ':' の数字以外の文字を含むフォーマットされた 083 * 日付文字列を、日付データだけに変換する場合に利用することを想定しています。 084 * よって、マイナス記号や、小数点、コンマなども削除されます。 085 * このメソッドでは、日付としての整合性や桁チェックは行いませんが、 086 * 桁数は、6桁、8桁、14桁のどれかに、合わせます。 087 * 「yyyy/MM/dd HH:mm:ss」 形式を基準としますが、「yyyy/M」「yyyy/M/d」「yy/M/d」「M/d」 088 * 「HH:mm:ss」「H:m」形式にも、対応します。 089 * "/" が、"-" に変更されているケースも対応可能ですが、月/年 形式や、英語、日本語の 090 * 月表示には未対応です。 091 * 092 * 引数が、null の場合は、ゼロ文字列に、変換します。 093 * 094 * ※ 6.0.2.5 (2014/10/31) 桁数チェックだけは行います。 095 * 桁数は、6桁、8桁、14桁のどれかに、合わせます。 096 * 097 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 098 * @og.rev 5.5.8.3 (2012/11/17) 数字のみ返す仕様だったが、対象以外の文字入力はそのまま返すよう変更 099 * @og.rev 6.0.2.5 (2014/10/31) 簡易的な桁数チェックだけは行います。 100 * @og.rev 6.2.3.0 (2015/05/01) 内部処理を大幅に変更します。 101 * 102 * @param value 任意の文字列(例:2001/04/17 15:48:22) 103 * 104 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 105 * @og.rtnNotNull 106 */ 107 public static String parseNumber( final String value ) { 108 if( value == null || value.isEmpty() ) { return ""; } 109 110 // 年 や、年月日 が省略された場合は、実行日をセットする。 111 final String today = DateSet.getDate( "yyyyMMdd" ); 112 113 String val = value.trim(); 114 val = val.replaceAll( "-" , "/" ); // yyyy-MM-dd 形式を、yyyy/MM/dd 形式にする。 115 116 final int ad = val.indexOf( ' ' ) ; 117 String ymd = val ; 118 String hms = null ; 119 120 if( ad > 0 ) { // スペースがあれば、年月日 と 時分秒 に別れる。 121 ymd = val.substring( 0,ad ); 122 hms = val.substring( ad+1 ); 123 } 124 else if( val.indexOf( ':' ) > 0 ) { 125 ymd = today; // 年月日 は今日になる。 126 hms = val; 127 } 128 129 final StringBuilder buf = new StringBuilder( BUFFER_SMALL ); 130 131 if( ymd != null ) { 132 final String[] ymdSp = ymd.split( "/" ); 133 switch( ymdSp.length ) { 134 case 1 : buf.append( ymdSp[0] ); break; // "/" が存在しない。 135 case 2 : if( ymdSp[0].length() < 4 ) { // MM/dd のケース。yy/MM は想定外 136 buf.append( today.substring( 0,4 ) ); // yyyy の年を設定 137 } 138 buf.append( addZero( ymdSp[0] ) ).append( addZero( ymdSp[1] ) ); break; 139 default: if( ymdSp[0].length() == 2 ) { // yy/MM/dd のケースを想定 140 buf.append( today.substring( 0,2 ) ); // yy の年の先頭2桁を設定 141 } 142 buf.append( ymdSp[0] ) 143 .append( addZero( ymdSp[1] ) ) 144 .append( addZero( ymdSp[2] ) ); break; 145 } 146 } 147 if( hms != null ) { 148 final String[] hmsSp = hms.split( ":" ); // HH:mm:ss 149 switch( hmsSp.length ) { 150 case 1 : buf.append( hmsSp[0] ); break; // ":" が存在しない。 151 case 2 : buf.append( addZero( hmsSp[0] ) ) // HH:mm のケース。mm:ss は想定外 152 .append( addZero( hmsSp[1] ) ) 153 .append( "00" ); break; 154 default: buf.append( addZero( hmsSp[0] ) ) // HH:mm:ss のケースを想定 155 .append( addZero( hmsSp[1] ) ) 156 .append( addZero( hmsSp[2] ) ); break; 157 } 158 } 159 160 return buf.toString(); 161 } 162 163 /** 164 * 指定の文字列が、一桁の場合、先頭に 0 を追加します。 165 * 166 * これは、3/4 の様な日付を、0304 にする場合のサポートメソッドです。 167 * 168 * @og.rev 6.2.3.0 (2015/05/01) 新規追加 169 * 170 * @param val 任意の文字列 171 * 172 * @return 一桁の場合、先頭に 0 を追加 173 */ 174 private static String addZero( final String val ) { 175 return val.length() == 1 ? "0" + val : val ; 176 } 177 178 /** 179 * 指定の文字列から、yyyy-mm-dd hh:mm:ss 形式の文字列を作成します。 180 * 181 * これは、java.sql.Timestamp オブジェクトを文字列から作成するに当たり、 182 * Timestamp の文字列形式にしなければならないためです。 183 * 桁数は、8桁 または、14桁以外の場合は、変換エラーとします。 184 * 185 * @og.rev 5.5.8.5 (2012/11/27) 新規作成 186 * 187 * @param value 任意の文字列(例:20010417 or 20010417154822) 188 * 189 * @return Timestampの文字列形式(例:2001-04-17 00:00:00 or 2001-04-17 15:48:22) 190 */ 191 public static String parseTimestamp( final String value ) { 192 if( value == null || value.length() != 8 && value.length() != 14 ) { // 6.9.7.0 (2018/05/14) PMD 193 final String errMsg = "日付文字列は、8桁 または、14桁で指定してください。" 194 + " value=[" + value + "]" ; 195 throw new OgRuntimeException( errMsg ); 196 } 197 198 // 6.0.2.5 (2014/10/31) char を append する。 199 final StringBuilder buf = new StringBuilder( BUFFER_SMALL ) 200 .append( value.substring( 0,4 ) ).append( '-' ) 201 .append( value.substring( 4,6 ) ).append( '-' ) 202 .append( value.substring( 6,8 ) ).append( ' ' ); 203 if( value.length() == 8 ) { 204 buf.append( "00:00:00" ); 205 } 206 else { 207 buf.append( value.substring( 8,10 ) ).append( ':' ) 208 .append( value.substring( 10,12 ) ).append( ':' ) 209 .append( value.substring( 12,14 ) ); 210 } 211 212 return buf.toString(); 213 } 214 215 /** 216 * 日付文字列の桁数の整合性を取ります。 217 * これは、内部で、parseNumber(String) 処理により、不要なフォーマット記号を削除します。 218 * ここでは、基本的には、6文字(yyyyMM)、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss) 219 * の日付文字列を作成することを想定していますが、指定の桁数以外は、エラーになります。 220 * 221 * 引数が、null ⇒ 桁数に無関係に、空文字列を返す。 222 * 引数の桁数が一致 ⇒ その値を返す。 223 * 引数の桁数が不一致 ⇒ エラー 224 * ただし、引数の最大長は、14ケタに制限しています。 225 * 226 * このメソッドでは、日付として成立しているかどうか(99999999など)は判定していません。 227 * 228 * @og.rev 5.6.6.0 (2013/07/05) メソッドの内容を移す。 229 * 230 * @param value 任意の日付け文字列 231 * @param size 変換したい桁数 232 * 233 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 234 * @og.rtnNotNull 235 */ 236 public static String parseDate( final String value , final int size ) { 237 return parseDate( value , size , size ); // 最小と最大を同じ値にする。 238 } 239 240 /** 241 * 日付文字列の桁数の整合性を取ります。 242 * これは、内部で、parseNumber(String) 処理により、不要なフォーマット記号を削除します。 243 * ここでは、基本的には、6文字(yyyyMM)、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss) 244 * の日付文字列を作成することを想定していますが、それ以外の桁数でも下記のルールに従って 245 * 処理されます。 246 * 247 * 引数が、null ⇒ 桁数に無関係に、空文字列を返す。 248 * 引数の桁数が範囲内 ⇒ 以下の処理を実行する。 249 * 引数の桁数を同じ ⇒ そのまま返す。 250 * 引数の桁数より大きい ⇒ 余をカットして、引数の最大長にそろえる。 251 * 引数の桁数に足りない ⇒ "20000101000000" の文字列の部分文字列を結合させて、引数の最大長にそろえる。 252 * ただし、引数の最大長は、14ケタに制限しています。 253 * 254 * このメソッドでは、日付として成立しているかどうか(99999999など)は判定していません。 255 * 256 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 257 * @og.rev 5.6.1.1 (2013/02/08) 桁数チェック導入。6桁以下だとエラーにする。 258 * @og.rev 5.6.6.0 (2013/07/05) 桁数チェックの最小-最大指定 259 * @og.rev 6.2.3.0 (2015/05/01) len == maxSize のとき、パース文字列ではなく、元の値を返していた。 260 * 261 * @param value 任意の日付け文字列 262 * @param minSize 変換したい桁数の最小値 263 * @param maxSize 変換したい桁数の最大値 264 * 265 * @return 数字だけで構成される文字列(例:20010417154822)(nullはゼロ文字列を返します) 266 * @og.rtnNotNull 267 */ 268 public static String parseDate( final String value , final int minSize , final int maxSize ) { 269 if( value == null ) { return ""; } 270 271 // 引数の最大長は、14ケタに制限しています。 272 if( maxSize > 14 ) { 273 final String errMsg = "日付登録に許可できる最大桁数は、14ケタです。" 274 + " maxSize=[" + maxSize + "]" ; 275 throw new OgRuntimeException( errMsg ); 276 } 277 278 final String rtn = parseNumber( value ); 279 final int len = rtn.length() ; 280 281 if( len < minSize || len > maxSize ) { 282 final String errMsg = "日付文字列は、最小[" 283 + minSize + "] から、最大[" + maxSize + "]の範囲で指定してください。" 284 + " value=[" + value + "]" ; 285 throw new OgRuntimeException( errMsg ); 286 } 287 288 return rtn ; 289 } 290 291 /** 292 * 日付文字列の厳密な整合性チェックを行います。 293 * ここで指定できるのは、8文字(yyyyMMdd)、14文字(yyyyMMddHHmmss)のどちらかの 294 * 数字だけの日付文字列であり、それが、日付として正しいかどうかのチェックを行います。 295 * 正しければ、true を、間違っていれば、false を返します。 296 * ここでは、20120230(2月30日)などの日付や、20120101235960 なども false になります。 297 * 引数が、null および、空文字列の場合も、false を返しますので、避けたい場合は、事前に 298 * 判定しておいてください。 299 * 300 * 内部処理としては、DateFormat で、setLenient( false ) を設定することで、 301 * 日付/時刻解析を厳密に解析するにして、ParseException が発生しないかどうか判定しています。 302 * 303 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 304 * 305 * @param value 数字だけで構成される日付け文字列 306 * 307 * @return true:日付として正しい場合/false:日付として間違っている場合 308 */ 309 public static boolean isStrict( final String value ) { 310 if( value == null || value.length() != 8 && value.length() != 14 ) { return false; } // 6.9.7.0 (2018/05/14) PMD Useless parentheses. 311 312 // 日付の厳密なチェック 313 final String form = (value.length() == 8) ? "yyyyMMdd" : "yyyyMMddHHmmss" ; 314 final DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN ); 315 formatter.setLenient( false ); // 日付/時刻解析を厳密に行う(false=厳密) 316 317 boolean flag ; 318 try { 319 formatter.parse( value ); 320 flag = true; 321 } 322 catch( final ParseException ex ) { 323 flag = false; 324 } 325 326 return flag; 327 } 328 329 /** 330 * 日付関係の情報を簡易的に処理します。 331 * 332 * 引数に与えるのは、{@DATE.XXXX} の XXXX 文字列になります。 333 * この "XXXX" 文字列は、"key prmA prmB prmC" 形式を取ることができます。 334 * 各文字列をスペースで分割して、先頭から変数に割り当てます。 335 * また、prmA の日付文字判定と、数値変換と、prmC の数値変換も行います。 336 * ただし、リクエスト変数の @ 文字列変換は、出来ません。 337 * 338 * @og.rev 6.9.2.1 (2018/03/12) 新規追加 339 * 340 * @param value 日付引数のパラメータ 341 * 342 * @return メッセージ情報 343 * @og.rtnNotNull 344 * @see #getDateFormat( String , String ,String , int ) 345 */ 346 public static String getDateFormat( final String value ) { 347 // {@DATE.XXXX AA BB CC} を分割 348 final String[] vals = StringUtil.csv2Array( value,' ' ); // ダブルクオート内は保持される。 349 350 final String key = vals[0] ; 351 352 String prmA = vals.length >= 2 ? vals[1] : null ; 353 String prmB = vals.length >= 3 ? vals[2] : null ; 354 String prmC = vals.length >= 4 ? vals[vals.length-1] : null ; // 互換性。最後の値が、CC引数 355 356 // AA 引数のコマンド判定方法(先頭が数字以外) 357 if( StringUtil.isNotNull( prmA ) ) { 358 final char chA = prmA.charAt(0); 359 if( chA < '0' || chA > '9' ) { // 先頭が、数字以外の場合は、コマンドなので、一つずつずらす。 360 prmC = prmB; 361 prmB = prmA; 362 prmA = null; 363 } 364 } 365 366 // CC 引数を、"H" , "D" , "M" 以外でも使用できるように拡張します。 367 int intC = 0; 368 if( StringUtil.isNotNull( prmC ) ) { 369 try { 370 intC = Integer.parseInt( prmC ); 371 } 372 catch( final NumberFormatException ex ) { 373 final String errMsg = "CC引数が数字ではありません。value=[" + value + "]" 374 + ex.getMessage() ; 375 System.err.println( errMsg ); 376 } 377 } 378 379 // prmA が null か、isEmpty() の場合は、現在時刻が使用される。 380 return getDateFormat( key,prmA,prmB,intC ); 381 } 382 383 /** 384 * 日付関係の情報を簡易的に処理します。 385 * 386 * 処理コマンドと、CC引数の加減算パラメータを使用しないバージョンです。 387 * 388 * @og.rev 6.9.2.1 (2018/03/12) メソッドの引数を簡素化 389 * 390 * @param key フォーマットの予約語 391 * @param prmA 基準となる日付(nullの場合は、処理時刻) 392 * 393 * @return メッセージ情報 394 * @og.rtnNotNull 395 * @see #getDateFormat( String , String ,String , int ) 396 */ 397 public static String getDateFormat( final String key , final String prmA ) { 398 return getDateFormat( key,prmA,null,0 ); 399 } 400 401// /** 402// * 日付関係の情報を簡易的に処理します。 403// * 404// * CC引数の加減算パラメータは、0 です。 405// * 406// * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため、旧メソッドを再現しておきます。 407// * @og.rev 6.9.2.1 (2018/03/12) 廃止 408// * 409// * @param key フォーマットの予約語 410// * @param prmA 基準となる日付(nullの場合は、処理時刻) 411// * @param prmB 処理コマンド 412// * 413// * @return メッセージ情報 414// * @og.rtnNotNull 415// * @see #getDateFormat( String , String ,String , int ) 416// */ 417// public static String getDateFormat( final String key ,final String prmA ,final String prmB ) { 418// return getDateFormat( key,prmA,prmB,0 ); 419// } 420 421 /** 422 * 日付関係の情報を簡易的に処理します。 423 * 424 * 第一引数(key) "XXXX" は、日付処理を行うフォーマットの予約語になっています。 425 * ・Y4 :4文字の年データ(yyyy)を扱います。 426 * ・YMD :8文字の4-2-2年月日データ(yyyyMMdd)を扱います。 427 * ・Y2MD :6文字の2-2-2年月日データ(yyMMdd)を扱います。 428 * ・YM :6文字の4-2年月データ(yyyyMM)を扱います。 429 * ・HMS :6文字の2-2-2時分秒データ(HHmmss)を扱います。 430 * ・HM :4文字の2-2時分データ(HHmm)を扱います。6.7.4.1 (2017/02/17) 431 * ・YMDHMS :14文字の4-2-2-2-2-2年月日時分秒データ(yyyyMMddHHmmss)を扱います。 432 * ・EEE :曜日をデフォルトロケールで表示します。 433 * 434 * F付きは、フォーマットされた日付を返します。 435 * ・YMDF :10文字の日付表現(yyyy/MM/dd)を扱います。 436 * ・Y2MDF :8文字の日付表現(yy/MM/dd)を扱います。 437 * ・YMF :7文字の日付表現(yyyy/MM)を扱います。 438 * ・HMSF :8文字の時刻表現(HH:mm:ss)を扱います。 439 * ・HMF :5文字の時刻表現(HH:mm)を扱います。6.7.4.1 (2017/02/17) 440 * ・YMDHMSF:19文字の日付表現(yyyy/MM/dd HH:mm:ss)を扱います。 441 * ・MDF :5文字の月日表現(MM/dd)を扱います。 442 * ・MDEF :5文字+曜日の月日表現(MM/dd(EEE))を扱います。 443 * ・MD2F :和暦の月日表現(MM月dd日)を扱います。(5.5.5.2 追加) 444 * ・GYMDF :和暦の年月日表現(GGGGyyyy年MM月dd日)を扱います。 445 * ・G2YMDF :和暦の日付表現(Gyyyy/MM/dd)を扱います。 446 * ・GYMF :和暦の年月表現(GGGGyyyy年MM月)を扱います。 447 * ・GYF :和暦の年表現(GGGGyyyy)を扱います。 448 * 449 * なお、上記以外のフォーマットを指定する場合は、XXXX部分に直接記述できます。(5.5.5.2 追加) 450 * ただし、基本的には、自由フォーマットは、エラーチェックがない為、使わないでください。 451 * 452 * 第二引数(prmA) AA は、基準となる日付を、yyyyMMdd形式で指定します。nullの場合は、現在時刻を使用します。 453 * 指定できる日付は、yyyyMMdd形式を推奨しますが、'/' , '-' , ' ' , ':' を削除して使います。 454 * 6桁の場合は、yyyyMM + 01 とし、8ケタの場合は、yyyyMMdd とし、14ケタ以上の場合は、前半14文字を 455 * yyyyMMddHHmmss として処理します。それ以外の桁数の場合は、エラーになります。 456 * たとえば、"2012/09/05 16:52:36" のようなフォーマットデータの場合、'/' , '-' , ' ' , ':' を削除して 457 * "20120905165236" に変換後、日付オブジェクトに変換されます。 458 * 459 * 第三引数(prmB) BB は、日付についての加減算処理を行うためのコマンドを指定します。 460 * nullの場合は、なにも加減算処理を行いません。 461 * ・SY :当年の最初の日付にセットします。(当年1月1日)。CC引数は、-N:N年前、0:当年(=SY)、N:N年後 6.9.2.1 (2018/03/12) 462 * ・SD :当月の最初の日付にセットします。(当月1日)。CC引数は、-N:N月前、0:当月(=SD)、N:N月後、-1:BSD と同じ、1:ASD と同じ 463 * ・SW :日付処理の週初め(月曜日)にセットします。日付は当日より前に移動します。CC引数は、-N:N週前、0:今週(=SW)、N:N週後 464 * ・SH :指定の最初の時にセットします。(分秒を0000にする)。CC引数は、時の倍数(4と指定すれば、4時間単位に前に戻る) 6.7.4.1 (2017/02/17) 465 * ・SM :指定の最初の分にセットします。(秒を00にする)。CC引数は、分の倍数(15と指定すれば、15分単位に前に戻る) 6.7.4.1 (2017/02/17) 466 * ・SS :指定の最初の秒にセットします。CC引数は、秒の倍数(15と指定すれば、15秒単位に前に戻る) 6.7.4.1 (2017/02/17) 467 * ・EY :当年の最後の日付にセットします。(当年年末)。CC引数は、-N:N年前、0:当年(=EY)、N:N年後 6.9.2.1 (2018/03/12) 468 * ・ED :当月の最後の日付にセットします。(当月月末)。CC引数は、-N:N月前、0:当月(=ED)、N:N月後、-1:BED と同じ、1:AED と同じ 469 * ・EW :日付処理の週末(日曜日)にセットします。日付は当日より後ろに移動します。CC引数は、-N:N週前、0:今週(=EW)、N:N週後 470 * ・EH :指定の次の時にセットします。(分秒を0000にした次の時)。CC引数は、時の倍数(4と指定すれば、4時間単位に前に進む) 6.7.4.1 (2017/02/17) 471 * ・EM :指定の次の分にセットします。(秒を00にした次の分)。CC引数は、分の倍数(15と指定すれば、15分単位に前に進む) 6.7.4.1 (2017/02/17) 472 * ・ES :指定の次の秒にセットします。CC引数は、秒の倍数(15と指定すれば、15秒単位に前に進む) 6.7.4.1 (2017/02/17) 473 * ・M1 ~ MXXX :月を指定の分だけ進めます。M1なら翌月、M6 なら半年後 474 * ・D1 ~ DXXX :日を指定の分だけ進めます。D1なら翌日、D200 なら200日後 475 * ・H1 ~ HXXX :時を指定の分だけ進めます。H1なら1時間後、H24 なら24時間後(5.5.5.6 (2012/08/31) 追加) 476 * ・MI :分を指定の分だけ進めます。第四引数(intC) で、時間を指定します。(6.8.4.1 (2017/12/18) 追加) 477 * ・YMD :CC 引数のYMD表記の日付を加減算します。6.8.4.1 (2017/12/18) 追加 478 * ・HM :CC 引数のHM表記の時刻を加減算します。6.8.4.1 (2017/12/18) 追加 479 * ・(有閑)BSD :先月の最初の日付にセットします。(先月1日)(5.5.5.2 追加)。SD -1 と同等 480 * ・(有閑)BED :先月の最後の日付にセットします。(先月月末)(5.5.5.2 追加)。ED -1 と同等 481 * ・(有閑)ASD :翌月の最初の日付にセットします。(翌月1日)(5.5.5.2 追加)。SD 1 と同等 482 * ・(有閑)AED :翌月の最後の日付にセットします。(翌月月末)(5.5.5.2 追加)。ED 1 と同等 483 * 484 * CC 引数は、特別な処理で、BB 引数に対して、加算、減算のための数字を指定できます。(5.7.4.1 (2014/03/14) 追加) 485 * 従来は、BB 引数が、"H" , "D" , "M" の 1文字パラメータの場合のみ利用可能でした。 486 * 487 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 488 * @og.rev 5.6.1.1 (2013/02/08) prmB処理を、calendarCalc メソッドへ移動 489 * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張 490 * @og.rev 6.4.3.3 (2016/03/04) Map#getOrDefault で対応する。 491 * 492 * @param key フォーマットの予約語 493 * @param prmA 基準となる日付(nullの場合は、処理時刻) 494 * @param prmB 処理コマンド 495 * @param intC 加減算処理を行うための数字。0 は、BB引数の従来計算のまま。 496 * 497 * @return メッセージ情報 498 * @og.rtnNotNull 499 * @see #getDateFormat( String ) 500 * @see #getDateFormat( String , String ) 501 * @see #getCalendar( String ) AA 引数 からカレンダオブジェクトを作成します。 502 * @see #calendarCalc( Calendar , String , int ) BB 引数、CC 引数を元に、日付計算します。 503 */ 504 public static String getDateFormat( final String key ,final String prmA ,final String prmB ,final int intC ) { 505 // prmA が null の場合は、そのまま、現在時刻が使われます。 506 final Calendar now = getCalendar( prmA ); 507 508 // 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離。 509 calendarCalc( now,prmB,intC ); // 5.7.4.1 (2014/03/14) CC 引数を拡張 510 511 // DATE_FORMAT に存在しないフォーマットを指定しても、エラーにしません。 512 // ただし、後処理でフォーマットエラーになる可能性は残ります。 513 // 6.4.3.3 (2016/03/04) Map#getOrDefault を使用します。 514 final String format = DATE_FORMAT.getOrDefault( key,key ); // 後ろの key は、値が null のときの初期値 515 516 //5.5.0.2 先頭Gの場合は和暦なのでformatterのLocaleを変更する 517 DateFormat formatter = null; 518 if( key.indexOf('G') == 0 ){ 519 formatter = new SimpleDateFormat( format, new Locale("ja","JP","JP")); 520 } 521 else{ 522 formatter = new SimpleDateFormat( format,Locale.JAPAN ); 523 } 524 525 return formatter.format( now.getTime() ); 526 } 527 528 /** 529 * 開始前設定値、または 終了後設定値の文字列から、オプション文字列を合成します。 530 * 基準となる日付に計算した結果を反映させます。 531 * 532 * CC引数の加減算パラメータは、0 です。 533 * 534 * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため、旧メソッドを再現しておきます。 535 * 536 * @param now 基準となる日付(Calendarオブジェクト) 537 * @param prmB 処理コマンド 538 */ 539 public static void calendarCalc( final Calendar now,final String prmB ) { 540 calendarCalc( now,prmB,0 ); 541 } 542 543 /** 544 * 開始前設定値、または 終了後設定値の文字列から、オプション文字列を合成します。 545 * 基準となる日付に計算した結果を反映させます。 546 * 547 * prmB は、日付についての加減算処理を行うためのコマンドを指定します。 548 * ・SY :当年の最初の日付にセットします。(当年1月1日)。CC引数は、-N:N年前、0:当年(=SY)、N:N年後 6.9.2.1 (2018/03/12) 549 * ・SD :当月の最初の日付にセットします。(当月1日)。CC引数は、-N:N月前、0:当月(=SD)、N:N月後、-1:BSD と同じ、1:ASD と同じ 550 * ・SW :日付処理の週初め(月曜日)にセットします。日付は当日より前に移動します。CC引数は、-N:N週前、0:今週(=SW)、N:N週後 551 * ・SH :指定の最初の時にセットします。(分秒を0000にする)。CC引数は、時の倍数(4と指定すれば、4時間単位に前に戻る) 6.7.4.1 (2017/02/17) 552 * ・SM :指定の最初の分にセットします。(秒を00にする)。CC引数は、分の倍数(15と指定すれば、15分単位に前に戻る) 6.7.4.1 (2017/02/17) 553 * ・SS :指定の最初の秒にセットします。CC引数は、秒の倍数(15と指定すれば、15秒単位に前に戻る) 6.7.4.1 (2017/02/17) 554 * ・EY :当年の最後の日付にセットします。(当年年末)。CC引数は、-N:N年前、0:当年(=EY)、N:N年後 6.9.2.1 (2018/03/12) 555 * ・ED :当月の最後の日付にセットします。(当月月末)。CC引数は、-N:N月前、0:当月(=ED)、N:N月後、-1:BED と同じ、1:AED と同じ 556 * ・EW :日付処理の週末(日曜日)にセットします。日付は当日より後ろに移動します。CC引数は、-N:N週前、0:今週(=EW)、N:N週後 557 * ・EH :指定の次の時にセットします。(分秒を0000にした次の時)。CC引数は、時の倍数(4と指定すれば、4時間単位に前に進む) 6.7.4.1 (2017/02/17) 558 * ・EM :指定の次の分にセットします。(秒を00にした次の分)。CC引数は、分の倍数(15と指定すれば、15分単位に前に進む) 6.7.4.1 (2017/02/17) 559 * ・ES :指定の次の秒にセットします。CC引数は、秒の倍数(15と指定すれば、15秒単位に前に進む) 6.7.4.1 (2017/02/17) 560 * ・M1 ~ MXXX :月を指定の分だけ進めます。M1なら翌月、M6 なら半年後 561 * ・D1 ~ DXXX :日を指定の分だけ進めます。D1なら翌日、D200 なら200日後 562 * ・H1 ~ HXXX :時を指定の分だけ進めます。H1なら1時間後、H24 なら24時間後(5.5.5.6 (2012/08/31) 追加) 563 * ・MI :分を指定の分だけ進めます。第四引数(intC) で、時間を指定します。(6.8.4.1 (2017/12/18) 追加) 564 * ・YMD :CC 引数のYMD表記の日付を加減算します。6.8.4.1 (2017/12/18) 追加 565 * ・HM :CC 引数のHM表記の時刻を加減算します。6.8.4.1 (2017/12/18) 追加 566 * ・(有閑)BSD :先月の最初の日付にセットします。(先月1日)(5.5.5.2 追加)。SD-1 と同等 567 * ・(有閑)BED :先月の最後の日付にセットします。(先月月末)(5.5.5.2 追加)。ED-1 と同等 568 * ・(有閑)ASD :翌月の最初の日付にセットします。(翌月1日)(5.5.5.2 追加)。SD1 と同等 569 * ・(有閑)AED :翌月の最後の日付にセットします。(翌月月末)(5.5.5.2 追加)。ED1 と同等 570 * ・数字:日を指定の分だけ進めます。D1 ~ DXXX の簡略系 571 * 572 * CC 引数は、特別な処理で、BB 引数に対して、加算、減算のための数字を指定できます。(5.7.4.1 (2014/03/14) 追加) 573 * HXXX,DXXX,MXXX 形式に、CC 引数を付けた場合は、XXX にさらに加算されます。 574 * prmB に、数字を使用した場合、(コマンドでない場合)にも、CC 引数は、加算されます。 575 * 6.8.4.1 (2017/12/18) BB 引数に、HM を指定した場合、時分のデータを加算します。この場合、時に関しては、24時間を越える 576 * 場合は、日付に加算されます。例えば、翌朝の6時を指定する場合、3000 と指定することで、1日+0600 となります。 577 * 578 * @og.rev 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離。 579 * @og.rev 5.7.4.1 (2014/03/14) H1 ~ HXXX :時を指定の分だけ進める処理が実装されていなかった。 580 * @og.rev 5.7.4.1 (2014/03/14) CC 引数追加 581 * @og.rev 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 582 * @og.rev 6.8.4.1 (2017/12/18) YMD , HM , MI 追加 583 * @og.rev 6.9.2.1 (2018/03/12) 年関連の機能(Y4,SY,EY)追加 584 * 585 * @param now 基準となる日付(Calendarオブジェクト) 586 * @param prmB 処理コマンド 587 * @param intC 加減算処理を行うための数字。0 は、BB引数の従来計算のまま。 588 */ 589 public static void calendarCalc( final Calendar now , final String prmB , final int intC ) { 590 591 // 基準は、intC == 0 の場合 592 if( prmB != null && prmB.length() > 0 ) { // 6.9.2.1 (2018/03/12) 年関連の機能(Y4,SY,EY)追加 593 if( "SY".equals( prmB ) ) { // (当年1月1日) 594 if( intC != 0 ) { now.add( Calendar.YEAR,intC ); } 595 now.set( Calendar.DAY_OF_YEAR,1 ); // 現在の年の何日目かで指定します。 596 } 597 else if( "EY".equals( prmB ) ) { // (当年年末) 598 if( intC != 0 ) { now.add( Calendar.YEAR,intC ); } 599 now.set( Calendar.MONTH,11 ); // 月は、0~11 の値で指定。 600 now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 601 } 602 else if( "SD".equals( prmB ) ) { // (当月1日) 603 if( intC != 0 ) { now.add( Calendar.MONTH,intC ); } // 5.7.4.1 (2014/03/14) CC 引数追加 604 now.set( Calendar.DATE,1 ); 605 } 606 else if( "ED".equals( prmB ) ) { // (当月月末) 607 if( intC != 0 ) { now.add( Calendar.MONTH,intC ); } // 5.7.4.1 (2014/03/14) CC 引数追加 608 now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 609 } 610 else if( "SH".equals( prmB ) ) { // (時戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 611 // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にキャストしている 612// final int hh = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ; // 切捨て 613 final int hh = intC == 0 ? 0 : ( now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ; // 切捨て 614 now.set( Calendar.HOUR_OF_DAY,hh ); 615 now.set( Calendar.MINUTE ,0 ); 616 now.set( Calendar.SECOND ,0 ); 617 now.set( Calendar.MILLISECOND,0 ); 618 } 619 else if( "SM".equals( prmB ) ) { // (分戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 620 // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にキャストしている 621// final int mm = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.MINUTE ) / intC ) * intC ; // 切捨て 622 final int mm = intC == 0 ? 0 : ( now.get( Calendar.MINUTE ) / intC ) * intC ; // 切捨て 623 now.set( Calendar.MINUTE ,mm ); 624 now.set( Calendar.SECOND ,0 ); 625 now.set( Calendar.MILLISECOND,0 ); 626 } 627 else if( "SS".equals( prmB ) ) { // (秒戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 628 // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にキャストしている 629// final int ss = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.SECOND ) / intC ) * intC ; // 切捨て 630 final int ss = intC == 0 ? 0 : ( now.get( Calendar.SECOND ) / intC ) * intC ; // 切捨て 631 now.set( Calendar.SECOND ,ss ); 632 now.set( Calendar.MILLISECOND,0 ); 633 } 634 else if( "EH".equals( prmB ) ) { // (時進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 635 final int hh = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ; // 切り上げ 636 if( hh == 0 || hh >= 24 ) { 637 now.add( Calendar.DATE ,1 ); // 日を加算 638 now.set( Calendar.HOUR_OF_DAY,0 ); 639 } 640 else { 641 now.set( Calendar.HOUR_OF_DAY,hh ); 642 } 643 now.set( Calendar.MINUTE ,0 ); 644 now.set( Calendar.SECOND ,0 ); 645 now.set( Calendar.MILLISECOND,0 ); 646 } 647 else if( "EM".equals( prmB ) ) { // (分進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 648 final int mm = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.MINUTE ) / intC ) * intC ; // 切切り上げ 649 if( mm == 0 || mm >= 60 ) { 650 now.add( Calendar.HOUR_OF_DAY,1 ); // 時を加算 651 now.set( Calendar.MINUTE ,0 ); 652 } 653 else { 654 now.set( Calendar.MINUTE,mm ); 655 } 656 now.set( Calendar.SECOND ,0 ); 657 now.set( Calendar.MILLISECOND,0 ); 658 } 659 else if( "ES".equals( prmB ) ) { // (秒進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加 660 final int ss = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.SECOND ) / intC ) * intC ; // 切り上げ 661 if( ss == 0 || ss >= 60 ) { 662 now.add( Calendar.MINUTE ,1 ); // 分を加算 663 now.set( Calendar.SECOND ,0 ); 664 } 665 else { 666 now.set( Calendar.SECOND,ss ); 667 } 668 now.set( Calendar.MILLISECOND,0 ); 669 } 670 else if( "BSD".equals( prmB ) ) { // (先月1日) 671 // 5.7.4.1 (2014/03/14) CC 引数追加 672 now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,1 ); 673 } 674 else if( "BED".equals( prmB ) ) { // (先月月末) 675 // 5.7.4.1 (2014/03/14) CC 引数追加 676 now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 677 } 678 else if( "ASD".equals( prmB ) ) { // (翌月1日) 679 // 5.7.4.1 (2014/03/14) CC 引数追加 680 now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,1 ); 681 } 682 else if( "AED".equals( prmB ) ) { // (翌月月末) 683 // 5.7.4.1 (2014/03/14) CC 引数追加 684 now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) ); 685 } 686 else if( "SW".equals( prmB ) ) { // 週初め(月曜日)セット 687 // 5.7.4.1 (2014/03/14) CC 引数追加 688 if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); } // まず、基準の日付を週単位で加減算する。 689 690 // 日付型文字列入力データの開始日を月曜日にセットします。 691 // SUNDAY=1 , MONDAY=2 になります。月曜日との差だけ、前に戻します。 692 // 指定日が日曜日の場合は、月曜日まで戻します。 693 694 final int shu = now.get( Calendar.DAY_OF_WEEK ) - Calendar.MONDAY ; 695 696 if( shu > 0 ) { now.add( Calendar.DATE, -shu ); } 697 else if( shu < 0 ) { now.add( Calendar.DATE, -6 ); } 698 } 699 else if( "EW".equals( prmB ) ) { // 週末(日曜日)にセット 700 // 5.7.4.1 (2014/03/14) CC 引数追加 701 if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); } // まず、基準の日付を週単位で加減算する。 702 703 // 日付型文字列入力データの終了日を日曜日にセットします。 704 // SUNDAY=1 , MONDAY=2 になります。日曜日になるように、先に進めます。 705 final int shu = now.get( Calendar.DAY_OF_WEEK ) ; 706 if( shu != Calendar.SUNDAY ) { now.add( Calendar.DATE, 8-shu ); } 707 } 708 // 6.8.4.1 (2017/12/18) YMD 追加(年月日の繰り上げ表記を加味した加算) 709 else if( "YMD".equals( prmB ) ) { 710 final int year = intC / 10000; 711 final int month = ( intC / 100 ) % 100; 712 final int date = intC % 100; 713 714 now.add( Calendar.YEAR , year ); 715 now.add( Calendar.MONTH , month ); 716 now.add( Calendar.DATE , date ); 717 } 718 // 6.8.4.1 (2017/12/18) HM 追加(時分の24時間表記を加味した加算) 719 else if( "HM".equals( prmB ) ) { // 注意:prmB.charAt(0) == 'H' より先に判定しておきます。 720 final int hour = intC / 100; 721 final int minute = intC % 100; 722 723 now.add( Calendar.HOUR_OF_DAY , hour ); 724 now.add( Calendar.MINUTE , minute ); 725 } 726 // 6.8.4.1 (2017/12/18) HM 分を指定の分だけ進めます。 727 else if( "MI".equals( prmB ) ) { // 注意:prmB.charAt(0) == 'M' より先に判定しておきます。 728 now.add( Calendar.MINUTE , intC ); 729 } 730 // 6.9.2.1 (2018/03/12) Y1 ~ YXXX :年を指定の分だけ進める処理 731 else if( prmB.charAt(0) == 'Y' ) { 732 int year = intC ; 733 if( prmB.length() > 1 ) { year += Integer.parseInt( prmB.substring( 1 ) ); } 734 now.add( Calendar.YEAR , year ); 735 } 736 else if( prmB.charAt(0) == 'H' ) { // 6.1.0.0 (2014/12/26) refactoring 737 int hour = intC ; 738 if( prmB.length() > 1 ) { hour += Integer.parseInt( prmB.substring( 1 ) ); } 739 now.add( Calendar.HOUR_OF_DAY , hour ); 740 } 741 else if( prmB.charAt(0) == 'D' ) { // 6.1.0.0 (2014/12/26) refactoring 742 int day = intC ; 743 if( prmB.length() > 1 ) { day += Integer.parseInt( prmB.substring( 1 ) ); } 744 now.add( Calendar.DATE, day ); 745 } 746 else if( prmB.charAt(0) == 'M' ) { // 6.1.0.0 (2014/12/26) refactoring 747 int month = intC ; 748 if( prmB.length() > 1 ) { month += Integer.parseInt( prmB.substring( 1 ) ); } 749 now.add( Calendar.MONTH , month ); 750 } 751 else { 752 // 上記のパターン以外は、数字(加減算する日数)なので、変換できなければ、フォーマットエラー 753 try { 754 final int day = Integer.parseInt( prmB ) + intC ; // 5.7.4.1 (2014/03/14) CC 引数追加 755 now.add( Calendar.DATE, day ); 756 } 757 catch( final NumberFormatException ex ) { 758 final String errMsg = "日付変数パラメータに、不正な値が指定されました。以下の中から指定しなおしてください。" 759 + "指定可能:[SD,ED,SW,SH,SM,SS,EW,EH,EM,ES,H1~HXXX,D1~DXXX,M1~MXXX,HMS,BSD,BED,ASD,AED]" 760 + " prmB=[" + prmB + "]" ; 761 throw new OgRuntimeException( errMsg,ex ); 762 } 763 } 764 } 765 } 766 767 /** 768 * 指定の引数の日付け文字列より、カレンダオブジェクトを作成します。 769 * 引数は、数字以外の文字を削除した状態に変換後、処理に回します。 770 * 不要な文字を削除した状態で、8文字以上になるように指定してください。 771 * 例外的に、6文字の場合は、yyyyMM01 とみなして、"01" 文字列を付与します。 772 * 引数に null を指定すると、現在時刻のカレンダを返します。 773 * それ以外のデータで、8ケタ以下の場合は、RuntimeException が発生します。 774 * 8ケタ以上14ケタ未満の場合は、8ケタ分を、年月日に分離したカレンダ 775 * オブジェクトを作成します。14ケタ以上で初めて、時分秒を含むカレンダ 776 * を作成します。 777 * 778 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 779 * @og.rev 5.5.8.2 (2012/11/09) value の判定に、null と ゼロ文字列を判定する。 780 * 781 * @param value 日付け文字列 782 * 783 * @return カレンダオブジェクト(引数がnullの場合は、現在時刻) 784 * @og.rtnNotNull 785 */ 786 public static Calendar getCalendar( final String value ) { 787 final Calendar cal = Calendar.getInstance(); 788 789 if( value == null || value.isEmpty() ) { return cal; } // 5.5.8.2 (2012/11/09) null と ゼロ文字列を判定する。 790 791 // 日付表記に不要な文字を削除します。 792 String dateStr = parseNumber( value ) ; 793 794 if( dateStr.length() == 6 ) { dateStr = dateStr + "01"; } // yyyyMM01 形式に無理やり合わせる。 795 else if( dateStr.length() < 8 ) { 796 final String errMsg = "日付指定パラメータに、不正な値が指定されました。value=[" + value + "]" ; 797 throw new OgRuntimeException( errMsg ); 798 } 799 800 cal.clear(); // 日付文字列が存在するので、カレンダをリセット 801 802 final int year = Integer.parseInt( dateStr.substring( 0,4 ) ); 803 final int month = Integer.parseInt( dateStr.substring( 4,6 ) ) - 1; 804 final int date = Integer.parseInt( dateStr.substring( 6,8 ) ); 805 806 // 6.3.9.0 (2015/11/06) Use one line for each declaration, it enhances code readability.(PMD) 807 int hour =0; 808 int minute=0; 809 int second=0; 810 if( dateStr.length() >= 14 ) { 811 hour = Integer.parseInt( dateStr.substring( 8,10 ) ); 812 minute = Integer.parseInt( dateStr.substring( 10,12 ) ); 813 second = Integer.parseInt( dateStr.substring( 12,14 ) ); 814 } 815 816 cal.set( year,month,date,hour,minute,second ); 817 818 return cal; 819 } 820 821 /** 822 * 指定の引数の日付け文字列(yyyyMMdd)より、日付を加算して返します。 823 * マイナスを与えると、減算します。 824 * 日付以上の精度の文字列を渡しても、日付のみの計算となります。 825 * 結果は、引数の日付フォーマットとは全く別で、yyyyMMdd の8文字形式になります。 826 * 引数に null を渡すと、実行時の日付をベースとして処理します。 827 * 828 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 829 * 830 * @param baseDate 日付け文字列(yyyyMMdd) 831 * @param plus 加算する日数(過去にするにはマイナス値を指定する) 832 * 833 * @return 結果の日付(yyyyMMdd) 834 * @og.rtnNotNull 835 */ 836 public static String getDatePlus( final String baseDate,final int plus ) { 837 final Calendar cal = getCalendar( baseDate ); 838 cal.add( Calendar.DATE,plus ); 839 840 return DateSet.getDate( cal.getTimeInMillis() , "yyyyMMdd" ); 841 } 842 843 /** 844 * 現在の月に、指定の月数をプラスした日付文字列を返します。 845 * 日付文字列のフォーマットは、"yyyyMM" です。 846 * 指定する月数にマイナスを指定すると、減算できます。 847 * 848 * @og.rev 5.5.7.2 (2012/10/09) 新規作成 849 * 850 * @param baseDate 日付け文字列(yyyyMM) 851 * @param plus 加算する月数(過去にするにはマイナス値を指定する) 852 * 853 * @return 指定の月数をプラスした日付文字列(yyyyMM) 854 * @og.rtnNotNull 855 */ 856 public static String getMonthPlus( final String baseDate,final int plus ) { 857 final Calendar cal = getCalendar( baseDate ); 858 cal.set( Calendar.DATE, 1 ); // 当月の 1 日に設定 859 cal.add( Calendar.MONTH , plus ); 860 861 return DateSet.getDate( cal.getTimeInMillis() , "yyyyMM" ); 862 } 863 864 /** 865 * 指定の引数の日付け文字列(yyyyMMdd、yyyyMMddHHmmss)に、日付を加算して返します。 866 * マイナスを与えると、減算します。 867 * 868 * 指定する日付には、単位を付与することが可能です。 869 * 単位は、yyyyMMddHHmmss 形式の1文字を指定します。大文字、小文字も識別します。 870 * plus="5M" とすれば、5か月、plus="5d" とすれば、5日 追加します。 871 * plus に単位を付けない場合は、tani に指定の単位を使います。 872 * plus そのものが、null か、isEmpty の場合は、加算は、1 になります。 873 * 874 * baseDate 文字列を日付文字列に変換後、Calendar で計算し、結果を、format 形式に変換します。 875 * 引数に null を渡すと、実行時の日付をベースとして処理します。 876 * 877 * @og.rev 5.6.1.0 (2013/02/01) 新規作成 878 * 879 * @param baseDate 日付け文字列(yyyyMMdd、yyyyMMddHHmmss 形式の日付文字列) 880 * @param plus 加算する日数(日付単位を含む。単位は、y,M,d,H,m,s の文字で、大文字小文字の区別があります) 881 * @param defTani 日付単位が未指定の場合の初期単位('y','M','d','H','m','s' のどれか) 882 * @param format 返す日付文字列のフォーマット(yyyyMMdd、yyyyMMddHHmmss) 883 * 884 * @return 結果の日付(yyyyMMdd) 885 * @throws NumberFormatException 加算する日数の単位が('y','M','d','H','m','s')以外の場合。 886 * @og.rtnNotNull 887 */ 888 public static String getDatePlus( final String baseDate,final String plus,final int defTani,final String format ) { 889 890 int addSu = 1; // 初期値(plus が null や Empty の場合は、+1となる) 891 int tani = defTani; 892 893 if( plus != null && !plus.isEmpty() ) { 894 boolean flag = true; // 日付単位を持っているかどうか。持っている場合は、true 895 final char ch = plus.charAt( plus.length()-1 ); // 最後の一文字を取得(単位か、数字本体) 896 switch( ch ) { 897 case 'y' : tani = Calendar.YEAR; break ; 898 case 'M' : tani = Calendar.MONTH; break ; 899 case 'd' : tani = Calendar.DATE; break ; 900 case 'H' : tani = Calendar.HOUR_OF_DAY; break ; 901 case 'm' : tani = Calendar.MINUTE; break ; 902 case 's' : tani = Calendar.SECOND; break ; 903 default : flag = false; break ; // 日付単位を持っていない。 904 } 905 if( flag ) { 906 addSu = Integer.parseInt( plus.substring( 0,plus.length()-1 ) ); // 日付単位 あり 907 } 908 else { 909 addSu = Integer.parseInt( plus ) ; // 日付単位 なし 910 } 911 } 912 913 final Calendar cal = getCalendar( baseDate ); 914 cal.add( tani,addSu ); 915 916 return DateSet.getDate( cal.getTimeInMillis() , format ); 917 } 918}