You are only looking at Jan 1st 2019. (And really, a single second of that day, I believe)
WHERE EXTRACT(YEAR FROM o.ts) = 2019
...though I imagine some people dislike the way EXTRACT treats words like YEAR as keywords. Always interesting to see which solution people choose when there are several options. :) WHERE DATE_TRUNC('year', o.ts) = '2019-01-01'::timestamptz
will filter out customers without orders even before the HAVING (because DATE_TRUNC of NULL is NULL)? I mean, I guess you're still demonstrating the perils of NULL with that ;)