Answers.Body: <p>You could order the dates inside the for-loop, but I would order the dates before they're grouped, much simpler. You can do this in one clean pipeline, much easier to reason about and understand:</p>
  <pre class="lang-twig prettyprint-override"><code>{% set datesByMonth = entry.dates
      |filter(date =&gt; date.start &gt;= now)
      |sort((a, b) =&gt; a.start &lt;=&gt; b.start)
      |group(date =&gt; date.start | date('F Y'))
  %}
  </code></pre>
  <p>First, the <code>filter</code> removes all dates before today, this means you can get rid of the first for-loop. Then, the array is sorted using the <code>sort</code> filter. Finally, the sorted array is grouped using the <code>group</code> filter. Since the array was already sorted, the grouped items will be sorted as well.</p>
  <p>This assumes that <code>entry.dates</code> returns an array of <code>DateTime</code> objects. You can compare <code>DateTime</code> objects directly (both in PHP and Twig), so you don't need the <code>date</code> filter. If <code>entry.dates</code> is an array of something else (like dates string in a specific format), you can first map that to an array of <code>DateTime</code> objects using the <a href="https://twig.symfony.com/doc/3.x/filters/map.html" rel="nofollow noreferrer"><code>map</code> filter</a> and the <a href="https://craftcms.com/docs/4.x/dev/functions.html#date" rel="nofollow noreferrer"><code>date</code> function</a>:</p>
  <pre class="lang-twig prettyprint-override"><code>{% set datesByMonth = entry.dates
      |map(dateString =&gt; date(dateString))
      |filter(date =&gt; date.start &gt;= now)
      |sort((a, b) =&gt; a.start &lt;=&gt; b.start)
      |group(date =&gt; date.start | date('F Y'))
  %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-09-27T23:36:31.730Z
Answers.Text: That's nearly there except that on the page I'm testing, there are events in September, October, November, but the first heading that appears on the page is October 2023.
Answers.UserDisplayName: Tyssen
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-09-27T23:54:06.290Z
Answers.Text: Actually, not looking at the dates closely enough, there are dates in September, but none after today, so all good, thanks. :)
Answers.UserDisplayName: Tyssen
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-09-28T11:07:45.703Z
Answers.Text: @Tyssen If the order is really inverted, just switch the `a` and `b`, I always get the order wrong the first time :-)
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-09-27T08:57:33.343Z
Answers.LastActivityDate: 2023-09-27T08:57:33.343Z
Answers.UserDisplayName: MoritzLost
Body: <p>I need to be able to group dates by their month but then order them by month too because the order they're inserted into the database in na super field table isn't always in date order.</p>
  <p>So far, I have this:</p>
  <pre><code>{% set today = now|date('U') %}
  {% set dates = [] %}
  {% for date in entry.dates %}
      {% if date.start|date('U') &gt;= today %}
      {% set dates = dates|merge([date]) %}
      {% endif %}
  {% endfor %}
  
  {% set datesByMonth = dates|group('start|date(&quot;F Y&quot;)') %}
  {% for month, dates in datesByMonth %}
      {{ month }}
      dates stuff
  {% endfor %}
  </code></pre>
  <p>which works fine except for the ordering.</p>
  <p>I thought for the ordering, I might be able to do this:</p>
  <pre><code>{% for month, dates in datesByMonth|multisort(['start|date(&quot;c&quot;)']) %}
  …
  {% endfor %}
  </code></pre>
  <p>but that doesn't change the order. Am I doing that wrong or is there another way?</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-09-27T05:47:32.233Z
Comments.Text: What's in your `dates` variable - entries, `DateTime` values?
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-09-27T05:48:43.447Z
Comments.Text: If it's entries, please post the entry query as well, might be possible to order the results right in the query.
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-09-27T05:51:33.627Z
Comments.Text: @MoritzLost it's an array from a super table field which contains datetime start and end columns.
Comments.UserDisplayName: Tyssen
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-09-27T05:54:42.413Z
Comments.Text: @MoritzLost I've edited the question to include more of the code prior to what I originally posted.
Comments.UserDisplayName: Tyssen
Tags: <datetime><group>
Title: Grouping and ordering entries by month
ThreadText: # Grouping and ordering entries by month
  
  (Asked by: username_0 on 2023-09-27)
  
  I need to be able to group dates by their month but then order them by month too because the order they're inserted into the database in na super field table isn't always in date order.
  
  So far, I have this:
  
  ```
  {% set today = now|date('U') %}
  {% set dates = [] %}
  {% for date in entry.dates %}
      {% if date.start|date('U') >= today %}
      {% set dates = dates|merge([date]) %}
      {% endif %}
  {% endfor %}
  
  {% set datesByMonth = dates|group('start|date("F Y")') %}
  {% for month, dates in datesByMonth %}
      {{ month }}
      dates stuff
  {% endfor %}
  
  ```
  
  which works fine except for the ordering.
  
  I thought for the ordering, I might be able to do this:
  
  ```
  {% for month, dates in datesByMonth|multisort(['start|date("c")']) %}
  …
  {% endfor %}
  
  ```
  
  but that doesn't change the order. Am I doing that wrong or is there another way?
  
  **Tags:** datetime, group
  
  > **Comments:**
  > **username_1**: What's in your `dates` variable - entries, `DateTime` values?  
  > **username_1**: If it's entries, please post the entry query as well, might be possible to order the results right in the query.  
  > **username_0**: @username_1 it's an array from a super table field which contains datetime start and end columns.  
  > **username_0**: @username_1 I've edited the question to include more of the code prior to what I originally posted.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2023-09-27. Score: 1 | Accepted answer
  
  You could order the dates inside the for-loop, but I would order the dates before they're grouped, much simpler. You can do this in one clean pipeline, much easier to reason about and understand:
  
  ```twig
  {% set datesByMonth = entry.dates
      |filter(date => date.start >= now)
      |sort((a, b) => a.start <=> b.start)
      |group(date => date.start | date('F Y'))
  %}
  
  ```
  
  First, the `filter` removes all dates before today, this means you can get rid of the first for-loop. Then, the array is sorted using the `sort` filter. Finally, the sorted array is grouped using the `group` filter. Since the array was already sorted, the grouped items will be sorted as well.
  
  This assumes that `entry.dates` returns an array of `DateTime` objects. You can compare `DateTime` objects directly (both in PHP and Twig), so you don't need the `date` filter. If `entry.dates` is an array of something else (like dates string in a specific format), you can first map that to an array of `DateTime` objects using the [`map` filter](https://twig.symfony.com/doc/3.x/filters/map.html) and the [`date` function](https://craftcms.com/docs/4.x/dev/functions.html#date):
  
  ```twig
  {% set datesByMonth = entry.dates
      |map(dateString => date(dateString))
      |filter(date => date.start >= now)
      |sort((a, b) => a.start <=> b.start)
      |group(date => date.start | date('F Y'))
  %}
  
  ```
  
  > **Comments:**
  > **username_0**: That's nearly there except that on the page I'm testing, there are events in September, October, November, but the first heading that appears on the page is October 2023.  
  > **username_0**: Actually, not looking at the dates closely enough, there are dates in September, but none after today, so all good, thanks. :)  
  > **username_1**: @username_0 If the order is really inverted, just switch the `a` and `b`, I always get the order wrong the first time :-)  
  
  ---
  
  