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

Posted

技术标签:

【中文标题】在 Libreoffice Basic 中将日期存储在数组中【英文标题】:Storing dates in an array in Libreoffice Basic 【发布时间】:2016-01-28 17:59:36 【问题描述】:

在过去的几天里,我一直在研究这个问题,但没有找到答案。我有一个交易列表,我从中过滤一个子集。对于子集,我将日期和金额存储在一个数组中,以用于 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 复制到新的来克服这个问题。但是运气不好,又双打了……

任何帮助将不胜感激。

【问题讨论】:

如果将生成的双精度数组放入电子表格,并将单元格格式设置为日期,它们是否正确显示? (如果双打是自 1899 年 12 月 31 日以来的天数 - 电子表格内部存储日期的方式与显示设置无关 - 这应该有效。) 是的,当我将结果数组放入工作表并将它们格式化为日期时,它们确实显示正确。但我正在寻找一种方法将这个特别的日期数组提供给 XIRR 函数,而这部分似乎不起作用(因为该数组包含日期的等值数,但不存储为日期) . XIRR 函数是否将字符串日期作为输入? 好问题!据我所知,XIRR 需要数值和日期。但我试图将日期作为字符串“输入”它,这给出了同样的错误。 【参考方案1】:

数字日期。 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,但这似乎不起作用。

【讨论】:

【参考方案2】:

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

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

下面是我用来测试这个概念的工作代码。将“C1:C3”更改为 TempSheet 上包含arrDates 内容的范围,例如"TempSheet.A1:A" &amp; 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

注意:我推荐我的其他答案而不是这个答案。

【讨论】:

以上是关于在 Libreoffice Basic 中将日期存储在数组中的主要内容,如果未能解决你的问题,请参考以下文章

Libreoffice calc 宏将当前日期 + 14 天放入单元格

如何在 Basic 中使用 LibreOffice 功能?

使用 LibreOffice Basic 迭代控件

在 Basic 中计算自己的对数(LibreOffice Calc Macro)

在 LibreOffice 宏的 Basic 中获取文档路径

使用 BASIC 在 LibreOffice 中复制表格的最后一行