NocoBase 日期时间(不含时区)字段:datetimeNoTz 的配置、存储与筛选实现原理

📅 发布时间:2026/9/14 16:32:39
NocoBase 日期时间(不含时区)字段:datetimeNoTz 的配置、存储与筛选实现原理
NocoBase 日期时间不含时区字段datetimeNoTz 的配置、存储与筛选实现原理【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobaseNocoBase 的「日期时间不含时区」Date time without timezone字段用于保存不做时区转换的日期时间是排班、营业时间、课程时间等本地时间业务的基础数据类型。本文以该字段的创建与配置方法为主体深入结合nocobase/database中的DatetimeNoTzField源码讲清它在不同数据库方言下的真实存储类型、写入时的时区处理逻辑以及筛选操作符如何按00:00固定时区解析条件帮助你在建模、写 API 查询和理解测试断言时做到心中有数。字段定位与适用场景在 NocoBase 中日期时间不含时区用于保存不做时区转换的日期和时间适合更关注本地显示值的业务本地排班时间课程开始时间、考试时间门店营业时间点不希望跨时区转换的业务时间选型上它与两个近邻类型形成互补如果业务需要表达一个全球一致的真实时间点预约、截止时间、跨时区协作应选择日期时间含时区如果只需要日期部分选择日期。完整的字段分类与映射逻辑见字段总览。前端界面上该字段的注册信息在 datetimeNoTz.ts 中可以确认name datetimeNoTz、分组为datetime、组内排序order 2、界面标题为 Datetime (without time zone)并且标记sortable true、validationType date默认 UI 组件是带showTime: false的DatePicker。这解释了文档中「页面组件编辑模式使用日期时间选择器」「支持按时间排序」这两条特性。创建字段与配置项在数据表的「Configure fields」页面中点击「Add field」选择「日期时间不含时区」即可创建该类型字段。创建表单中的配置项如下配置说明Field interface字段的界面类型。日期时间不含时区对应datetimeNoTz决定页面中如何录入和展示。Field display name字段在界面中显示的名称比如「排班时间」「课程时间」「营业时间」。建议使用业务人员能直接理解的名称。Field name字段标识名称用于 API、关系字段、权限、工作流等内部引用。创建后通常不再修改只支持字母、数字和下划线并且必须以字母开头。Field type字段在数据层的类型。日期时间不含时区通常使用datetimeNoTz。Default value默认值。新增记录时如果用户没有填写可以自动带出默认值。Validation rules校验规则。可以配置必填、时间范围等。Description字段说明。适合写字段含义、填写要求、数据来源或维护人。注意字段名创建后会被页面区块、权限、工作流和 API 引用。创建前先确认命名避免后续修改带来配置调整成本。界面上的两个专属配置项同样来自 datetimeNoTz.ts 中的properties定义defaultToCurrentTime「默认值取当前服务器时间」新增记录时未填写该字段自动写入当前时间onUpdateToCurrentTime「更新时自动把时间戳刷新为当前服务器时间」每次更新记录时把该字段重置为当前时间。后端字段选项类型见 datetime-no-tz-field.ts 中的DatetimeNoTzFieldOptions其type固定为datetimeNoTz并在 fields/index.ts 中被并入全局FieldOptions联合类型保证集合建模时类型校验通过。默认行为一览日期时间不含时区字段的默认行为如下特性说明默认 Field interfacedatetimeNoTz。默认 Field typedatetimeNoTz。可选 Field typedatetimeNoTz前端availableTypes另允许string见下文源码分析。页面组件编辑模式使用日期时间选择器。筛选支持按时间点、区间、为空、不为空筛选。排序支持按时间排序。校验支持必填和时间范围等校验。存储实现不同数据库方言下的真实列类型「不含时区」的语义最终落在数据库列类型上。从源码看DatetimeNoTzField 的dataType按方言分支get dataType() { if (this.database.inDialect(postgres)) { return DatetimeNoTzTypePostgres; // key TIMESTAMP } if (this.database.isMySQLCompatibleDialect()) { return DatetimeNoTzTypeMySQL; // key DATETIME } return DataTypes.DATE; }也就是说PostgreSQL下创建TIMESTAMP不带time zone后缀数据库不保存任何时区偏移MySQL 及兼容方言含 MariaDB下创建DATETIME同样不携带时区信息其他方言如 SQLite退化为 Sequelize 的DATE类型。这与含时区字段形成对照后两者在数据库层都可能保存带偏移的时间而datetimeNoTz列中存的就是字面值本身。写入路径set/get 钩子与时区归一化DatetimeNoTzField通过additionalSequelizeOptions()返回一对自定义 getter/setterdatetime-no-tz-field.ts这是值进出模型时实际生效的时区逻辑读值getter如果从数据库取出的值是Date实例用 moment 格式化为YYYY-MM-DD HH:mm:ss字符串返回。因此 API 响应中该字段呈现的正是列中存储的原始字面时间测试用例也验证了这一点——在时区为01:00的数据库中写入2023-03-24 12:00:00读回toJSON()得到的仍是2023-03-24 12:00:00见 datetime-no-tz.test.ts。写值setterconst dateOffset new Date().getTimezoneOffset(); const momentVal moment(val); if ((typeof val string isIso8601(val)) || val instanceof Date) { momentVal.utcOffset(timezone); // timezone rawTimezone || 00:00 momentVal.utcOffset(-dateOffset, true); // 折算到服务器本地时区 } if (isMySQLCompatibleDialect) { momentVal.millisecond(0); // MySQL 列不保留毫秒 }可以推断出这套逻辑的业务含义普通YYYY-MM-DD HH:mm:ss字符串原样落库不做任何转换——这正是不含时区的核心承诺业务传什么本地时间库里就存什么带时区语义的输入严格 ISO 8601 的...Z字符串或Date对象会先按rawTimezone默认00:00对齐再折算为服务器本地时区表示后落库。测试用例证实时区01:00的库中写入2023-03-24T12:00:00.892Z最终存为2023-03-24 13:00:00datetime-no-tz.test.tsMySQL 系方言下毫秒被截断避免DATETIME列的精度丢精度告警。此外beforeSave钩子绑定到beforeSave与beforeBulkCreate事件实现了两个默认值行为新建记录且未赋值时若配置了defaultToCurrentTime写入new Date()配置了onUpdateToCurrentTime时任何更新都会把该字段刷新为当前时间。两者均有对应测试覆盖datetime-no-tz.test.ts。筛选实现操作符如何固定 00:00筛选能力由日期操作符模块 operators/date.ts 提供其中对datetimeNoTz有两处特判时区解析parseDateTimezone(ctx)判断字段是否为DatetimeNoTzFieldfield?.type datetimeNoTz是则强制返回00:00否则回落到数据库级timezone配置date.ts。这意味着筛选条件中的时间不会被服务器时区二次折算直接按字面值比较。条件值格式化toDate()中datetimeNoTz字段的条件值被格式化为moment(val).utcOffset(00:00).format(YYYY-MM-DD HH:mm:ss)date.ts与列中存储的字面格式对齐。在此基础上导出了一组可用的操作符覆盖了文档所述按时间点、区间、为空、不为空筛选操作符语义$dateOn等于某天/某时间点值可为范围数组展开为gte lt$dateNotOn不等于$dateBefore/$dateAfter早于 / 晚于数组取对应边界$dateNotBefore/$dateNotAfter不早于含 / 不晚于含$dateBetween闭开区间gte lt操作符级行为由 operator/date/datetime-no-tz.test.ts 单独验证可用于确认各操作符在不同方言下的实际 SQL 效果。编辑与删除字段创建后点击字段右侧的「Edit」可以编辑字段配置。编辑字段主要用于调整字段在 NocoBase 中的展示和使用方式比如修改显示名称、说明、默认值、校验规则或字段专属配置。如果字段来自主数据库中已经同步的表编辑时通常是在做字段映射——把数据库字段映射为 NocoBase 的 Field type 和 Field interface。配置允许编辑说明Field display name是修改字段在界面中的显示名称不改变字段标识名称。Field name否字段标识名称创建后通常不能在编辑表单中修改。Field interface条件支持主数据库字段或同步字段在字段映射时可以调整。调整后会影响页面输入、展示和校验方式。Field type条件支持主数据库字段或同步字段在字段映射时可以调整。调整前需要确认已有数据能否按新类型使用。Default value是调整新增记录时的默认值。Validation rules是调整字段校验规则。Description是补充字段含义、填写要求、数据来源或维护人。注意切换 Field type 或 Field interface 不等于简单改一个显示名称。它会影响字段的存储方式上文dataType分支、输入组件、校验规则、筛选条件和工作流变量使用方式。已有数据较多时先确认数据格式是否匹配——比如从string映射为datetimeNoTz后存量非标准格式字符串会在 setter 解析时产生异常行为。删除方面点击字段右侧的「Delete」可以删除日期时间不含时区字段主数据库中还可以勾选多个字段后批量删除。删除主数据库中新建的字段时通常会同时删除数据库中的真实列及该列已有数据删除从数据库同步或外部数据源映射出的字段时影响范围取决于对应数据源和字段来源。警告删除字段可能影响页面区块、表单、筛选、权限、工作流、API、导入导出和已有数据。删除前先确认字段是否仍被业务配置引用。页面与工作流中的使用日期时间不含时区字段适合本地时间业务典型用法场景用途表单区块选择日期和时间。表格区块展示、排序和筛选时间。日历区块作为本地事件时间字段。工作流作为时间条件字段。在普通表中创建和管理字段的完整流程见普通表文档。与日期时间含时区相比不含时区类型在工作流定时条件等场景下更保守——它只比较字面时间不会因运行环境与数据录入者时区不同而产生偏移适合北京时间 09:00 的门店开店这类明确绑定单一本地时区的业务。小结日期时间不含时区字段的完整技术画像可以归纳为三点配置层面它是datetimeNoTz界面对应的本地时间类型支持默认值、自动更新时间与日期校验存储层面它在 PostgreSQL 落为TIMESTAMP、MySQL 落为DATETIME普通字符串原样落库、带时区的输入折算后落库且 MySQL 截断毫秒查询层面筛选操作符固定按00:00解析条件值并与列值字面对比。理解了这三层你就能准确判断它何时该选、何时应改用含时区字段以及测试断言中那些看起来反直觉的时间值从何而来。【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考