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

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

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

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

Q&A

1回答

1861閲覧

複数年の営業日カレンダー作成(java)

nasubi_yade

総合スコア0

Java

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

0グッド

0クリップ

投稿2020/12/23 10:42

前提・実現したいこと

課題で2020年から2025年までの間の営業日カレンダーを作成したいのですがうまくいきません。

【条件】 ・指定範囲内の正しい日付なら経過日および営業日を計算する。  ただし結果が 2020 年から 2025 年までの範囲から外れるときは、値が正しくなくても良い。例外が発生してもよい。 ・指定範囲外または存在しない日付なら「x 年 x 月 x 日は指定条件を満たしていません。」と表示して処理を終了する。 ・間隔を表す引数に負の数を指定すると過去の日付と営業日を出力するようにする。 ・間隔を表す引数に 0 を指定すると、指定日が営業日でなくても指定日をそのまま出力する。 ・休みは通常のカレンダーに 12 月 29 日から翌年の 1 月 3 日までの年末年始の休みを加えたものとすること。 ・2020 年はオリンピックに関連しての休日の特例が適用されたが、この特例は無いものとして計算すること。  また 2021 年以降に法律が改正され特例または恒久的に休日が設定されても、  それは無視してそのような休日は無いものと考えて計算すること。

コンパイルはできるのですが、実行すると以下のようなエラーがでてしまいます。

色々と調べてみたり修正してみたりはしたのですが、当方の知識不足のため解決に至りませんでした。
どのようにエラーを解消すればよいかアドバイスをいただきたいです。

エラーメッセージ

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 12 at BusinessDayMulti.daysOfMonth(BusinessDayMulti.java:32) at BusinessDayMulti.getYYYYMMDD(BusinessDayMulti.java:84) at BusinessDayMulti.main(BusinessDayMulti.java:14)

該当のソースコード

java

