Answering my own question...
In brief
I'm using a case function to set a token that, depending on the time range, specifies either an empty string (to rely on auto-spanning) or a span attribute:
eval span=case(diff>20," ",diff>1,"span=50ms",diff>0.01,"span=10ms",true(),"span=1ms")
where diff is the difference in seconds between the earliest and latest records in the time range.
The "breakpoints" in the case function are an experimental work in progress. I might change these breakpoints, and add more.
In detail
I use the following search(es):
<search id="base_metrics">
<query>index=my_index sourcetype=my_sourcetype | stats count, earliest(_time) as earliest, latest(_time) as latest</query>
<earliest>$earliest$</earliest>
<latest>$latest$</latest>
</search>
<search base="base_metrics">
<query>eval startTime=strftime(earliest, "%x %H:%M:%S"), endTime=if(strftime(earliest, "%x")=strftime(latest, "%x"), strftime(latest, "%H:%M:%S"), strftime(latest, "%x %H:%M:%S")), diff=(latest-earliest) | eval hours=floor(diff/3600) | eval minutes=floor((diff-(hours*3600))/60) | eval seconds=floor(diff-(hours*3600)-(minutes*60)) | eval duration=hours." hour".if(hours>1,"s "," ").minutes." minute".if(minutes>1,"s "," ").seconds." second".if(seconds>1,"s",""), span=case(diff>20," ",diff>1,"span=50ms",diff>0.01,"span=10ms",true(),"span=1ms")</query>
<progress>
<condition match="'job.resultCount' > 0">
<set token="startTime">$result.startTime$</set>
<set token="endTime">$result.endTime$</set>
<set token="duration">$result.duration$</set>
<set token="eventCount">$result.count$</set>
<set token="span">$result.span$</set>
</condition>
<condition>
<unset token="startTime"></unset>
<unset token="endTime"></unset>
<unset token="duration"></unset>
<unset token="eventCount"></unset>
<unset token="span"></unset>
</condition>
</progress>
</search>
Here, I've included tokens that are not required for this particular solution (sorry, I couldn't be bothered stripping them out for this answer), which I use in the following HTML panel:
<html depends="$eventCount$,$duration$,$startTime$,$endTime$">
$eventCount$ events spanning $duration$ ($startTime$ to $endTime$)
</html>
I use the span token in timechart commands:
timechart $span$ ...
... View more