Filtering content based on year in a front-end yearly archive.

8 replies
Last updated: Nov 24, 2023
I have content that have a duration (example: 2022–02–03 to 2023–01–05), how can I filter these on year? Imagine a front-end having a yearly archive, so the example should not show up if you're on
2024
but if you're on
2022
or
2023
it should.
Nov 24, 2023, 5:45 PM
You could use the
string::split()
function to split on
-
and get the first index:

*[_type == 'post' && string::split(date, "-")[0] == $year]

// params
{
  'year': '2023',
}
Potential downside is that the year param probably needs to be handled as a string.
Nov 24, 2023, 5:51 PM
You can also replace the
string::split()
predicate with:

&& date >= "2023" && date < "2024"
This would filter the year 2023.
Nov 24, 2023, 6:00 PM
thanks for your reply geoff! I'm curious, since it's a duration rather than just a simple date:
duration:{…} 3 properties
  _type:duration
  start:2022-11-05T12:16:00.000Z
  end:2023-01-08T12:17:00.000Z
isn't it a bit more complicated?
🤔
Nov 24, 2023, 6:04 PM
That may be different from the question I thought I was answering, which was about filtering by year, yearly archives, etc. I may have misunderstood you.
Nov 24, 2023, 6:06 PM
I think you could still use the comparison operators, but the
>=
would be against
duration.start
and
<
would be against
duration.end
. Does that accomplish what you’re after?
Nov 24, 2023, 6:07 PM
*[
  _type == 'exhibition'
 && (
  // Condition 1: Posts that started within the specified year
  (duration.start >= $startOfYear && duration.start <= $endOfYear) || 
  
  // Condition 2: Posts that ended within the specified year
  (duration.end >= $startOfYear && duration.end <= $endOfYear) ||
  
  // Condition 3: Posts that spanned the entire specified year
  (duration.start < $startOfYear && duration.end > $endOfYear)
)]
Nov 24, 2023, 6:13 PM
chat gpt helped me out 🙂
Nov 24, 2023, 6:13 PM
GROQ string comparisons are using lexicographic ordering rules, just as in JavaScript.
That means that timestamps in the standard RFC 3339 and ISO 8601 formats, such as:

2022-11-05T12:16:00.000Z
are lexicographically ordered, if they're in the same time zone.

In other words,
laterDateTime > newerDateTime
is always true. The same goes for
>=
,
<
,
<=
.
This is because lexicographic ordering ensures
2
&gt;
1
and so on. Since such timestamps are written with the most significant part (year) first, and each part is always equally long, they are comparable:
This also means you can omit any trailing part when using
<=
and
>=
. For example,
"2023-03-02T00:00:00Z" >= "2023"
will be true, and also true for any date past the year 2023.
It seems hacky, but it actually isn't when you think about it. And it's fast. The
string::split()
trick also works, but is not optimized to an efficient filter operation.
Nov 24, 2023, 8:02 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?