通过


使用代码配置日期和时间列的行为和格式

如果你有世界各地的用户和办公室,则必须在多个时区中正确表示日期和时间值。 使用 DateTimeAttributeMetadataDateTimeAttributeMetadata 实体类型DateTimeAttributeMetadata 类) 定义和管理 Microsoft Dataverse 中类型 DateTime 的列。 使用 DateTimeBehavior 属性(for SDK for .NET,请参阅 DateTimeBehavior 属性)定义是使用还是不使用时区信息存储日期和时间值。 使用 DateTimeAttributeMetadata.Format 属性 指定这些列的显示格式。

还可以使用 Dataverse 中的自定义区域来定义日期和时间列的行为和格式。 有关详细信息,请参阅 “日期和时间”列的行为和格式

注释

Dataverse 中所有日期时间列均支持最早至 1/1/1753 12:00 AM。

若日期或日期时间字段位于解决方案中,仅发布者可修改现有管理字段的行为。 若要对这些字段进行更改,必须升级添加“仅日期”或“日期时间”列的解决方案。 有关详细信息,请参阅 升级或更新解决方案

指定日期时间列的行为

使用 DateTimeBehavior (DateTimeBehavior 复合类型DateTimeBehavior 类) 为DateTimeAttributeMetadata 实体类型指定值。 DateTimeBehavior 属性。 以下是 DateTimeBehavior 的成员。 每个成员返回一个字符串,其值与成员名称相同:

成员名称和值 Description
UserLocal - 在系统中将日期和时间值存储为 UTC 值。
- 检索操作返回 UTC 值。
- 更新作将 UTC 值转换为当前用户的时区值,然后按原样或等效的 UTC 值存储更新值,具体取决于为更新指定的值的类型(DateTimeKind)。 如果指定的值为 UTC 类型,则它按原样存储。 否则,将存储 UTC 等效值。
- 获取格式化值时,根据用户的时区和区域设置,将值从 UTC 转换为用户的当前时区。
对于 Web API,该列会以 DateTimeOffset 形式公开。
- 此行为用于类似 CreatedOnModifiedOn无法更改的系统列。 此行为适用于需存储带时区信息的日期时间值的自定义列。
DateOnly - 存储没有时间值的实际日期值。
- 检索格式化值将显示日期值。
- 对于 Web API,该列以日期的形式公开。
- 将此行为用于存储生日和周年纪念日(其中不需要时间信息)的自定义列。
TimeZoneIndependent - 将实际日期和时间值存储在系统中,而不考虑用户时区。
- 对于检索和更新操作,不执行时区转换,无论用户时区如何,都会在系统中分别返回和更新实际日期和时间值。
- 检索格式化值时,将根据当前用户时区和区域设置显示日期时间值(不进行时区转换)。
对于 Web API,该列会以 DateTimeOffset 形式公开。
- 此行为适用于存储酒店入住/退房时间等信息的列。

以下示例代码演示如何为新的日期时间列设置 UserLocal 行为:

/// <summary>
/// Create a new DateTime column for the Account table with UserLocal behavior
/// </summary>
/// <param name="service">Authenticated IOrganizationService instance</param>
static void CreateUserLocalDateTimeColumn(IOrganizationService service) {

   int _languageCode = 1033; //English

   DateTimeAttributeMetadata dtAttribute = new()
   {
       SchemaName = "new_SampleDateTimeAttribute",
       DisplayName = new Label("Sample Date Time Attribute", _languageCode),
       RequiredLevel = new AttributeRequiredLevelManagedProperty(AttributeRequiredLevel.None),
       Description = new Label("Created by SDK Sample", _languageCode),
       DateTimeBehavior = DateTimeBehavior.UserLocal,
       Format = Microsoft.Xrm.Sdk.Metadata.DateTimeFormat.DateAndTime,
       ImeMode = ImeMode.Disabled
   };

   CreateAttributeRequest request = new()
   {
       EntityName = Account.EntityLogicalName,
       Attribute = dtAttribute
   };

   service.Execute(request);
}

在示例代码中,还可以通过直接指定字符串值来设置 DateTimeBehavior 属性的值:DateTimeBehavior = "UserLocal"

如果在创建日期和时间列时未指定该行为,则默认情况下会使用 UserLocal 该行为创建该列。

