エクセルVBAでプリザンターから情報取得、シリーズ。第8回です。
前回までVBAでエクスポートする方法をあれこれやってきました。今回はちょっと閑話休題番外編みたいな感じ。
プリザンターからVBAでエクスポートすると、日付の部分が 2023-08-15T16:09:21 のようになります。(APItypeでKeyValuesを指定した場合は日付型で出ましたが)
で、Tってなんなん?・・・というと、Timeを表しているのかもだけど、JsonConverterモジュールを使うとそうなっちゃうのかなあ、と思っております。
で、日付時刻型で出てくれた方がありがたいので、vbaコード内で日付時刻型に変換する方法をやってみたいと思います。
プリザンターも何も関係なくただ文字列の日付時刻をシリアル値に変換するってだけの話なんですけどね。。。
なお、VBAでのエクスポートのやり方、フィルター条件のやりかた、は割愛しますので、前回までの記事を参照してください。
※おことわり
2023年8月時点の情報です。プリザンターのバージョンは 1.3.20.0 です。Google Chrome でやっています。
javascript,html,cssともに初心者です。調べながら、やってみながら、きっとこうすればいいんだ!という感じで書いていますので、間違っている場合、効率的な書き方ではない可能性が大いにあります。間違ってるよ!とか、こうしたほうがいいよ!ということがありましたら、コメント等で教えていただけると大変ありがたいです。
1.変換せずに出力した場合
以下のコードで出力します。
Sub pleasanter_export14()
Const myApikey As String = "abcde12345"
Dim jsonRequest As Dictionary
Dim parseResponse As Dictionary
Dim httpRequest As Object
Set jsonRequest = New Dictionary
jsonRequest.Add "ApiVersion", "1.1"
jsonRequest.Add "ApiKey", myApikey
'jsonRequest.Add "View", New Dictionary
Set httpRequest = CreateObject("msxml2.xmlhttp")
httpRequest.Open "POST", "http://localhost/api/items/426/get"
httpRequest.setRequestHeader "Content-Type", "application/json;charset=utf-8"
httpRequest.send JsonConverter.ConvertToJson(jsonRequest)
Do While httpRequest.readyState < 4
DoEvents
Loop
Set parseResponse = JsonConverter.ParseJson(httpRequest.responseText)
If parseResponse("Response")("Data").Count <= 0 Then
MsgBox "なし"
Exit Sub
End If
Dim responseData As Variant
Dim i As Long: i = 2
For Each responseData In parseResponse("Response")("Data")
With ActiveSheet
.Cells(i, 1).Value = responseData("Title")
.Cells(i, 2).Value = responseData("DateHash")("DateA")
.Cells(i, 3).Value = responseData("UpdatedTime")
End With
i = i + 1
Next
MsgBox "出力完了"
End Sub
出力結果は以下のようになりました。
ちなみに日付Aの書式は「年月日」です。
2行目のタイトル200の日付Aが「1899-12-30T00:00:00」となっていますね。
これは実はこのレコードの日付A欄が空欄なのです。
空欄だと「1899-12-30T00:00:00」とでるので注意が必要です。
2.文字列を日付時刻型に変換するFunctionを作成する
(1)Cdate(日付だけ)
変換する文字列は 2023-08-15T16:09:21 のような形です。
日付だけ取り出したい場合は、左から10文字を取り出して、CDateに突っ込みます。
Function strDateToDate(ByVal str As String) As Date
'日付だけ
strDateToDate = CDate(Left(str, 10))
End Function
なお、日付欄が空欄の場合、 1899-08-15T00:00:00 のようにでるので、文字列の左4文字が「1899」の場合の処理も追加しておきます。
その場合空白を返したいのでstrDateToDateの返却の型はVariantにしておきます。
Function strDateToDate(ByVal str As String) As Variant
'日付だけ
If Val(Left(str, 4)) < 1900 Then '日付欄が空欄の場合の対応
strDateToDate = ""
Else
strDateToDate = CDate(Left(str, 10))
End If
End Function
これを先ほどのコードの出力個所に埋め込みます。
出力結果。空欄の処理もちゃんとできましたね。そして日付だけが返っています。
(2)Cdate(日付時刻)
同じくCDateで文字列(2023-08-15T16:09:21)から日付時刻を取り出します。
Replace関数で「T」をスペースに置換してからCDateにかけています。
Function strDateToDate(ByVal str As String) As Variant
'日付時刻
If Val(Left(str, 4)) < 1900 Then
strDateToDate = ""
Else
strDateToDate = CDate(Replace(str, "T", " "))
End If
End Function
結果はこうなりました(B・C列の書式設定は事前にyyyy/mm/dd hh:mm:ssにしています)
(3)DateSerial、TimeSerialを利用する
chatGTPさんに聞いたら、DateSerial、TimeSerialを使った方法も教えてくれました。
Function strDateToDate(ByVal str As String) As Variant
Dim dateParts() As String
Dim timeParts() As String
Dim dateTimeValue As Date
If Left(str, 4) < 1900 Then
strDateToDate = ""
Else
dateParts = Split(Split(str, "T")(0), "-")
timeParts = Split(Split(str, "T")(1), ":")
dateTimeValue = DateSerial(CInt(dateParts(0)), CInt(dateParts(1)), CInt(dateParts(2))) + _
TimeSerial(CInt(timeParts(0)), CInt(timeParts(1)), CInt(timeParts(2)))
strDateToDate = dateTimeValue
End If
End Function
chatGPT先生、変数名の付け方も粋ですね。いくらきいても「は?バカじゃない」みたいな顔されないからいいわ~。
結果は上記(2)と同じでした。
ちょっと解説をすると
dateParts = Split(Split(str, “T”)(0), “-“)
timeParts = Split(Split(str, “T”)(1), “:”)
Split(str, “T”)(0) Split(str, “T”)(1)
Split(str, “T”) で「T」で文字列を分割して前半部分をと後半部分にわけています。
すると [ “2023-08-15” , “16:09:21” ] のようなイメージの配列になります。
Split(str, “T”)(0) が 前半部分の “2023-08-15”
Split(str, “T”)(1) が 後半部分の “16:09:21”
さらにそれを日付部分は 「-」で [ “2023” , “08” , “15” ]に分割。
時刻部分は 「:」で [ “16” , “09” , “21” ]に分割。
それぞれ、用意してあった配列dateParts、timePartsに代入します。
DateSerialで年月日の文字列を日付型に変換(CIntで文字列を数値にしていますね)
DateSerial(CInt(dateParts(0)), CInt(dateParts(1)), CInt(dateParts(2)))
TimeSerialで年月日の文字列を日付型に変換(CIntで文字列を数値にしています)
TimeSerial(CInt(TimeParts(0)), CInt(TimeParts(1)), CInt(TimeParts(2)))
このそれぞれの結果を足しています。
連結しているわけではなく足しています。
シリアル値にすると、2023/8/15 16:9:21 は 45153.6731597222 になるようです。
DateSerialの結果 45153 と、TimeSerialの結果 0.6731597222 を足し合わせています。
で、返しています。
(4)正規表現を使った方法
わざわざ正規表現を使わなくってもよいのですが、いま特訓中なので。。。
Microsoft VBScript Regular Expressions 5.5を参照設定しています。
'参照設定:Microsoft VBScript Regular Expressions 5.5
Function strDateToDate(ByVal str As String) As Variant
If Val(Left(str, 4)) < 1900 Then
strDateToDate = ""
Exit Function
End If
'正規表現クラスオブジェクト
Dim re As RegExp
Set re = New RegExp
'検索条件設定
re.Global = True '検索範囲(True:文字列の最後まで検索)
re.IgnoreCase = True '大文字小文字の区別(True:区別しない)
re.Pattern = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" '検索パターン"
'検索結果を受け取るMatchesコレクション
Dim Matches As MatchCollection
Set Matches = re.Execute(str)
'日付時刻型変数でいったん受け取る
Dim dateTimeValue As Date
If Matches.Count > 0 Then
Dim match As match
Set match = Matches.Item(0)
Dim subMatches As Variant
Set subMatches = match.subMatches
With subMatches
dateTimeValue = DateSerial(.Item(0), .Item(1), .Item(2)) + _
TimeSerial(.Item(3), .Item(4), .Item(5))
End With
End If
strDateToDate = dateTimeValue
End If
こちらも結果は(2)と同じです。
これも途中からの部分はchatGPT先生に聞きました。
解説すると長くなるので割愛します。
苦労したところは、
ヒットしたアイテムの中の一つ目を取り出す
Set Matches = re.Execute(str)
その中からsubMatchesプロパティを取り出すところ
Set match = Matches.Item(0)
Set subMatches = match.subMatches
subMatches.Item(0)
subMatches.Item(1)
・・・
正規表現については自分で書いたこちらを見ながらやりました(もう忘れていた)
https://mwkexcelfriend.com/excel-vba-regexp/
3.最後に
文字列の日付をシリアル値に変換する方法をいくつかやりました。
エクスポートするときに変換をかけていますが、ワークシートに出力後一気に変換してもよいかもしれないです。
お読みいただきありがとうございました。
プリザンザンターVBAエクスポートシリーズ
【pleasanter/VBA】エクセルからプリザンターのデータを取得する
【pleasanter/VBA】エクセルからプリザンターのデータを取得する②絞り込み条件の指定
【pleasanter/VBA】エクセルからプリザンターのデータを取得する③変数で絞り込み条件を指定する
【pleasanter/VBA】エクスポート④絞り込み条件で〇〇を含むを指定する
【pleasanter/VBA】エクスポート⑤並べ替え
【pleasanter/VBA】エクスポート⑥表示名を出したい
【pleasanter/VBA】エクスポート⑦データがちょん切れる時の対応 Offset
【pleasanter/VBA】エクスポート⑧出力される日付を文字列ではなく日付時刻型で出したい(今回)
【pleasanter/VBA】エクスポート⑨汎用ツールを作ってみた
【pleasanter/VBA】エクスポート⑩汎用ツール増強版
VBAでインポート
【pleasanter/VBA】エクセルからプリザンターへデータを追加、更新する~import~
内部リンク:正規表現
https://mwkexcelfriend.com/excel-vba-regexp/
プリザンターPowerQuery連携シリーズ
【pleasanter/PowerQuery】プリザンターの情報をパワークエリで取得する①
【pleasanter/PowerQuery】プリザンターの情報をパワークエリで取得する②取得条件の指定方法
【pleasanter/PowerQuery】プリザンターの情報をパワークエリで取得する③上限値以上のレコードを連続で取得する
【pleasanter/PowerQuery】プリザンターの情報をパワークエリで取得する④ユーザーテーブルとマージ
コメント