Fork me on GitHub
#clojure-europe
<
2020-07-09
>
synthomat06:07:47

good morning!

otfrom07:07:37

@ordnungswidrig just makess it tricky to create a series of intervals where the interval switches at one point on the same date

otfrom07:07:45

but yeah, I'm not sure there is a good answer

ordnungswidrig08:07:23

The problem is that were lacking the notion of "rounding" with timestamps. It's clear to everybody that the integer 2 "corresponds" with the rational interval [1.0...2.0)

ordnungswidrig08:07:20

We have a date notions of the interval as e.g. "2020-05-03" but all libraries I know internally represent this to the revision of the nanosecond.

ordnungswidrig08:07:28

It's like using floats to represent integer values. Prepare for some weird confusing stuff to happen :-)

jasonbell08:07:51

Morning

šŸ‘‹ 3
otfrom08:07:00

@ordnungswidrig yeah, I think you are right there. I wonder if there is other prior art like the relational algrebra that they borrow that makes this behaviour a bit more principled. I think my worry is that any work around I do could change in a later version if it is undefined

ordnungswidrig08:07:37

Something like ā€œfloating point datesā€. One property of FP is the change of absolute precision.

ordnungswidrig08:07:06

But dates are weird because they are a weird mix of absolute values, intervals, the use of arbitrary, mixed and changing units, UI features which change over time, non-unique representations (DST change) and bad compatibitlity with the binary and decimal system.

plexus08:07:20

java.time is generally pretty good at this stuff though, since they actually recognize that a date is different from a "year-month", is different from a timestamp, etc. for instance LocalDate is really just a year+month+day fields, no unix timestamp in sight https://github.com/frohoff/jdk8u-jdk/blob/master/src/share/classes/java/time/LocalDate.java#L169-L177

plexus08:07:12

the problem to me in the above @otfrom is that you're asking for an interval between dates, but you're getting an interval between date-times

plexus08:07:13

