Bug 161469 - NOW() Function in Calc Macro Omits Sub-Seconds
Summary: NOW() Function in Calc Macro Omits Sub-Seconds
Status: VERIFIED FIXED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: BASIC (show other bugs)
Version:
(earliest affected)
unspecified
Hardware: All All
: medium normal
Assignee: Andreas Heinisch
URL:
Whiteboard: target:25.2.0
Keywords:
Depends on:
Blocks:
 
Reported: 2024-06-08 05:05 UTC by Daniel Baran
Modified: 2024-06-21 05:18 UTC (History)
2 users (show)

See Also:
Crash report or crash signature:


Attachments
ODS File with macro to insert static timestamps. (15.09 KB, application/vnd.oasis.opendocument.spreadsheet)
2024-06-08 05:05 UTC, Daniel Baran
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Baran 2024-06-08 05:05:04 UTC
Created attachment 194603 [details]
ODS File with macro to insert static timestamps.

I'm using a basic macro in calc to insert
static timestamps via the NOW() function.
Cells are formatted for both Date/Time
and just Time (including sub-seconds).
This works perfectly well with one exception.
The sub-seconds are always "00" instead of the expected values.
Using NOW() in the formula bar returns the sub-seconds as expected.
I'm attaching a demo file that illustrates the issue.

Version: 7.6.7.2 (X86_64) / LibreOffice Community
Build ID: dd47e4b30cb7dab30588d6c79c651f218165e3c5
CPU threads: 12; OS: Windows 10.0 Build 22631; UI render: Skia/Raster; VCL: win
Locale: en-US (en_US); UI: en-US
Calc: CL threaded
Comment 1 Werner Tietz 2024-06-08 17:40:38 UTC
this python-snippet works as expected:

```
from datetime import datetime as dt

def timestamp(*event):
    doc = XSCRIPTCONTEXT.getDocument()
    sel = doc.CurrentSelection
    sel.Formula = f'{dt.now().isoformat()}'
```
Comment 2 Daniel Baran 2024-06-08 21:46:00 UTC
Thank you Werner.
I can confirm that your workaround works exactly as I intended.
I had to go learn how to employ Python in LO for the first time.
The only drawback is that the time-tracking utility I've built is
intended to be distributed to LO users who may not have Python
installed on their machines. So I'm hoping there is (or will be) a
way to do the same thing in LO Basic.
Comment 3 Werner Tietz 2024-06-09 10:38:22 UTC
Hello Daniel

my suggestion is not a WORKAROUND, because python, like basic, is a programming language available in Libreoffice.

There exists nowadays NO Libreoffice-package WITHOUT python**!


**either embedded into LO, or linked to the python-environment of the Operating System
Comment 4 Daniel Baran 2024-06-10 19:54:09 UTC
Having researched this further, I found that this rounding to
seconds is a known behavior of the NOW() function in Basic.

https://forum.openoffice.org/en/forum/viewtopic.php?p=455955&sid=32227f1e230f851464c32171720f030e#p455955

The suggested solution works for me in Libre Calc.

Example:

Dim TimeStamp()
	Dim svc As Object
	svc = createUnoService("com.sun.star.sheet.FunctionAccess") 
	Cell.Value = svc.callFunction("NOW",TimeStamp())

It is a somewhat unanticipated behavior of the NOW() function.
It's not clear to me what Status is warranted.
Comment 5 Andreas Heinisch 2024-06-12 05:44:04 UTC
Repro in:
Version: 7.6.1.2 (X86_64) / LibreOffice Community
Build ID: f5defcebd022c5bc36bbb79be232cb6926d8f674
CPU threads: 16; OS: Windows 10.0 Build 22631; UI render: Skia/Raster; VCL: win
Locale: en-GB (de_DE); UI: en-GB
Calc: CL threaded

Code pointer: https://opengrok.libreoffice.org/xref/core/basic/source/runtime/methods.cxx#2117
Comment 6 Werner Tietz 2024-06-12 08:51:19 UTC
disclaimer: I'm NOT a c++ programmer

@ https://opengrok.libreoffice.org/xref/core/basic/source/runtime/methods.cxx#2117
? should it work with:

```
2117  double Now_Impl()
2118  {
2119      DateTime aDateTime( DateTime::SYSTEM );
2120      double aSerial = static_cast<double>(GetDayDiff( aDateTime ));
2121      tools::Long nSeconds = aDateTime.GetHour();
2122      nSeconds *= 3600;
2123      nSeconds += aDateTime.GetMin() * 60;
2124      nSeconds += aDateTime.GetSec();
2125      double nDays = static_cast<double>(nSeconds) / (24.0*3600.0);
+2126     nano = aDateTime.GetNanoSec();
+2127     divisor = 86400000000000.0; 
+2128     double nanoSeconds = static_cast<double> nano / divisor ;
2129      aSerial += nDays;
+2130     aSerial += nanoSeconds;
2129  return aSerial;
2130  }

```
???

