ExcelVBA 　関数

::: note warn
自分用のメモなので、形は整ってないです。
:::
### データ型の判定をする　VarType関数
```
Sub nnn()

'定数               値    内容
'vbEmpty            0     Empty値(未初期化)
'vbNull             1     Null値(無効な値)
'vbInteger          2     整数型(Integer)
'vbLong             3     長整数型(Long)
'vbSingle           4     単精度浮動小数点数型(Single)
'vbDouble           5     倍精度浮動小数点数型(Double)
'vbCurrency         6     通貨型(Currency)
'vbDate             7     日付型(Date)
'vbString           8     文字列型(String)
'vbObject           9     オブジェクト
'vbError            10    エラー値
'vbBoolean          11    ブール型(Boolean)
'vbVariant          12    バリアント型(Variant)  (バリアント型配列にのみ使用)
'vbDataObject       13    非OLE オートメーション オブジェクト
'vbDecimal          14    10進数型
'vbByte             17    バイト型(Byte)
'vbUserDefinedType  36    ユーザー定義型を含むバリアント型
'vbArray            8192～  配列 データ型によって8192+αになる

Dim var1 As Variant
Debug.Print VarType(var1)  '0

var1 = Null
Debug.Print VarType(var1)  '1

Dim int1 As Integer
Debug.Print VarType(int1)  '2

Dim long1 As Long
Debug.Print VarType(long1) '3

Dim sng1 As Single
Debug.Print VarType(sng1)  '4

Dim dbl1 As Double
Debug.Print VarType(dbl1)  '5

Dim cur1 As Currency
Debug.Print VarType(cur1)  '6

Dim date1 As Date
Debug.Print VarType(date1)  '7

Dim str1 As String
Debug.Print VarType(str1)  '8

Dim obj1 As Range
Debug.Print VarType(obj1)  '9

Dim bol1 As Boolean
Debug.Print VarType(bol1)  '11

Dim varArr() As Variant
varArr = Array(100, "aaa", 12.45)
Debug.Print VarType(varArr)  '8204   8192+12 ということらしい

Debug.Print VarType(CDec(10.45))  '14

Dim byt1 As Byte
Debug.Print VarType(byt1)  '17

Debug.Print "-----------------------"

'Cells(1, 1)の書式は標準
Cells(1, 1).Value = 100
Debug.Print VarType(Cells(1, 1).Value)  '5  Doubleになるらしい

Cells(1, 1).Value = "aaa"
Debug.Print VarType(Cells(1, 1).Value)  '8


Cells(1, 1).Value = 100
Cells(1, 2).Value = "aaa"
Cells(2, 1).Value = 30.45
Cells(2, 2).Value = "500"
var1 = Range(Cells(1, 1), Cells(2, 2)).Value
Debug.Print VarType(var1)  ' 8204

Cells(1, 1).Value = 100
Cells(1, 2).Value = 200
Cells(2, 1).Value = 300
Cells(2, 2).Value = 400
var1 = Range(Cells(1, 1), Cells(2, 2)).Value
Debug.Print VarType(var1)  ' 8204

Cells(1, 1).Value = ""
Cells(1, 2).Value = ""
Cells(2, 1).Value = ""
Cells(2, 2).Value = ""
var1 = Range(Cells(1, 1), Cells(2, 2)).Value
Debug.Print VarType(var1)  ' 8204

'セル範囲をVariant変数に格納した場合は、セルの値にかかわらず8204になるみたい
'ただし、以下のような例外もあり

Cells(1, 1).Value = ""
var1 = Range(Cells(1, 1), Cells(1, 1)).Value  '空白の1セルのみをVariantに格納
Debug.Print VarType(var1)  ' 0  Emptyになる

Cells(1, 1).Value = 100
var1 = Range(Cells(1, 1), Cells(1, 1)).Value  '空白ではない1セルのみをVariantに格納
Debug.Print VarType(var1)  ' 5　配列ではなく、Double型の数値となる

'※1セルのみ範囲をVariantに格納すると、配列扱いにならない事に注意。空白セルだとEmptyである事も

Debug.Print "-----------------------"

Dim arr1(1 To 3) As Long
Debug.Print VarType(arr1)  '8195   8192+3 ということらしい

Dim arr2(1 To 3) As String
Debug.Print VarType(arr2)  '8200  8192+8

Debug.Print VarType(Array(100, 200, 300))  '8204  こうしても8204らしい

End Sub
```
### 日付・時刻
```
Dim str1

str1 = Date
MsgBox str1   ' yyyy/mm/dd の形で表示

str1 = Year(Date)
MsgBox str1   ' 年を取得

str1 = Month(Date)
MsgBox str1   ' 月を取得

str1 = Day(Date)
MsgBox str1   ' 日を取得

str1 = Format(Date, "yyyy年mm月dd日")
MsgBox str1   ' yyyy年mm月dd の形で表示


str1 = Now
MsgBox str1   ' yyyy/mm/dd hh:mm:ss の形で表示


str1 = Time
MsgBox str1  ' hh:mm:ss の形で表示

str1 = Hour(Time)
MsgBox str1   ' 時を取得

str1 = Minute(Time)
MsgBox str1   ' 分を取得

str1 = Second(Time)
MsgBox str1   ' 秒を取得


Dim long1 As Long
long1 = Weekday(Date)   ' 曜日を整数値で取得する

Select Case long1
Case 1
    MsgBox "日曜日"
Case 2
    MsgBox "月曜日"
Case 3
    MsgBox "火曜日"
Case 4
    MsgBox "水曜日"
Case 5
    MsgBox "木曜日"
Case 6
    MsgBox "金曜日"
Case 7
    MsgBox "土曜日"
End Select

long1 = Weekday(Date + 3)   ' ３日後の曜日を整数値で取得


Dim startTime As Single
startTime = Timer     ' 0:00:00　からの経過秒数を、Single型で取得する
MsgBox startTime


MsgBox DateAdd("d", 10, "2017/6/23")       ' 2017/6/23の10日後を取得("d"で日)
MsgBox DateAdd("yyyy", 10, "2017/6/23")    ' 2017/6/23の10年後を取得("yyyy"で年)
MsgBox DateAdd("m", -5, "2017/6/23")       ' 2017/6/23の5月前を取得("m"で月)
MsgBox DateAdd("h", 3, "11:40:50")         ' 11:40:50の3時間後を取得("h"で時)
' ※この他にもプロパティ値はあるので、詳しくは調べて


' 文字列から日付を取得。DateValue関数でもほぼ同様の機能
MsgBox CDate("2017/01/01") + 10         ' 10日後
MsgBox CDate("17/01/01") + 10           ' 同上
MsgBox CDate("平成29年1月1日") + 10     ' 同上
MsgBox CDate(60000) + 10                ' シリアル値からも取得できる
```
### VBAでワークシート関数を使う
```
MsgBox Application.WorksheetFunction.Max(Range("A1:A10"))
' ワークシート関数の"MAX関数"を使う

MsgBox Application.Max(Range("A1:A10"))   'これでもいいらしい
```
### 文字列から数値に変換できる部分までを取得する(Val関数)
```
MsgBox Val("123abc")   ' 123 が返る
MsgBox Val("123.456")   ' 123.456 が返る
MsgBox Val("123,456")   ' 123 が返る
MsgBox Val("123+456")   ' 123 が返る
MsgBox Val("-100")     '  -100が返る
MsgBox Val("ABC")      ' 0 が返る

Dim long1 As Long

long1 = Val(InputBox("0以外の数値を入力してください"))
If long1 = 0 Then
' 0か数値に変換できない文字列が入力された場合  キャンセルした場合もこちらになってしまうが
    MsgBox "正しく数値を入力してください"
Else
    MsgBox "入力された数値は " & long1
End If
```
### 文字列操作
```
Dim str1 As String
Dim str2 As String

str1 = "abcdefg123"
str2 = "日本語の文字列"

MsgBox Left(str1, 3)   ' 左から3文字を取得
MsgBox Left(str2, 4)

MsgBox LeftB(str1, 3)   ' 左から3バイト分を取得
MsgBox LeftB(str2, 4)

MsgBox Right(str1, 5)  ' 右から5文字を取得
MsgBox RightB(str1, 7)  ' 右から7バイトを取得。取得バイト数を奇数にすると文字化けするみたい
MsgBox RightB(str1, 8)

MsgBox Len(str1)  ' 文字列長を取得
MsgBox Len(str2)
MsgBox LenB(str1)   ' 文字列のバイト数を取得
MsgBox LenB(str2)

MsgBox LenB(StrConv(str1, vbFromUnicode))  ' 半角文字は1バイト、全角文字は2バイトとしてバイト数を取得
MsgBox LenB(StrConv(str2, vbFromUnicode))

MsgBox Mid$(str1, 3, 5)   ' 3文字目から5文字分を取得。0文字目という指定はエラーになるので注意
MsgBox Mid$(str1, 1, Len(str1))    ' 文字列全体を取得
MsgBox Mid$(str1, 1)               ' これも文字列全体を取得
    
' ※※  Left Right Mid 等の関数は、末尾に$をつけたほうが処理が高速・データ型の食い違いを防ぐらしい


MsgBox InStr(str1, "e")    ' str1の文字列内で左から検索し、"e"のある位置を取得
MsgBox InStr(str1, "x")    ' 指定の文字列が存在しない場合は、0が返る

str1 = "ABCDE"
MsgBox InStr(1, str1, "abc", 0)
' 1文字目から検索開始、バイナリ比較。大文字小文字、全角半角、ひらがなカタカナの区別をする
MsgBox InStr(1, str1, "abc", 1)
' 1文字目から検索開始、テキスト比較。大文字小文字、全角半角、ひらがなカタカナの区別をしない

str1 = "abcdefgabc"
MsgBox InStrRev(str1, "a")   ' str1の文字列内で右から検索し、左から何番目の位置かを取得


str1 = "ABCDEFG"
MsgBox LCase(str1)   ' 小文字に変換

str1 = "hijklmn"
MsgBox UCase(str1)   ' 大文字に変換


str1 = "abcDEFひらがなカタカナ"
MsgBox StrConv(str1, vbUpperCase)    ' 大文字に変換
MsgBox StrConv(str1, vbLowerCase)    ' 小文字に変換
MsgBox StrConv(str1, vbProperCase)   ' 先頭の文字を大文字に変換
MsgBox StrConv(str1, vbWide)         ' 全角文字に変換
MsgBox StrConv(str1, vbNarrow)       ' 半角文字に変換
MsgBox StrConv(str1, vbKatakana)     ' カタカナに変換
MsgBox StrConv(str1, vbHiragana)     ' ひらがなに変換
MsgBox StrConv(str1, vbUnicode)      ' システムの既定のコードページを使って文字列をUnicodeに変換
MsgBox StrConv(str1, vbFromUnicode)  ' 文字列をUnicodeからシステムの既定のコードページに変換


MsgBox Chr(0)                         ' vbNullChar  値0を持つ文字
MsgBox "aaa" & Chr(8)                 ' vbBack  バックスペース
MsgBox "a" & Chr(9) & "b"             ' vbTab  タブ
MsgBox "a" & Chr(10) & "b"            ' vbLf  ラインフィールド
MsgBox "a" & Chr(13) & "b"            ' vbCr　キャリッジリターン
MsgBox "a" & Chr(13) + Chr(10) & "b"  ' vbCrLf　ラインフィールドとキャリッジリターン


MsgBox Asc("abc")   ' 文字列の先頭の文字の文字コードを取得


str1 = " ABC "
MsgBox "X" & LTrim(str1) & "X"   ' 左側にあるスペース(全角スペースも)を削除する
MsgBox "X" & RTrim(str1) & "X"   ' 右側にあるスペースを削除する
MsgBox "X" & Trim(str1) & "X"    ' 左右にあるスペースを削除する


str1 = "abc abc ABC"
MsgBox Replace(str1, " ", "")   ' スペースを空文字に置換
MsgBox Replace(str1, "a", "X")
MsgBox Replace(str1, "a", "X", , , 1)
' テキストモード(大文字小文字、全角半角等の区別をしない)で検索し、置換する。デフォルトはバイナリモード


MsgBox StrComp("abc", "abc")    ' 2つの文字列が一致する場合、0を返す
MsgBox StrComp("abc", "ABC")    ' 2つの文字列が一致しない場合、1または-1を返す
MsgBox StrComp("abc", "ABC", 1)   ' テキストモードで比較。デフォルトはバイナリモード


MsgBox StrReverse("1234567890")   ' 逆順の文字列を取得
MsgBox StrReverse("ﾌﾞﾛｯｸﾌﾟﾗﾝ")    ' 半角カタカナは濁点・半濁点の位置がおかしくなるので注意


MsgBox WeekdayName(1)           ' "日曜日"が返る
MsgBox WeekdayName(7)           ' "土曜日"が返る
MsgBox WeekdayName(7, True)     ' "土"が返る　("曜日"を省略した形)


' 大文字小文字を区別しないで検索したい場合の、１つの方法
Dim var1 As Variant
Dim seachStr As String
seachStr = "aBc"

For Each var1 In Range("A1:A10")
    If LCase(seachStr) = LCase(var1.Value) Then
    ' 検索文字列とセルの値を、両方小文字に変換してから比較する
        MsgBox var1.Address & " で検索ヒット"
    End If
Next var1
```
### Format　関連
```
MsgBox Format(123, "0000")     ' 0123  0の数分の数値で表記。桁が足りない部分は0埋め
MsgBox Format(123, "####")     ' 123  #の数分の数値で表記。桁が足りない部分は表示無し
MsgBox Format(123.4, "0.00")   ' 123.40
MsgBox Format(0.456, "0%")     ' 46%  パーセント表記。はみ出る桁は四捨五入
MsgBox Format(123456789, "#,##0")  ' 123,456,789  1000単位で区切り表記
MsgBox Format(456.5, "0.00\c\m")  ' 456.50cm  \の後の1文字をそのまま表示する

MsgBox Format(40000, "Long Date")     ' 2009年7月6日　　シリアル値を長い日付表記
MsgBox Format(40000, "Medium Date")   ' 09-07-06　　シリアル値を簡略日付表記
MsgBox Format(40000, "Short Date")    ' 2009/7/6　　シリアル値を短い日付表記

MsgBox FormatCurrency(1234567)   ' \1,234,567   通貨形式で表示。Windowsの設定に影響される
```
### 配列要素を連結して文字列に、文字列を分割して配列に格納する(Join Split関数)
```
Dim array1(3) As String
array1(0) = "AA"
array1(1) = "BB"
array1(2) = "CC"

MsgBox Join(array1, " ")   ' 半角スペースを区切り文字として、配列の要素を連結

Dim i As Long
Dim array2() As String ' 可変長配列

array2 = Split("ああ-いい-うう-ええ-おお", "-")  ' "-"を区切り文字として、文字列を分割し配列に格納
For i = 0 To UBound(array2)
    MsgBox "要素" & i & "の値：" & array2(i)
Next i
```
### データ型変換関数　　文字列型に変換するCStr、Long型に変換するCLng等
```
Debug.Print CBool(0)  ' Boolean型変換　0はFalse、それ以外の数値はTrueに変換される。数値以外はエラーになるので注意
Debug.Print CBool(1)
Debug.Print CBool(-1000)

Debug.Print CByte(123.456)   ' バイト型変換
Debug.Print CCur(123.456)    ' 通貨型変換
Debug.Print CDate(123.456)   ' 日付型変換
Debug.Print CSng(123.456)    ' Single型変換
Debug.Print CDbl(123.456)    ' Double型変換
Debug.Print CDec(123.456)    ' Decimal型変換
Debug.Print CInt(123.456)    ' Integer型変換
Debug.Print CLng(123.456)    ' Long型変換
Debug.Print CStr(123.456)    ' 文字列型変換
Debug.Print CVar(123.456)    ' バリアント型変換

Debug.Print Hex(1000)   ' 16進数変換
Debug.Print Oct(1000)   ' 8進数変換

'Debug.Print CLng(1E+22)  これはオーバーフローでエラーになるので注意
```
### 値が数値・日付に変換できるか、空でないか等をチェックをする関数　　IsNumeric関数など
```
' 日付に評価できるか
Debug.Print IsDate("2017/01/01")   ' True
Debug.Print IsDate("12:00:00")     ' True
Debug.Print IsDate(456)            ' False
Debug.Print IsDate("ABC")          ' False

' 数値に評価できるか
Debug.Print IsNumeric("123")          ' True
Debug.Print IsNumeric("123,456")      ' True
Debug.Print IsNumeric("\123.50")      ' True
Debug.Print IsNumeric("2017/12/02")   ' False

' オブジェクトに評価できるか
Dim obj1 As Object
Dim obj2 As Object
Dim obj3 As Object
Set obj1 = ThisWorkbook
Set obj2 = ActiveSheet
Set obj3 = Nothing

Debug.Print IsObject(obj1)    ' True
Debug.Print IsObject(obj2)    ' True
Debug.Print IsObject(obj3)    ' True
Debug.Print IsObject(123)     ' False
Debug.Print IsObject("ABC")   ' False

' Empty値か  ※Empty値とは、バリアント変数に値が格納されていない状態
Dim var1 As Variant
Debug.Print IsEmpty(var1)   ' True
var1 = ""
Debug.Print IsEmpty(var1)   ' False

' 配列に評価できるか
var1 = Array(1, 2, 3)
Debug.Print IsArray(var1)    ' True
var1 = 1000
Debug.Print IsArray(var1)    ' False

' エラー値であるか
var1 = CVErr(2007)  ' CVErr()は数値をエラー値に変換する関数。No.2007は#DIV/0
Debug.Print IsError(var1)    ' True
var1 = 2007
Debug.Print IsError(var1)    ' False
```
### ユーザ定義関数
```
*************   ユーザ定義関数   *****************

Function Triangle() As Double  ' 三角形の面積を返すFunction

    Triangle = Cells(13, 1).Value * Cells(13, 2).Value / 2
    ' ワークシート上で「=Triangle()」として、関数として利用できる

End Function


Function sumRange(range1 As Range) As Long  ' 引数で指定されたセル範囲の合計を返す

    Dim range2 As Range
    Dim long1 As Long

    For Each range2 In range1
        long1 = long1 + range2.Value
    Next range2
    
    sumRange = long1

End Function


Function autoCalculate(long1 As Long) As Long  ' 自動再計算をする関数

    Application.Volatile   ' 自動再計算を行うように設定

    autoCalculate = Cells(30, 1).Value * long1
    ' 自動再計算をするので、Cells(30, 1)の値を変更するたびに再計算される
    
    ' ※実際には、Excelの自動計算の設定に影響されるみたいだけど･･･

End Function
```
### A1参照形式から、R1C1形式へ変換する　(ConvertFormula関数)
```
Dim formulaStr As String

' ※現在のExcelの計算式方式はA1表記、Range("C3")の数式は =SUM(A1:B3) になっている

formulaStr = Application.ConvertFormula(Formula:=Range("C3").Formula, _
    FromReferenceStyle:=xlA1, ToReferenceStyle:=xlR1C1, RelativeTo:=Range("C3"))
' Range("C3")に入っているA1形式の数式を、R1C1形式に変換したものを取得。RelativeTo:= には変換対象の数式が入っているセルを選択

Debug.Print formulaStr   ' =SUM(R[-2]C[-2]:RC[-1]) となっている


' ※逆の変換も可能。Excelの計算式方式はR1C1表記にして、Range("C3")の数式は =SUM(R[-2]C[-2]:RC[-1]) になっている

formulaStr = Application.ConvertFormula(Formula:=Range("C3").Formula, FromReferenceStyle:=xlR1C1, ToReferenceStyle:=xlA1, RelativeTo:=Range("C3"))
Debug.Print formulaStr
' =SUM('A1':'B3') と表示された？？。一応変換はされたが、このままでは使えない

Debug.Print Replace(formulaStr, "'", "")   ' こうやって =SUM(A1:B3) に直すくらいか。使いにくいな


'　正直言って、使いにくい。ヘルプの間違いもあるようなので、それも考えて使うかどうか
```
### 絶対参照の数式から、相対参照の数式に変換する　(ConvertFormula関数)
```
Dim formulaStr As String

' ※現在のExcelの計算式方式はA1表記、Range("C3")の数式は =SUM($A$1:$B$3) になっている

formulaStr = Application.ConvertFormula(Range("C3").Formula, xlA1, xlA1, xlRelative)
' 絶対参照の式を相対参照に変換
' xlA1, xlA1の部分は、A1形式からA1形式へという意味だが、これは省略しないほうがいい

Debug.Print formulaStr   ' =SUM(A1:B3) となっている
Range("C3").Formula = formulaStr  ' セルの数式を相対参照へ


formulaStr = Application.ConvertFormula(Range("C3").Formula, xlA1, xlA1, xlAbsolute)
' これは相対参照を絶対参照へ変換

Debug.Print formulaStr   ' =SUM($A$1:$B$3) となっている


' Excelの計算式方式をR1C1表記に変更、Range("C3")の数式は =SUM(R1C1:R3C2) になっている

formulaStr = Application.ConvertFormula(Range("C3").Formula, xlA1, xlR1C1, xlRelative)
' 相対参照へ変換
' xlA1, xlR1C1 はA1形式からR1C1形式へということだが、なぜかこれで上手くいく。xlR1C1,xlR1C1 にすると、エラーになる。なぜ？

Debug.Print formulaStr   ' =SUM(R[-2]C[-2]:RC[-1]) になっている
Range("C3").Formula = formulaStr  ' セルの数式を相対参照へ

formulaStr = Application.ConvertFormula(Range("C3").Formula, xlA1, xlR1C1, xlAbsolute)  ' 絶対参照へ
Debug.Print formulaStr  ' =SUM(R1C1:R3C2) になっている


' ※ヘルプの間違いがあるらしいし、仕様も謎が多いので使いにくいかも
```
### 数値を四捨五入する　Round関数
```
Sub aaa()

    Debug.Print Round(123.123456, 0)  ' 結果は123
    Debug.Print Round(123.123456, 1)  ' 結果は123.1
    Debug.Print Round(123.123456, 2)  ' 結果は123.12
    Debug.Print Round(123.123456, 3)  ' 結果は123.123
    Debug.Print Round(123.123456, 4)  ' 結果は123.1235
    Debug.Print Round(123.123456, 5)  ' 結果は123.12346

    ' 四捨五入する桁の数値が「5」で、それ以降の桁の数値が存在しない場合、四捨五入する桁の前の桁の数値が偶数になるようにしてしまう仕様らしいので注意
    Debug.Print Round(123.15, 1)  ' 結果は123.2
    Debug.Print Round(123.25, 1)  ' 結果は123.2  本来なら切り上げて123.3になりそうなものだが、小数1桁目を偶数にする仕様なのでこうなる
    Debug.Print Round(123.5, 0)  ' 結果は124
    Debug.Print Round(124.5, 0)  ' 結果は124

    ' ワークシート関数を使うと、この問題を解決できる
    Debug.Print WorksheetFunction.Round(123.15, 1)  ' 結果は123.2
    Debug.Print WorksheetFunction.Round(123.25, 1)  ' 結果は123.3
    Debug.Print WorksheetFunction.Round(123.5, 0)  ' 結果は124
    Debug.Print WorksheetFunction.Round(124.5, 0)  ' 結果は125
    
    
    ' ワークシート関数を使うと、整数部の四捨五入もできる
    Debug.Print WorksheetFunction.Round(12345.678, -1)  ' 結果は12350  整数部の1桁目を四捨五入
    Debug.Print WorksheetFunction.Round(12345.678, -2)  ' 結果は12300  整数部の2桁目を四捨五入
    Debug.Print WorksheetFunction.Round(12345.678, -3)  ' 結果は12000  整数部の3桁目を四捨五入

End Sub
```
### Enviroment　　環境変数の値を取得する
```
Debug.Print Environ("PATH")       '  PATH環境変数
Debug.Print Environ("OS")         '  オペレーティングシステム
Debug.Print Environ("HOMEDRIVE")  '  プライマリ ローカル ドライブ
Debug.Print Environ("HOMEPATH")   '  既定のユーザー用ディレクトリ
Debug.Print Environ("TEMP")       '  tempディレクトリ
Debug.Print Environ("USERNAME")   '  ユーザー名
Debug.Print Environ("WINDIR")     '  システムディレクトリ
```
### 配列数式(FREQUENCY等)を使う方法
```
range(Cells(16, 8), Cells(21, 8)).FormulaArray = "=FREQUENCY(R[-13]C[-5]:R[31]C[-4],RC[-1]:R[5]C[-1])"

' FREQUENCY関数は配列関数。FormulaArrayで設定できる
' {} で囲んでも駄目らしい
```
### 日付・時刻データの比較と演算　　CDate関数の利用等
```
Sub aaaa()
  Debug.Print bbbb("2020/1/15")       '2020/1/1より大きい(未来)
  Debug.Print bbbb("2020/1/1")        '2020/1/1と等しい
  Debug.Print bbbb("2019/12/31")      '2020/1/1より小さい(過去)
'  Debug.Print bbbb("令和2年1月1日")　　これはエラーになる。Excel2016での実行
  Debug.Print bbbb("平成25年1月1日")  '2020/1/1より小さい(過去)
  Debug.Print bbbb("昭和63年1月1日")  '2020/1/1より小さい(過去)
  Debug.Print bbbb("2022-12-31")      '2020/1/1より大きい(未来)
  Debug.Print bbbb("2020/01/01")      '2020/1/1と等しい
  
  Debug.Print CDate("2020/1/1")           '2020/01/01
  Debug.Print VarType(CDate("2020/1/1"))  '7  日付型
  Debug.Print CDbl(CDate("2020/1/1"))     '43831
  
  Debug.Print bbbb("2020/1/1 12:00:00")    '2020/1/1より大きい(未来)
  Debug.Print bbbb("2020/1/1 0:00:00")     '2020/1/1と等しい
  Debug.Print bbbb("2019/12/31 23:59:59")  '2020/1/1より小さい(過去)
  
  Debug.Print CDbl(CDate("2020/1/1 12:00:00"))    '43831.5
  Debug.Print CDbl(CDate("2020/1/1 0:00:00"))     '43831
  Debug.Print CDbl(CDate("2019/12/31 23:59:59"))  '43830.9999884259
  
  Debug.Print bbbb(CStr(Date))  '2020/1/1より大きい(未来)  Date関数での比較も可能

  Debug.Print bbbb(Format("20200101", "@@@@/@@/@@"))  '2020/1/1と等しい  Format関数を使って日付型へ変換
  
  
  Debug.Print TimeValue("15:1:2")          '15:01:02
  Debug.Print VarType(TimeValue("15:1:2")) '7  日付型
  Debug.Print CDbl(TimeValue("15:1:2"))    '0.625717592592593
  Debug.Print CDate("15:1:2")              '15:01:02   CDate関数でも時刻型に変換できる
  Debug.Print TimeValue("15:1:2") = "15:01:02"  'True
  Debug.Print TimeValue("15:1:2") > "15:01:01"  'True
  Debug.Print TimeValue("15:1:2") < "15:01:03"  'True
  Debug.Print TimeValue("15:1:2") < "15:01:00"  'False
  
  
  Debug.Print CDate("2020/1/15") - CDate("2020/1/10")           '5  日付での引き算
  Debug.Print VarType(CDate("2020/1/15") - CDate("2020/1/10"))  '5  小数型になっている
  Debug.Print CDate(CDate("2020/1/15") - CDate("2020/1/10"))    '1900/01/04
  Debug.Print CDate("2020/1/15 12:15:15") - CDate("2020/1/10 0:00:00")  '5.51059027777956
  
  Debug.Print CDate("2:15:15") - CDate("1:00:00")        '5.22569444444444E-02
  Debug.Print CDate(5.22569444444444E-02)                '1:15:15
  Debug.Print CDate(CDate("2:15:15") - CDate("1:00:00")) '1:15:15  時間の演算なら、こうするのが分かりやすいか
  'Debug.Print TimeValue(5.22569444444444E-02)  'これはエラーになってしまう
  
End Sub

Function bbbb(dateStr As String) As String

  If CDate(dateStr) > "2020/1/1" Then
    bbbb = "2020/1/1より大きい(未来)"
  ElseIf CDate(dateStr) = "2020/1/1" Then
    bbbb = "2020/1/1と等しい"
    ElseIf CDate(dateStr) < "2020/1/1" Then
    bbbb = "2020/1/1より小さい(過去)"
  End If

End Function
```
### 日付・時刻の加算と減算　　日付・時刻の差分を求める　　DateAdd関数、DateDiff関数
```
Sub AAA()  '**********  日付・時刻の加算と減算  ************

Debug.Print DateAdd("yyyy", 1, CDate("2021/1/1"))       '1年後  2022/01/01
Debug.Print DateAdd("m", 1, CDate("2021/1/1"))          '1月後  2021/02/01
Debug.Print DateAdd("d", 1, CDate("2021/1/1"))          '1日後  2021/01/02
Debug.Print DateAdd("ww", 1, CDate("2021/1/1"))         '1週間後  2021/01/08
Debug.Print DateAdd("q", 1, CDate("2021/1/1"))          '1四半期後  2021/04/01
Debug.Print DateAdd("h", 1, CDate("2021/1/1 12:15:26")) '1時間後  2021/01/01 13:15:26
Debug.Print DateAdd("n", 1, CDate("2021/1/1 12:15:26")) '1分後  2021/01/01 12:16:26
Debug.Print DateAdd("s", 1, CDate("2021/1/1 12:15:26")) '1秒後  2021/01/01 12:15:27

Debug.Print DateAdd("yyyy", -2, CDate("2021/1/1"))       '2年前  2019/01/01
Debug.Print DateAdd("m", -2, CDate("2021/1/1"))          '2月前  2020/11/01
Debug.Print DateAdd("d", -2, CDate("2021/1/1"))          '2日前  2020/12/30
Debug.Print DateAdd("ww", -2, CDate("2021/1/1"))         '2週間前  2020/12/18
Debug.Print DateAdd("q", -2, CDate("2021/1/1"))          '2四半期前  2020/07/01
Debug.Print DateAdd("h", -2, CDate("2021/1/1 12:15:26")) '2時間前  2021/01/01 10:15:26
Debug.Print DateAdd("n", -2, CDate("2021/1/1 12:15:26")) '2分前  2021/01/01 12:13:26
Debug.Print DateAdd("s", -2, CDate("2021/1/1 12:15:26")) '2秒前  2021/01/01 12:15:24

Debug.Print DateAdd("y", 10, CDate("2021/1/1"))     '通年での日数  2021/01/11
Debug.Print DateAdd("y", 365, CDate("2021/1/1"))    '2022/01/01
Debug.Print DateAdd("y", 365, CDate("2020/1/1"))    '2020/12/31
Debug.Print DateAdd("y", 366, CDate("2020/1/1"))    '2021/01/01
Debug.Print DateAdd("y", -61, CDate("2021/3/1"))    '2020/12/30
Debug.Print DateAdd("y", -61, CDate("2020/3/1"))    '2019/12/31


'うるう年
Debug.Print DateAdd("yyyy", 1, CDate("2020/2/29"))  '2021/02/28
Debug.Print DateAdd("m", 1, CDate("2020/2/29"))     '2020/03/29
Debug.Print DateAdd("d", 1, CDate("2020/2/29"))     '2020/03/01

Debug.Print DateAdd("yyyy", -2, CDate("2020/2/29"))  '2018/02/28
Debug.Print DateAdd("m", -2, CDate("2020/2/29"))     '2019/12/29
Debug.Print DateAdd("d", -2, CDate("2020/2/29"))     '2020/02/27


'時間の+-
Debug.Print DateAdd("h", 2, TimeValue("09:45:17"))  '11:45:17
Debug.Print DateAdd("h", 23, TimeValue("09:45:17")) '1899/12/31 8:45:17   これは注意で
Debug.Print DateAdd("n", 2, TimeValue("09:45:17"))  '9:47:17
Debug.Print DateAdd("s", 2, TimeValue("09:45:17"))  '9:45:19

End Sub


Sub BBB()  '**********  日付・時刻の差分を求める  ************

Debug.Print DateDiff("yyyy", CDate("2021/1/1 0:00:00"), CDate("2023/3/4 12:15:21")) '2
'パラメータ2の日時から、パラメータ3の日時が何年先かを取得

Debug.Print DateDiff("yyyy", CDate("2023/3/4 12:15:21"), CDate("2021/1/1 0:00:00")) '-2
Debug.Print DateDiff("m", CDate("2021/1/1 0:00:00"), CDate("2021/3/4 12:15:21"))    '月　2
Debug.Print DateDiff("d", CDate("2021/1/1 0:00:00"), CDate("2021/1/4 12:15:21"))    '日　3
Debug.Print DateDiff("d", CDate("2021/1/1 0:00:00"), CDate("2022/1/4 12:15:21"))    '368
Debug.Print DateDiff("h", CDate("2021/1/1 0:00:00"), CDate("2021/1/1 12:15:21"))    '時　12
Debug.Print DateDiff("n", CDate("2021/1/1 0:00:00"), CDate("2021/1/1 0:15:21"))     '分　15
Debug.Print DateDiff("s", CDate("2021/1/1 0:00:00"), CDate("2021/1/1 0:00:21"))     '秒　21

End Sub
```