new library: https://github.com/esuomi/coll-tracker Track which keys and indices of deep data structures are accessed. Meant to be used when debugging large data structures with unclear access patterns to identify unused or otherwise inaccessible subsets of data.
What a great idea
https://github.com/filipesilva/inst v1.0.0 is out
inst is a small Clojure time library that always returns a #inst.
It is meant to complement Clojure's #inst reader and inst?, inst-ms functions. Works in Clojure, ClojureScript, and Babashka. No dependencies.
(require '[filipesilva.inst :as inst])
;; create from string, ms, existing inst, or no args for now
(def t (inst/inst "2018-03-28T10:48:00.000-08:00"))
(inst/inst 1522195200000)
(inst/inst #inst "2018-03-28")
(inst/inst)
;; add and subtract
;; units: :millis :seconds :minutes :hours :days :weeks :months :years
(inst/+ t 3 :days)
(inst/- t 2 :months)
;; compare via inst-ms
(< (inst-ms t) (inst-ms (inst/inst)))
;; cron: find next/previous matching inst
;; * * * * *
;; | | | | |
;; | | | | day of the week (0–6) (Sunday to Saturday)
;; | | | month (1–12)
;; | | day of the month (1–31)
;; | hour (0–23)
;; minute (0–59)
;;
;; * any value
;; , value list separator
;; - range of values
;; / step values
(inst/next t "0 0 * * 2") ; next Tuesday midnight
(inst/next t "0 0 * * 2" "-08:00") ; with offset
(inst/previous t "0 0 * * 2") ; previous Tuesday midnight
;; lazy seq of next values
(->> t
(iterate #(inst/next % "0 0 * * 2"))
(take 4))
;; => (#inst "2018-03-28T18:48:00.000-00:00" ; t
;; #inst "2018-04-03T00:00:00.000-00:00"
;; #inst "2018-04-10T00:00:00.000-00:00"
;; #inst "2018-04-17T00:00:00.000-00:00")I didn't measure the bundle size. But it has no dependencies and is only about 200 lines of cljc. So it should be very small.
Was thinking about that usecase a lot today, it's very interesting. I think the happy path for a dev is something like: 1. I have an inst 2. I want 6am the same day for it 3. I want to go back two weeks on it 4. I want to read it as if it was in a specific tz Step 4 is the odd one, but also the valuable one imho. It's what lets you say "what was 2026-01-15T06:00 in America/Chicago?"
🙂, big agree - there are some very fun subtleties when this stuff hits the real world. Right, in the case I'm pondering presently I have a local date, "2026-02-16", and a lambda running in UTC, and I'm trying to detect "It's after 6am in America/Denver on that local date."
I built a scheduler on top of cron-utils in the past, the only way to keep this sane and understandable was to use UTC only
wdyt of this for timezone support?
## Timezones
An #inst is always in +00:00 (UTC) even it was created with an offset.
But sometimes we need to work with timezones at the edges: reading or printing times as they show in that timezone.
inst, str, next, and previous accept an optional tz-or-offset parameter.
It can either be a fixed offset like "-06:00" or a timezone like "America/Chicago".
The timezone only affects how local time is interpreted or displayed: inst, next, and previous still return a #inst.
An offset is a fixed number of hours from UTC:
clojure
;; "6am at offset -06:00" is always 6 hours behind UTC
(inst/inst "2024-01-15T06:00" "-06:00")
;; => #inst "2024-01-15T12:00:00.000-00:00"
(inst/inst "2024-07-15T06:00" "-06:00")
;; => #inst "2024-07-15T12:00:00.000-00:00"
;; ^ same 12:00 UTC both times, offset doesn't change
But a timezone maps to different offsets depending on the date due to daylight saving time (DST):
clojure
;; "6am in Chicago" offset changes with DST between CST and CDT
(inst/inst "2024-01-15T06:00" "America/Chicago") ; winter: CST = -06:00
;; => #inst "2024-01-15T12:00:00.000-00:00"
(inst/inst "2024-07-15T06:00" "America/Chicago") ; summer: CDT = -05:00
;; => #inst "2024-07-15T11:00:00.000-00:00"
;; ^ 11:00 UTC instead of 12:00, one hour difference from DST
str with a timezone shows what the clock reads in that zone:
clojure
(def noon (inst/inst "2024-01-15T12:00"))
(inst/str noon "America/Chicago")
;; => "2024-01-15T06:00:00.000-06:00" ; winter offset
(inst/str (inst/inst "2024-07-15T12:00") "America/Chicago")
;; => "2024-07-15T07:00:00.000-05:00" ; summer offset
;; round-trips back to the same inst
(= noon (-> noon (inst/str "America/Chicago") inst/inst))
;; => true
next and previous with a timezone give you DST-correct cron matching:
clojure
;; "next 6am in Chicago" is a different UTC hour in winter vs summer
(inst/next (inst/inst "2024-01-14") "0 6 * * *" "America/Chicago")
;; => #inst "2024-01-14T12:00:00.000-00:00" ; 6am CST = 12:00 UTC
(inst/next (inst/inst "2024-07-14") "0 6 * * *" "America/Chicago")
;; => #inst "2024-07-14T11:00:00.000-00:00" ; 6am CDT = 11:00 UTC
;; on spring-forward day, 2:30am doesn't exist so it resolves to 3:30am CDT
(inst/next (inst/inst "2024-03-10T07:00:00.000Z") "30 2 * * *" "America/Chicago")
;; => #inst "2024-03-10T08:30:00.000-00:00" ; 2:30am CST skipped → 3:30am CDT
tzs returns all supported timezone strings:
clojure
(take 3 (inst/tzs))
;; => ("Africa/Abidjan" "Africa/Accra" "Africa/Addis_Ababa")
I would have to think about it, but on first skim that seems powerful, and like a reasonable improvement. Do you have a link to the code diff?
I see - very cool. I will try this lib the next time I need to do something in this area 👍
I really appreciate the thoughts.
I'll merge it in as 1.1.0, it's fully backwards compatible
done
so your "2 weeks ago at 6am in a tz" example would be
(-> event
(inst/- 2 :weeks)
(inst/previous "0 0 * * *" "America/Chicago")
(inst/next "0 6 * * *" "America/Chicago"))inst is all you need <3 - looks great
small nitpick though: >
(inst/next t "0 0 * * 2" "-08:00") ; with timezone
I think you mean 'with offset' hereyeah offset might be better there.. I put it there for the timezone in general, but that's not really a timezone
gonna edit
done
This is very cool! Do you know the bundle size for Clojurescript/javascript? That would be a very big selling point as alternatives would pull in js-joda which is huge
Note: this might be difficult if it pulls in what it needs from clojurescript as most of the time, apps that would use the lib already have those contents pulled in.
it's very possible that I'm the only person with this view laughcry, but afaict inst ≠ Date . was mostly thinking about literals when I wrote this https://widdindustries.com/blog/what-is-inst.html
that's my view as well, inst is not date... but one way or another when I'm using dates, I'm gonna have to end up turning them into insts to do anything of use
by 'turning into inst', do you mean converting into something that implements Inst?
really depends on what time library I was using at the time, but it'd have to be something that could be converted into ms from epoch
Just read the source, and it does look cool. Was a little surprised to see the cron impl in there, what are you using this for? Also, just to say, I was recently looking at our use of cljs-time in a project, and this looks like it could replace a lot of our uses of that there and simplify things quite a bit. Thanks for making this gratitude
I needed a scheduler for a lib of mine. It needed to work on clj and babashka, and support at least cron. Most stuff I found needed Java libs and that could be tough to get working on babashka.
At the same time I had been thinking about making a minimal time lib based on just #inst. Figured that having a cron step fn would obliviate the need for a lot of other common time lib operations.
This is what implementing a scheduler with it looks like: https://github.com/filipesilva/invoker/commit/c99d4cbead9bd675a396e41bd922eb2bb8017893
that's rad - we have subtle code in clj and cljs that does touchy and error-prone stuff with all kinds of java.time.*-ish things.
The simple idea here that doing it all with inst/epoch-ms is certainly intriguing.
One area I have questions about now thinking this way is inst+(timezone or offset)->local-date, which is pretty easy in clj, but kind of a mess in cljs (we have used google closure for this in the past and been sad about performance on low-spec lambdas). Do you have any thoughts on inst+(timezone or offset)->local-date in cljs?
hm... depends a bit on what it's supporting imho
if it's a matter of rendering things in cljs, I'd say you can probably just always use inst and punt the render to the edge, where you always render that inst as a local-date
good question - we have a case where a user expects to receive a notification at 6am in their local time zone two weeks before a stored inst, so the calculation is happening in a lambda. Your point about separating that from display is well-taken though; in the browser this lib, with perhaps some small helpers, supports display really well (I think).
Ok then for cases where you need a local date, I think what you want to do is still use the Inst, with cron/next, and determine what the offset should be based on their timezone
Cuz that offset will change with daylight savings and stuff like that
Actually cron/previous
Was thinking the same and wondered if you'd say that - very cool! Thank you again.
eca Subagents are here in ECA 0.101.0! 🎉 ✨
ECA now supports foreground subagents, after long design discussions and work with @zikajk (kudos 👏) for weeks, this is a huge feature for ECA:
• A subagent is a specialized agent that focus on solving a given task e.g code-reviewer , the LLM will call this subagent when its description matches the task that needs to be done
• The major advantage of subagents are less context polution + less context window usage, since each agent has clean context a part from main agent.
• Besides eca config, it has compatibility with markdown subagents from Claude/Opencode.
• Parallel subagents are supported, LLM just need to spawn it as normal parallel toolcalls (Opus 4.6 does a lot that), improving speed.
• Built-in subagents:
◦ explorer: Used by ECA when needs to find things in codebase
◦ general: Generic subagent for anything that LLM think it's best to delegate to a subagent.
For more details, check the https://eca.dev/config/agents/#subagents
Please provide feedback in #eca!
Thank you Clojurists Together for sponsor me to work on this! clojurists-together💙
Happy vice coding AI pair programming!