質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Java

    13528questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

SimpleDateFormatで日時形式判定

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,281

Hyonta

score 20

実現したいこと

Javaの初心者です。
ログ解析用のツールを作成しているのですが、
標準入力から入力された日時が以下のいづれかの形式でなければエラーとなり、もう一度標準入力を求めるメッセージを出力させたいです。
yyyy/MM/dd
yyyy/MM/dd-hh
yyyy/MM/dd-hh:mm
yyyy/MM/dd-hh:mm:ss

SimpleDateFormatを使用して判定する方法を教えていただきたいです。
また、存在しない日時のとき、開始日時が終了日時より大きい時もエラーとしたいです。
現在作成中ですが、日時フォーマットを、例えば「yyyy/MM/dd-hh」で入力した場合もエラーとなってしまいます。
修正方法を教えていただきたいです。また、ソースコードにおかしいところがあれば教えていただきたいです。

ソースコード

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;

public class Execute {

    private static final int OK = 0;
    private static final int ERROR_DATE_FORMAT = 1;
    private static final int ERROR_DATE_NO_EXIST = 2;
    private static final int ERROR_DATE_START_TO_END = 3;

    public static void main(String[] args) {

        System.out.println("開始日時を入力してください。");
        Scanner scan = new Scanner(System.in);
        String startTime = scan.next();

        if (CheckDate(startTime) == ERROR_DATE_FORMAT) {
            System.out.println("日時の形式が正しくありません。もう一度入力してください。");
        }
        if (CheckDate(startTime) == ERROR_DATE_NO_EXIST) {
            System.out.println("存在しない日時が入力されています。");
        }
        if (CheckDate(startTime) == OK) {
            System.out.println("終了日時を入力してください。");
            //終了日時を入力する処理を記載する。
        }
        scan.close();
    }

    private static int CheckDate(String startTime) {

        final String FORMAT1 = "^[0-9][4]/[01]?[0-9]/[0123]?[0-9]$";
        final String FORMAT2 = "^[0-9][4]/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3])$";
        final String FORMAT3 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3]):([0-5]?[0-9])$";
        final String FORMAT4 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$";
        long startTimes;
        //long endTime;

        //while (true) {

            SimpleDateFormat format = null;
            if (startTime.matches(FORMAT1)) {
                format = new SimpleDateFormat("yyyy/MM/dd");
            } else if (startTime.matches(FORMAT2)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh");
            } else if (startTime.matches(FORMAT3)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm");
            } else if (startTime.matches(FORMAT4)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm:ss");
            } else {
                return ERROR_DATE_FORMAT;
                // System.out.println("日時の形式が正しくありません。もう一度入力してください。");
                // continue;
            }

            try {
                format.setLenient(false);
                startTimes = format.parse(startTime).getTime();
            } catch (ParseException e) {
                return ERROR_DATE_NO_EXIST;
                // System.out.println("存在しない日時が入力されています。");
                // continue;
            }
            // break;
            return OK;
    }
}

現在の問題点

・yyyy/MM/dd
yyyy/MM/dd-hh のフォーマットの場合もエラーとなってしまう。

・15行目などの
System.out.println("日時の形式が正しくありません。もう一度入力してください。");
のあとにもう一度標準入力を再開する方法がわからない。

エラー種類

・日時の形式が正しくありません。もう一度入力してください。
・存在しない日時が入力されています。もう一度入力してください。
・開始日時>終了日時となっています。もう一度入力してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2016/04/30 17:07

    こちらの質問が他のユーザから「やってほしいことだけを記載した丸投げの質問」という指摘を受けました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 4

checkベストアンサー

0

こんな感じでしょうか。デバッグしていないので間違っていたらごめんなさい。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;

public class Main {