重要

  • 创建一个行为设置为 DateOnlyTimeZoneIndependent 的日期和时间列后,无法更改该列的行为。 有关详细信息,请参阅 更改 DateTime 列的行为
  • 使用 DateOnlyTimeZoneIndependent 行为的日期和时间列在 Dynamics 365 for Outlook 客户端的早期版本中以脱机模式编辑时,被视同具有 UserLocal 行为。 存在此限制,因为客户端不了解新行为,并且不会以 UserLocal不同的方式对待它们。 升级时不会将日期和时间列转换为新行为。 为了避免此限制,请在定制器采用新的功能之前,将所有 Dataverse 客户端升级到最新版本。 在线编辑时,具有新行为的列数据可正常修改。

指定日期和时间列的格式

使用Format属性来指定列的日期/时间显示格式,而不管系统如何存储它。 使用 DateTimeFormat 枚举(DateTimeFormat 枚举类型DateTimeFormat 枚举)指定显示格式: DateAndTimeDateOnly

如果将DateTimeAttributeMetadata.DateTimeBehavior属性设置为DateOnly,则无法将DateTimeAttributeMetadata.Format属性的值设置为DateAndTime

DateOnly 行为不支持的日期和时间查询运算符

DateOnly 行为不支持与时间相关的查询运算符。 除了此处列出的特定于时间的查询运算符之外,所有其他查询运算符均受支持。

  • X 分钟以前
  • X 小时以前
  • 过去 X 小时
  • 接下来 X 小时

详细信息: Datetime 数据运算符

使用 OData API 提交用户本地日期和时间值

在Microsoft Power Platform中,当用户通过 UI 在用户特定的时区中提交日期和时间时,自动计算会将数据设置为正确的日期和时间。 它执行分析,以根据列和 UI 设置将提交的任何日期更改为相应的 UTC 值。 使用 Web API 提交日期和时间值时,计算不会发生,从而导致无法解释的数据展示。 例如,如果你位于太平洋时区,并且提交 2021 年 4 月 4 日 12:00,则会发生以下情况:

  • 原文:2021/4/12:00 提交者位于太平洋时区。
  • 通过 UI 提交并作为用户本地数据检索:4/4/2021 12:00
  • 通过 API 提交并以用户本地时间检索:2021/4/4 04:00

通过 UI 提交

UI 将值设置为用户本地,列设置为用户本地。

  • 原始值: 2021/4/12:00 太平洋时区。
  • 计算为 UTC 并在 Dataverse 中存储的值: 2021/4/4 12:00 + 8:00 = 2021T20:00:00Z。 由于 PST 与 UTC 相差 -8:00,因此在存储的值上加上 +8。
  • 太平洋时区的用户在 UI 中显示的值: 2021/4/4 12:00。 UI 将-8:00 UTC的偏移量计算应用于2021年4月4日T20:00:00Z,以确保值的正确性。

通过 API 提交

UI 将值设置为用户本地,列设置为用户本地。

  • 原始值: 4/4/2021T12:00:00 或 4/4/2021T12:00:00Z——未提供偏移量或 UTC 指示符。 提交者位于太平洋时区。
  • 计算为 UTC 并在 Dataverse 中存储的值: 从 OData API 提交时不进行 UI 计算,所以该值被存储为 2021-04-04T12:00:00Z。
  • 太平洋时区的用户在 UI 中显示的值: 2021/4/4 4:00。 UI 对 Dataverse 中的值应用 -8:00 UTC 偏移量计算。

为避免通过 API 调用向用户本地列输入数据时出现此问题,请计算提交数据用户的偏移量并应用该偏移量。

使用前面的示例: 2021/4/2021 12:00 需要通过 API 提交为 4/4/2021T12:00:00-08:00。 原始时间和日期包括对当前用户时区的偏移量计算。 或者,提交者可以在提交之前执行计算,并提交 2021年4月4日T20:00:00Z

如果选择包括偏移量计算,请不要包含 ZUTC 指示器,因为 Dataverse 不接受它。

更改日期和时间列的行为

如果在 Dataverse 实例中具有系统定制器角色,并且 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 日期和时间列的托管属性设置为 True,则可以更新日期和时间列以更改其行为。

注意

在更改日期和时间列的行为之前,请查看该列的所有依赖项,例如业务规则、工作流以及计算列或汇总列,以确保更改行为时没有问题。 系统定制器可以使用托管属性限制修改现有日期和时间列 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 的行为。

更改日期和时间列的行为后,至少要打开每个依赖于该日期和时间列的业务规则、工作流、计算列和汇总列记录,查看信息,并保存记录以确保使用最新的列行为和值。