1 2class BusinessDayMulti{ 3static final int BASIS_YEAR = 2020; // 起算年 4static final int LIMIT_YEAR = 2025; // 限界年 5static final int YOUBI_OF_BASIS = 3; // 起算年の初日の曜日(水曜日) 6public static void main(String[] args) { 7 int year = Integer.parseInt(args[0]); // 年の入力 8 int month = Integer.parseInt(args[1]); // 月の入力 9 int date = Integer.parseInt(args[2]); // 日の入力 10 int span = Integer.parseInt(args[3]); // 間隔の入力 11 if (checkDate(year, month, date)) { 12 // 年月日で与えた日付の起算日からの日数を得る 13 int days = elapsedDays(year, month, date); 14 // 起算日からの日数を与えその日付を YYYYMMDD 形式で得る 15 int eymd = getYYYYMMDD(days + span); 16 // days から span 日後の営業日付を YYYYMMDD 形式で得る 17 int bymd = getBusinessDay(days, span); 18 19 System.out.println(year + "年" + month + "月" + date + "日は起算日から" + days + "日目です。"); 20 String zengo = span < 0 ? "前" : "後"; 21 System.out.println(Math.abs(span) + "日" + zengo + "は" 22 + (eymd / 10000) + "年" + (eymd % 10000) / 100 + "月" 23 + (eymd % 100) + "日です。"); 24 System.out.println(Math.abs(span) + "営業日" + zengo + "は" 25 + (bymd / 10000) + "年" + (bymd % 10000) / 100 + "月" + (bymd % 100) + "日です。"); 26 } else { 27 System.out.println(year + "年" + month + "月" 28 + date + "日は指定条件を満たしていません。"); 29 } 30 } 31static int daysOfMonth(int year, int month) { 32 int[] DAYS_OF_MONTH = {31,28,31,30,31,30,31,31,30,31,30,31}; 33 int day = DAYS_OF_MONTH[month-1]; 34 if (year % 4==0 && month==2){ 35 if(year % 100!=0 && month==2){ 36 day++; 37 if (year % 400==0 && month==2){ 38 day++; //閏年なので1加算 39 }else{ 40 } 41} 42 43} 44 return day; 45} 46 47 48 // 指定月日が存在すれば true を返す 49 static boolean checkDate(int year,int month, int date) { 50 if (year<2020 || 2025<year)return false; 51 if (month < 1 || 12 < month) return false; 52 if (date < 1) return false; 53 if (month == 1 && date <=31) return true; 54 if (month == 2 && date <=28) return true; 55 if (month == 2 && date <=29 && year % 4==0 && year % 100!=0 || year % 400==0)return true; 56 if (month == 3 && date <=31) return true; 57 if (month == 4 && date <=30) return true; 58 if (month == 5 && date <=31) return true; 59 if (month == 6 && date <=30) return true; 60 if (month == 7 && date <=31) return true; 61 if (month == 8 && date <=31) return true; 62 if (month == 9 && date <=30) return true; 63 if (month == 10 && date <=31) return true; 64 if (month == 11 && date <=30) return true; 65 if (month == 12 && date <=31) return true; 66 return false; 67 } 68 69 70 // 1 月 1 日からの経過日数 71 static int elapsedDays(int year,int month,int date){ 72 int dYear = year-BASIS_YEAR; //起算年との差 73 int days = dYear * 365+((dYear+3)/4)-((dYear+3)/100)+((dYear+3)/400); //閏年補正 74 for (int m = 1 ; m<month;m++){ 75 days += daysOfMonth(year,m); 76 } 77 return days+date-1; 78 } 79 80 // 1 月 1 日から指定日数後の日付 81 static int getYYYYMMDD(int days) { 82 days++; // 0 日目は 1 日なので+1 する 83 int year=0; 84 int month = 0; 85 while(daysOfMonth(year,month)<days){ 86 days -= daysOfMonth(year++,month++); 87 } 88 if (month>12){ 89 year = 2020+(month-12); 90 }else{ 91 return year; 92 } 93 return year + (month + 1) * 100 + days; 94 } 95 96 // 1 月 1 日からの経過日数 days から間隔日数 span 日後の営業日 97 static int getBusinessDay(int days, int span) { 98 for (int i = 0; i < span; ) { 99 days++; 100 if (isWeekend(days)) continue; 101 if (isTotalHoliday(getYYYYMMDD(days))) continue; 102 i++; 103 } 104 return getYYYYMMDD(days+span); 105 106 } 107 108 // 週末判定 109 static boolean isWeekend(int days) { 110 if ((days + YOUBI_OF_BASIS) % 7 == 0) return true; 111 if ((days + YOUBI_OF_BASIS) % 7 == 6) return true; 112 return false; 113 } 114 115//休日判定呼び出し 116 static boolean isTotalHoliday(int yyyymmdd) { 117 int year=0; 118 int month=0; 119 int date=0; 120 if (isNationalHoliday(year, month, date)) return true; 121 if (isFurikaeHoliday(year, month, date)) return true; 122 if (isOtherHoliday(month, date)) return true; 123 return false; 124 } 125 // 普通の休日判定 126 static boolean isNationalHoliday(int year, int month, int date) { 127 int[] FIX_HOLIDAYS = {101, 211, 223, 429, 503, 504, 505, 811, 1103, 1123,}; 128 int mmdd = month * 100 + date; 129 for (int holiday: FIX_HOLIDAYS) { 130 if (holiday == mmdd) return true; 131 } 132 if (isHappyMonday(year, month, date)) return true; 133 if (isEquinox(year, month, date)) return true; return false; 134 } 135 //ハッピーマンデー 136 static boolean isHappyMonday(int year, int month, int date) { 137 int[] HAPPY_MONDAYS = {102, 703, 903, 1002,}; 138 int youbiOfFirstDay = (elapsedDays(year, month, 1) + YOUBI_OF_BASIS) % 7; 139 for (int mmnn: HAPPY_MONDAYS) { 140 if (mmnn / 100 != month) continue; 141 int n = mmnn % 100; 142 int happyMonday = (8 - youbiOfFirstDay) % 7 + n * 7 - 6; 143 if (date == happyMonday) return true; 144 } 145 return false; 146 } 147 //春分の日、秋分の日 148 static boolean isEquinox(int year,int month, int date) { 149 int[][] EQUINOX = {{320, 922},{320, 923},{321, 923},{321, 923}}; 150 int mmdd = month * 100 + date; 151 for (int equinox: EQUINOX[year % 4]) { 152 if (equinox == mmdd) return true; 153 } 154 return false; 155 } 156 157 158 //振替休日 159 static boolean isFurikaeHoliday(int year, int month, int date) { 160 int[] MULTI_SHIFT = {2020, 2025, 2026}; 161 for (int shift_year: MULTI_SHIFT) { 162 if (year == shift_year && month == 5 && date == 6) return true; 163 } 164 int youbi = (elapsedDays(year, month, date) + YOUBI_OF_BASIS) % 7; 165 if (youbi != 1) return false; // 月曜でなけれは非該当 166 return isNationalHoliday(year, month, date - 1); // 前日が祝日なら休日 167 } 168 169 //そのほかの休日 170 static boolean isOtherHoliday(int month, int date) { 171 int[] OTHER_HOLIDAYS = {101,102,103,1229,1230,1231,}; 172 int mmdd = month * 100 + date; 173 for (int holiday: OTHER_HOLIDAYS) { 174 if (holiday == mmdd) return true; 175 } 176 return false; 177 } 178 179 180 } 181

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

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

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

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

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

guest

回答1

0

エラー以外の部分はまったく見ていませんが。

daysOfMonth(int year, int month)は、monthに1以上の値を指定することを想定して作られています。DAYS_OF_MONTH[month-1]で、配列からその月の日数を得ていますね。

ところが、getYYYYMMDD(int days)では、最初にmonthに0を指定していますから、DAYS_OF_MONTH[-1]にアクセスしようとして、質問文のようなエラーが発生します。

あと、2020年から2025年までだけに限定しているのですから、閏年の判定は「4で割り切れる」だけ使えば十分です。100年ルールとか400年ルールが必要な西暦は出てきません。

投稿2020/12/23 11:57

Daregada

総合スコア11990

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問