    private static final String FORMAT1 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]$";
    private static final String FORMAT2 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3])$";
    private static final String FORMAT3 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3]):([0-5]?[0-9])$";
    private static final String FORMAT4 = "^[0-9]{4}/[01]?[0-9]/[0123]?[0-9]-([01]?[0-9]|[2]?[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$";

    public static void main(String[] args) {

        long startDateTime;
        long endDateTime;
        System.out.println("開始日時を入力してください");
        Scanner scan = new Scanner(System.in);

        while (true) {

            String s = scan.next();

            SimpleDateFormat format = null;
            if (s.matches(FORMAT1)) {
                format = new SimpleDateFormat("yyyy/MM/dd");
            } else if (s.matches(FORMAT2)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh");
            } else if (s.matches(FORMAT3)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm");
            } else if (s.matches(FORMAT4)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm:ss");
            } else {
                System.out.println("日時の形式が正しくありません。もう一度入力してください。");
                continue;
            }

            try {
                format.setLenient(false);
                startDateTime = format.parse(s).getTime();
            } catch (ParseException e) {
                System.out.println("存在しない日時が入力されています。もう一度入力してください。");
                continue;
            }

            break;
        }

        System.out.println("終了日時を入力してください");
        while (true) {
            String s = scan.next();

            SimpleDateFormat format = null;
            if (s.matches(FORMAT1)) {
                format = new SimpleDateFormat("yyyy/MM/dd");
            } else if (s.matches(FORMAT2)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh");
            } else if (s.matches(FORMAT3)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm");
            } else if (s.matches(FORMAT4)) {
                format = new SimpleDateFormat("yyyy/MM/dd-hh:mm:ss");
            } else {
                System.out.println("日時の形式が正しくありません。もう一度入力してください。");
                continue;
            }

            try {
                format.setLenient(false);
                endDateTime = format.parse(s).getTime();
            } catch (ParseException e) {
                System.out.println("存在しない日時が入力されています。もう一度入力してください。");
                continue;
            }

            if (endDateTime - startDateTime < 0) {
                System.out.println("開始日時>終了日時となっています。もう一度入力してください。");
                continue;
            }

            break;
        }

        scan.close();

    }

}

メソッドに分けた方がいいとかあるでしょうけど、そこまでやろうとすると面倒なので手を抜いています。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 11:39 編集

    回答ありがとうございます!本当にありがとうございます。
    kenteiさんの回答内容をもとに作成しましたがわからない箇所がありますので、質問内容を編集しております。見ていただけると幸いです。

    キャンセル

  • 2016/05/03 13:28

    >・yyyy/MM/dd
    >yyyy/MM/dd-hh のフォーマットの場合もエラーとなってしまう。
    正規表現FORMAT1 ,2が間違っているからです。
    "^[0-9][4] ← ここは{}で囲んでください。4文字の意味です

    >15行目などの
    >System.out.println("日時の形式が正しくありません。もう一度入力してください。");
    >のあとにもう一度標準入力を再開する方法がわからない。
    while文で回してないと動かないです。
    私のソースではそうしていると思いますが。

    デバッグするなり何なりして、自分で調べることも重要ですよ。

    キャンセル

  • 2016/05/03 21:35

    ありがとうございました。
    やりたい処理を実装することができました。
    自分でもデバッグなどを駆使しながら調べて、できるだけ成長できるように頑張ります。

    キャンセル

  • 2016/05/03 21:55

    これだと"2016/20/01"のような文字列も「日時の形式が正しくない」になるのですがいいのでしょうか?
    シンプルに"^\\d{4}/\\d{2}/\\d{2}-\\d{2}:\\d{2}:\\d{2}$"かとも思うのですが…

    キャンセル

0

まずは自分なりに実装してみたらどうでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 11:41

    回答ありがとうございます。質問内容を編集しました。

    キャンセル

0

java parse SimpleDateFormat
で google 検索してみると良いです。

たとば、次のページなどを読んでみてください。

文字列を Data 型に変換できれば、あとは大小比較ができます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 11:41

    回答ありがとうございます。質問内容を編集しました。

    キャンセル

0

私自身思いついたことが実際できるのか気になり、実験してみました。
ParsePositionを使って解析位置を追跡し、先頭から段階的に解析しています。

