Repository: notionnext-org/NotionNext (2026-07-18T15:42:25Z)

Issue:
Gallery 中 Date 字段排序未生效
> 若为「如何使用 / 部署咨询」而非可复现缺陷，请改用 [Discussions · 使用问答](https://github.com/notionnext-org/NotionNext/discussions/new/choose)，Issue 仅用于可跟踪的 Bug。

---

<!--
  !!! 重要 !!!
  请遵守这个模板的格式填写，否则你的Issue将被关闭
-->

**描述bug**
首先感谢作者以及各位维护者一直以来对项目的维护与更新。
这是之前 Gallery 排序问题的后续测试结果。
之前关于 Gallery 筛选以及 Slug、数字字段排序的修复我已经更新测试，目前都已经恢复正常，非常感谢！
不过更新到最新版本重新部署后继续测试时，我发现 Date 字段排序目前似乎仍然没有生效。

**期望的正常结果**
Gallery 应按照 Notion 中配置的 Date 排序正常显示，无论升序还是降序，都应与 Notion 保持一致。

**复现步骤**
1. 创建一个 Gallery 视图；
2. 使用 Date 字段作为排序字段（已测试升序和降序）；
3. 更新到最新版本并重新部署。

测试结果：
* Notion 中排序正常；
* 网站端显示顺序没有变化，仍然保持默认顺序。

**环境**

- 【必填】NotionNext版本 [4.10.7]
- 【必填】主题 [hexo]
- 【必填】部署方案 [vercel]
- 【可选】操作系统:  [iOS, Android, windows]
- 【可选】浏览器 [chrome, safari, firefox]

**补充说明**
这个问题是在之前修复的基础上继续测试发现的。
目前测试结果如下：
* ✅ Slug（文本）字段排序正常；
* ✅ 数字字段排序正常；
* ❌ Date 字段排序未生效（升序、降序均如此）。

另外，我之前也在排序相关 Issue（#4224）的评论中补充过一些新的测试结果（包括 Gallery 视频封面和 Page URL Mapping 的现象）。为了方便继续跟踪 Date 排序问题，我单独整理成新的 Issue。

如果还需要我补充其他测试信息，请告诉我，我很愿意继续配合。



Discussion:
感谢继续反馈，我这边已经按 #4224 后续线索继续追到了根因，并提交了 draft PR：#4290。

这次问题不是 Gallery 组件本身，而是 collection view 排序入口在读取 Date 属性时拿到了 Notion rich-text Date token 的占位符，真实日期在 `start_date` metadata 里。结果 Date 字段比较值相同，稳定排序就保留了默认顺序，所以升序和降序看起来都没有生效。

修复方式：

- 继续复用已有的 collection view 排序处理，不在 Gallery 渲染层单独补逻辑；
- 对 schema 明确为 `date` 的属性值先归一化出真实 `YYYY-MM-DD` 日期；
- 补了 Date 排序回归测试，覆盖 Notion Date token 的占位符 + metadata 结构。

本地已通过定向测试：

```bash
jest __tests__/lib/notion-data-format.test.js --runInBand
```

等 #4290 合并后，请再更新到最新 main 重新部署，测试 Date 字段升序和降序是否与 Notion 一致。




Patch:
diff --git a/lib/db/notion/filterCollectionViewData.js b/lib/db/notion/filterCollectionViewData.js
index d3ee442b833..b31b5d579dd 100644
--- a/lib/db/notion/filterCollectionViewData.js
+++ b/lib/db/notion/filterCollectionViewData.js
@@ -253,10 +253,12 @@ function getSchemaPropertyId(schema, property) {
 }
 
 function getSortValue(block, propertyId, propertySchema) {
-  return expandPropertyValues(
-    getPropertyValues(block?.properties?.[propertyId]),
-    propertySchema
-  )[0]
+  const values = getPropertyValues(block?.properties?.[propertyId])
+  if (propertySchema?.type === 'date') {
+    return values.map(normalizeDateTime).find(Boolean)
+  }
+
+  return expandPropertyValues(values, propertySchema)[0]
 }
 
 function comparePropertyValues(left, right, propertySchema) {
@@ -276,7 +278,7 @@ function comparePropertyValues(left, right, propertySchema) {
   }
 
   if (propertySchema?.type === 'date') {
-    return normalizeDate(left).localeCompare(normalizeDate(right))
+    return normalizeDateTime(left).localeCompare(normalizeDateTime(right))
   }
 
   return String(left).localeCompare(String(right), undefined, {
@@ -374,6 +376,10 @@ function getPropertyValues(property) {
 
     item?.[1]?.forEach(decoration => {
       const metadata = decoration?.[1]
+      if (metadata?.start_date && metadata?.start_time) {
+        values.push(`${metadata.start_date} ${metadata.start_time}`)
+      }
+
       ;[
         metadata?.id,
         metadata?.page_id,
@@ -407,6 +413,11 @@ function getExpectedValues(value, propertySchema) {
 }
 
 function expandPropertyValues(values, propertySchema) {
+  if (propertySchema?.type === 'date') {
+    const dates = values.map(normalizeDate).filter(Boolean)
+    return dates.length > 0 ? [...new Set(dates)] : values
+  }
+
   if (propertySchema?.type === 'multi_select') {
     return [
       ...new Set(
@@ -461,7 +472,17 @@ function toNumber(value) {
 
 function normalizeDate(value) {
   if (!value) return ''
-  return String(value).slice(0, 10)
+  return String(value).match(/\d{4}-\d{2}-\d{2}/)?.[0] || ''
+}
+
+function normalizeDateTime(value) {
+  if (!value) return ''
+  const text = String(value)
+  const date = normalizeDate(text)
+  const time = text.match(/(\d{1,2}):(\d{2})(?::(\d{2}))?/)
+  return date && time
+    ? `${date}T${time[1].padStart(2, '0')}:${time[2]}:${time[3] || '00'}`
+    : date
 }
 
 function getRecordById(record, id) {


Test patch:
diff --git a/__tests__/lib/notion-data-format.test.js b/__tests__/lib/notion-data-format.test.js
index f2b8cb08c6b..cab8102e99f 100644
--- a/__tests__/lib/notion-data-format.test.js
+++ b/__tests__/lib/notion-data-format.test.js
@@ -967,6 +967,145 @@ describe('Notion data format compatibility', () => {
     ])
   })
 
+  it('sorts embedded collection results from query2 date sorts', () => {
+    const blockMap = {
+      block: {
+        later_page: {
+          value: {
+            id: 'later_page',
+            type: 'page',
+            properties: {
+              date: [['‣', [['d', { start_date: '2026-07-18' }]]]]
+            }
+          }
+        },
+        earlier_page: {
+          value: {
+            id: 'earlier_page',
+            type: 'page',
+            properties: {
+              date: [['‣', [['d', { start_date: '2026-07-01' }]]]]
+            }
+          }
+        }
+      },
+      collection: {
+        collection_1: {
+          value: {
+            schema: {
+              date: { name: 'Date', type: 'date' }
+            }
+          }
+        }
+      },
+      collection_view: {
+        view_1: {
+          value: {
+            value: {
+              id: 'view_1',
+              page_sort: ['later_page', 'earlier_page'],
+              format: {
+                collection_pointer: { id: 'collection_1' }
+              },
+              query2: {
+                sort: [{ property: 'Date', direction: 'ascending' }]
+              }
+            }
+          }
+        }
+      },
+      collection_query: {
+        collection_1: {
+          view_1: {
+            collection_group_results: {
+              blockIds: ['later_page', 'earlier_page']
+            }
+          }
+        }
+      }
+    }
+
+    filterCollectionViewData(blockMap)
+
+    expect(
+      blockMap.collection_query.collection_1.view_1.collection_group_results
+        .blockIds
+    ).toEqual(['earlier_page', 'later_page'])
+    expect(blockMap.collection_view.view_1.value.value.page_sort).toEqual([
+      'earlier_page',
+      'later_page'
+    ])
+  })
+
+  it('sorts embedded collection date results by time on the same day', () => {
+    const blockMap = {
+      block: {
+        evening_page: {
+          value: {
+            id: 'evening_page',
+            type: 'page',
+            properties: {
+              date: [
+                ['‣', [['d', { start_date: '2026-07-18', start_time: '18:00' }]]]
+              ]
+            }
+          }
+        },
+        morning_page: {
+          value: {
+            id: 'morning_page',
+            type: 'page',
+            properties: {
+              date: [
+                ['‣', [['d', { start_date: '2026-07-18', start_time: '09:00' }]]]
+              ]
+            }
+          }
+        }
+      },
+      collection: {
+        collection_1: {
+          value: {
+            schema: {
+              date: { name: 'Date', type: 'date' }
+            }
+          }
+        }
+      },
+      collection_view: {
+        view_1: {
+          value: {
+            value: {
+              id: 'view_1',
+              format: {
+                collection_pointer: { id: 'collection_1' }
+              },
+              query2: {
+                sort: [{ property: 'date', direction: 'ascending' }]
+              }
+            }
+          }
+        }
+      },
+      collection_query: {
+        collection_1: {
+          view_1: {
+            collection_group_results: {
+              blockIds: ['evening_page', 'morning_page']
+            }
+          }
+        }
+      }
+    }
+
+    filterCollectionViewData(blockMap)
+
+    expect(
+      blockMap.collection_query.collection_1.view_1.collection_group_results
+        .blockIds
+    ).toEqual(['morning_page', 'evening_page'])
+  })
+
   it('inherits sibling filters for embedded collection views without filters', () => {
     const blockMap = {
       block: {