更改计算列或汇总列的数据和时间行为后,打开计算列或汇总列定义编辑器,并保存列定义以确保该列在行为更改后仍然有效。 系统定制员可在 Dataverse 定制区域,通过选择编辑按钮(位于字段类型旁)打开计算列或汇总列的列定义编辑器。 有关详细信息,请参阅 定义计算列以自动执行计算定义聚合值的汇总列

  • 默认情况下,开箱即用表和自定义表的CreatedOnModifiedOn列的行为设置为UserLocal,同时,DateTimeAttributeMetadata.CanChangeDateTimeBehavior托管属性设置为False,这意味着无法更改这些列的行为。 尽管用户可以更改自定义表中这些列的 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 托管属性的值,但用户仍无法更改列的行为。

  • 对于新的自定义日期和时间列,托管 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 属性设置为 True。 此设置意味着你可以将自定义日期和时间列的行为从UserLocal更改为DateOnlyTimeZoneIndependent;不允许进行其他行为转换。

    对于属于 Dataverse 组织的自定义日期和时间列,除非列或父表不可自定义,否则托管 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 属性将设置为 True

    注释

    当您将列的DateTimeAttributeMetadata.DateTimeBehavior属性从UserLocal更改为DateOnly时,请确保也将DateTimeAttributeMetadata.Format属性从DateAndTime更改为DateOnly。 否则,会发生异常。

  • Dataverse 中的以下开箱即用的日期和时间列默认设置为 DateOnly,且托管属性 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 设置为 False,这意味着无法更改这些列的行为:

    日期和时间列 父表
    anniversary 联系人​​
    birthdate 联系人​​
    duedate Invoice
    estimatedclosedate 潜在顾客
    actualclosedate 机会
    estimatedclosedate 机会
    finaldecisiondate 机会
    validfromdate 产品
    validtodate 产品
    closedon 报价单
    expireson 报价单

    这些列的行为被设置为 UserLocal,并且 DateTimeAttributeMetadata.CanChangeDateTimeBehavior 管理的属性被设置为 True,你只能将这些列的行为更改为 DateOnly。 不允许进行其他行为转换。

更新列的行为后,必须发布有关更改的自定义配置,以使其生效。 更新日期和时间列的行为可确保更改列行为 输入或更新的所有值都按照新行为存储在系统中。 此更改不会影响数据库中已存储的值,并且它们将继续存储为 UTC 值。 但是,使用 SDK 检索现有值或在 UI 中查看现有值时,根据列的新行为显示现有值。 例如,如果将帐户自定义列的行为从UserLocal更改为DateOnly,并使用 SDK 检索现有帐户记录,则日期和时间显示为<日期>,后跟时间为 12 AM (00:00:00)。 同样,对于从 UserLocalTimeZoneIndependent 的行为变化,数据库中的实际值按原样显示,没有进行任何时区转换。

以下示例代码演示如何更新日期和时间列的行为:

/// <summary>
/// Update the behavior of a DateTime column
/// </summary>
/// <param name="service">Authenticated IOrganizationService instance</param>
static void UpdateBehaviorOfDateTimeColumn(IOrganizationService service) {

    // Retrieve the attribute to update its behavior and format
    RetrieveAttributeRequest retrieveColumnRequest = new()
    {
        EntityLogicalName = Account.EntityLogicalName,
        LogicalName = "new_sampledatetimeattribute",
        RetrieveAsIfPublished = false
    };
    // Execute the request
    RetrieveAttributeResponse attributeResponse =
                    (RetrieveAttributeResponse)service.Execute(retrieveColumnRequest);

    // Modify the values of the retrieved attribute
    DateTimeAttributeMetadata retrievedAttributeMetadata =
                    (DateTimeAttributeMetadata)attributeResponse.AttributeMetadata;

    retrievedAttributeMetadata.DateTimeBehavior = DateTimeBehavior.DateOnly;
    retrievedAttributeMetadata.Format = Microsoft.Xrm.Sdk.Metadata.DateTimeFormat.DateOnly;

    // Update the attribute with the modified value
    UpdateAttributeRequest updateRequest = new()
    {
        Attribute = retrievedAttributeMetadata,
        EntityName = Account.EntityLogicalName,
        MergeLabels = false
    };
    service.Execute(updateRequest);


    // Publish customizations to the account 
    PublishXmlRequest pxReq = new()
    {
        ParameterXml = "<importexportxml><entities><entity>account</entity></entities></importexportxml>"
    };
    service.Execute(pxReq);
}
 

转换数据库中的现有日期和时间值的行为。

当您更新日期和时间列以将其行为从 UserLocal 更改为 DateOnlyTimeZoneIndependent 时,数据库中现有的列值不会自动转换。 此行为变更仅影响您在修改行为后之后输入或更新的列值。 系统中的现有日期和时间值保持 UTC。 通过 SDK 或 UI 检索这些值时,Dataverse 会根据新行为显示这些值,如上一部分所述。 对于行为从UserLocal更改为DateOnly的列,可以使用DateOnly消息将数据库中的现有 UTC 值转换为适当的ConvertDateAndTimeBehavior值,以避免出现任何数据异常。

