How to query a composite tuple containing a date (`:db.type/instant`) using d/index-range, such that the returned index range is inclusive of that date, e.g. if I store #inst "2025-10-13", I want to pass a tuple-end value to d/index-range that will include all values up to & including that value? Do I need to increment the date and filter out any values that might be 1ms after midnight? Is there a better way to do it?
what does "date" mean with an instant?
by date I mean that I convert a LocalDate to java.util.Date because Datomic only supports storing :db.type/instant
... that's not a good idea
localdate is just a Y-M-D; it has to both add precision that doesn't exist and project it into the unix epoch chronology, both of which are easy to do incorrectly and incrementally accumulate errors
storing accounting entries which have a posting date (not datetime, currently), but they could have time associated with them how should I be storing dates and datetimes, if not using instant?
something that doesn't add extra precision or a unix epoch chronology
should I separate out year / month / day / hour / minute / seconds / ms as Datomic attrs?
things that work fine: string in ISO, Epoch days, a long (20251019), a tuple of these, etc
anything that lexically sorts the same way and has a straightforward round-tripping encoding
wouldn't that string be much costlier to store than an Instant?
probably, but it's also human readable; all of these have tradeoffs
the most compact is Epoch Day (for LocalDate), but it's not very readable
anyway, to your original question: index-range termination when you want the termination condition to be "inclusive"
you can either bump the end value by exactly one quantum, or you can leave it nil and use take-while
I mentioned LocalDate, but I convert all dates to UTC before storage. Is :db.type/instant still a bad idea? I don't see why it's a bad idea if I want to support posting dates with datetime or just date (zero time) in future.
How will you tell the difference in the future?
Keep in mind that a Date or Instant is a long counting milliseconds since unix epoch, meant to represent a moment in time and be converted into locally-reckoned values as perceived in the past according to complex rules. If your time is not that (which LocalDate and LocalDateTime are not--they are ymd hms values that don't represent a moment on the unix epoch timeline), then encoding them as instants is fraught with peril. If you have a sidechannel where you keep the "real" type of the time (e.g. on the attribute), and completely control all encoding, decoding and display of these times in and out of java.util.Date perfectly forever, then you can get away with it. If you mess up, you get at best confused users and at worst irrecoverably corrupt data
however I have never seen it done successfully, and I have cleaned up multiple messes related to this problem in my career, in both datomic and sql databases
so my advice is Just Don't
if it's not a moment in time, don't use a type with those semantics or store it that way at rest
Why don't heterogeneous :db/tupleTypes https://docs.datomic.com/schema/schema-reference.html#tuples :db.type/short? I want to store [entity-ref some-boolean year month day hour minute seconds] but now I have to use Long for most components, which is costly to store.
what is :db.type/short? I don't think that exists even outside tuples
clojure doesn't store numbers at any precision less than long
and they are typically boxed
datomic stores data with https://github.com/Datomic/fressian, which has a variable-length integer encoding
You can bitpack a long, too
xml schema has a bunch of https://www.w3.org/TR/xmlschema11-2/#built-in-primitive-datatypes which at some point in my career I wanted to represent in datomic and javascript in a single attribute in a precision-preserving way (to map to another xml format 1:1 instead of across multiple attributes) with temporal sorting (there was a defined way to sort datetimes with mixed precisions). Turns out you can do this in 52 bits if you make some compromises. https://gist.github.com/favila/d635c5aeb3a391f424d6 Note the abuse of the unix epoch.
How will you tell the difference between something that was originally a date only and something that was a date+time? (or is this not a thing in your schema?)
What is the underlying storage for :db.type/boolean? Is it a bit, or a Long that stores 1 or 0? The docs don't specify the cost.
In jvm, memory cost of primitive bool is typically sizeof int; but in clojure it's going to almost always be boxed
But what is it Datomic, though? Is there an optimized storage format for boolean, esp. as part of a heterogeneous tuple?
yes, as one byte in fressian https://github.com/Datomic/fressian/wiki/Bytecodes
F5 or F6