如何:让用户解决不明确的时间

不明确的时间是指映射到多个协调世界时 (UTC) 的时间。 当向回调整时钟时间时(例如某时区在从夏时制转换为标准时间的过程中),就会出现此情况。 在处理不明确的时间时,可执行下列操作之一:

  • 如果该不明确的时间是用户输入的数据项,则可将这种多义性留给用户解决。

  • 就时间映射到 UTC 的方式进行假设。 例如,可以假定某个不明确的时间始终表示为时区的标准时间。

本主题介绍如何让用户解决不明确的时间。

让用户解决不明确的时间

  1. 获取用户输入的日期和时间。

  2. 调用 IsAmbiguousTime 方法以确定时间是否明确。

  3. 如果时间不明确,请调用 GetAmbiguousTimeOffsets 方法以检索 TimeSpan 对象的数组。 该数组中的每个元素都包含不明确的时间可以映射到的一个 UTC 偏移量。

  4. 让用户选择所需的偏移量。

  5. 通过从本地时间中减去用户选择的偏移量来得到 UTC 日期和时间。

  6. 调用 static(在 Visual Basic .NET 中为 Shared)SpecifyKind 方法,将 UTC 日期和时间值的 Kind 属性设置为 DateTimeKind.Utc

示例

下面的示例提示用户输入一个日期和时间;如果输入的值不明确,则让用户选择不明确的时间映射到的 UTC 时间。

Private Sub GetUserDateInput()
   ' Get date and time from user
   Dim inputDate As Date = GetUserDateTime()
   Dim utcDate As Date

   ' Exit if date has no significant value
   If inputDate = Date.MinValue Then Exit Sub

   If TimeZoneInfo.Local.IsAmbiguousTime(inputDate) Then
      Console.WriteLine("The date you've entered is ambiguous.")
      Console.WriteLine("Please select the correct offset from Universal Coordinated Time:")
      Dim offsets() As TimeSpan = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate)
      For ctr As Integer = 0 to offsets.Length - 1
         Dim zoneDescription As String
         If offsets(ctr).Equals(TimeZoneInfo.Local.BaseUtcOffset) Then 
            zoneDescription = TimeZoneInfo.Local.StandardName
         Else
            zoneDescription = TimeZoneInfo.Local.DaylightName
         End If
         Console.WriteLine("{0}.) {1} hours, {2} minutes ({3})", _
                           ctr, offsets(ctr).Hours, offsets(ctr).Minutes, zoneDescription)
      Next         
      Console.Write("> ")
      Dim selection As Integer = CInt(Console.ReadLine())

      ' Convert local time to UTC, and set Kind property to DateTimeKind.Utc
      utcDate = Date.SpecifyKind(inputDate - offsets(selection), DateTimeKind.Utc)

      Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())
   Else
      utcDate = inputDate.ToUniversalTime()
      Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())    
   End If
End Sub

Private Function GetUserDateTime() As Date
   Dim exitFlag As Boolean = False            ' flag to exit loop if date is valid
   Dim dateString As String 
   Dim inputDate As Date = Date.MinValue

   Console.Write("Enter a local date and time: ")
   Do While Not exitFlag
      dateString = Console.ReadLine()
      If dateString.ToUpper = "E" Then exitFlag = True
      If Date.TryParse(dateString, inputDate) Then
         exitFlag = true
      Else   
         Console.Write("Enter a valid date and time, or enter 'e' to exit: ")
      End If
   Loop

   Return inputDate        
End Function
private void GetUserDateInput()
{
   // Get date and time from user
   DateTime inputDate = GetUserDateTime();
   DateTime utcDate;

   // Exit if date has no significant value
   if (inputDate == DateTime.MinValue) return;

   if (TimeZoneInfo.Local.IsAmbiguousTime(inputDate))
   {
      Console.WriteLine("The date you've entered is ambiguous.");
      Console.WriteLine("Please select the correct offset from Universal Coordinated Time:");
      TimeSpan[] offsets = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate);
      for (int ctr = 0; ctr < offsets.Length; ctr++)
      {
         Console.WriteLine("{0}.) {1} hours, {2} minutes", ctr, offsets[ctr].Hours, offsets[ctr].Minutes);
      }
      Console.Write("> ");
      int selection = Convert.ToInt32(Console.ReadLine());

      // Convert local time to UTC, and set Kind property to DateTimeKind.Utc
      utcDate = DateTime.SpecifyKind(inputDate - offsets[selection], DateTimeKind.Utc);

      Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());
   }
   else
   {
      utcDate = inputDate.ToUniversalTime();
      Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());    
   }
}

private DateTime GetUserDateTime() 
{
   bool exitFlag = false;             // flag to exit loop if date is valid
   string dateString;  
   DateTime inputDate = DateTime.MinValue;

   Console.Write("Enter a local date and time: ");
   while (! exitFlag)
   {
      dateString = Console.ReadLine();
      if (dateString.ToUpper() == "E")
         exitFlag = true;

      if (DateTime.TryParse(dateString, out inputDate))
         exitFlag = true;
      else
         Console.Write("Enter a valid date and time, or enter 'e' to exit: ");
   }

   return inputDate;        
}

该代码示例的核心使用 TimeSpan 对象的数组指示不明确时间的各个可能的 UTC 偏移量。 但是,这些偏移量对用户不可能有意义。 为了阐明偏移量的含义,该代码还通过注释说明了偏移量表示的是本地时区的标准时间还是其夏时制。 该代码通过将偏移量与 BaseUtcOffset 属性的值进行比较来确定哪个时间是标准时间,哪个时间是夏时制时间。 此属性指示 UTC 与时区标准时间之差。

在此示例中,本地时区都通过 TimeZoneInfo.Local 属性来引用,而从未分配给对象变量。 这是一种建议做法,因为调用 TimeZoneInfo.ClearCachedData 方法会使分配了本地时区的任何对象都失效。

编译代码

此示例需要:

  • 在项目中添加一个对 System.Core.dll 的引用。

  • 使用 using 语句导入 System 命名空间(在 C# 代码中需要)。

请参见

任务

如何:解决不明确的时间

其他资源

日期、时间和时区