バックグラウンド
ご存知のように、「怠惰は進歩の原動力です」。私の仕事では、ローン契約の利息を計算するためのテーブルを作成する必要があるときに問題に直面しました。ここで、1年の実際の日数はベースであるはずです。不便な点は、うるう年を忘れずに、うるう年に属する日とうるう年以外の日を分ける必要があることでした。簡単な式が書かれていましたが、うるう年の計算はそれほど簡単ではないことが後でわかりました。
問題の説明
式を改善したかった。インターネット上で、ある期間のうるう年またはうるう年以外の年数と日数が計算されたプログラムテキストをたくさん見つけました。しかし、残念ながら、これらの機能の速度が期間の年数に依存しているという事実には満足していませんでした。そして、その期間が何年であっても、同じようにすばやく機能するようにしたかったのです。しかし、開発中は、関数の許容期間を制限する必要がありました。
理由1
ほとんどの国はグレゴリオ暦に従って生活しています。うるう年の規則は、1582年に教皇グレゴリウス13世によって決定されました。
1.数が400で割り切れる年はうるう年です。
2.残りの年(数は100の倍数)はうるう年ではありません(たとえば、1700、1800、1900、2100、2200、2300年)。
3. , 4, - .
2900, 3200, 4000, 01.01.2900.
2
Excel VBA (Visual Basic for Applications). , MS Office, .
Excel , 1900 1904. 1900. , 1 01 1900 , 2 – 2 .
VBA CDate(expression), Date . 1, Date 31 1899 . 60 CDate 28.02.1900, 29.02.1900 (, , 1900 ). , 01 1900 .
Excel, Microsoft , . 01 1900 .
, () , .
, 4, 4 () 1 . 1- 1 4, 2- 5 8 .
1 4 (, 2021 506- , 1)
3 :
:
:
, , :
, , :
, , , 1- 366 ( 1 3, ).
VBA:
Private Function first_quartet_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long
Dim result As Long
result = 0
Dim year_diff As Long
Dim quartet_index_diff As Long
year_diff = year(d_end) - year(d_begin)
quartet_index_diff = quartet_index(year(d_end)) - quartet_index(year(d_begin))
If year_diff = 0 And is_year_leap(d_begin) Then
result = DateDiff("d", d_begin, d_end)
first_quartet_leap_year_days = result
Exit Function
End If
If quartet_index_diff = 0 Then
If is_year_leap(d_begin) Then
result = DateDiff("d", d_begin, CDate(DateSerial(year(d_begin), 12, 31)))
first_quartet_leap_year_days = result
Exit Function
End If
If is_year_leap(d_end) Then
result = DateDiff("d", CDate(DateSerial(year(d_end) - 1, 12, 31)), d_end)
first_quartet_leap_year_days = result
Exit Function
End If
Else
If is_year_leap(d_begin) Then
result = DateDiff("d", d_begin, CDate(DateSerial(year(d_begin), 12, 31)))
first_quartet_leap_year_days = result
Exit Function
Else
If Not is_quartet_noleap(quartet_index(year(d_begin))) Then
result = 366
first_quartet_leap_year_days = result
Exit Function
End If
End If
End If
first_quartet_leap_year_days = result
End Function
>0, 3- " ".
, , :
Private Function last_quartet_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long
Dim result As Long
result = 0
Dim quartet_index_diff As Long
quartet_index_diff = quartet_index(year(d_end)) - quartet_index(year(d_begin))
If quartet_index_diff > 0 Then
If is_year_leap(d_end) Then
result = DateDiff("d", CDate(DateSerial(year(d_end) - 1, 12, 31)), d_end)
End If
End If
last_quartet_leap_year_days = result
End Function
>1, 2- " ".
– . 1999 – 19, 2001 – 20, 1.
400-.
Private Function middle_quartets_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long
Dim quartet_count As Long
quartet_count = middle_quartets_count(d_begin, d_end)
If quartet_count = 0 Then
middle_quartets_leap_year_days = 0
Exit Function
End If
Dim q_begin, q_end As Long
q_begin = quartet_index(year(d_begin))
q_end = quartet_index(year(d_end)) - 1
Dim quot_25, quot_100 As Integer
quot_25 = WorksheetFunction.Quotient(q_end, 25) - WorksheetFunction.Quotient(q_begin, 25)
quot_100 = WorksheetFunction.Quotient(q_end, 100) - WorksheetFunction.Quotient(q_begin, 100)
Dim result As Long
result = (quartet_count - quot_25 + quot_100) * 366
middle_quartets_leap_year_days = result
End Function
:
Public Function LEAP_DAYS(ByVal val_begin As Long, ByVal val_end As Long, Optional count_first_day = 0, Optional count_last_day = 1) As Long
Dim d_begin, d_end As Date
count_first_day = IIf(count_first_day <> 0, 1, 0)
count_last_day = IIf(count_last_day <> 0, 1, 0)
d_begin = CDate(val_begin)
d_end = CDate(val_end)
Dim check_error As Variant
check_error = check_constrains(d_begin, d_end)
If IsError(check_error) Then
LEAP_DAYS = check_error
Exit Function
End If
Dim result As Long
result = 0
If is_year_leap(d_begin) And count_first_day = 1 Then result = result + 1
If is_year_leap(d_end) And count_last_day = 0 Then result = result - 1
result = result + first_quartet_leap_year_days(d_begin, d_end) _
+ middle_quartets_leap_year_days(d_begin, d_end) _
+ last_quartet_leap_year_days(d_begin, d_end)
LEAP_DAYS = result
End Function
count_first_day
count_last_day
1 0. Date . .
, , . 23-24 .
, .
, . , (2900 - 1900). , 2900 .
以下はgithubへのリンクです。ここでは、Excelで機能するように設計された、VBAの期間のうるう日と一般的な日を計算する関数の完全な実装がレイアウトされています。この関数をお気に入りの言語に簡単に移植して、プロジェクトで使用できます。