- ベストアンサー
日付や時刻の01を 1に変換する方法
- 日付や時刻の01を 1に変換する方法についてアドバイスをお願いします。
- SimpleDateFormatで指定された書式の文字列にした後、年月日時分秒ミリ秒の01~09を 1~9のように前0を半角スペースに一括変換したい方法を教えてください。
- 検討案として、引数の書式を修正してからSimpleDateFormatで変換する方法と、SimpleDateFormatで変換後の文字列に置換する方法を考えていますが、どちらが適切かアドバイスをいただきたいです。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
こんなのでどうでしょうか。 (「_」は半角スペースの意味で使用しています。) (1)パターン文字ごとに分解する。 (2)1つのパターン文字のみでフォーマットする。 (3)それぞれの前0を半角スペースに置換する。(半角スペースのみになってしまう場合は0に置換。) (4)フォーマット後の分解した文字列を連結する。 例:yyyy/MM/dd_HH:mm:ss.SSS形式の日時が2009/07/23_09:10:00.000の場合 (1)yyyy/MM/dd_HH:mm:ss.SSSを[yyyy][/][MM][/][dd][_][HH][:][mm][:][ss][.][SSS]の13個に分解する。 (2)(1)で分解した13個をそれぞれSimpleDateFormatの引数にしてフォーマットする。 記号[/]は以下を実行するとわかるが、そのまま「/」が出力される。 SimpleDateFormat formatter = new SimpleDateFormat("/"); String hoge = formatter.format(new Date(System.currentTimeMillis())); System.out.println(hoge); (3)それぞれの前0を半角スペースに置換する。対象は以下。 月は[07]となるので[0]を半角スペースに置換。 時は[09]となるので[0]を半角スペースに置換。 秒は[00]となり、半角スペースのみになってしまうので[0]とする。 ミリ秒(以下省略。) (4)(3)の置換後を連結する。
その他の回答 (5)
- pcbeginner
- ベストアンサー率46% (261/560)
パターン文字列を分解する部分のコードを書いてみました。 (ってまだ見てるかな?) 稚拙なコードですが、参考になれば。(パターンも2個ほどしか試していません。) ※インデントをつけるために全角スペースを使用しています。 package test; import java.util.ArrayList; public class Hoge{ /** * SimpleDateFormat用のパターン文字列を連続する同じ文字に分解した各要素を格納したArrayListを返す。<br> * 「 * '(シングルクォーテーション)」で囲まれた部分はSimpleDateFormatでは「テキスト」として扱うため、内容によらず一まとめとして格納する。<br> * 対応する「'(シングルクォーテーション)」がない、1つのみの場合は、1つの「'(シングルクォーテーション)」として格納する。<br> * (例)<br> * ※以降「_」は半角スペースとする。<br> * 分解対象のパターン文字列:yyyy/MM/dd_HH:mm:ss.SSS'''yyyy/MM/dd_HH:mm:ss.SSS''<br> * 分解後のArrayListに格納される各要素:[yyyy][/][MM][/][dd][_][HH][:][mm][:][ss][.][SSS]['']['yyyy/MM/dd_HH:mm:ss.SSS']['] * * @param pattern 分解するSimpleDateFormat用のパターン文字列 * @return 分解後のパターン文字列を格納したArrayList */ public static ArrayList<String> divideFormatPattern(String pattern){ ArrayList<String> rtn = new ArrayList<String>(); //戻り値用 ArrayList<Integer> al_sq_index = getSingleQuotationIndex(pattern); //引数pattern中のシングルクォーテーションの位置を格納 ArrayList<SingleQuotationSet> al_sq_set = new ArrayList<SingleQuotationSet>(); //シングルクォーテーションのセットの位置情報を格納 //シングルクォーテーションのセットを作成 for (int i = 0; i < al_sq_index.size(); i = i + 2) { SingleQuotationSet sq_set = new SingleQuotationSet(); //シングルクォーテーションのセット sq_set.setBegin(al_sq_index.get(i)); //セットの開始の位置を設定 if (i + 1 < al_sq_index.size()) { //次のシングルクォーテーションがあればセットの終了位置として設定 sq_set.setEnd(al_sq_index.get(i + 1)); } al_sq_set.add(sq_set); } int begin = 0; // 分割開始位置(初期値は先頭) char c_ = Character.MIN_VALUE; // 比較用の1つ前の文字(初期値はありえない文字) SingleQuotationSet sq_set = null; for (int i = 0, j = 0; i < pattern.length(); i++) { int sq_index = -1; // シングルクォーテーションの位置 if (!al_sq_set.isEmpty()) { // シングルクォーテーションがある場合 sq_set = al_sq_set.get(j); // シングルクォーテーションのセット sq_index = sq_set.getBegin(); // ↑のセットから開始位置取得 } char c = pattern.charAt(i); // 現在の位置(i)の文字 // 比較 if (c == c_) { // 前の文字と同じ場合 // 最後の文字かどうか if (i == pattern.length() - 1) { // 最後の場合は切り出して格納 rtn.add(pattern.substring(begin)); } else { // 最後の文字でない場合は続行 continue; } } else { // 前の文字と違う場合 if (c != '\'') { // シングルクォーテーションでない場合は分解して格納 rtn.add(pattern.substring(begin, i)); } // シングルクォーテーション対応 if (i == sq_index && sq_set.getEnd() != -1) { // 現在の位置(i)がシングルクォーテーションの開始位置の場合 // かつ // 対応する閉じシングルクォーテーションがある場合 // 分割するパターン文字列からシングルクォーテーション間を分割する rtn.add(pattern.substring(sq_index, sq_set.getEnd() + 1)); // 分割開始位置の再設定(閉じシングルクォーテーションの次) begin = sq_set.getEnd(); // 現在の位置(i)も再設定 i = sq_set.getEnd(); // 比較用の1つ前の文字の再設定(必ず違う文字としたいため通常ありえない文字にしておく) c_ = Character.MIN_VALUE; // 次のシングルクォーテーション j++; // 続行 continue; } // 最後の文字かどうか if (i == pattern.length() - 1) { // 最後の場合は切り出して格納 rtn.add(pattern.substring(i)); } begin = i;// 開始位置再設定 c_ = c;// 前の文字再設定 } } return rtn; } /** * 引数strにおける「'(シングルクォーテーション)」の位置を格納したArrayListを返す。 * * @param str 「'(シングルクォーテーション)」を探す文字列 * @return 引数strにおける「'(シングルクォーテーション)」の位置を格納したArrayList、「'(シングルクォーテーション)」がない場合はnull */ public static ArrayList<Integer> getSingleQuotationIndex(String str){ ArrayList<Integer> rtn = null; if (str != null && !str.isEmpty() && str.indexOf("'") != -1) { rtn = new ArrayList<Integer>(); for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == '\'') { rtn.add(new Integer(i)); } } } return rtn; } /** * メインメソッド。<br> * 動作確認に使用。 * * @param args 未使用 */ public static void main(String[] args){ ArrayList<String> al = divideFormatPattern("yyyy/MM/dd HH:mm:ss.SSS'''yyyy/MM/dd HH:mm:ss.SSS''"); for (int i = 0; i < al.size(); i++) { System.out.println(al.get(i)); } al = divideFormatPattern("'''yyyy/MM/dd HH:mm:ss.SSS'''"); for (int i = 0; i < al.size(); i++) { System.out.println(al.get(i)); } } } //////////////////////////////////////////////////////////////////////////////// package test; /** * 対になる「'(シングルクォーテーション)」のセットの開始位置と終了位置を保持する。 */ public class SingleQuotationSet{ /** 開始位置 */ public int begin = -1; /** 終了位置 */ public int end = -1; /** * デフォルトコンストラクタ。 */ public SingleQuotationSet(){ } /** * 開始位置と終了位置の引数指定コンストラクタ。 * * @param b 開始位置 * @param e 終了位置 */ public SingleQuotationSet(int b,int e){ begin = b; end = e; } /** * 開始位置取得 * * @return 開始位置 */ public int getBegin(){ return begin; } /** * 開始位置設定 * * @param begin 開始位置 */ public void setBegin(int begin){ this.begin = begin; } /** * 終了位置取得 * * @return 終了位置 */ public int getEnd(){ return end; } /** * 終了位置設定 * * @param end 終了位置 */ public void setEnd(int end){ this.end = end; } /** * 対になる終了の「'(シングルクォーテーション)」が存在するかを返す。 * * @return true:終了の「'(シングルクォーテーション)」が存在する,false:存在しない */ public boolean existEnd(){ if (end == -1) { return false; } else { return true; } } /** * このオブジェクトの文字列表現を返す。 * @return オブジェクトの文字列表現 */ public String toString(){ return "begin:" + begin + ",end:" + end; } }
お礼
お返事ありがとうございます。 詳細なソースまで頂けて感謝しております。 私の確認文字列を流したところ、下記の文字列に例外 または 結果が期待値と異なってしまいました。※これは常識的にないだろうという文字列もありますが・・・。 現在、頂いたソースを確認しながら考えているところになります。 返事が遅くなってしまい申し訳ありません。 "yyyy/MM/dd HH:mm:ss:SSS" "''yyyy/MM/dd HH:mm:ss:SSS" "''''yyyy/MM/dd HH:mm:ss:SSS" "''''yyyy/MM/dd HH:mm:ss:SSS''" "''''yyyy/MM/dd ''HH:mm:ss:SSS''" "'yyyy/''MM/dd HH:mm:ss:'SSS" "'yyyy/''MM/dd HH:mm:ss:'SSS''''" "'yyyy/''MM/dd HH:mm:ss:'SSS'あいう'" "'yyyy/''MM/dd HH:mm:ss:SSSあいう'''" "''あいう" "あいう''" "'yyyy/''''MM/dd HH:mm:ss:'SSS''''" "yyyy/MMMM/dd HH:mm:ss:SSS"
- pcbeginner
- ベストアンサー率46% (261/560)
ごめんなさい。 >下記の箇所はミリ病が001の時は" "が必要になるという認識でよろしいでしょうか? >>String spc = " "; // 置換用半角スペース(とりあえず10個) ですが、ここで回答するすときに、連続した半角スペースを記入すると1個の半角スペースになってしまうことを失念していました。 正しくは String spc = "__________"; // 置換用半角スペース(とりあえず10個) (「_」は半角スペースの意味で使用しています。) です。 「とりあえず10個」としたのは「前0」が何個まで連続する仕様なのかわからないので「とりあえず10個」としています。 他の補足部分は今から読ませてもらいます。
お礼
お返事ありがとうございます。 なるほどそういうことだったのですね。打ったまま表示してくれるといいのにといつも思ってしまいます(笑)。 'の話は"''"や"yyyyMM''dd"や""'yyyy''MMdd"や"'yyyy''''MMdd"や"yyyyMMdd''"など、ロジックを書いてはみるのですが、どれかを対応するとどれかがうまくいかないという・・・。 今考えているのは、下記になります。書式変換後にスペース変換の考えは前回教えて頂いた内容が良いと思いますので、後はListの要素にうまく切り分ける事かと思っています。 ・最初の'~最後の'までひとつの文字列で取得する。他はパターン文字毎に1つの文字列とする。 例)"'yyyyMM''''''dd' yyyy/MM/dd''" 要素1:"'yyyyMM''''''dd'" 要素2:" " 要素3:"yyyy" 要素4:"/" 要素5:"MM" 要素6:"/" 要素7:"dd" 要素8:"''" 要素1が中々難しくて試行錯誤しています。想定外のところで区切られてむきーと・・・。 ロジック案 ・'が見つかったらテキスト扱い開始とする。 ・次の'が見つかったらテキスト扱い終了とする。 但し下記の場合はテキスト扱い続行とする。 a.2個目の'の後に'が2の倍数で続いた場合 例)"'yyyyMM''''''dd' yyyy/MM/dd''" 2個目の'は6個続いているので、テキスト扱いは終了していない。 例)"'yyyyMMdd''' yyyy/MM/dd''" 2個目の'は3個続いているので、テキスト扱いは終了している。 "'yyyyMMdd'''" " " "yyyy" "/" "MM" "/" "dd" "''" まだ実際のロジックを書いていないので、いろいろと問題が出てくるとは思うのですが、これから自分でも思考錯誤致します。 こんな方法があるよってご指摘があれば助かります。
- pcbeginner
- ベストアンサー率46% (261/560)
No.2です。 コード書いてみました。 とりあえず動かしてみましたが、フォーマットのパターンはあまり試していません…。 参考になれば…。 String pattern = "yyyy/MM/dd HH:mm:ss.SSS"; ArrayList<String> al = new ArrayList<String>(); // 分解後の文字列格納 char c_ = pattern.charAt(0); // 比較用前の文字(初期値は先頭の文字) int begin = 0;// 文字の開始位置(初期値は先頭) // (1)分解 for (int i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i);// 文字取得 // 比較 if (c == c_) { // 前の文字と同じ場合 // 最後の文字かどうか if (i == pattern.length() - 1) { // 最後の場合は切り出して格納 al.add(pattern.substring(begin)); } else { // 最後の文字でない場合は続行 continue; } } else { // 前の文字と違う場合 // 分解して格納 al.add(pattern.substring(begin, i)); begin = i;// 開始位置再設定 c_ = c;// 前の文字再設定 } } StringBuilder sb = new StringBuilder();// 連結用 String temp = "";// 変換用 Date date = new Date(System.currentTimeMillis()); String spc = " "; // 置換用半角スペース(とりあえず10個) for (int i = 0; i < al.size(); i++) { SimpleDateFormat formatter = new SimpleDateFormat(al.get(i)); // (2)フォーマット temp = formatter.format(date); // (3)前0を半角スペースに置換 if (temp.matches("0+")) { // 全部0→「0」1個 temp = spc.substring(0, temp.length() - 1) + "0"; } else { // 全部0じゃない場合は前0の数だけ半角スペースに for (int j = 0; j < temp.length(); j++) { // 0以外の文字が出てくるindexを探す if (temp.charAt(j) != '0') { temp = spc.substring(0, j) + temp.substring(j); break; } } } // (4)連結 sb.append(temp); } System.out.println(sb.toString());
お礼
お返事ありがとうございます。 詳細なコードまでありがとうございます。とても感謝しております。 拝見させて頂きました。 下記の箇所はミリ病が001の時は" "が必要になるという認識でよろしいでしょうか? >String spc = " "; // 置換用半角スペース(とりあえず10個) 少し書式を変えて動かしてみたのですが、とてもいい感じでした。 ただ2点ほど弱った事が・・・。 (1)"'yyyy/MM/dd形式:'yyyy/MM/dd"という感じでテキスト扱いの''に囲まれた文字がある場合に下記のような配列になり、"'"で例外が発生してしまいました。 またそこが通っても''の中の"MM"などが"MM"ではなく日付変換されてしまいそうです。 "'"←ここで例外 "yyyy" "/" ・ ・ ・ "'" 分解する時に下記のようになるように考えればよろしいのでしょうか。 "'yyyy/MM/dd形式:'" "yyyy" "/" "MM" "/" "dd" (2)"'yyyy/MM/dd''形式:'yyyy/MM/dd"のように''で囲まれたテキスト扱いの中に'自身が含まれる場合、本来は下記でSimpleDateFormatに渡すのが良いとは思いますが、 "'yyyy/MM/''dd形式:'" "yyyy" "/" "MM" "/" "dd" ''の部分が少し困っています。 「1個目の'と2個目の'の間は1つの文字列」とすると、下記のようになりますが、これだと「yyyy/MM/'dd」ではなく「yyyy/MM/dd」となり'が消えてしまいます。 "'yyyy/MM/dd'" "'形式:'" "yyyy" "/" "MM" "/" "dd" 何かうまい書き方はないでしょうか。 もしよろしければ引き続き助言を頂ければと思います。
補足
すみません、" "にはスペース2個いれたつもりだったのですが、1個になってしまっていました。 >下記の箇所はミリ病が001の時は" "が必要になるという認識でよろしいでしょうか? また下記は初めの回答を頂いて書いたものです(べたべたで恥ずかしいですが・・・)。 (1)には辛うじて対応できたのですが、(2)がうまくいっていません。 String str1 = "'yyyy/''MMMM/dd' HH:mm:ss:SSS''MM"; String date1 = "yyyyMMddHHmmssSSS"; String date2 = "2009011001011001"; SimpleDateFormat date3 = new SimpleDateFormat(date1); Date date4 = date3.parse(date2); // 連続文字か判定用 String str2 = str1.substring(0, 1); // 分割用一時変数 String str3 = ""; // 書式変換後用 String str4 = ""; List list = new ArrayList(); // シングルクォート対策(まだうまくいってませんが・・・) boolean flg1 = false; for (int i = 0; i < str1.length(); i++) { if (str1.substring(i, i + 1).equals("'")) { // テキスト扱い開始 if (!flg1) { // 'の時点で新しい文字列にする必要がある list.add(str3); str3 = str1.substring(i, i + 1); flg1 = true; // テキスト扱い終了 } else { str3 += str1.substring(i, i + 1); flg1 = false; } // テキスト扱い中 } else if (flg1) { str3 += str1.substring(i, i + 1); // 連続文字の場合 } else if (str1.substring(i, i + 1).equals(str2)) { str3 += str1.substring(i, i + 1); // 違う文字になった場合 } else { list.add(str3); str3 = str1.substring(i, i + 1); } str2 = str1.substring(i, i + 1); } // 最終文字の分割処理 // 連続した文字で終わった場合("aaabbccc"など) if (str1.substring(str1.length() - 1).equals(str2)) { list.add(str3); // 連続しない文字で終わった場合("aaabbcccd"など) } else { list.add(str3); list.add(str1.substring(str1.length() - 1)); } // 書式変換 for (int i = 0; i < list.size(); i++) { SimpleDateFormat format = new SimpleDateFormat((String) list.get(i)); // addする前に"0"→" "変換 String str5 = format.format(date4); boolean flg2 = true; // 数字のみの場合(年月日時分秒ミリ秒を想定) if (str5.matches("[0-9]+")) { // 全部0の場合、最後の0以外をスペース変換 if (Integer.parseInt(str5) == 0) { for (int j = 0; j < str5.length() - 1; j++) { StringBuffer buf = new StringBuffer(str5); str5 = buf.replace(j, j + 1, " ").toString(); } } else { // 前の0だけスペース変換 for (int j = 0; j < str5.length() && flg2; j++) { if (!str5.substring(j, j + 1).equals("0")) { flg2 = false; } else { StringBuffer buf = new StringBuffer(str5); str5 = buf.replace(j, j + 1, " ").toString(); } } } } // 書式変換後の文字列を連結 str4 += str5; } System.out.println(str4); } 結果:yyyy/MMMM/dd 1: 1:10: 1' 1 希望:yyyy/'MMMM/dd 1: 1:10: 1' 1
- sh_hirose
- ベストアンサー率66% (56/84)
あんまりきれいじゃないけどこんな感じでどうでしょう? テストしてないんでエラーが出る可能性もあると思いますが・・・。 public String sample(String format) { SimpleDateFormat sdFormat = new SimpleDateFomat(format); String date = sdFormat.format(new Date()); StringBuffer sb = new StringBuffer(); for( int i = 0; i < date.length; i++ ) { String dateChar = date.substring(i, i + 1); String formatChar = format.substring(i, i + 1); if( formatChar.equals("M") ) { if( dateChar.equals("0") && i + 2 <= format.length && format.substring(i + 1, i + 2).equals("M") ) { sb.append(" "); } else { sb.append(dateChar); } } else if( formatChar.equals("d") ) { if( dateChar.equals("0") && i + 2 <= format.length && format.substring(i + 1, i + 2).equals("d") ) { sb.append(" "); } else { sb.append(dateChar); } } ・・・ } return sb.toString(); }
お礼
お返事ありがとうございます。 日付と書式を対応しながら"0"→" "をする感じですね。参考に致します。 MMMやM4つ以上など、ずれが生じるので仕組みを考える必要がありそうですね。 0ではなくスペース埋めの要望はありそうなのですが、javaのAPIで用意してくれていないのが残念です。
- zionic
- ベストアンサー率39% (31/79)
書式が書式:"yyyy/MMMM/dd HH:mm:ss:SSS"のばあいのみですが、 1.SimpleDateFormatで得られた値をスペースで日付と時間に分割する。 2.日付の部分を/で分割して年、月、日の値をとる 3.時間の部分を:で分割して時、分、秒、ミリ秒をとる。 4.分割したそれぞれの値の先頭が0なら置換する。 5.4.で置換したものを連結する。 という感じでどうでしょう。
お礼
お返事有難うございます。 "/"が書式に必ずあるのであればよい方法なのですが、エラーにならない書式はフリーの為、"yymm dd"や"yyyy 年MM月"など変換後のどこが年月日なのか判定ができないのかなと考えています。 いぢわるな書式をするならば、"'2009/07/22' yyyy/MM/dd"で、結果が"2009/07/22 2009/07/22"のどちらが日付だったのか判定が・・・。 書式が何でもありなので困っております。
お礼
お返事ありがとうございます。 この発想は思いつきませんでした! 下の回答でコードも頂けたのでよく読んで検討したいと思います。 取り急ぎお礼を・・・。ありがとうございます。