Better - But Fiddlier - Conversion of DateTime Objects
Wed Sep 03 10:20:22 EDT 2025
Among the many classes in the lotus.domino
API, DateTime
has always been particularly cursed. Not quite as cursed as its brother DateRange
, which has never been - and still is not - readable from views and is only barely reconstructable in documents, but still rather cursed.
The Curse
For one, because it shares the trait with most other objects of having a backing C++ object that needs to be explicitly freed, it's important to make sure they're recycled regularly. But they immediately throw you a curveball in that they're children of Session
and not the Document
or ViewEntry
they're pulled from, making it highly likely that you're going to leave them floating in memory for longer than expected when you do a loop. Moreover, they're likely to show up in viewEntry.getColumnValues()
even if you don't care, so you have to make sure to studiously call, say, viewEntry.recycle(columnValues)
in your loop too - and how many of us remember to do that? And all that hassle just for 64 bits of data total.
To make matters worse, DateTime
had the bad luck of being paired with the famously bad java.util.Date
class, which is itself a weird wrapper around essentially just an Epoch timestamp and riddled with early-Java-era bad decisions. It's also a very poor representation for a Notes time value, since it can only represent a full date+time pair and has no concept of a time zone or offset. The remaining Notes-isms are left to methods like getDateOnly()
and getTimeOnly()
that return Strings. While an American may not worry about what "A string representation of the date part of the time-date" implies, that vagueness should send a shiver down the spine of anyone more worldly.
Better Ways
The thing is, though, that the Notes time format actually matches up pretty closely with three of the java.time
classes added in Java 8: LocalDate
, LocalTime
, and OffsetDateTime
. Though these classes are now over a decade old, IBM and now HCL have not added support for them in the lotus.domino
API. JNX does, though, and the results are much nicer than dealing with DateTime
. The trouble is that JNX can do this by way of accessing the two 32-bit integers that make up the "Innards" property of the TIMEDATE
struct, which isn't accessible on DateTime
.
Well, not properly accessible, anyway. I got a wild hair to improve the use in the NoSQL driver yesterday, so I started digging. Immediately, I noticed that the lotus.domino.local.DateTime
concrete class - the one used when not using CORBA or whatever "cso" references - has two int
instance members named "mInnards0" and "mInnards1". Well, that looked promising! My first attempt was to just get those values using reflection, but they were still set as 0 - that makes sense, since all the actual methods in that class go to native code that presumably accesses the C-side value.
Those properties are referenced in some methods to do with "restoring" the object, which is not really a concept in the API in general, but I figured it could be like how there seems to be some auto-GC code floating around in Notes.jar that doesn't really come into play. And, by gum, that's exactly what it is: for some reason, these values are written when you call recycle()
on the object. I don't know if this restoration mechanism is actually used or useful, but I don't really care; those two innards values are everything I need.
Putting It To Work
So I snagged the code from JNX that handles this and dropped it into the NoSQL driver, and now I can have a path that handles lotus.domino.local.DateTime
objects specially, recycling them and then reading the now-set innards values to convert to near-perfect java.time
representations.
For the driver, this has some big benefits. Under profiling, when fetching 1000 view entries with a couple time values, calls to toTemporal
took up 560 ms (about 20% of the total time spent), while now it takes 64 ms (now 2% of the total time). Moreover, not only have I now eliminated on of the bigger performance sinks, the result is better: now you can get an OffsetDateTime
that actually represents the offset of the stored time. While 3 AM Eastern Daylight Time is technically the same moment as 7 AM UTC, the meaning of a document being created at 3 AM local time compared to 7 AM is potentially very significant.
I'm pleased as punch about this. Normally, relying on a weird side-effect and reflectively accessing non-public implementation instance methods is not a good idea, but I think it's fair to assume that this behavior is not going to change any time soon. I'll still likely convert the NoSQL driver to use JNX eventually, but this honestly really lowered the priority: I'm able to get to most other things I want in a fast-enough way, and these date/time values were the main thing where it was outright deficient.