在 Libreoffice Basic 中将日期存储在数组中

Storing dates in an array in Libreoffice Basic

最近几天我一直在研究这个问题,但没有找到答案。我有一个交易列表,我从中过滤了一个子集。对于子集,我将日期和金额存储在数组中,以用于 XIRR 计算。

输入列用'IsDate'测试,发现为True。此外,我在存储日期时使用 'ReDim Preserve (0 to n) As Date'。但是,在测试结果时,数组中包含的不是Dates而是Doubles。

请参考以下代码

Function FundXIRRTotal(ByVal FundISIN As String, ByVal KiesDatum As Date) As Double

Dim wshT As Object
Dim wshS As Object
Dim wshP As Object
Dim wsh As Object
Dim LastRow As Long
Dim i As Long
Dim NumberOfTrans As Long
Dim Guess As Double
Dim arrValues() As Double
Dim arrDates() As Date
Dim oFA As Object

Set wshT = ThisComponent.Sheets.getByName("Transacties")
Set wshP = ThisComponent.Sheets.getByName("Portefeuille")
Set wshS = ThisComponent.Sheets.getByName("Instellingen")

'Find Last Used Row
wsh = wshT.createCursor
wsh.gotoEndOfUsedArea( False )
LastRow = wsh.getRangeAddress().EndRow

NumberOfTrans = 0

'Create Transaction Array
For i = 1 To LastRow
    If wshT.getCellByPosition(3, i).String = FundISIN And CDate(wshT.getCellByPosition(0, i).Value) <= KiesDatum Then

        ReDim Preserve arrValues(0 To NumberOfTrans) As Double
        ReDim Preserve arrDates(0 To NumberOfTrans) As Date

        arrDates(NumberOfTrans) = CDate(wshT.getCellByPosition(0, i).Value)

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundBuy").String Then
            arrValues(NumberOfTrans) = -CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundSell").String Then
            arrValues(NumberOfTrans) = CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundDeposit").String Then
            arrValues(NumberOfTrans) = CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundDivCash").String Then
            arrValues(NumberOfTrans) = CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundDivShares").String Then
            arrValues(NumberOfTrans) = CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundSplit").String Then
            arrValues(NumberOfTrans) = -CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundFee").String Then
            arrValues(NumberOfTrans) = -CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        If wshT.getCellByPosition(1, i).String = wshS.getCellRangeByName("FundWarUit").String Then
            arrValues(NumberOfTrans) = -CDbl(wshT.getCellByPosition(9, i).Value / wshT.getCellByPosition(10, i).Value)
        End If

        NumberOfTrans = NumberOfTrans + 1      

    End If
Next i

'Add current value to Array
'NumberOfTrans = NumberOfTrans + 1
ReDim Preserve arrValues(0 To NumberOfTrans) As Double
ReDim Preserve arrDates(0 To NumberOfTrans) As Date
arrValues(NumberOfTrans) = CDbl(Waarde(FundISIN, KiesDatum))
arrDates(NumberOfTrans) = CDate(KiesDatum)

If Portfolio(FundISIN, KiesDatum) = 0 Then
    FundXIRRTotal = 0
    Exit Function
End If

'Calculate XIRR
oFA = createUNOService("com.sun.star.sheet.FunctionAccess")
FundXIRRTotal = oFA.callFunction("XIRR", Array(arrValues()), Array(arrDates()))

End Function

我知道 Array 函数存在数据类型丢失的问题。我试图通过创建一个新的 Array As Date 并将其从 arrDates 复制到新数组来克服这个问题。但是运气不好,又翻倍了...

如有任何帮助,我们将不胜感激。

作为解决方法,创建一个名为 "TempSheet" 的 sheet。它可以隐藏,因为它只是用于临时处理。

在 FundXIRRTotal 中,将 arrDates 写入 TempSheet 列 A。然后将该单元格范围传递给 oFA.callFunction()

下面是我用来测试这个概念的工作代码。将 "C1:C3" 更改为包含 arrDates 内容的 TempSheet 上的范围,例如 "TempSheet.A1:A" & Ubound(arrDates).

Function FundXIRRTotal(ByVal FundISIN As String, ByVal KiesDatum As Date) As Double
    Dim wshT As Object
    Dim i As Long
    Dim arrValues(2, 0) As Double
    Dim arrDates(2, 0) As Date
    Dim args as Array
    Dim oFA As Object

    Set wshT = ThisComponent.Sheets.getByName("Transacties")
    For i = 0 To 2
        arrDates(i, 0) = wshT.getCellByPosition(2, i).Value
        arrValues(i, 0) =  wshT.getCellByPosition(3, i).Value    
    Next i
    oFA = createUNOService("com.sun.star.sheet.FunctionAccess")
    args = Array(arrValues, wshT.getCellRangeByName("C1:C3"))
    FundXIRRTotal = oFA.callFunction("XIRR", args)
End Function

注意:我推荐我的另一个答案而不是这个。

数字日期。 UNO FunctionAccess 调用将不接受 OpenOffice Basic Date 类型,而是需要数字类型。

这是工作示例代码:

Function FundXIRRTotal(ByVal FundISIN As String, ByVal KiesDatum As Date) As Variant
    Dim wshT As Object
    Dim i As Long
    Dim arrValues(0, 2) As Double
    Dim unoDates(0, 2) As Double
    Dim theDate As Double
    Dim oFA As Object
    Dim args(2) As Variant
    Dim result As Variant

    Set wshT = ThisComponent.Sheets.getByName("Transacties")
    For i = 0 To 2
        arrValues(0, i) = wshT.getCellByPosition(3, i).Value
        'The date value will be a number, for example 42020 for 2015-01-16.
        theDate = wshT.getCellByPosition(2, i).Value
        unoDates(0, i) = theDate
    Next i
    oFA = createUNOService("com.sun.star.sheet.FunctionAccess")
    args = Array(arrValues, unoDates)
    result = oFA.callFunction("XIRR", args)
    FundXIRRTotal = result
End Function

另见 https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=67996

顺便说一句,我也尝试过使用 com.sun.star.util.Date,但似乎没有用。