前言
本文系统整理了(自称) Dynamics 365 / Dataverse 中「日期和时间(Date and Time)」字段 的基础概念、配置选项以及在不同使用场景下的实际表现。
由于 Dataverse 统一以 UTC 时区存储日期时间数据,而界面显示、Client API 与 Web API 又会根据字段配置和用户时区产生不同的行为,这类字段常常成为以下问题的“重灾区”:
- 不同用户看到的日期不一致
- 表单显示正确,但数据库或接口返回“少了 / 多了 8 小时”
- Client API / Web API 返回的时间与预期不符
本文通过字段配置说明 + 实际实验 + 数据库存储 / API 返回对比的方式,一次性理清这些容易混淆的点。
基本概念
Dataverse 以 UTC 时区存储所有日期和时间值。
当应用显示值或处理用户输入时,会根据字段的 “格式” 和 “时区调整” 选项,结合当前用户的时区设置进行转换。
新建「日期和时间」字段
在实体新建 日期和时间(Date and Time) 字段时,可以选择以下以下格式:仅日期或日期和时间。
| 格式 | 描述 |
|---|---|
| 仅日期 | 存储时间为 00:00:00(UTC),界面仅显示日期 |
| 日期和时间 | 同时存储并显示日期与时间 |

时区调整选项
在「高级选项」中,可以配置 时区调整。
可选项会随字段格式发生变化:
格式:仅日期
| 选项 | 时区调整 | 描述 |
|---|---|---|
| 1 | 用户当地时间 | 默认值,根据用户时区进行转换 |
| 2 | 时区无关 | 不进行时区转换 |
| 3 | 仅日期 | 不存储时间部分(始终为 00:00:00) |
格式:日期和时间
| 选项 | 时区调整 | 描述 |
|---|---|---|
| 1 | 用户当地时间 | 默认值,根据用户时区进行转换 |
| 2 | 时区无关 | 不进行时区转换 |
💡 字段创建完成后,“格式” 和 “时区调整” 在一定条件下仍可修改(详见下文)。
已创建字段还能修改吗?
经实际验证,结论如下:
| 当前配置 | 格式可改 | 时区调整可改 |
|---|---|---|
| 仅日期 - 用户当地时间 | ✅ | ✅ |
| 仅日期 - 时区无关 | ✅ | ❌ |
| 仅日期 - 仅日期 | ❌ | ❌ |
| 日期和时间 - 用户当地时间 | ✅ | ✅ |
| 日期和时间 - 时区无关 | ✅ | ❌ |
时区调整该如何选择?
| 选项 | 描述 |
|---|---|
| 时区无关 | 当不需要 “时区” 信息时,例如酒店入住登记时间、发票付款时间等,使用该选项,选择该选项后,所有时区的用户将看到相同的日期和时间值。 |
| 仅限日期 | 不关注一天的 “时间” 或 “时区” 时,例如生日或纪念日等,使用该选项,选择该选项后,所有时区的用户将看到完全相同的日期值。 |
💡 如果未来可能需要时间部分,优先选择「仅日期 - 时区无关」,一旦选择「用户当地时间」,不同时区用户可能看到不同日期
小实验:字段配置、存储、展示
我将在 Invoice 实体新添如下 5 个 “日期和时间” 字段,然后对它们进行赋值,接着到 DB 上看看存储情况。
- 目前我使用的的时区是
(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi - 用户 Test06 使用的的时区是
(GMT+04:00) Baku
(1)新建字段
5 个“日期和时间”字段如下:
| # | 名称 | 字段名称 | 格式 | 时区调整 |
|---|---|---|---|---|
| 1 | D - User Local | gdh_d_userlocal | 仅日期 | 用户当地时间 |
| 2 | D - TZ independent | gdh_d_tz_independent | 仅日期 | 时区无关 |
| 3 | D - D | gdh_d_d | 仅日期 | 仅日期 |
| 4 | DT - User Local | gdh_dt_userlocal | 日期和时间 | 用户当地时间 |
| 5 | DT - TZ independent | gdh_dt_tz_independent | 日期和时间 | 时区无关 |

(2)在表单中填写“日期和时间”字段
在 (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi 时区下,对字段进行赋值:
| 字段 | 填写值 |
|---|---|
| D - User Local | 2025-03-10 |
| D - TZ independent | 2025-03-12 |
| D - D | 2025-03-14 |
| DT - User Local | 2025-03-10 14:30 |
| DT - TZ independent | 2025-03-24 09:30 |

(3)在数据库查看数据

结果如下:
| 字段 | 填写值 | 数据库存储的值 |
|---|---|---|
| D - User Local | 2025-03-10 | 2025-03-09 16:00:00.000 |
| D - TZ independent | 2025-03-12 | 2025-03-12 00:00:00.000 |
| D - D | 2025-03-14 | 2025-03-14 00:00:00.000 |
| DT - User Local | 2025-03-10 14:30 | 2025-03-10 06:30:00.000 |
| DT - TZ independent | 2025-03-24 09:30 | 2025-03-24 09:30:00.000 |
❓ 为什么 D - User Local 在 DB 中存储的是 2025-03-09 16:00:00.000 ?
我在 (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi 时区下,对 D - User Local 进行赋值,
填写的时间是 2025-03-10
但是在数据库中,时间被存储为 UTC 时区,在东八区到 UTC 之间有 8 小时的时差
所以在本地填写的 2025-03-10 日期被转换到 UTC 时区时,
就变成了 2025-03-09 16:00:00.000
DT - User Local 同理。
SELECT gdh_d_userlocal AS 'D - User Local',
gdh_d_tz_independent AS 'D - TZ independent',
gdh_d_d AS 'D - D',
gdh_dt_userlocal AS 'DT - User Local',
gdh_dt_tz_independent AS 'DT - TZ independent'
FROM gdh_invoice
WHERE gdh_no = 'SAS-00000001';
(4)使用 Test06 查看数据
注:用户 Test06 使用的的时区是 (GMT+04:00) Baku

❓ 为什么 用户 Test06 在表单上看到的 D - User Local 是 2025-03-10 10:30:00.000 ?
D - User Local 在数据库中存储的时间是 2025-03-10 06:30:00.000 (UTC 时区),
当这个时间转换到用户 Test06 所在的时区:“(GMT+04:00) Baku”,
时间就变成了 2025-03-10 10:30:00.000( UTC + 4),
所以用户 Test06 在表单上看到的 D - User Local 是 2025-03-10 10:30:00.000
(4)使用 Client API 获取
a. 获取 D - User Local 和 DT - User Local
| 名称 | 字段名称 | 格式 | 时区调整 | GMT+08:00 时区下填写 |
|---|---|---|---|---|
| D - User Local | gdh_d_userlocal | 仅日期 | 用户当地时间 | 2025-03-10 |
| DT - User Local | gdh_dt_userlocal | 日期和时间 | 用户当地时间 | 2025-03-10 14:30 |
// 'Sun, 09 Mar 2025 16:00:00 GMT'
Xrm.Page.getAttribute("gdh_d_userlocal").getValue().toUTCString();
// 'Sun, 09 Mar 2025 16:00:00 GMT'
Xrm.Page.getAttribute("gdh_d_userlocal").getValue().toUTCString();
b.对于 “时区无关”,返回的是浏览器的时区
获取 D-TZ independent 和 DT-TZ independent
| 名称 | 字段名称 | 格式 | 时区调整 |
|---|---|---|---|
| D-TZ independent | gdh_d_tz_independent | 仅日期 | 时区无关 |
| DT-TZ independent | gdh_dt_tz_independent | 日期和时间 | 时区无关 |
// 'Wed Mar 12 2025 00:00:00 GMT+0800 (中国标准时间)'
Xrm.Page.getAttribute("gdh_d_tz_independent").getValue().toString();
// 'Mon Mar 24 2025 09:30:00 GMT+0800 (中国标准时间)'
Xrm.Page.getAttribute("gdh_dt_tz_independent").getValue().toString();
💡JavaScript 日期值受浏览器的时区(来自设备操作系统设置)的影响,所以需要注意:
- 对于 “用户当地时间” 的字段,Client API 获取到的结果为 “UTC” 值,应使用
Date.getUTCDate()、Date.getUTCHours(),而不是Date.getDate() - 如果要获取用户看到的时间,应用
getTimeZoneOffsetMinutes。 不要使用Date.getDate()、Date.getHours()等,因为它们显示的是浏览器时区 - 对于 “时区无关”、“仅限日期” 的字段,应该使用
Date.getDate()、Date.getHours()等,不要使用Date.getUTCDate()、Date.getUTCHours(),因为本身就不需要进行时区的转换
(5)使用 Web API 获取
在 (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi 时区下,对字段进行赋值,并通过 Web API 获取:
| 字段 | 填写值 | 数据库存储的值 | 通过 Web API 获取得出 |
|---|---|---|---|
| D-User Local | 2025-03-10 | 2025-03-09 16:00:00.000 | 2025-03-09T16:00:00Z |
| D-TZ independent | 2025-03-12 | 2025-03-12 00:00:00.000 | 2025-03-12T00:00:00Z |
| D-D | 2025-03-14 | 2025-03-14 00:00:00.000 | 2025-03-14 |
| DT-User Local | 2025-03-10 14:30 | 2025-03-10 06:30:00.000 | 2025-03-10T06:30:00Z |
| DT-TZ independent | 2025-03-24 09:30 | 2025-03-24 09:30:00.000 | 2025-03-24T09:30:00Z |
可以看出,通过 Web API 获取的原始值,和数据库存储的一样。
❓ 关于 T 与 Z
“2025-03-10T06:30:00Z” 中的 “T”和 “Z” 分别是什么意思?
- T 是 ISO 8601 日期时间格式中的一个特殊字符,用于分隔日期和时间部分, 例如 2025-03-10T14:30:00 表示 2025 年 3 月 10 日 14 时 30 分 0 秒
- Z 是 ISO 8601 日期时间格式中的一个特殊字符,代表 “Zulu time” 或者说 UTC (Coordinated Universal Time) 时区。它表示该时间是以 UTC 时区表示的,没有时区偏移量。例如 2025-03-10T14:30:00Z 表示 2025 年 3 月 10 日 14 时 30 分 0 秒 (UTC 时区)。
var req = new XMLHttpRequest();
req.open(
"GET",
Xrm.Page.context.getClientUrl() +
"/api/data/v9.1/gdh_invoices(98F83878-1E35-EF11-8409-0017FA0671FA)?$select=gdh_d_d,gdh_d_tz_independent,gdh_d_userlocal,gdh_dt_tz_independent,gdh_dt_userlocal",
true
);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", 'odata.include-annotations="*"');
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var result = JSON.parse(this.response);
var gdh_d_d = result["gdh_d_d"];
var gdh_d_tz_independent = result["gdh_d_tz_independent"];
var gdh_d_userlocal = result["gdh_d_userlocal"];
var gdh_dt_tz_independent = result["gdh_dt_tz_independent"];
var gdh_dt_userlocal = result["gdh_dt_userlocal"];
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
查询运算符不支持?
“仅限日期” 类型的日期和时间字段,不允许使用下面的查询运算符,当这些运算符用于查询时,会引发无效运算符异常错误。
- X 分钟以前
- X 小时以前
- 过去 X 小时
- 接下来 X 小时
例如:对 “D-D” 列进行筛选,筛选条件如下:
<condition attribute="gdh_d_d" operator="last-x-hours" value="5"/>

执行后会报错:2147779605The operator is not valid or it is not supported.

如何设置用户的时区?
右上角的设置按钮 –> 个性化设置 –> General Tab –> 选择时区

参考
如果本文对你有所帮助,可以请我喝杯咖啡
(完)