在 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" & 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 Calc Macro)