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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Q&A

解決済

3回答

3493閲覧

和暦の入力検証(元号 + 年)

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

0グッド

1クリップ

投稿2019/01/16 12:57

例えば、「H30」「S63」などの、アルファベットの元号1字と年のみの文字列に対して、存在する年であるかの検証をしたいと考えています。
「S65」や、「H32」はダメとなります。
(「H31」や、「S64」などは正常値です。)
以下のテストコードで失敗してしまう箇所について悩んでおります。

java

1//テストコード 2 assertThat(Main.isWarekiGyy("H31"), is(true)); 3 assertThat(Main.isWarekiGyy("H01"), is(true)); //※ここでテスト失敗しまう 4 assertThat(Main.isWarekiGyy("H32"), is(false)); 5 assertThat(Main.isWarekiGyy("S65"), is(false));

java

1//実装 2 public static boolean isWarekiGyy(String warekiGyy) { 3 4 Locale japan = new Locale("ja", "JP", "JP"); 5 SimpleDateFormat format = new SimpleDateFormat("Gyy", japan); 6 format.setLenient(false); 7 8 try { 9 format.parse(warekiGyy); 10 return true; 11 } catch (ParseException e) { 12 return false; 13 } 14 }

テスト失敗個所について調査したのですが、どうも月日を指定しないと1月1日として認識されてしまう(?)ため、「H01年01月01日」として存在しない日付になってしまっているようです。

ここまではわかったのですが、ではどうするかについて思案しているところです。

単純に元号ごとにif文で開始日付を渡してからparseするなどしかないでしょうか。

java

1 //こんな感じの処理を挟みこんでGyyMMddでparse? 2 //なんか長くなるが・・ 3 String startDate; 4 switch (warekiGyy.substring(0, 1)) { 5 case "H": 6 startDate = "0108"; 7 break; 8 case "S": 9 startDate = "1225"; 10 break; 11 default: 12 return false; 13 }

上記を入れればたぶんうまく動く気もするのですが、単純に「GYY」ではできないでしょうか。

一応、LocalDate版も作ってみたのですが、こちらもうまくいきません・・。

java

1 public static boolean isWarekiGyy2(String warekiGyy) { 2 3 Locale japan = new Locale("ja", "JP", "JP"); 4 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("Gyy", japan); 5 try { 6 LocalDate.parse(warekiGyy, formatter); 7 return true; 8 } catch (DateTimeParseException e) { 9 return false; 10 } 11 } 12

質問内容は以上です。
何かうまい方法あればお教えください。
よろしくお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

というかJava 自体 次の元号は対応してないんだからハードコーディングでよくない?

可変性を高めるならプロパティファイルで設定して

追記

プログラム

java

