起算日から6月経過しているか調べる【解説編】

この記事は約10分で読めます。

前回、「起算日から6月経過しているか調べる」ための関数を作成しましたが、どのようにして求めたか解説したいと思います。

Function hantei(KISAN_YMD As Date, KIZYUN_YMD As Date, tukisu As Long) As Boolean

Function で記述することで、関数を自作することができます。関数に入力したい数値など(引数といいます。)は、カッコ内に変数を宣言することで渡すことができます。

スポンサーリンク

手順1

'手順1 日付A(起算日)、日付B(基準日)、判定する月数(今回の例では6月)を指定する

今回の例で、計算に必要な数値(引数)は起算日、基準日、月数の3つです。

  • 起算日… KISAN_YMD (日付型で定義)
  • 基準日… KIZYUN_YMD (日付型で定義)
  • 月数… tukisu (長整数型で定義)

カッコの次の「As Boolean」ですが、関数は入力したものを計算し、結果を出力するという特徴があります。今回、求めたい答えは「〇」か「×」かの判定ですので、テーブルデザインで使用するYes/No型、VBAの型でいうと「Boolean型」で出力するように設定しました。

スポンサーリンク

手順2

'手順2 起算日からn月後の満了日を民法第143条第2項に沿って計算する

今回の処理のキモとなる部分です。

応当日と満了日を求める

民法第143条は、このように定めています。

(暦による期間の計算)
第143条  週、月又は年によって期間を定めたときは、その期間は、暦に従って計算する。
2  週、月又は年の初めから期間を起算しないときは、その期間は、最後の週、月又は年においてその起算日に応当する日の前日に満了する。ただし、月又は年によって期間を定めた場合において、最後の月に応当する日がないときは、その月の末日に満了する。

e-Gov 法令データ提供システム から引用しました
  • n月後に起算日に応当する日付があれば、その日の前日に期間が満了する。
  • n月後に起算日に応当する日付がなければ、その月の末日に期間が満了する。

「応当する日」とは、例えば2019/7/11を起算日として1週間後という期間を定めたとき、1週間後に当たる日は2019/7/18です。この1週間後に当たる日を「応当日」といいます。

同様に、2019/7/11を起算日として1月後という期間を定めたとき、1月後に当たる日は2019/8/11です。


ところが難しいのが、第2項のただし書き「最後の月に応当する日がないときは、その月の末日に満了する。」という一文。

例えば2019/8/31を起算日として6月後という期間を定めたとき、6月後に当たる日は、2020/2/31となりますが、2月には31日なんて日付はありませんので、2月末日が満了日となります。

さらに、2020年はうるう年なので、29日まであります。

そう、月によって、場合によっては年によって満了する日が変動するのです。

今回、和休はこれを実現するためにこんな条件を設定しました。

  1. n月後の月の日数を調べる
  2. 起算日の日付がその日数より大きいかどうか
  3. 大きければ起算日からn月後の応当日を求め、その前日を満了日とし、そうでなければn月後の最終日を満了日とする

n月後の月の日数を調べる

では、n月後の月の日数を調べていきましょう。

起算日からn月後の翌日1日の日付を求め、その前日を求めれば、n月後の月の最終日の日付を取得できますね。

その日付を数値に変換すれば、n月後の月に含まれている日数が分かりますね。

変数を宣言しました。n月後の月に含まれる日数を格納する変数「NISSU」、満了日を格納する「MANRYO_YMD」です。

Dim NISSU As Long  '日数を格納する
Dim MANRYO_YMD As Date  '満了日を格納する

n月後の月に含まれる日数を求めます。

NISSU = Day(DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu + 1, 1) - 1)

今回、起算日は2019/7/11、月数は6月と指定します。

この式の変数を、入力された数値に置き換えます。

