    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;
    026import java.util.List;                                                                          // 7.0.5.0 (2019/09/09)
    027import java.util.ArrayList;                                                                     // 7.0.5.0 (2019/09/09)
    028
    029import org.opengion.fukurou.system.DateSet;                                                             // 6.4.2.0 (2016/01/29)
    030import static org.opengion.fukurou.system.HybsConst.BUFFER_SMALL;               // 6.1.0.0 (2014/12/26) refactoring
    031
    032/**
    033 * HybsDateUtil.java は､共通的に使用される Date,Calender関連ﾒｿｯﾄﾞを集約した､staticﾒｿｯﾄﾞのみで構成されるｸﾗｽです｡
    034 *
    035 * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    036 *
    037 * @og.group ﾕｰﾃｨﾘﾃｨ
    038 *
    039 * @version  5.5
    040 * @author       Kazuhiko Hasegawa
    041 * @since    JDK7.0,
    042 */
    043public final class HybsDateUtil {
    044
    045        /** 各種ﾌｫｰﾏｯﾄを簡易的に表した文字列 */
    046        /** staticｲﾆｼｬﾗｲｻﾞ後､読み取り専用にするので､ConcurrentHashMap を使用しません｡ */
    047        private static final Map<String,String> DATE_FORMAT = new HashMap<>();
    048        static {
    049                DATE_FORMAT.put( "Y4"           ,"yyyy"                                 );      // 6.9.2.1 (2018/03/12)
    050                DATE_FORMAT.put( "YMD"          ,"yyyyMMdd"                             );
    051                DATE_FORMAT.put( "Y2MD"         ,"yyMMdd"                               );
    052                DATE_FORMAT.put( "YM"           ,"yyyyMM"                               );
    053                DATE_FORMAT.put( "MD"           ,"MMdd"                                 );      // 5.5.5.2 (2012/08/18)
    054                DATE_FORMAT.put( "HMS"          ,"HHmmss"                               );
    055                DATE_FORMAT.put( "HM"           ,"HHmm"                                 );      // 6.7.4.1 (2017/02/17)
    056                DATE_FORMAT.put( "YMDHMS"       ,"yyyyMMddHHmmss"               );
    057                DATE_FORMAT.put( "YMDHM"        ,"yyyyMMddHHmm"                 );      // 7.0.5.0 (2019/09/16)
    058                DATE_FORMAT.put( "YMDH"         ,"yyyyMMddHH"                   );      // 7.0.5.0 (2019/09/16)
    059                DATE_FORMAT.put( "EEE"          ,"EEE"                                  );
    060                DATE_FORMAT.put( "YMDF"         ,"yyyy/MM/dd"                   );
    061                DATE_FORMAT.put( "YMD-F"        ,"yyyy-MM-dd"                   );      // 8.0.1.2 (2021/11/19) HTML5 type="date"
    062                DATE_FORMAT.put( "Y2MDF"        ,"yy/MM/dd"                     );
    063                DATE_FORMAT.put( "YMF"          ,"yyyy/MM"                              );
    064                DATE_FORMAT.put( "YM-F"         ,"yyyy-MM"                              );      // 8.0.1.2 (2021/11/19) HTML5 type="month"
    065                DATE_FORMAT.put( "HMSF"         ,"HH:mm:ss"                     );
    066                DATE_FORMAT.put( "HMF"          ,"HH:mm"                                );      // 6.7.4.1 (2017/02/17)
    067                DATE_FORMAT.put( "YMDHMSF"      ,"yyyy/MM/dd HH:mm:ss"  );
    068                DATE_FORMAT.put( "YMDHMF"       ,"yyyy/MM/dd HH:mm"             );      // 7.0.5.0 (2019/09/16)
    069                DATE_FORMAT.put( "YMDHM-F"      ,"yyyy-MM-dd'T'HH:mm"   );      // 8.0.1.2 (2021/11/19) HTML5 type="datetime-local"
    070                DATE_FORMAT.put( "MDF"          ,"MM/dd"                                );      // 5.5.0.2 (2012/03/09)
    071                DATE_FORMAT.put( "MDEF"         ,"MM/dd(EEE)"                   );      // 5.5.0.2 (2012/03/09) 曜日
    072                DATE_FORMAT.put( "MDHMF"        ,"MM/dd HH:mm"                  );      // 7.0.0.1 (2018/10/09)
    073                DATE_FORMAT.put( "MD2F"         ,"MM月dd日"                               );      // 5.5.5.2 (2012/08/18) 漢字
    074                DATE_FORMAT.put( "HM2F"         ,"HH時mm分"                               );      // 7.0.0.1 (2018/10/09) 漢字
    075                DATE_FORMAT.put( "MDHM2F"       ,"MM月dd日 HH時mm分"        );      // 7.0.0.1 (2018/10/09) 漢字
    076                DATE_FORMAT.put( "GYMDF"        ,"GGGGyyyy年MM月dd日"      );      // 5.5.0.2 (2012/03/09) 和暦
    077                DATE_FORMAT.put( "G2YMDF"       ,"Gyyyy/MM/dd"                  );      // 5.5.0.2 (2012/03/09) 和暦
    078                DATE_FORMAT.put( "GYMF"         ,"GGGGyyyy年MM月"         );      // 5.5.0.2 (2012/03/09) 和暦
    079                DATE_FORMAT.put( "GYF"          ,"GGGGyyyy"                     );      // 5.5.0.2 (2012/03/09) 和暦
    080        }
    081
    082        private static final int DD = 1000 * 60 * 60 * 24 ;             // ﾐﾘ秒 → 日
    083        private static final int HH = 1000 * 60 * 60 ;                  // ﾐﾘ秒 → 時
    084        private static final int MM = 1000 * 60 ;                               // ﾐﾘ秒 → 分
    085        private static final int SS = 1000 ;                                    // ﾐﾘ秒 → 秒
    086
    087        /**
    088         *      ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰをprivateにして､
    089         *      ｵﾌﾞｼﾞｪｸﾄの生成をさせないようにする｡
    090         *
    091         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    092         *
    093         */
    094        private HybsDateUtil() {}
    095
    096        /**
    097         * 指定の文字列から､以下の文字を削除した文字列を返します｡
    098         * '/' , '-' , ' ' , ':' の数字以外の文字を含むﾌｫｰﾏｯﾄされた
    099         * 日付文字列を､日付ﾃﾞｰﾀだけに変換する場合に利用することを想定しています｡
    100         * よって､ﾏｲﾅｽ記号や､小数点､ｺﾝﾏなども削除されます｡
    101         * このﾒｿｯﾄﾞでは､日付としての整合性や桁ﾁｪｯｸは行いませんが､
    102         * 桁数は､6桁､8桁､14桁のどれかに､合わせます｡
    103         * ｢yyyy/MM/dd HH:mm:ss｣ 形式を基準としますが､｢yyyy/M｣｢yyyy/M/d｣｢yy/M/d｣｢M/d｣
    104         * ｢HH:mm:ss｣｢H:m｣形式にも､対応します｡
    105         * "/" が､"-" に変更されているｹｰｽも対応可能ですが､月/年 形式や､英語､日本語の
    106         * 月表示には未対応です｡
    107         *
    108         * 引数が､null の場合は､ｾﾞﾛ文字列に､変換します｡
    109         *
    110         * ※ 6.0.2.5 (2014/10/31) 桁数ﾁｪｯｸだけは行います｡
    111         *   桁数は､6桁､8桁､14桁のどれかに､合わせます｡
    112         *
    113         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    114         * @og.rev 5.5.8.3 (2012/11/17) 数字のみ返す仕様だったが､対象以外の文字入力はそのまま返すよう変更
    115         * @og.rev 6.0.2.5 (2014/10/31) 簡易的な桁数ﾁｪｯｸだけは行います｡
    116         * @og.rev 6.2.3.0 (2015/05/01) 内部処理を大幅に変更します｡
    117         * @og.rev 8.0.1.2 (2021/11/19) yyyy-MM-ddTHH:mm 対応(ｽﾍﾟｰｽではなくTで区切る)
    118         *
    119         * @param       value 任意の文字列（例：2001/04/17 15:48:22）
    120         *
    121         * @return      数字だけで構成される文字列（例：20010417154822）(nullはｾﾞﾛ文字列を返します)
    122         * @og.rtnNotNull
    123         */
    124        public static String parseNumber( final String value ) {
    125                if( value == null || value.isEmpty() ) { return ""; }
    126
    127                // 年 や､年月日 が省略された場合は､実行日をｾｯﾄする｡
    128                final String today = DateSet.getDate( "yyyyMMdd" );
    129
    130                String val = value.trim();
    131                val = val.replaceAll( "-" , "/" );                      // yyyy-MM-dd 形式を､yyyy/MM/dd 形式にする｡
    132
    133                // 8.0.1.2 (2021/11/19) yyyy-MM-ddTHH:mm 対応(ｽﾍﾟｰｽではなくTで区切る)
    134                val = val.replaceAll( "T" , " " );
    135
    136                final int ad = val.indexOf( ' ' ) ;
    137                String ymd = val  ;
    138                String hms = null ;
    139
    140                if( ad > 0 ) {                                          // ｽﾍﾟｰｽがあれば､年月日 と 時分秒 に別れる｡
    141                        ymd = val.substring( 0,ad );
    142                        hms = val.substring( ad+1 );
    143                }
    144                else if( val.indexOf( ':' ) > 0 ) {
    145                        ymd = today;                                    // 年月日 は今日になる｡
    146                        hms = val;
    147                }
    148
    149                final StringBuilder buf = new StringBuilder( BUFFER_SMALL );
    150
    151                if( ymd != null ) {
    152                        final String[] ymdSp = ymd.split( "/" );
    153                        switch( ymdSp.length ) {
    154                                case 1 : buf.append( ymdSp[0] );        break;                                  // "/" が存在しない｡
    155                                case 2 : if( ymdSp[0].length() < 4 ) {                                          // MM/dd のｹｰｽ｡yy/MM は想定外
    156                                                        buf.append( today.substring( 0,4 ) );                   // yyyy の年を設定
    157                                                 }
    158                                                 buf.append( addZero( ymdSp[0] ) ).append( addZero( ymdSp[1] ) );       break;
    159                                default:  if( ymdSp[0].length() == 2 ) {                                        // yy/MM/dd のｹｰｽを想定
    160                                                        buf.append( today.substring( 0,2 ) );                   // yy の年の先頭２桁を設定
    161                                                 }
    162                                                 buf.append( ymdSp[0] )
    163                                                        .append( addZero( ymdSp[1] ) )
    164                                                        .append( addZero( ymdSp[2] ) ); break;
    165                        }
    166                }
    167                if( hms != null ) {
    168                        final String[] hmsSp = hms.split( ":" );                                                // HH:mm:ss
    169                        switch( hmsSp.length ) {
    170                                case 1 : buf.append( hmsSp[0] );                        break;                  // ":" が存在しない｡
    171                                case 2 : buf.append( addZero( hmsSp[0] ) )                                      // HH:mm のｹｰｽ｡mm:ss は想定外
    172                                                        .append( addZero( hmsSp[1] ) )
    173                                                        .append( "00" );                                break;
    174                                default: buf.append( addZero( hmsSp[0] ) )                                      // HH:mm:ss のｹｰｽを想定
    175                                                        .append( addZero( hmsSp[1] ) )
    176                                                        .append( addZero( hmsSp[2] ) ); break;
    177                        }
    178                }
    179
    180                return buf.toString();
    181        }
    182
    183        /**
    184         * 指定の文字列が､一桁の場合､先頭に 0 を追加します｡
    185         *
    186         * これは､3/4 の様な日付を､0304 にする場合のｻﾎﾟｰﾄﾒｿｯﾄﾞです｡
    187         *
    188         * @og.rev 6.2.3.0 (2015/05/01) 新規追加
    189         *
    190         * @param       val 任意の文字列
    191         *
    192         * @return      一桁の場合､先頭に 0 を追加
    193         */
    194        private static String addZero( final String val ) {
    195                return val.length() == 1 ? "0" + val : val ;
    196        }
    197
    198        /**
    199         * 指定の文字列から､yyyy-mm-dd hh:mm:ss 形式の文字列を作成します｡
    200         *
    201         * これは､java.sql.Timestamp ｵﾌﾞｼﾞｪｸﾄを文字列から作成するに当たり､
    202         * Timestamp の文字列形式にしなければならないためです｡
    203         * 桁数は､８桁 または､１４桁以外の場合は､変換ｴﾗｰとします｡
    204         *
    205         * @og.rev 5.5.8.5 (2012/11/27) 新規作成
    206         *
    207         * @param       value 任意の文字列（例：20010417 or 20010417154822）
    208         *
    209         * @return      Timestampの文字列形式（例：2001-04-17 00:00:00 or 2001-04-17 15:48:22）
    210         */
    211        public static String parseTimestamp( final String value ) {
    212                if( value == null || value.length() != 8 && value.length() != 14 ) {                            // 6.9.7.0 (2018/05/14) PMD
    213                        final String errMsg = "日付文字列は､８桁 または､１４桁で指定してください｡"
    214                                                + " value=[" + value + "]" ;
    215                        throw new OgRuntimeException( errMsg );
    216                }
    217
    218                // 6.0.2.5 (2014/10/31) char を append する｡
    219                final StringBuilder buf = new StringBuilder( BUFFER_SMALL )
    220                        .append( value.substring( 0,4 ) ).append( '-' )
    221                        .append( value.substring( 4,6 ) ).append( '-' )
    222                        .append( value.substring( 6,8 ) ).append( ' ' );
    223                if( value.length() == 8 ) {
    224                        buf.append( "00:00:00" );
    225                }
    226                else {
    227                        buf.append( value.substring( 8,10  ) ).append( ':' )
    228                                .append( value.substring( 10,12 ) ).append( ':' )
    229                                .append( value.substring( 12,14 ) );
    230                }
    231
    232                return buf.toString();
    233        }
    234
    235        /**
    236         * 日付文字列の桁数の整合性を取ります｡
    237         * これは､内部で､parseNumber(String) 処理により､不要なﾌｫｰﾏｯﾄ記号を削除します｡
    238         * ここでは､基本的には､６文字（yyyyMM）､８文字（yyyyMMdd）､１４文字（yyyyMMddHHmmss）
    239         * の日付文字列を作成することを想定していますが､指定の桁数以外は､ｴﾗｰになります｡
    240         *
    241         * 引数が､null         ⇒ 桁数に無関係に､空文字列を返す｡
    242         * 引数の桁数が一致     ⇒ その値を返す｡
    243         * 引数の桁数が不一致   ⇒ ｴﾗｰ
    244         * ただし､引数の最大長は､１４ｹﾀに制限しています｡
    245         *
    246         * このﾒｿｯﾄﾞでは､日付として成立しているかどうか（99999999など）は判定していません｡
    247         *
    248         * @og.rev 5.6.6.0 (2013/07/05) ﾒｿｯﾄﾞの内容を移す｡
    249         *
    250         * @param       value   任意の日付け文字列
    251         * @param       size    変換したい桁数
    252         *
    253         * @return      数字だけで構成される文字列（例：20010417154822）(nullはｾﾞﾛ文字列を返します)
    254         * @og.rtnNotNull
    255         */
    256        public static String parseDate( final String value , final int size ) {
    257                return parseDate( value , size , size );                // 最小と最大を同じ値にする｡
    258        }
    259
    260        /**
    261         * 日付文字列の桁数の整合性を取ります｡
    262         * これは､内部で､parseNumber(String) 処理により､不要なﾌｫｰﾏｯﾄ記号を削除します｡
    263         * ここでは､基本的には､６文字（yyyyMM）､８文字（yyyyMMdd）､１４文字（yyyyMMddHHmmss）
    264         * の日付文字列を作成することを想定していますが､それ以外の桁数でも下記のﾙｰﾙに従って
    265         * 処理されます｡
    266         *
    267         * 引数が､null         ⇒ 桁数に無関係に､空文字列を返す｡
    268         * 引数の桁数が範囲内   ⇒ 以下の処理を実行する｡
    269         * 引数の桁数を同じ     ⇒ そのまま返す｡
    270         * 引数の桁数より大きい ⇒ 余をｶｯﾄして､引数の最大長にそろえる｡
    271         * 引数の桁数に足りない ⇒ "20000101000000" の文字列の部分文字列を結合させて､引数の最大長にそろえる｡
    272         * ただし､引数の最大長は､１４ｹﾀに制限しています｡
    273         *
    274         * このﾒｿｯﾄﾞでは､日付として成立しているかどうか（99999999など）は判定していません｡
    275         *
    276         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    277         * @og.rev 5.6.1.1 (2013/02/08) 桁数ﾁｪｯｸ導入｡６桁以下だとｴﾗｰにする｡
    278         * @og.rev 5.6.6.0 (2013/07/05) 桁数ﾁｪｯｸの最小-最大指定
    279         * @og.rev 6.2.3.0 (2015/05/01) len == maxSize のとき､ﾊﾟｰｽ文字列ではなく､元の値を返していた｡
    280         *
    281         * @param       value   任意の日付け文字列
    282         * @param       minSize 変換したい桁数の最小値
    283         * @param       maxSize 変換したい桁数の最大値
    284         *
    285         * @return      数字だけで構成される文字列（例：20010417154822）(nullはｾﾞﾛ文字列を返します)
    286         * @og.rtnNotNull
    287         */
    288        public static String parseDate( final String value , final int minSize , final int maxSize ) {
    289                if( value == null ) { return ""; }
    290
    291                // 引数の最大長は､１４ｹﾀに制限しています｡
    292                if( maxSize > 14 ) {
    293                        final String errMsg = "日付登録に許可できる最大桁数は､１４ｹﾀです｡"
    294                                                + " maxSize=[" + maxSize + "]" ;
    295                        throw new OgRuntimeException( errMsg );
    296                }
    297
    298                final String rtn = parseNumber( value );
    299                final int len = rtn.length() ;
    300
    301                if( len < minSize || len > maxSize ) {
    302                        final String errMsg = "日付文字列は､最小["
    303                                                + minSize + "] から､最大[" + maxSize + "]の範囲で指定してください｡"
    304                                                + " value=[" + value + "]" ;
    305                        throw new OgRuntimeException( errMsg );
    306                }
    307
    308                return rtn ;
    309        }
    310
    311        /**
    312         * 日付文字列の厳密な整合性ﾁｪｯｸを行います｡
    313         * ここで指定できるのは､８文字（yyyyMMdd）､１４文字（yyyyMMddHHmmss）のどちらかの
    314         * 数字だけの日付文字列であり､それが､日付として正しいかどうかのﾁｪｯｸを行います｡
    315         * 正しければ､true を､間違っていれば､false を返します｡
    316         * ここでは､20120230（２月３０日）などの日付や､20120101235960 なども false になります｡
    317         * 引数が､null および､空文字列の場合も､false を返しますので､避けたい場合は､事前に
    318         * 判定しておいてください｡
    319         *
    320         * 内部処理としては､DateFormat で､setLenient( false ) を設定することで､
    321         * 日付/時刻解析を厳密に解析するにして､ParseException が発生しないかどうか判定しています｡
    322         *
    323         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    324         *
    325         * @param       value  数字だけで構成される日付け文字列
    326         *
    327         * @return      true:日付として正しい場合/false:日付として間違っている場合
    328         */
    329        public static boolean isStrict( final String value ) {
    330                if( value == null || value.length() != 8 && value.length() != 14 ) { return false; }    // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    331
    332                // 日付の厳密なﾁｪｯｸ
    333                final String form = (value.length() == 8) ? "yyyyMMdd" : "yyyyMMddHHmmss" ;
    334                final DateFormat formatter = new SimpleDateFormat( form,Locale.JAPAN );
    335                formatter.setLenient( false );          // 日付/時刻解析を厳密に行う(false=厳密)
    336
    337                boolean flag ;
    338                try {
    339                        formatter.parse( value );
    340                        flag = true;
    341                }
    342                catch( final ParseException ex ) {
    343                        flag = false;
    344                }
    345
    346                return flag;
    347        }
    348
    349        /**
    350         * 日付関係の情報を簡易的に処理します｡
    351         *
    352         * 引数に与えるのは､{&#064;DATE.XXXX} の XXXX 文字列になります｡
    353         * この "XXXX" 文字列は､"key prmA prmB prmC" 形式を取ることができます｡
    354         * 各文字列をｽﾍﾟｰｽで分割して､先頭から変数に割り当てます｡
    355         * また､prmA の日付文字判定と､数値変換と､prmC の数値変換も行います｡
    356         * ただし､ﾘｸｴｽﾄ変数の &#064; 文字列変換は､出来ません｡
    357         *
    358         * @og.rev 6.9.2.1 (2018/03/12) 新規追加
    359         *
    360         * @param   value       日付引数のﾊﾟﾗﾒｰﾀ
    361         *
    362         * @return   ﾒｯｾｰｼﾞ情報
    363         * @og.rtnNotNull
    364         * @see         #getDateFormat( String , String ,String , int )
    365         */
    366        public static String getDateFormat( final String value ) {
    367                // {@DATE.XXXX AA BB CC} を分割
    368                final String[] vals = StringUtil.csv2Array( value,' ' );                // ﾀﾞﾌﾞﾙｸｵｰﾄ内は保持される｡
    369
    370                final String key = vals[0] ;
    371
    372                String prmA = vals.length >= 2 ? vals[1] : null ;
    373                String prmB = vals.length >= 3 ? vals[2] : null ;
    374                String prmC = vals.length >= 4 ? vals[vals.length-1] : null ;   // 互換性｡最後の値が､CC引数
    375
    376                // AA 引数のｺﾏﾝﾄﾞ判定方法（先頭が数字以外）
    377                if( StringUtil.isNotNull( prmA ) ) {
    378                        final char chA = prmA.charAt(0);
    379                        if( chA < '0' || chA > '9' ) {          // 先頭が､数字以外の場合は､ｺﾏﾝﾄﾞなので､一つずつずらす｡
    380                                prmC = prmB;
    381                                prmB = prmA;
    382                                prmA = null;
    383                        }
    384                }
    385
    386                // CC 引数を､"H" , "D" , "M" 以外でも使用できるように拡張します｡
    387                int intC = 0;
    388                if( StringUtil.isNotNull( prmC ) ) {
    389                        try {
    390                                intC = Integer.parseInt( prmC );
    391                        }
    392                        catch( final NumberFormatException ex ) {
    393                                final String errMsg = "CC引数が数字ではありません｡value=[" + value + "]"
    394                                                                + ex.getMessage() ;
    395                                System.err.println( errMsg );
    396                        }
    397                }
    398
    399                // prmA が null か､isEmpty() の場合は､現在時刻が使用される｡
    400                return getDateFormat( key,prmA,prmB,intC );
    401        }
    402
    403        /**
    404         * 日付関係の情報を簡易的に処理します｡
    405         *
    406         * 処理ｺﾏﾝﾄﾞと､CC引数の加減算ﾊﾟﾗﾒｰﾀを使用しないﾊﾞｰｼﾞｮﾝです｡
    407         *
    408         * @og.rev 6.9.2.1 (2018/03/12) ﾒｿｯﾄﾞの引数を簡素化
    409         *
    410         * @param   key         ﾌｫｰﾏｯﾄの予約語
    411         * @param   prmA        基準となる日付(nullの場合は､処理時刻)
    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 ) {
    418                return getDateFormat( key,prmA,null,0 );
    419        }
    420
    421//      /**
    422//       * 日付関係の情報を簡易的に処理します｡
    423//       *
    424//       * CC引数の加減算ﾊﾟﾗﾒｰﾀは､0 です｡
    425//       *
    426//       * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため､旧ﾒｿｯﾄﾞを再現しておきます｡
    427//       * @og.rev 6.9.2.1 (2018/03/12) 廃止
    428//       *
    429//       * @param   key         ﾌｫｰﾏｯﾄの予約語
    430//       * @param   prmA        基準となる日付(nullの場合は､処理時刻)
    431//       * @param   prmB        処理ｺﾏﾝﾄﾞ
    432//       *
    433//       * @return   ﾒｯｾｰｼﾞ情報
    434//       * @og.rtnNotNull
    435//       * @see         #getDateFormat( String , String ,String , int )
    436//       */
    437//      public static String getDateFormat( final String key ,final String prmA ,final String prmB ) {
    438//              return getDateFormat( key,prmA,prmB,0 );
    439//      }
    440
    441        /**
    442         * 日付関係の情報を簡易的に処理します｡
    443         *
    444         * 第一引数(key) "XXXX" は､日付処理を行うﾌｫｰﾏｯﾄの予約語になっています｡
    445         * ･Y4     ：４文字の年ﾃﾞｰﾀ(yyyy)を扱います｡
    446         * ･YMD    ：８文字の4-2-2年月日ﾃﾞｰﾀ(yyyyMMdd)を扱います｡
    447         * ･Y2MD   ：６文字の2-2-2年月日ﾃﾞｰﾀ(yyMMdd)を扱います｡
    448         * ･YM     ：６文字の4-2年月ﾃﾞｰﾀ(yyyyMM)を扱います｡
    449         * ･MD     ：４文字の月日ﾃﾞｰﾀ(MMdd)を扱います｡
    450         * ･HMS    ：６文字の2-2-2時分秒ﾃﾞｰﾀ(HHmmss)を扱います｡
    451         * ･HM     ：４文字の2-2時分ﾃﾞｰﾀ(HHmm)を扱います｡6.7.4.1 (2017/02/17)
    452         * ･YMDHMS ：１４文字の4-2-2-2-2-2年月日時分秒ﾃﾞｰﾀ(yyyyMMddHHmmss)を扱います｡
    453         * ･YMDHM  ：１２文字の4-2-2-2-2年月日時分ﾃﾞｰﾀ(yyyyMMddHHmm)を扱います｡
    454         * ･YMDH   ：１０文字の4-2-2-2年月日時ﾃﾞｰﾀ(yyyyMMddHH)を扱います｡
    455         * ･EEE    ：曜日をﾃﾞﾌｫﾙﾄﾛｹｰﾙで表示します｡
    456         *
    457         * F付きは､ﾌｫｰﾏｯﾄされた日付を返します｡
    458         * ･YMDF   ：１０文字の日付表現(yyyy/MM/dd)を扱います｡
    459         * ･YMD-F  ：HTML5 type="date" の日付表現(yyyy-MM-dd)を扱います｡8.0.1.2 (2021/11/19)
    460         * ･Y2MDF  ：８文字の日付表現(yy/MM/dd)を扱います｡
    461         * ･YMF    ：７文字の日付表現(yyyy/MM)を扱います｡
    462         * ･YM-F   ：HTML5 type="month"の日付表現(yyyy-MM)を扱います｡8.0.1.2 (2021/11/19)
    463         * ･HMSF   ：８文字の時刻表現(HH:mm:ss)を扱います｡
    464         * ･HMF    ：５文字の時刻表現(HH:mm)を扱います｡6.7.4.1 (2017/02/17)
    465         * ･YMDHMSF：１９文字の日付表現(yyyy/MM/dd HH:mm:ss)を扱います｡
    466         * ･YMDHMF ：１７文字の日付表現(yyyy/MM/dd HH:mm)を扱います｡
    467         * ･YMDHM-F：１７文字の日付表現(yyyy-MM-ddTHH:mm)を扱います｡8.0.1.2 (2021/11/19)
    468         * ･MDF    ：５文字の月日表現(MM/dd)を扱います｡
    469         * ･MDEF   ：５文字＋曜日の月日表現(MM/dd(EEE))を扱います｡
    470         * ･MDHMF  ：１１文字の月日時分表現(MM/dd HH:mm)を扱います｡ (7.0.0.1 (2018/10/09) 追加)
    471         * ･MD2F   ：漢字の月日表現(MM月dd日)を扱います｡(5.5.5.2 追加)
    472         * ･HM2F   ：漢字の時分表現(HH時mm分)を扱います｡(7.0.0.1 (2018/10/09) 追加)
    473         * ･MDHM2F ：漢字の月日時分表現(MM月dd日 HH時mm分)を扱います｡(7.0.0.1 (2018/10/09) 追加)
    474         * ･GYMDF  ：和暦の年月日表現(GGGGyyyy年MM月dd日)を扱います｡
    475         * ･G2YMDF ：和暦の日付表現(Gyyyy/MM/dd)を扱います｡
    476         * ･GYMF   ：和暦の年月表現(GGGGyyyy年MM月)を扱います｡
    477         * ･GYF    ：和暦の年表現(GGGGyyyy)を扱います｡
    478         *
    479         * ･DIFF   ：日付の差分を求めます｡(7.0.1.1 (2018/10/22) 追加)
    480         *               AA - BB を求め､CCの数値で単位を指定します｡
    481         *
    482         * なお､上記以外のﾌｫｰﾏｯﾄを指定する場合は､XXXX部分に直接記述できます｡(5.5.5.2 追加)
    483         * ただし､基本的には､自由ﾌｫｰﾏｯﾄは､ｴﾗｰﾁｪｯｸがない為､使わないでください｡
    484         *
    485         * 第二引数(prmA) AA は､基準となる日付を､yyyyMMdd形式で指定します｡nullの場合は､現在時刻を使用します｡
    486         * 指定できる日付は､yyyyMMdd形式を推奨しますが､'/' , '-' , ' ' , ':' を削除して使います｡
    487         * ６桁の場合は､yyyyMM + 01 とし､８ｹﾀの場合は､yyyyMMdd とし､14ｹﾀ以上の場合は､前半１４文字を
    488         * yyyyMMddHHmmss として処理します｡それ以外の桁数の場合は､ｴﾗｰになります｡
    489         * たとえば､"2012/09/05 16:52:36" のようなﾌｫｰﾏｯﾄﾃﾞｰﾀの場合､'/' , '-' , ' ' , ':' を削除して
    490         * "20120905165236" に変換後､日付ｵﾌﾞｼﾞｪｸﾄに変換されます｡
    491         *
    492         * 第三引数(prmB) BB は､日付についての加減算処理を行うためのｺﾏﾝﾄﾞを指定します｡
    493         * nullの場合は､なにも加減算処理を行いません｡
    494         * ･SY ：当年の最初の日付にｾｯﾄします｡(当年１月１日)｡CC引数は､-N:N年前､0:当年(=SY)､N:N年後 6.9.2.1 (2018/03/12)
    495         * ･SD ：当月の最初の日付にｾｯﾄします｡(当月１日)｡CC引数は､-N:N月前､0:当月(=SD)､N:N月後､-1:BSD と同じ､1:ASD と同じ
    496         * ･SW ：日付処理の週初め(月曜日)にｾｯﾄします｡日付は当日より前に移動します｡CC引数は､-N:N週前､0:今週(=SW)､N:N週後
    497         * ･SH ：指定の最初の時にｾｯﾄします｡(分秒を0000にする)｡CC引数は､時の倍数(4と指定すれば､4時間単位に前に戻る) 6.7.4.1 (2017/02/17)
    498         * ･SM ：指定の最初の分にｾｯﾄします｡(秒を00にする)｡CC引数は､分の倍数(15と指定すれば､15分単位に前に戻る) 6.7.4.1 (2017/02/17)
    499         * ･SS ：指定の最初の秒にｾｯﾄします｡CC引数は､秒の倍数(15と指定すれば､15秒単位に前に戻る) 6.7.4.1 (2017/02/17)
    500         * ･EY ：当年の最後の日付にｾｯﾄします｡(当年年末)｡CC引数は､-N:N年前､0:当年(=EY)､N:N年後 6.9.2.1 (2018/03/12)
    501         * ･ED ：当月の最後の日付にｾｯﾄします｡(当月月末)｡CC引数は､-N:N月前､0:当月(=ED)､N:N月後､-1:BED と同じ､1:AED と同じ
    502         * ･EW ：日付処理の週末(日曜日)にｾｯﾄします｡日付は当日より後ろに移動します｡CC引数は､-N:N週前､0:今週(=EW)､N:N週後
    503         * ･EH ：指定の次の時にｾｯﾄします｡(分秒を0000にした次の時)｡CC引数は､時の倍数(4と指定すれば､4時間単位に前に進む) 6.7.4.1 (2017/02/17)
    504         * ･EM ：指定の次の分にｾｯﾄします｡(秒を00にした次の分)｡CC引数は､分の倍数(15と指定すれば､15分単位に前に進む) 6.7.4.1 (2017/02/17)
    505         * ･ES ：指定の次の秒にｾｯﾄします｡CC引数は､秒の倍数(15と指定すれば､15秒単位に前に進む) 6.7.4.1 (2017/02/17)
    506         * ･M1 ～ MXXX ：月を指定の分だけ進めます｡M1なら翌月､M6 なら半年後
    507         * ･D1 ～ DXXX ：日を指定の分だけ進めます｡D1なら翌日､D200 なら200日後
    508         * ･H1 ～ HXXX ：時を指定の分だけ進めます｡H1なら１時間後､H24 なら２４時間後(5.5.5.6 (2012/08/31) 追加)
    509         * ･MI  ：分を指定の分だけ進めます｡第四引数(intC) で､時間を指定します｡(6.8.4.1 (2017/12/18) 追加)
    510         * ･YMD ：CC 引数のYMD表記の日付を加減算します｡6.8.4.1 (2017/12/18) 追加
    511         * ･HM  ：CC 引数のHM表記の時刻を加減算します｡6.8.4.1 (2017/12/18) 追加
    512         * ･NO  ：AA 引数がnullの場合､現在時刻ではなく空文字列にします｡  7.0.1.3 (2018/11/12) 追加
    513         * ･(有閑)BSD ：先月の最初の日付にｾｯﾄします｡(先月１日)(5.5.5.2 追加)｡SD -1 と同等
    514         * ･(有閑)BED ：先月の最後の日付にｾｯﾄします｡(先月月末)(5.5.5.2 追加)｡ED -1 と同等
    515         * ･(有閑)ASD ：翌月の最初の日付にｾｯﾄします｡(翌月１日)(5.5.5.2 追加)｡SD 1  と同等
    516         * ･(有閑)AED ：翌月の最後の日付にｾｯﾄします｡(翌月月末)(5.5.5.2 追加)｡ED 1  と同等
    517         *
    518         * 7.0.1.1 (2018/10/22)
    519         *   DATE.DIFF の場合､BB 引数は､日付ﾃﾞｰﾀになります｡AA-BB の関係です｡
    520         *
    521         * CC 引数は､特別な処理で､BB 引数に対して､加算､減算のための数字を指定できます｡(5.7.4.1 (2014/03/14) 追加)
    522         * 従来は､BB 引数が､"H" , "D" , "M" の １文字ﾊﾟﾗﾒｰﾀの場合のみ利用可能でした｡
    523         * これは､"H15" と指定するのと､"H" "15" と指定するのと同じ意味になります｡
    524         * 異なるのは､CC 引数も､(&#064;CC)指定で､ﾘｸｴｽﾄﾊﾟﾗﾒｰﾀが使用できます｡
    525         * 従来は､文字列として結合された状態でしか､BB 引数を渡せませんでしたが､この､CC 引数の
    526         * 追加で､日付の加減算を､ﾊﾟﾗﾒｰﾀ指定できるようになります｡
    527         * 数字以外の文字が指定されたり､ﾊﾟﾗﾒｰﾀの解析結果が NULL の場合には､BB引数自体も無視されます｡
    528         * 注意点は､各 BB 引数に応じて､数字の意味が異なるという事です｡
    529         *
    530         * HXXX,DXXX,MXXX 形式に､CC 引数を付けた場合は､XXX にさらに加算されます｡
    531         * prmB に､数字を使用した場合､(ｺﾏﾝﾄﾞでない場合)にも､CC 引数は､加算されます｡
    532         *
    533         * 7.0.1.1 (2018/10/22)
    534         *   DATE.DIFF の場合､CC 引数は､差分の単位を指定するｷｰﾜｰﾄﾞになります｡AA-BB の結果を､
    535         *   1:年 2:月 3:日 4:時 5:分 6:秒 に換算 して返します｡端数は切り捨てで整数で返します｡
    536         *
    537         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    538         * @og.rev 5.6.1.1 (2013/02/08) prmB処理を､calendarCalc ﾒｿｯﾄﾞへ移動
    539         * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張
    540         * @og.rev 6.4.3.3 (2016/03/04) Map#getOrDefault で対応する｡
    541         * @og.rev 7.0.1.1 (2018/10/22) DATE.DIFF 追加
    542         * @og.rev 7.0.1.3 (2018/11/12) BB 引数に NO追加
    543         * @og.rev 8.0.1.2 (2021/11/19) 日付ﾌｫｰﾏｯﾄ(key引数)に、\\n文字列が含まれる場合、変換しておきます。
    544         *
    545         * @param   key         ﾌｫｰﾏｯﾄの予約語
    546         * @param   prmA        基準となる日付(nullの場合は､処理時刻)
    547         * @param   prmB        処理ｺﾏﾝﾄﾞ
    548         * @param   intC        加減算処理を行うための数字｡0 は､BB引数の従来計算のまま｡
    549         *
    550         * @return   ﾒｯｾｰｼﾞ情報
    551         * @og.rtnNotNull
    552         * @see         #getDateFormat( String )
    553         * @see         #getDateFormat( String , String )
    554         * @see         #getCalendar( String )                                          AA 引数 からｶﾚﾝﾀﾞｵﾌﾞｼﾞｪｸﾄを作成します｡
    555         * @see         #calendarCalc( Calendar , String , int )        BB 引数､CC 引数を元に､日付計算します｡
    556         */
    557        public static String getDateFormat( final String key ,final String prmA ,final String prmB ,final int intC ) {
    558                // 7.0.1.3 (2018/11/12) prmA が null の場合で､prmB が "NO" の場合は､ｾﾞﾛ文字列を返します｡
    559                if( StringUtil.isEmpty( prmA ) && "NO".equalsIgnoreCase( prmB ) ) {
    560                        return "";
    561                }
    562
    563                // prmA が null の場合は､そのまま､現在時刻が使われます｡
    564                final Calendar now = getCalendar( prmA );
    565
    566                // 7.0.1.1 (2018/10/22) DATE.DIFF 追加
    567                if( "DIFF".equalsIgnoreCase( key ) ) {
    568                        return calendarDiff( now,prmB,intC );
    569                }
    570
    571                // 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離｡
    572                calendarCalc( now,prmB,intC );          // 5.7.4.1 (2014/03/14) CC 引数を拡張
    573
    574                // DATE_FORMAT に存在しないﾌｫｰﾏｯﾄを指定しても､ｴﾗｰにしません｡
    575                // ただし､後処理でﾌｫｰﾏｯﾄｴﾗｰになる可能性は残ります｡
    576                // 6.4.3.3 (2016/03/04) Map#getOrDefault を使用します｡
    577                // 8.0.1.2 (2021/11/19) 日付ﾌｫｰﾏｯﾄ(key引数)に、\\n文字列が含まれる場合、変換しておきます。
    578//              final String format = DATE_FORMAT.getOrDefault( key,key );              // 後ろの key は､値が null のときの初期値
    579                final String format ;
    580                if( key.contains( "\\n" ) ) {
    581                        format = key.replace( "\\n" , "\n" );   // \\n を含むなら、DATE_FORMAT には存在しないハズ。
    582                }
    583                else {
    584                        format = DATE_FORMAT.getOrDefault( key,key );
    585                }
    586
    587                // 5.5.0.2 先頭Gの場合は和暦なのでformatterのLocaleを変更する
    588                DateFormat formatter = null;
    589                if( key.indexOf('G') == 0 ){
    590                        formatter = new SimpleDateFormat( format, new Locale("ja","JP","JP"));
    591                }
    592                else{
    593                        formatter = new SimpleDateFormat( format,Locale.JAPAN );
    594                }
    595
    596                return formatter.format( now.getTime() );
    597        }
    598
    599        /**
    600         * 開始前設定値､または 終了後設定値の文字列から､ｵﾌﾟｼｮﾝ文字列を合成します｡
    601         * 基準となる日付に計算した結果を反映させます｡
    602         *
    603         * CC引数の加減算ﾊﾟﾗﾒｰﾀは､0 です｡
    604         *
    605         * @og.rev 5.7.4.1 (2014/03/14) CC 引数を拡張するため､旧ﾒｿｯﾄﾞを再現しておきます｡
    606         *
    607         * @param   now     基準となる日付（Calendarｵﾌﾞｼﾞｪｸﾄ）
    608         * @param   prmB        処理ｺﾏﾝﾄﾞ
    609         */
    610        public static void calendarCalc( final Calendar now,final String prmB ) {
    611                calendarCalc( now,prmB,0 );
    612        }
    613
    614        /**
    615         * 開始前設定値､または 終了後設定値の文字列から､ｵﾌﾟｼｮﾝ文字列を合成します｡
    616         * 基準となる日付に計算した結果を反映させます｡
    617         *
    618         * prmB は､日付についての加減算処理を行うためのｺﾏﾝﾄﾞを指定します｡
    619         * ･SY ：当年の最初の日付にｾｯﾄします｡(当年１月１日)｡CC引数は､-N:N年前､0:当年(=SY)､N:N年後 6.9.2.1 (2018/03/12)
    620         * ･SD ：当月の最初の日付にｾｯﾄします｡(当月１日)｡CC引数は､-N:N月前､0:当月(=SD)､N:N月後､-1:BSD と同じ､1:ASD と同じ
    621         * ･SW ：日付処理の週初め(月曜日)にｾｯﾄします｡日付は当日より前に移動します｡CC引数は､-N:N週前､0:今週(=SW)､N:N週後
    622         * ･SH ：指定の最初の時にｾｯﾄします｡(分秒を0000にする)｡CC引数は､時の倍数(4と指定すれば､4時間単位に前に戻る) 6.7.4.1 (2017/02/17)
    623         * ･SM ：指定の最初の分にｾｯﾄします｡(秒を00にする)｡CC引数は､分の倍数(15と指定すれば､15分単位に前に戻る) 6.7.4.1 (2017/02/17)
    624         * ･SS ：指定の最初の秒にｾｯﾄします｡CC引数は､秒の倍数(15と指定すれば､15秒単位に前に戻る) 6.7.4.1 (2017/02/17)
    625         * ･EY ：当年の最後の日付にｾｯﾄします｡(当年年末)｡CC引数は､-N:N年前､0:当年(=EY)､N:N年後 6.9.2.1 (2018/03/12)
    626         * ･ED ：当月の最後の日付にｾｯﾄします｡(当月月末)｡CC引数は､-N:N月前､0:当月(=ED)､N:N月後､-1:BED と同じ､1:AED と同じ
    627         * ･EW ：日付処理の週末(日曜日)にｾｯﾄします｡日付は当日より後ろに移動します｡CC引数は､-N:N週前､0:今週(=EW)､N:N週後
    628         * ･EH ：指定の次の時にｾｯﾄします｡(分秒を0000にした次の時)｡CC引数は､時の倍数(4と指定すれば､4時間単位に前に進む) 6.7.4.1 (2017/02/17)
    629         * ･EM ：指定の次の分にｾｯﾄします｡(秒を00にした次の分)｡CC引数は､分の倍数(15と指定すれば､15分単位に前に進む) 6.7.4.1 (2017/02/17)
    630         * ･ES ：指定の次の秒にｾｯﾄします｡CC引数は､秒の倍数(15と指定すれば､15秒単位に前に進む) 6.7.4.1 (2017/02/17)
    631         * ･M1 ～ MXXX ：月を指定の分だけ進めます｡M1なら翌月､M6 なら半年後
    632         * ･D1 ～ DXXX ：日を指定の分だけ進めます｡D1なら翌日､D200 なら200日後
    633         * ･H1 ～ HXXX ：時を指定の分だけ進めます｡H1なら１時間後､H24 なら２４時間後(5.5.5.6 (2012/08/31) 追加)
    634         * ･MI  ：分を指定の分だけ進めます｡第四引数(intC) で､時間を指定します｡(6.8.4.1 (2017/12/18) 追加)
    635         * ･YMD ：CC 引数のYMD表記の日付を加減算します｡6.8.4.1 (2017/12/18) 追加
    636         * ･HM  ：CC 引数のHM表記の時刻を加減算します｡6.8.4.1 (2017/12/18) 追加
    637         * ･NO  ：AA 引数がnullの場合､現在時刻ではなく空文字列にします｡  7.0.1.3 (2018/11/12) 追加
    638         * ･(有閑)BSD ：先月の最初の日付にｾｯﾄします｡(先月１日)(5.5.5.2 追加)｡SD-1 と同等
    639         * ･(有閑)BED ：先月の最後の日付にｾｯﾄします｡(先月月末)(5.5.5.2 追加)｡ED-1 と同等
    640         * ･(有閑)ASD ：翌月の最初の日付にｾｯﾄします｡(翌月１日)(5.5.5.2 追加)｡SD1  と同等
    641         * ･(有閑)AED ：翌月の最後の日付にｾｯﾄします｡(翌月月末)(5.5.5.2 追加)｡ED1  と同等
    642         * ･数字：日を指定の分だけ進めます｡D1 ～ DXXX の簡略系
    643         *
    644         * CC 引数は､特別な処理で､BB 引数に対して､加算､減算のための数字を指定できます｡(5.7.4.1 (2014/03/14) 追加)
    645         * HXXX,DXXX,MXXX 形式に､CC 引数を付けた場合は､XXX にさらに加算されます｡
    646         * prmB に､数字を使用した場合､(ｺﾏﾝﾄﾞでない場合)にも､CC 引数は､加算されます｡
    647         * 6.8.4.1 (2017/12/18) BB 引数に､HM を指定した場合､時分のﾃﾞｰﾀを加算します｡この場合､時に関しては､24時間を越える
    648         * 場合は､日付に加算されます｡例えば､翌朝の６時を指定する場合､3000 と指定することで､１日＋0600 となります｡
    649         *
    650         * @og.rev 5.6.1.1 (2013/02/08) getDateFormat( String ,String ,String ) から分離｡
    651         * @og.rev 5.7.4.1 (2014/03/14) H1 ～ HXXX ：時を指定の分だけ進める処理が実装されていなかった｡
    652         * @og.rev 5.7.4.1 (2014/03/14) CC 引数追加
    653         * @og.rev 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    654         * @og.rev 6.8.4.1 (2017/12/18) YMD , HM , MI 追加
    655         * @og.rev 6.9.2.1 (2018/03/12) 年関連の機能(Y4,SY,EY)追加
    656         * @og.rev 7.0.1.3 (2018/11/12) BB 引数に NO追加
    657         *
    658         * @param   now     基準となる日付（Calendarｵﾌﾞｼﾞｪｸﾄ）
    659         * @param   prmB        処理ｺﾏﾝﾄﾞ
    660         * @param   intC        加減算処理を行うための数字｡0 は､BB引数の従来計算のまま｡
    661         */
    662        public static void calendarCalc( final Calendar now , final String prmB , final int intC ) {
    663
    664                // 基準は､intC == 0 の場合
    665                if( prmB != null && prmB.length() > 0 ) {                               // 6.9.2.1 (2018/03/12) 年関連の機能(Y4,SY,EY)追加
    666                        if( "SY".equals( prmB ) ) {                                                     // (当年１月１日)
    667                                if( intC != 0 ) { now.add( Calendar.YEAR,intC ); }
    668                                now.set( Calendar.DAY_OF_YEAR,1 );                              // 現在の年の何日目かで指定します｡
    669                        }
    670                        else if( "EY".equals( prmB ) ) {                                        // (当年年末)
    671                                if( intC != 0 ) { now.add( Calendar.YEAR,intC ); }
    672                                now.set( Calendar.MONTH,11 );                                   // 月は､0～11 の値で指定｡
    673                                now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) );
    674                        }
    675                        else if( "SD".equals( prmB ) ) {                                                        // (当月１日)
    676                                if( intC != 0 ) { now.add( Calendar.MONTH,intC ); }     // 5.7.4.1 (2014/03/14) CC 引数追加
    677                                now.set( Calendar.DATE,1 );
    678                        }
    679                        else if( "ED".equals( prmB ) ) {                                        // (当月月末)
    680                                if( intC != 0 ) { now.add( Calendar.MONTH,intC ); }     // 5.7.4.1 (2014/03/14) CC 引数追加
    681                                now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) );
    682                        }
    683                        else if( "SH".equals( prmB ) ) {                                        // (時戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    684                                // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にｷｬｽﾄしている
    685//                              final int hh = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ;       // 切捨て
    686                                final int hh = intC == 0 ? 0 : ( now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ;      // 切捨て
    687                                now.set( Calendar.HOUR_OF_DAY,hh );
    688                                now.set( Calendar.MINUTE     ,0 );
    689                                now.set( Calendar.SECOND     ,0 );
    690                                now.set( Calendar.MILLISECOND,0 );
    691                        }
    692                        else if( "SM".equals( prmB ) ) {                                        // (分戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    693                                // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にｷｬｽﾄしている
    694//                              final int mm = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.MINUTE ) / intC ) * intC ;    // 切捨て
    695                                final int mm = intC == 0 ? 0 : ( now.get( Calendar.MINUTE ) / intC ) * intC ;   // 切捨て
    696                                now.set( Calendar.MINUTE     ,mm );
    697                                now.set( Calendar.SECOND     ,0 );
    698                                now.set( Calendar.MILLISECOND,0 );
    699                        }
    700                        else if( "SS".equals( prmB ) ) {                                        // (秒戻し) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    701                                // 6.9.8.0 (2018/05/28) FindBugs:整数の除算の結果を double または float にｷｬｽﾄしている
    702//                              final int ss = intC == 0 ? 0 : (int)Math.floor( now.get( Calendar.SECOND ) / intC ) * intC ;    // 切捨て
    703                                final int ss = intC == 0 ? 0 : ( now.get( Calendar.SECOND ) / intC ) * intC ;   // 切捨て
    704                                now.set( Calendar.SECOND     ,ss );
    705                                now.set( Calendar.MILLISECOND,0 );
    706                        }
    707                        else if( "EH".equals( prmB ) ) {                                        // (時進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    708                                final int hh = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.HOUR_OF_DAY ) / intC ) * intC ;        // 切り上げ
    709                                if( hh == 0 || hh >= 24 ) {
    710                                        now.add( Calendar.DATE       ,1 );                      // 日を加算
    711                                        now.set( Calendar.HOUR_OF_DAY,0 );
    712                                }
    713                                else {
    714                                        now.set( Calendar.HOUR_OF_DAY,hh );
    715                                }
    716                                now.set( Calendar.MINUTE     ,0 );
    717                                now.set( Calendar.SECOND     ,0 );
    718                                now.set( Calendar.MILLISECOND,0 );
    719                        }
    720                        else if( "EM".equals( prmB ) ) {                                        // (分進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    721                                final int mm = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.MINUTE ) / intC ) * intC ;             // 切切り上げ
    722                                if( mm == 0 || mm >= 60 ) {
    723                                        now.add( Calendar.HOUR_OF_DAY,1 );                      // 時を加算
    724                                        now.set( Calendar.MINUTE     ,0 );
    725                                }
    726                                else {
    727                                        now.set( Calendar.MINUTE,mm );
    728                                }
    729                                now.set( Calendar.SECOND     ,0 );
    730                                now.set( Calendar.MILLISECOND,0 );
    731                        }
    732                        else if( "ES".equals( prmB ) ) {                                        // (秒進め) 6.7.4.1 (2017/02/17) SH,SM,SS,EH,EM,ES 追加
    733                                final int ss = intC == 0 ? 0 : (int)Math.ceil( (double)now.get( Calendar.SECOND ) / intC ) * intC ;     // 切り上げ
    734                                if( ss == 0 || ss >= 60 ) {
    735                                        now.add( Calendar.MINUTE ,1 );                          // 分を加算
    736                                        now.set( Calendar.SECOND ,0 );
    737                                }
    738                                else {
    739                                        now.set( Calendar.SECOND,ss );
    740                                }
    741                                now.set( Calendar.MILLISECOND,0 );
    742                        }
    743                        else if( "BSD".equals( prmB ) ) {                                       // (先月１日)
    744                                // 5.7.4.1 (2014/03/14) CC 引数追加
    745                                now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,1 );
    746                        }
    747                        else if( "BED".equals( prmB ) ) {                                       // (先月月末)
    748                                // 5.7.4.1 (2014/03/14) CC 引数追加
    749                                now.add( Calendar.MONTH,intC-1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) );
    750                        }
    751                        else if( "ASD".equals( prmB ) ) {                                       // (翌月１日)
    752                                // 5.7.4.1 (2014/03/14) CC 引数追加
    753                                now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,1 );
    754                        }
    755                        else if( "AED".equals( prmB ) ) {                                       // (翌月月末)
    756                                // 5.7.4.1 (2014/03/14) CC 引数追加
    757                                now.add( Calendar.MONTH,intC+1 ); now.set( Calendar.DATE,now.getActualMaximum( Calendar.DATE ) );
    758                        }
    759                        else if( "SW".equals( prmB ) ) {                                        // 週初め(月曜日)ｾｯﾄ
    760                                // 5.7.4.1 (2014/03/14) CC 引数追加
    761                                if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); }    // まず､基準の日付を週単位で加減算する｡
    762
    763                                // 日付型文字列入力ﾃﾞｰﾀの開始日を月曜日にｾｯﾄします｡
    764                                // SUNDAY=1 , MONDAY=2 になります｡月曜日との差だけ､前に戻します｡
    765                                // 指定日が日曜日の場合は､月曜日まで戻します｡
    766
    767                                final int shu = now.get( Calendar.DAY_OF_WEEK ) - Calendar.MONDAY ;
    768
    769                                if(      shu > 0 ) { now.add( Calendar.DATE, -shu ); }
    770                                else if( shu < 0 ) { now.add( Calendar.DATE, -6 );   }
    771                        }
    772                        else if( "EW".equals( prmB ) ) {                                        // 週末(日曜日)にｾｯﾄ
    773                                // 5.7.4.1 (2014/03/14) CC 引数追加
    774                                if( intC != 0 ) { now.add( Calendar.DATE,intC*7 ); }    // まず､基準の日付を週単位で加減算する｡
    775
    776                                // 日付型文字列入力ﾃﾞｰﾀの終了日を日曜日にｾｯﾄします｡
    777                                // SUNDAY=1 , MONDAY=2 になります｡日曜日になるように､先に進めます｡
    778                                final int shu = now.get( Calendar.DAY_OF_WEEK ) ;
    779                                if( shu != Calendar.SUNDAY ) { now.add( Calendar.DATE, 8-shu ); }
    780                        }
    781                        // 6.8.4.1 (2017/12/18) YMD 追加(年月日の繰り上げ表記を加味した加算)
    782                        else if( "YMD".equals( prmB ) ) {
    783                                final int year  = intC / 10000;
    784                                final int month = ( intC / 100 ) % 100;
    785                                final int date  = intC % 100;
    786
    787                                now.add( Calendar.YEAR  , year );
    788                                now.add( Calendar.MONTH , month );
    789                                now.add( Calendar.DATE  , date );
    790                        }
    791                        // 6.8.4.1 (2017/12/18) HM 追加(時分の２４時間表記を加味した加算)
    792                        else if( "HM".equals( prmB ) ) {                        // 注意：prmB.charAt(0) == 'H' より先に判定しておきます｡
    793                                final int hour   = intC / 100;
    794                                final int minute = intC % 100;
    795
    796                                now.add( Calendar.HOUR_OF_DAY   , hour );
    797                                now.add( Calendar.MINUTE                , minute );
    798                        }
    799                        // 6.8.4.1 (2017/12/18) HM 分を指定の分だけ進めます｡
    800                        else if( "MI".equals( prmB ) ) {                        // 注意：prmB.charAt(0) == 'M' より先に判定しておきます｡
    801                                now.add( Calendar.MINUTE                , intC );
    802                        }
    803                        // 7.0.1.3 (2018/11/12) AA 引数がnullの場合､現在時刻ではなく空文字列にします｡
    804                        else if( "NO".equals( prmB ) ) {
    805                                ;       // 何もしません｡
    806                        }
    807                        // 6.9.2.1 (2018/03/12) Y1 ～ YXXX ：年を指定の分だけ進める処理
    808                        else if( prmB.charAt(0) == 'Y' ) {
    809                                int year = intC ;
    810                                if( prmB.length() > 1 ) { year += Integer.parseInt( prmB.substring( 1 ) ); }
    811                                now.add( Calendar.YEAR , year );
    812                        }
    813                        else if( prmB.charAt(0) == 'H' ) {                      // 6.1.0.0 (2014/12/26) refactoring
    814                                int hour = intC ;
    815                                if( prmB.length() > 1 ) { hour += Integer.parseInt( prmB.substring( 1 ) ); }
    816                                now.add( Calendar.HOUR_OF_DAY , hour );
    817                        }
    818                        else if( prmB.charAt(0) == 'D' ) {                      // 6.1.0.0 (2014/12/26) refactoring
    819                                int day = intC ;
    820                                if( prmB.length() > 1 ) { day += Integer.parseInt( prmB.substring( 1 ) ); }
    821                                now.add( Calendar.DATE, day );
    822                        }
    823                        else if( prmB.charAt(0) == 'M' ) {                      // 6.1.0.0 (2014/12/26) refactoring
    824                                int month = intC ;
    825                                if( prmB.length() > 1 ) { month += Integer.parseInt( prmB.substring( 1 ) ); }
    826                                now.add( Calendar.MONTH , month );
    827                        }
    828                        else {
    829                                // 上記のﾊﾟﾀｰﾝ以外は､数字（加減算する日数）なので､変換できなければ､ﾌｫｰﾏｯﾄｴﾗｰ
    830                                try {
    831                                        final int day = Integer.parseInt( prmB ) + intC ;       // 5.7.4.1 (2014/03/14) CC 引数追加
    832                                        now.add( Calendar.DATE, day );
    833                                }
    834                                catch( final NumberFormatException ex ) {
    835                                        final String errMsg = "日付変数ﾊﾟﾗﾒｰﾀに､不正な値が指定されました｡以下の中から指定しなおしてください｡"
    836//                                                              + "指定可能：[SD,ED,SW,SH,SM,SS,EW,EH,EM,ES,H1～HXXX,D1～DXXX,M1～MXXX,HMS,BSD,BED,ASD,AED]"
    837                                                                + "指定可能：[SY,SD,SW,SH,SM,SS,EY,ED,EW,EH,EM,ES,M1～MXXX,D1～DXXX,H1～HXXX,MI,YMD,HM,NO]"
    838                                                                + " prmB=[" + prmB + "]" ;
    839                                        throw new OgRuntimeException( errMsg,ex );
    840                                }
    841                        }
    842                }
    843        }
    844
    845        /**
    846         * 日付の差分を求めます｡
    847         * timeA - timeB を求め､intCの数値で単位を指定します｡
    848         *
    849         * intC は､1:年 2:月 3:日 4:時 5:分 6:秒 に換算した単位での差分になります｡
    850         * 端数は出ません｡
    851         *
    852         * @og.rev 7.0.1.1 (2018/10/22) DATE.DIFF 追加
    853         * @og.rev 7.2.9.4 (2020/11/20) spotbugs:switch 文の2つの case のために同じｺｰﾄﾞを使用しているﾒｿｯﾄﾞ
    854         *
    855         * @param   timeA   基準となる日付（Calendarｵﾌﾞｼﾞｪｸﾄ）
    856         * @param   prmB        日付ﾃﾞｰﾀになります｡AA-BB の関係です｡
    857         * @param   intC        差分の単位を指定するｷｰﾜｰﾄﾞ(1:年 2:月 3:日 4:時 5:分 6:秒 に換算)
    858         * @return      指定の時間の差(timeA - timeB ﾏｲﾅｽもある)
    859         */
    860        public static String calendarDiff( final Calendar timeA , final String prmB , final int intC ) {
    861                final Calendar timeB = getCalendar( prmB );
    862
    863                final int diff ;
    864                if( intC == 1 ) {                       // 差分年
    865                        diff = timeA.get( Calendar.YEAR ) - timeB.get( Calendar.YEAR );
    866                }
    867                else if( intC == 2 ) {          // 差分月数
    868                        diff = ( timeA.get( Calendar.YEAR  ) - timeB.get( Calendar.YEAR  ) ) * 12
    869                                +  ( timeA.get( Calendar.MONTH ) - timeB.get( Calendar.MONTH ) ) ;
    870
    871        //              // 月の計算ﾛｼﾞｯｸ( http://javatechnology.net/java/date-diff-month/ )
    872        //              // ﾏｲﾅｽ計算も必要なので､今回は不採用
    873        //              timeA.set( Calendar.DATE, 1 );          // 端数を無視するため､1日にｾｯﾄします｡
    874        //              timeB.set( Calendar.DATE, 1 );          // 同上
    875
    876        //              int count = 0;
    877        //              while( timeA.before( timeB ) ) {
    878        //                      timeA.add( Calendar.MONTH, 1 );
    879        //                      count++;
    880        //              }
    881        //              diff = count;
    882                }
    883                else {
    884                        final long diffSec = timeA.getTimeInMillis() - timeB.getTimeInMillis() ;        // 時間の差(ﾐﾘ秒)
    885
    886                        switch( intC ) {
    887        //                      case 3:  diff = (int)( diffSec / DD );  break;          // 日単位                  // 7.2.9.4 (2020/11/20)
    888                                case 4:  diff = (int)( diffSec / HH );  break;          // 時単位
    889                                case 5:  diff = (int)( diffSec / MM );  break;          // 分単位
    890                                case 6:  diff = (int)( diffSec / SS );  break;          // 秒単位
    891                                default: diff = (int)( diffSec / DD );  break;          // (初期値)日単位
    892                        }
    893                }
    894
    895                return Integer.toString( diff ) ;
    896        }
    897
    898        /**
    899         * 指定の引数の日付け文字列より､ｶﾚﾝﾀﾞｵﾌﾞｼﾞｪｸﾄを作成します｡
    900         * 引数は､数字以外の文字を削除した状態に変換後､処理に回します｡
    901         * 不要な文字を削除した状態で､８文字以上になるように指定してください｡
    902         * 例外的に､６文字の場合は､yyyyMM01 とみなして､"01" 文字列を付与します｡
    903         * 引数に null を指定すると､現在時刻のｶﾚﾝﾀﾞを返します｡
    904         * それ以外のﾃﾞｰﾀで､８ｹﾀ以下の場合は､RuntimeException が発生します｡
    905         * ８ｹﾀ以上１４ｹﾀ未満の場合は､８ｹﾀ分を､年月日に分離したｶﾚﾝﾀﾞ
    906         * ｵﾌﾞｼﾞｪｸﾄを作成します｡１４ｹﾀ以上で初めて､時分秒を含むｶﾚﾝﾀﾞ
    907         * を作成します｡
    908         *
    909         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    910         * @og.rev 5.5.8.2 (2012/11/09) value の判定に､null と ｾﾞﾛ文字列を判定する｡
    911         *
    912         * @param value 日付け文字列
    913         *
    914         * @return      ｶﾚﾝﾀﾞｵﾌﾞｼﾞｪｸﾄ(引数がnullの場合は､現在時刻)
    915         * @og.rtnNotNull
    916         */
    917        public static Calendar getCalendar( final String value ) {
    918                final Calendar cal = Calendar.getInstance();
    919
    920                if( value == null || value.isEmpty() ) { return cal; }          // 5.5.8.2 (2012/11/09) null と ｾﾞﾛ文字列を判定する｡
    921
    922                // 日付表記に不要な文字を削除します｡
    923                String dateStr = parseNumber( value ) ;
    924
    925                if( dateStr.length() == 6 ) { dateStr = dateStr + "01"; }       // yyyyMM01 形式に無理やり合わせる｡
    926                else if( dateStr.length() < 8 ) {
    927                        final String errMsg = "日付指定ﾊﾟﾗﾒｰﾀに､不正な値が指定されました｡value=[" + value + "]" ;
    928                        throw new OgRuntimeException( errMsg );
    929                }
    930
    931                cal.clear();    // 日付文字列が存在するので､ｶﾚﾝﾀﾞをﾘｾｯﾄ
    932
    933                final int year   = Integer.parseInt( dateStr.substring( 0,4 ) );
    934                final int month  = Integer.parseInt( dateStr.substring( 4,6 ) ) - 1;
    935                final int date   = Integer.parseInt( dateStr.substring( 6,8 ) );
    936
    937                // 6.3.9.0 (2015/11/06) Use one line for each declaration, it enhances code readability.(PMD)
    938                int hour  =0;
    939                int minute=0;
    940                int second=0;
    941                if( dateStr.length() >= 14 ) {
    942                        hour   = Integer.parseInt( dateStr.substring( 8,10 ) );
    943                        minute = Integer.parseInt( dateStr.substring( 10,12 ) );
    944                        second = Integer.parseInt( dateStr.substring( 12,14 ) );
    945                }
    946
    947                cal.set( year,month,date,hour,minute,second );
    948
    949                return cal;
    950        }
    951
    952        /**
    953         * 指定の引数の日付け文字列(yyyyMMdd)より､日付を加算して返します｡
    954         * ﾏｲﾅｽを与えると､減算します｡
    955         * 日付以上の精度の文字列を渡しても､日付のみの計算となります｡
    956         * 結果は､引数の日付ﾌｫｰﾏｯﾄとは全く別で､yyyyMMdd の８文字形式になります｡
    957         * 引数に null を渡すと､実行時の日付をﾍﾞｰｽとして処理します｡
    958         *
    959         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    960         *
    961         * @param baseDate 日付け文字列(yyyyMMdd)
    962         * @param plus     加算する日数(過去にするにはﾏｲﾅｽ値を指定する)
    963         *
    964         * @return      結果の日付(yyyyMMdd)
    965         * @og.rtnNotNull
    966         */
    967        public static String getDatePlus( final String baseDate,final int plus ) {
    968                final Calendar cal = getCalendar( baseDate );
    969                cal.add( Calendar.DATE,plus );
    970
    971                return DateSet.getDate( cal.getTimeInMillis() , "yyyyMMdd" );
    972        }
    973
    974        /**
    975         * 現在の月に､指定の月数をﾌﾟﾗｽした日付文字列を返します｡
    976         * 日付文字列のﾌｫｰﾏｯﾄは､"yyyyMM" です｡
    977         * 指定する月数にﾏｲﾅｽを指定すると､減算できます｡
    978         *
    979         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    980         *
    981         * @param baseDate 日付け文字列(yyyyMM)
    982         * @param plus     加算する月数(過去にするにはﾏｲﾅｽ値を指定する)
    983         *
    984         * @return      指定の月数をﾌﾟﾗｽした日付文字列(yyyyMM)
    985         * @og.rtnNotNull
    986         */
    987        public static String getMonthPlus( final String baseDate,final int plus ) {
    988                final Calendar cal = getCalendar( baseDate );
    989                cal.set( Calendar.DATE, 1 );            // 当月の 1 日に設定
    990                cal.add( Calendar.MONTH , plus );
    991
    992                return DateSet.getDate( cal.getTimeInMillis() , "yyyyMM" );
    993        }
    994
    995        /**
    996         * 指定の引数の日付け文字列(yyyyMMdd､yyyyMMddHHmmss)に､日付を加算して返します｡
    997         * ﾏｲﾅｽを与えると､減算します｡
    998         *
    999         * 指定する日付には､単位を付与することが可能です｡
    1000         * 単位は､yyyyMMddHHmmss 形式の１文字を指定します｡大文字､小文字も識別します｡
    1001         * plus="5M" とすれば､５か月､plus="5d"  とすれば､５日 追加します｡
    1002         * plus に単位を付けない場合は､tani に指定の単位を使います｡
    1003         * plus そのものが､null か､isEmpty の場合は､加算は､1 になります｡
    1004         *
    1005         * baseDate 文字列を日付文字列に変換後､Calendar で計算し､結果を､format 形式に変換します｡
    1006         * 引数に null を渡すと､実行時の日付をﾍﾞｰｽとして処理します｡
    1007         *
    1008         * @og.rev 5.6.1.0 (2013/02/01) 新規作成
    1009         *
    1010         * @param baseDate 日付け文字列(yyyyMMdd､yyyyMMddHHmmss 形式の日付文字列)
    1011         * @param plus     加算する日数(日付単位を含む｡単位は､y,M,d,H,m,s の文字で､大文字小文字の区別があります)
    1012         * @param defTani  日付単位が未指定の場合の初期単位('y','M','d','H','m','s' のどれか)
    1013         * @param format   返す日付文字列のﾌｫｰﾏｯﾄ(yyyyMMdd､yyyyMMddHHmmss)
    1014         *
    1015         * @return      結果の日付(yyyyMMdd)
    1016         * @throws      NumberFormatException 加算する日数の単位が('y','M','d','H','m','s')以外の場合｡
    1017         * @og.rtnNotNull
    1018         */
    1019        public static String getDatePlus( final String baseDate,final String plus,final int defTani,final String format ) {
    1020
    1021                int addSu = 1;                          // 初期値(plus が null や Empty の場合は､＋１となる)
    1022                int tani  = defTani;
    1023
    1024                if( plus != null && !plus.isEmpty() ) {
    1025                        boolean flag = true;    // 日付単位を持っているかどうか｡持っている場合は､true
    1026                        final char ch = plus.charAt( plus.length()-1 );         // 最後の一文字を取得(単位か､数字本体)
    1027                        switch( ch ) {
    1028                                case 'y' : tani = Calendar.YEAR;                break ;
    1029                                case 'M' : tani = Calendar.MONTH;               break ;
    1030                                case 'd' : tani = Calendar.DATE;                break ;
    1031                                case 'H' : tani = Calendar.HOUR_OF_DAY; break ;
    1032                                case 'm' : tani = Calendar.MINUTE;              break ;
    1033                                case 's' : tani = Calendar.SECOND;              break ;
    1034                                default  : flag = false;        break ;         // 日付単位を持っていない｡
    1035                        }
    1036                        if( flag ) {
    1037                                addSu = Integer.parseInt( plus.substring( 0,plus.length()-1 ) );        // 日付単位 あり
    1038                        }
    1039                        else {
    1040                                addSu = Integer.parseInt( plus ) ;                                                                      // 日付単位 なし
    1041                        }
    1042                }
    1043
    1044                final Calendar cal = getCalendar( baseDate );
    1045                cal.add( tani,addSu );
    1046
    1047                return DateSet.getDate( cal.getTimeInMillis() , format );
    1048        }
    1049
    1050        /**
    1051         * 指定の日付文字列を指定の形式の文字列に変換します｡
    1052         * 入力の日付文字列は､"yyyyMMddHHmmss" または､ "yyyyMMdd" です｡
    1053         * 記号が入っている場合でも､一応処理します｡
    1054         * 指定のﾌｫｰﾏｯﾄも､同様に､yyyyMMddHHmmss 形式で指定します｡
    1055         *
    1056         * @og.rev 7.0.1.2 (2018/11/04) 新規登録
    1057         *
    1058         * @param ymd           日付け文字列(yyyyMM)
    1059         * @param format        加算する月数(過去にするにはﾏｲﾅｽ値を指定する)
    1060         *
    1061         * @return      指定の日付文字列を指定の形式の文字列に変換
    1062         * @og.rtnNotNull
    1063         */
    1064        public static String toYmd( final String ymd,final String format ) {
    1065                final Calendar cal = getCalendar( ymd );
    1066
    1067                return DateSet.getDate( cal.getTimeInMillis() , format );
    1068        }
    1069
    1070        /**
    1071         * 指定の年月文字列のFrom-Toを､文字列の配列で返します｡
    1072         * "yyyyMM" 形式の範囲内の文字列配列を作成します｡
    1073         *
    1074         * ※ endがnullの場合は､beginそのものを配列にｾｯﾄして返します｡
    1075         *    つまり､1件のみの配列になります｡
    1076         * ※ end == beginの場合は､配列は､ｾﾞﾛ個の配列になります｡
    1077         *
    1078         * @og.rev 7.0.5.0 (2019/09/09) 新規追加
    1079         *
    1080         * @param begin         開始の年月(含む)
    1081         * @param end           終了の年月(含まない)
    1082         * @param step          加算する月数
    1083         *
    1084         * @return      指定の年月文字列のFrom-Toを､文字列の配列で返す
    1085         * @og.rtnNotNull
    1086         */
    1087        public static String[] stepYM( final String begin,final String end,final int step ) {
    1088                final List<String> list = new ArrayList<>();
    1089
    1090                if( StringUtil.isNull( end ) ) {
    1091                        list.add( begin );
    1092                }
    1093                else {
    1094                        final Calendar timeA = getCalendar( begin );
    1095                        final Calendar timeB = getCalendar( end );
    1096
    1097                        while( timeA.before( timeB ) ) {
    1098                                list.add( DateSet.getDate( timeA.getTimeInMillis() , "yyyyMM" ) );
    1099                                timeA.add( Calendar.MONTH, 1 );
    1100                        }
    1101                }
    1102
    1103                 return list.toArray( new String[list.size()] ) ;
    1104        }
    1105}