import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Q33781 {
    public static void main(String[] args) {

        // 出力用フォーマット
        DateFormat forOut = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss");

        // 段階的に解析するためのフォーマット
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy/MM/dd");
        SimpleDateFormat format2 = new SimpleDateFormat("-HH");
        SimpleDateFormat format3 = new SimpleDateFormat(":mm");
        SimpleDateFormat format4 = new SimpleDateFormat(":ss");
        SimpleDateFormat[] formats = { format1, format2, format3, format4 };

        // 解析する情報に応じたCalendarクラスのフィールド定数
        int[] fields = { Calendar.DATE, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND };

        // 各種フォーマットを厳密モードにする
        for (SimpleDateFormat format : formats) {
            format.setLenient(false);
        }

        String[] times = { "2016/04/30", "2016/04/30-17", "2016/04/30-17:30", "2016/04/30-17:30:50",
                "2016/04/32", "2016/04/30-25", "2016/04/30-17:60", "2016/04/30-17:30:60", "2016-04-30"};
        Text: for (String str : times) {
            // 日時設定用Calendarインスタンス
            Calendar cal = Calendar.getInstance();
            // 解析位置を保持するための、ParsePositionインスタンス
            ParsePosition pos = new ParsePosition(0);

            // 解析位置が対象文字列の最後に達するか、formatsのフォーマットの数ループするまでループ
            for (int i = 0; pos.getIndex() < str.length() && i < formats.length; i++) {
                Date date = formats[i].parse(str, pos);
                // 解析失敗時
                if (date == null) {
                    System.out.println(str + " の解析失敗 " + pos.getErrorIndex());
                    continue Text;
                }
                // 最初の年月日はそのまま設定
                if (i == 0) {
                    cal.setTime(date);
                // 時分秒はDateをCalendarに変換し、対象のフィールドだけ抽出
                } else {
                    Calendar temp = Calendar.getInstance();
                    temp.setTime(date);
                    cal.set(fields[i], temp.get(fields[i]));
                }
            }
            System.out.println(str + " の解析結果 " + forOut.format(cal.getTime()));
        }
    }

}

出力結果

2016/04/30 の解析結果 2016/04/30-00:00:00
2016/04/30-17 の解析結果 2016/04/30-17:00:00
2016/04/30-17:30 の解析結果 2016/04/30-17:30:00
2016/04/30-17:30:50 の解析結果 2016/04/30-17:30:50
2016/04/32 の解析失敗 0
2016/04/30-25 の解析失敗 10
2016/04/30-17:60 の解析失敗 13
2016/04/30-17:30:60 の解析失敗 16


これで解析の可不可の判定、および解析した時のCalendarオブジェクトの取得が可能になります。
開始、終了の時間の前後の判定はCalendarのcompareメソッドを使えば可能です。
また、エラーの内容として「書式が合っていない」か「存在しない日時」かを分けたければ、SimpleDateFormatを厳密モード、非厳密モードの2パターンで解析すれば可能かと思います。
厳密で失敗し、非厳密で成功すれば「存在しない日時」、両方失敗すれば「書式が合っていない」とエラーが出せます。
ただし、このフォーマットだと"2016/4/30"の様に2桁であるべきところが1桁しかない場合も通すので、厳密に4桁/2桁/2桁などを判定したいのならやはり正規表現になるかもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 21:33

    回答ありがとうございました!
    少し難しそうですが、こちらの方法も試してみます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    "YYYY/MM/DD"という文字列を"YYYY年MM月DD日"という書式で取得したい。

    データベースからgetStringで取得した、"2014/5/11"といった文字列を"2014年5月11日"という書式で取得できる関数をどなたか教えていただけないでしょうか? F

  • 受付中

    [java][日付チェック]質問

    java初心者です。 テキストファイルを一行づつ読み込んで行く時に、 32日や14月など、異常な日付が紛れていた場合例外として処理する方法はありますでしょうか? while ((

  • 解決済

    java 日付の取得と変更について

    javaの日付の取得と変更に関するコードについて質問です 参考書のとおりに、下記のコードを書いて実行してみたのですが 実行してみても、現在の日付から5日後の日付が出力されず、現在

  • 解決済

    javaでEclipseのプログラム

    クラス内変数について: 以下の条件を満たすプログラムについて、 作成例を示してください。 インスタンス生成時点の現在時刻を表示する機能をもつ シングルトランスを作成する。 2度目

  • 受付中

    JAVA dateの複数のデータの時刻だけを加算するには

    date型で 複数の日時と時刻が含まれるデータがあります、これをjavaで全部足して合計時間を出すにはどうすればいいでしょうか。 例えば 2016-2-25 06:30:10

  • 解決済

    タイムゾーンの時差計算

    前提・実現したいこと java7でプログラミングを行っています。 たとえばtimezone(Asia/Tokyo)と日付(new Date()で生成された時間)をもちいて 「

  • 解決済

    Javaのテキストを日付に変換したい

    Javaで西暦、年号がバラバラのデータ(格納されている日付データの型はString型)の フォーマットを整形したい場合の書き方を教えて頂きたいです。 例)2015年7月26日メ

  • 解決済

    Javaの日付に関するプログラムについて質問です。

    いつもお世話になっています。こんばんは。 このような表示結果のプログラムを作りたいのですがコンパイルは通るのですが、実行ができません。なぜでしょうか?まだJava初心者なのでみな

同じタグがついた質問を見る

  • Java

    13528questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。