(import '(java.time LocalDate Period))

(Period/between
 (LocalDate/of 2020 01 01)
 (LocalDate/of 2020 01 02))
;; => #object[java.time.Period 0x35860e12 "P1D"]
I guess interval is a tick-specific thing, java.time has Period (in days) and Duration (in nanoseconds)

ordnungswidrig08:07:54

@plexus java.time has some good stuff in it

ordnungswidrig09:07:36

Although now Iā€™m confused that LocalDate doesnā€™t implement a single Interface which is parametrized over a dozen generics šŸ˜›

ordnungswidrig09:07:45

Thatā€™s weird public boolean isSupported(TemporalField field) that sounds where you would use types for.

ordnungswidrig09:07:24

OMG ā€œ* Defend against malicious streams.ā€œ. I had enough java for today

otfrom09:07:38

@plexus tick wraps java.time and has durations and periods

otfrom09:07:11

and interval is what I need as it is anchored in calendar dates

otfrom09:07:55

looks like my real issue is whether or not this behaviour is correct:

(t/bounds (t/today))
  #:tick{:beginning #time/date-time "2020-07-09T00:00", :end #time/date-time "2020-07-10T00:00"}

otfrom09:07:24

or if :end should be 23:59 on the same day

otfrom09:07:13

(I'll still have the issue as my end of episode 1 and start of episode 2 are on the same day)

otfrom09:07:53

if only there was some way I could write some unit tests to make sure the behaviour stays the same as I change the code... šŸ˜‰

otfrom09:07:39

right... I think this is the core of my issue;

(t/end (t/date "2020-07-09"))
  #time/date-time "2020-07-10T00:00"

otfrom09:07:57

rather than being 2020-07-09T23:59

plexus09:07:31

so where does the minute between 2020-07-09T23:59 and 2020-07-10T00:00 go (or second or nanosecond)? seems to me to make sense that (= (end-of today) (start-of tomorrow)), it's the same point on the timeline

otfrom09:07:33

yeah, I think it is just a conversion problem with where you draw the bounds when you only have something less precise

plexus09:07:39

or that you're deriving date-level semantics for timestamp-level values

otfrom09:07:12

should an interval that is {:start 2020-01-02 :end 2020-01-03} and {:start 2020-01-03 :end 2002-01-05} be considered as overlapping or meeting on 3 January?

otfrom09:07:31

yeah, the problem is the library is doing the conversion for me rather than comparing the dates

plexus09:07:05

if you're talking about dates, and your intervals are ending exclusive, then those two would meet but not overlap

otfrom09:07:36

(t/relation
   #:tick{:beginning #time/date-time "2020-07-09T00:00", :end #time/date-time "2020-07-10T00:00"}
   #:tick{:beginning #time/date-time "2020-07-10T00:00", :end #time/date-time "2020-07-11T00:00"})
  :meets

otfrom09:07:05

so when the date times are equal, then the relation meets, but if only dates are supplied and equal then they overlap

otfrom09:07:28

so I have to pre-process my dates into suitable interval friendly date times before supplying them to t/relation

plexus09:07:17

yeah looks like it

otfrom09:07:34

which is fine as long as the conversion from date to date time bounded interval is stable behaviour

otfrom09:07:18

looks like I can use t/at and t/on rather than doing the arithmetic at least

otfrom09:07:31

(t/at (t/date "2018-01-01") (t/time "13:00")) => 2018-01-01T13:00

ordnungswidrig09:07:01

The weird things is that the answer to do these intervals overlap is quite obvious {:beginning 10 :end 15} {:beginning 15 :end 20}

ordnungswidrig09:07:17

.. it depends! On wether the ends are open or closed.

otfrom09:07:02

I think the behaviour of the date time example shows how it works: https://clojurians.slack.com/archives/CBJ5CGE0G/p1594287276141400

otfrom09:07:34

I think I'd down to my issue being how dates are converted to intervals, and I think I have a solution to it now

otfrom09:07:54

tho it feels a bit hacky

otfrom09:07:01

so, I've gone with this in my code and it gives me the :meets behaviour I want when creating relations

otfrom09:07:03

(defn episode-interval [{:keys [report-date ceased] :as rec}]
  (if ceased
    (assoc rec
           :episode-interval
           (t/new-interval (t/at report-date "13:00") (t/at ceased "13:00")))
    rec))

otfrom09:07:32

the common code for this is going here: https://github.com/MastodonC/witan.cic.driver

otfrom09:07:50

tho the code specific to the clients is in a private repo

synthomat12:07:45

(teaser: itā€™s not about owls šŸ˜ž )

Ben Hammond13:07:18

is the Web Ontology Language widely used? I almost never come across it for my work But that might just be because I'm boxed into a niche

otfrom13:07:09

will probably have some RDF impact (as they are often the same people) and thus impact on Rich who is a fan of RDF (see schema, datomic, etc)

otfrom13:07:32

and it is often well thought through and built on prior art

otfrom13:07:59

so it looks like you can't create a LocalDateTime from a LocalDate w/o supplying a time explicitly https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#of-java.time.LocalDate-java.time.LocalTime-

otfrom13:07:02

which makes sense

otfrom13:07:13

so I'm tripping over the sugar in tick then

synthomat20:07:29

does anyone work with hiccup here? or other templating engines?

9
synthomat20:07:53

Iā€™m wondering how to pass global objects to the templatesā€¦Ā things that shall be rendered on all sites.

synthomat20:07:12

I have a few ideas, like using thread-locals or soā€¦ or ^:dynamic (itā€™s technically also a thread local, right?), or injecting some payload into the request object and pass that to the templates, but somehow it doesnā€™t feel rightā€¦

RAMart06:07:32

> Iā€™m wondering how to pass global objects to the templatesā€¦Ā things that shall be rendered on all sites. Sorry, don't know what you mean. Since it's just data:tm:, you can have a page function to return it. And that function can call your own fixed-header or fixed-footer functions. What am I missing here?

synthomat06:07:00

hey, I want to carry some meta data to global elements in all templates; e.g. currently authenticated user in the header of a page. I was just wondering whether thereā€™s a idiomatic way of doing it

synthomat06:07:18

maybe I should just look for other projects at github and see how they do it šŸ™‚

RAMart06:07:23

Using Ring?

synthomat06:07:43

ring, backend rendered, no SPA

RAMart06:07:24

Sorry, still don't get it. Aren't the informationen needed to render the page all available in the request or session? > maybe I should just look for other projects at github and see how they do it Caution: Some things you'll see will be spooky. šŸ‘»

synthomat06:07:54

no itā€™s not available per-se, hence the question how to do it the best šŸ˜„

(defn outer-layout [] (header (user-session-info) (dynamic-navigation)))
(defn inner-layout [] (outer-layout))
(defn actual-page [payload] (inner-layout payload))
How do I get the data for user-sessio-info when my handlers just call the actual-page

synthomat06:07:07

I should maybe just reverse my call, so instead of calling actual-page directly, I could call the outer-layout pass the data from handlers direct to it and also pass the inner desired page

synthomat06:07:43

I think I just talk confusing things right now; I should rather just try something out šŸ˜…

ordnungswidrig08:07:50

I typically use a global reagent atom to hold state. Templates can reach out here and self-service what they need.

plexus08:07:18

just pass the data to where you need it. These days I like to have a single view-data map that gets passed both to the page's view functions as well as to the layout, just stick whatever either needs in there. :title, :current-user, :blog-posts etc.

plexus08:07:59

start with that and then add whatever sugar you like. we have some helpers that allow passing some values from the view to the layout based on metadata, which is nice for something like this:

(defn blog-post-html [{:keys [blog-post]}]
  ^{:title "Blog posts"}
  [:article ...])

synthomat09:07:22

thanks a lot! Will consider this!

synthomat09:07:57

@ordnungswidrig youā€™re likely talking about frontend, no?

ordnungswidrig09:07:13

aaah, sorry I had assumed reagent. But same for backend šŸ™‚

ordnungswidrig09:07:03

I typically pass-down the information often having a first ā€œcontextā€ argument which is a map with all kind of information you want to have everywhere, e.g. authentication information or resource handles.

ordnungswidrig09:07:16

Namespaced keys help to keep things apart: {:auth/user "synthomatc" :res/db-conn <DBConnection> :http/request raw-http-request} etc. and pass the more local parameters as separate keys.

ordnungswidrig09:07:33

I also used the ā€œall parameters and context in a single mapā€ approach which is nice for descructuring.

ordnungswidrig09:07:08

(defn template [{:keys [:res/db-conn :auth/user :posts :highlighted-post-id}])

synthomat10:07:58

ah okay, sounds also good, so first parameter should be a context-map

synthomat10:07:23

but I think I got the idea, thanks! šŸ™‚

synthomat10:07:56

actually itā€™s less of a problem than I thoughtā€¦Ā the parameter just needs to be passed to every ā€œsurroundingā€ layout function. I guess it will be at most 2-4 layers, so itā€™s really bearable