1import java.text.SimpleDateFormat; 2import java.time.LocalDate; 3import java.time.format.DateTimeFormatter; 4import java.util.Date; 5import java.util.Locale; 6import java.util.Objects; 7import java.util.ResourceBundle; 8 9public class GengoValid { 10 11 ResourceBundle bundle = ResourceBundle.getBundle("calendar"); 12 13 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("GGGGGy"); 14 15 SimpleDateFormat format = new SimpleDateFormat("Gy", new Locale("ja", "JP", "JP")); 16 SimpleDateFormat format2 = new SimpleDateFormat("YYYY-MM-dd"); 17 { 18 format.setLenient(false); 19 format2.setLenient(false); 20 } 21 22 public boolean check(String test) { 23 System.out.println(format.format(new Date())); 24 try { 25 test = test.toUpperCase(); 26 27 String g = (test.charAt(0) + "").toUpperCase(); 28 Integer y = Integer.valueOf(test.substring(1)); 29 30 String start = bundle.getString("calendars." + g + ".start"); 31 String end = bundle.getString("calendars." + g + ".end"); 32 33 Objects.requireNonNull(start); 34 35 LocalDate max; 36 if (end == null || end.length() == 0) { 37 max = LocalDate.now(); 38 } else { 39 max = LocalDate.parse(end); 40 } 41 42 if (y == 1) { 43 // 元年はハードコーディング 44 return true; 45 } 46 47 LocalDate inp = LocalDate.parse(format2.format(format.parse(test))); 48 49 50 System.out.println(inp); 51 System.out.println(max); 52 53 return inp.isBefore(max) || inp.equals(max); 54 } catch (Exception e) { 55 return false; 56 } 57 } 58 59}

プロパティファイル

properties

1calendars.M.start=1868-01-01 2calendars.M.end =1912-07-29 3calendars.T.start=1912-07-30 4calendars.T.end =1926-12-24 5calendars.S.start=1926-12-25 6calendars.S.end =1989-01-07 7calendars.H.start=1989-01-08 8calendars.H.end =2019-04-30 9calendars.X.start=2019-05-01 10calendars.X.end =

Test

import static org.junit.Assert.*; import org.junit.Test; public class GengoValidTest { GengoValid valid = new GengoValid(); @Test public void testM1() { assertTrue(valid.check("M1")); } @Test public void testM45() { assertTrue(valid.check("M45")); } @Test public void testM46() { assertFalse(valid.check("M46")); } @Test public void testT1() { assertTrue(valid.check("T1")); } @Test public void testT15() { assertTrue(valid.check("T15")); } @Test public void testT16() { assertFalse(valid.check("T16")); } @Test public void testS1() { assertTrue(valid.check("S1")); } @Test public void testS64() { assertTrue(valid.check("S64")); } @Test public void testS65() { assertFalse(valid.check("S65")); } @Test public void testH1() { assertTrue(valid.check("H1")); } @Test public void testH31() { assertTrue(valid.check("H31")); } @Test public void testH32() { assertFalse(valid.check("H32")); } }

投稿2019/01/16 15:10

編集2019/01/16 16:11
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/01/16 23:55

詳細なコードまで提示いただきありがとうございます。 参考にします。
guest

0

1月1日および12月31日の「少なくともどちらか一方」が有効なら、その年はあるものと判定できるかと思います。
ただ厳密には日にちまで考慮して判定する必要があるので(S640107 は有効ですが S640108 は無効ですから)すけれども。
※別回答のコメントに書きましたが、歴史上唯一「天平感宝」だけはこの条件では判定不可能です

まあ、日にちを考慮すると、明治以降に限ったとしても平成への改元以外は次の元号と開始・終了年月日がかぶるという特性があるからまた厄介ですが。
※大正15年12月25日=昭和元年12月25日であり、この日はどちらの元号でも存在するものとして扱う必要がある

投稿2019/01/17 00:15

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/01/17 01:46

明治以降、特例の明治を除いてその日の00:00に遡って適用されるはず。 (本日)をもって(元号)とする だったはずなので
tacsheaven

2019/01/17 02:03

いや、大正から昭和のときでも、昭和改元の詔は「大正十五年十二月二十五日」付けで、同日に公布された勅令では「昭和元年十二月二十五日」となるので、大正十五年十二月二十五日という日付は正しいものとして扱う必要があります。 現行法では元号は政令で定めることとしており、政令中で適用日を「翌日より」とすることで、重複を回避する形になっています。
guest

0

1年に2回の改元がないという前提を置くと、元年は12月31日の存在をチェックすれば良いかと思います。

投稿2019/01/16 14:43

otn

総合スコア84499

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2019/01/16 15:07

元年は確かに良い案と思ったのですが、そのまま一般化すると、最終年がアウト。手間を惜しまずに、最初と最後の日を置くべきでは? .... Windows辺りだと、レジストリに持ってなかったでしょうか。 あと、年に2回の改元が無いという保証はないですね。 (過去にはあった気もする... 奈良時代以前にあった)
otn

2019/01/16 15:12

> 最終年がアウト ?? 元年以外は1月1日をみるんですよ。勘違いしていませんか?
pepperleaf

2019/01/16 15:17

> 元年以外は1月1日をみるんですよ。 とすると、元年の判定が必要ですね。ただ、元年は全ての元号にあるし、、とさて。
tacsheaven

2019/01/17 00:06

現行の元号法では「皇位継承により改元する」ので、1年に複数回改元が「ない」ことは保証していません。不敬ではありますが、皇位継承が2回行われれば、2度改元はあり得るのですから。 歴史上では奈良時代(西暦749年)に、天平→天平感宝→天平勝宝という2回の改元が行われた例はあります。(天平感宝→天平勝宝は皇位継承に伴うもの)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問