使用此消息可以指定转换规则(如果使用 SDK for .NET,请参阅 ConvertDateAndTimeBehaviorRequest.ConversionRule 属性)选择要用于将值从 UTC 转换为 DateOnly 的时区。 可以指定下列转换规则之一:

  • SpecificTimeZone:根据指定的 Dataverse 时区代码,将 UTC 值转换为 DateOnly 值。 在这种情况下,还需要为 ConvertDateAndTimeBehaviorRequest.TimeZoneCode 属性指定值。
  • CreatedByTimeZone:将 UTC 值转换为创建记录的用户在 UI 中看到的 DateOnly 值。
  • OwnerTimeZone:将 UTC 值转换为拥有记录的用户在 UI 中看到的 DateOnly 值。
  • LastUpdatedByTimeZone:将 UTC 值转换为用户在 UI 中看到的上次更新记录的 DateOnly 值。

使用 DateTimeBehaviorConversionRule 类 的四个成员之一指定 ConversionRule 属性的有效值。

注释

必须在 Dataverse 实例中具有系统管理员角色才能执行 ConvertDateAndTimeBehaviorRequest 类

当您执行 ConvertDateAndTimeBehavior 时(如果您正在使用 SDK FOR .NET,请参阅 ConvertDateAndTimeBehaviorRequest 消息),您将创建一个系统作业(异步操作)来运行转换请求。 ConvertDateAndTimeBehaviorResponse.JobId消息响应中的列显示转换请求创建的系统作业的 ID。 系统作业完成后,检查作业详细信息 (AsyncOperation.Message) 来查看转换详细信息或错误(如果有)。

注释

将多个列的转换分组为单个转换作业,并且一次只运行一个转换作业,以确保转换过程中没有冲突并达到最佳系统性能。

使用 ConvertDateAndTimeBehavior 消息时,请考虑以下几点:

  • 避免在执行消息期间对 Dataverse 中的解决方案进行重大更改,例如导入解决方案或删除列或父表。 异常行为可能会发生。 但是,不会发生数据丢失。
  • 由于执行消息,系统中完成的更新不会运行工作流和插件。
  • 执行消息后在系统中完成的更新不会更改列的“上次修改时间”值。 但是,更新会被审核,以帮助管理员确定转换的时间以及列的原始值和更改后的值。

以下示例代码展示如何使用消息:

/// <summary>
/// Demonstrates use of the ConvertDateAndTimeBehavior message
/// </summary>
/// <param name="service">Authenticated IOrganizationService instance</param>
static void ConvertDateAndTimeBehavior(IOrganizationService service)
{

    ConvertDateAndTimeBehaviorRequest request = new()
    {
        Attributes = new EntityAttributeCollection()
        {
            new KeyValuePair<string, StringCollection>("account", new StringCollection()
            { "new_sampledatetimeattribute" })
        },
        ConversionRule = DateTimeBehaviorConversionRule.SpecificTimeZone.Value,
        TimeZoneCode = 190, // Time zone code for India Standard Time (IST) in Dataverse
        AutoConvert = false // Conversion must be done using ConversionRule
    };

    // Execute the request
    var response = (ConvertDateAndTimeBehaviorResponse)service.Execute(request);

    Console.WriteLine($"Asynchronous Job ID: {response.JobId}");
}

Web 客户端处理时区转换的方式不同于统一接口

Web 客户端 在 2019 年已弃用。 如果要将 客户端脚本 迁移到其后续的统一接口,请注意两个客户端如何处理用户本地列的时区转换的差异。

在 Web 客户端中,服务器处理时区转换。 如果用户在 Web 客户端窗体中输入 2018-10-15 07:30 ,客户端 API Xrm.Page.getAttribute(<column name>).getValue()2018-10-15 07:30返回。 在保存该值时,此值将发送到服务器,在服务器上进行时区调整。

在 Unified Client 中,客户端处理时区转换。 如果 UTC+8 时区的用户以统一客户端形式输入 2018-10-15 07:30 ,则客户端 API formContext.getAttribute(<column name>).getValue() 返回调整后的值 2018-10-14T23:30:00Z。 服务器接受值,并且不执行进一步的时区调整。

若要考虑这种差异,可以:

另请参阅

“日期和时间”列的行为和格式
解决模型驱动应用中的日期和时间问题
列概述
ConvertDateAndTimeBehaviorRequest 类
DateTimeAttributeMetadata 类
博客:提交日期和时间数据的方式是否重要?