NISSU = Day(DateSerial(Year(#2019/7/11#), Month(#2019/7/11#) + 6 + 1, 1) - 1)
NISSU = Day(DateSerial(2019, 7 + 6 + 1, 1) - 1)
NISSU = Day(DateSerial(2019,14, 1) - 1)
NISSU = Day(#2020/2/1# - 1)
NISSU = Day(#2020/1/31#)
NISSU = 31

7月の6月後は翌年の1月なので、「31」という答えが返ってきました。

式をバラしていきます。一番外側の関数は、Day関数です。指定した日付から日を取り出します。

例:2019/7/11 → Day(#2019/7/11#)→ 11

Accessでは、日付を指定するときは#で囲むことがお約束です(日付型の変数を使う場合、あらかじめ日付型であると宣言しているので#は不要です。)。

#で囲まないと、場合によっては 2019 ÷ 7 ÷ 11 の答えを指定したように判断されます。

DAY関数の中に入っている関数は、DateSerial関数です。カッコの中をカンマで区切り、年,月,日の数値を入れることで、日付型に変換する関数です。

例:DateSerial(2019,7,11) → 2019/7/11(日付型)

DateSerial関数の中にはさらにYear関数と、Month関数が入っています。それぞれ指定した日付からYear関数は年、Month関数は月を取り出します。

例:2019/7/11 → Year(#2019/7/11#)→ 2019

例:2019/7/11 → Month(#2019/7/11#)→ 7

DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu + 1, 1)

DateSerial関数に指定している数値を解説します。

まず、「年」を指定する部分には、Year関数で起算日の属する年を指定しています。

例:Year(KISAN_YMD) → Year(#2019/7/11#) → 2019

次に、「月」を指定する部分には、Month関数で起算日の属する月を指定しています。

例:Month(KISAN_YMD) → Month(#2019/7/11#) → 7

さらに変数「tukisu」で指定した「6」を加算し、DateSerial関数の「月」に入力された数値は「13」になります。

さらに「+1」することで7月後の月を取得しています。結果は「14」です。

NISSU = Day(DateSerial(2019,14, 1) - 1)

でも、2019年14月なんて日付、ありませんよね。でも大丈夫。DateSerial関数は、実際に存在する月に自動的に変換してくれるのです。

月に「14」を入力した場合、1年と2月に変換してくれるので、2020年2月になるのです。

最後に「日」を指定する部分には、「1」を入力しました。つまり、このDateSerial関数の結果は、2020/2/1となります。

NISSU = Day(#2020/2/1# - 1)

2020/2/1 から「-1」することで、1日前の日付を求めることができます。この結果、Day関数のカッコ内は、2020/1/31になっているのです。

NISSU = Day(#2020/1/31#)

結果、変数「NISSU」には「31」が入力されることになるのです。

起算日の日付がその月にある日数より大きいかどうか

ここまでの計算で、起算日は2019/7/11、6月後の月には31日まであることが分かりました。

起算日は「11日」なので6月後の月にも存在します。ですので応当日は2020/1/11となります。

もし、起算日が2019/8/31としたら、6月後の応当日はどうなるでしょう。

6月後は2020年2月なので、29日までしかありません。つまり応当日は存在しない、ということになります。

なお、この場合、民法第143条第2項のただし書き「最後の月に応当する日がないときは、その月の末日に満了する。」が適用されて、満了日は2020/2/29となります。

では、IF構文に当てはめてみましょう。

'起算日の日付とn月後の月に属する最後の日付とを比較
If Day(KISAN_YMD) <= NISSU Then

この式の変数を、入力された数値に置き換えます。

If Day(#2019/7/11#) <= 31 Then
If 11 <= 31 Then

11と31を比較した結果、条件を満たしているので、次の式へ飛びます。

'起算日からn月後の応当日の前日を満了日とする(応当日がその月に存在するとき)
MANRYO_YMD = DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu, Day(KISAN_YMD)) - 1
DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu, Day(KISAN_YMD))

DateSerial関数に指定している数値を解説します。

起算日は2019/7/11、6月後の応当日とします。

DateSerial(Year(#2019/7/11#),month(#2019/7/11#)+6,day(#2019/7/11#)
DateSerial(2019,7+6,11)
DateSerial(2019,13,11)
#2020/1/11#

この結果、2020/1/11となります。これが応当日です。

ここから「-1」することで、2020/1/10となります。これが満了日になります。

MANRYO_YMD = #2020/1/10#

変数「MANRYO_YMD」に2020/1/10が格納されました。


では、条件を満たさなかったときはどうでしょうか。

起算日を2019/8/31、6月後の応当日を求めます。

この場合、6月後は2020/2となり、変数「NISSU」には、2020/2に含まれる日数である「29」が格納されます。

起算日は「31」、2月に含まれる日数は「29」なので、31と29を比較すると、条件を満たしません。ですので、「Else」の次に記述した式へ飛ぶのです。

MANRYO_YMD = DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu, NISSU)

DateSerial関数に指定している数値を解説します。

DateSerial(Year(KISAN_YMD), Month(KISAN_YMD) + tukisu, NISSU)
DateSerial(Year(#2019/8/31#), Month(#2019/8/31#) + 6, 29)
DateSerial(2019, 8 + 6, 29)
DateSerial(2019, 14, 29)
#2020/2/29#

この結果、2020/2/29となります。これは「応当日」ではなく、「満了日」ですので、「-1」する必要はありません。

MANRYO_YMD = #2020/2/29#

変数「MANRYO_YMD」に2020/2/29が格納されました。

スポンサーリンク

手順3

'手順3 基準日と満了日を比較し、基準日>満了日 であればTRUE、そうでないときはFalseを返す

最後の手順です。あとは簡単です。基準日と満了日をIF構文で比較し、関数「Hantei」に計算の結果が「True」であるか「False」であるかを入力してやればよいのです。

If KIZYUN_YMD > MANRYO_YMD Then

    hantei = True
Else

    hantei = False
End If

計算の結果を入力したところです。関数「Hantei」は「Boolean型」なので、必ず「True」又は「False」になるように記述する必要があります。

コメントをどうぞ!