@Andreas Heinisch:
but the question is:
Why doesnt »Basic_now« use the same source as the »calc_now« ? both works obviously with the same epoch »1899-12-30«
Comment 7 Andreas Heinisch 2024-06-12 11:11:09 UTC
Code base with a many many different developers grown over time under different management
Comment 8 Andreas Heinisch 2024-06-12 12:25:31 UTC
I aligned the implementation with the implementation in calc: https://gerrit.libreoffice.org/c/core/+/168706
Comment 9 Daniel Baran 2024-06-14 22:57:23 UTC
For what it's worth:
I do a similar macro in Excel with VBA (example below).
Note that the square brackets around the NOW() function
are needed for fractional seconds to be displayed.
Without them, it still works, but output is rounded to
seconds similarly to the LO issue in this bug report.

Private Sub Insert_Time()
    Application.ActiveCell.Value = [Now()]
End Sub
Comment 10 Mike Kaganski 2024-06-20 04:55:27 UTC
(In reply to Werner Tietz from comment #6)
> Why doesnt »Basic_now« use the same source as the »calc_now« ? both works
> obviously with the same epoch »1899-12-30«

No, the Calc's NOW obviously (TM) ;) works with the epoch configured for Calc (which may vary); while the Basic one works with the fixed epoch.
Comment 11 Werner Tietz 2024-06-20 07:13:41 UTC
(In reply to Mike Kaganski from comment #10)
> (In reply to Werner Tietz from comment #6)
> > Why doesnt »Basic_now« use the same source as the »calc_now« ? both works
> > obviously with the same epoch »1899-12-30«
> 
> No, the Calc's NOW obviously (TM) ;) works with the epoch configured for
> Calc (which may vary); while the Basic one works with the fixed epoch.

Yes, I had found the source for basic_NOW, but unfortunatly I was not able to find the source of Calc_Now!

but that raises the next question... doesn't that inevitably lead to some unexpected errors that the  average Basic programmer would not expect? 

( as python-programmer I know about the different DateTime-models and can deal with it … but knows $random-basic-coder? and only in some hidden cornercases !! )
Comment 12 Mike Kaganski 2024-06-20 07:41:20 UTC
(In reply to Werner Tietz from comment #11)
> Yes, I had found the source for basic_NOW, but unfortunatly I was not able
> to find the source of Calc_Now!

FTR:
Basic implementation: https://opengrok.libreoffice.org/xref/core/basic/source/runtime/methods.cxx?r=&mo=62335&fi=2132#2132
Calc implementation: https://opengrok.libreoffice.org/xref/core/sc/source/core/tool/interpr2.cxx?r=&mo=3056&fi=111#111

> but that raises the next question... doesn't that inevitably lead to some
> unexpected errors that the  average Basic programmer would not expect?

Indeed. Using Calc, and working with its varying epoch, requires from a programmer taking that into account.
Comment 13 Werner Tietz 2024-06-20 08:33:18 UTC
@Mike thanks for the code-pointer!

Funny code-example ( assuming you've set the Calc-Epoch to »1904-01-01«


––––––––––
Sub Main
	' test with Calc-epoch »1904-01-01«
	doc = thisComponent
	svc = createUnoService("com.sun.star.sheet.FunctionAccess") 
	now_from_function_access = svc.callFunction("NOW",array())
	'! surprise ! the next  Print is correct…'
	print( format( now_from_function_access , "yyyy-mm-dd HH:MM:SS"))
	
	test_cell = doc.Sheets(0).getCellRangeByName("A1")
	test_cell.Formula = "=NOW()"
	'…but this fails:'
	print ( format( test_cell.Value , "yyyy-mm-dd HH:MM:SS"))
End Sub
Comment 14 Mike Kaganski 2024-06-20 09:13:16 UTC
(In reply to Werner Tietz from comment #13)
> 	doc = thisComponent
> 	svc = createUnoService("com.sun.star.sheet.FunctionAccess") 
> 	now_from_function_access = svc.callFunction("NOW",array())
> 	'! surprise ! the next  Print is correct…'
> 	print( format( now_from_function_access , "yyyy-mm-dd HH:MM:SS"))

Note how svc is completely unrelated to doc. The service instance uses its own internal settings. Imagine, that you would open several Calc documents, each with different own epoch (referenced them in doc1, doc2, doc3), and created the service as normal, without referencing any of the three: what would be your expectation, what epoch the service would use? ;-)
Comment 15 Commit Notification 2024-06-20 12:37:30 UTC
Andreas Heinisch committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/8730575016b15da4892c5adc0d26620688d174bc

tdf#161469 - Basic: align implementation now with the now function in calc

It will be available in 25.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 16 Daniel Baran 2024-06-21 03:21:06 UTC
Confirming that the fix works for me using the following.
Thanks all.

document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Doc = ThisComponent
Sheet = Doc.Sheets(0)
Cell = Doc.getCurrentSelection
Column = Cell.CellAddress.Column
Row = Cell.CellAddress.Row
Cell.Value = NOW()

Version: 25.2.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: 151d997365f7bf271d63af535d29a9c3439c6d46
CPU threads: 12; OS: Windows 11 X86_64 (10.0 build 22631); UI render: Skia/Vulkan; VCL: win
Locale: en-US (en_US); UI: en-US
Calc: CL threaded