使用 InvariantCulture(2 位数年份)将“12/25/35”解析为日期

Parsing "12/25/35" to a date using InvariantCulture (2-digit year)

当我使用 InvariantCulture 解析字符串时,同时使用:

var christ1 = DateTime.Parse("12/25/35", CultureInfo.InvariantCulture);

和:

var christ2 = DateTime.ParseExact("12/25/35", "MM/dd/yy", CultureInfo.InvariantCulture);

结果取决于运行应用程序的计算机。在一台机器上,我得到相当于:

December 25, 2035

而在另一台机器上我得到一个世纪前的日期,即:

December 25, 1935

这是怎么回事?

所谓的不变文化,在这种情况下并不是那么不变。这取决于您的 OS 版本和当前用户在 OS.

中的区域设置

在 .NET 术语中,感兴趣的 属性 是日历上的 TwoDigitYearMax,因此请检查 CultureInfo.InvariantCulture.DateTimeFormat.Calendar.TwoDigitYearMax(new GregorianCalendar()).TwoDigitYearMaxDocumentation of GregorianCalendar.TwoDigitYearMax override.

在 Windows 10 版本 1809(“2018 年 10 月更新”,“Redstone 5”)机器上,用户未更改区域设置(更多信息见下文),属性 TwoDigitYearMax2029,因此您得到 12 月 25 日,1935.

但在 Windows 10 版本 1903(“2019 年 5 月更新”,“19H1”)上,相同 属性 returns 2049,因此您的结果是12 月 25 日,2035.

然而,该值不仅取决于Windows版本。用户在区域设置中输入的内容也很重要。所以这并不是真正的“不变”。

您可以通过以下方式在控制面板中更改截止年份:

  1. 单击开始,单击左侧的“齿轮”图标(设置),然后单击时间和语言
  2. 单击左侧的区域
  3. 相关设置下,单击其他日期、时间和区域设置
  4. (您在控制面板中。)单击区域
  5. (在新的区域 window。)单击页面底部附近的按钮其他设置...,然后在新 window 单击 日期 选项卡。
  6. 日历组中,调整输入两位数年份时,将其解释为介于.[=95之间的年份=]

在较旧的 Windows 版本中,它可能是(从 microsoft.com 粘贴):

  1. 单击开始,指向设置,然后单击控制面板
  2. 双击 区域设置 图标。
  3. 单击日期 选项卡。
  4. 输入两位数年份时,解释年份介于 框中,键入所需的截止年份,然后单击 确定.

或者您可以直接使用 Windows 注册表,转到键 HKEY_CURRENT_USER\Control Panel\International\Calendars\TwoDigitYearMax,对于该键中的每个相关“值”,保留 name组件不变,并将值的 data 组件编辑为所需的截止年份(通常的十进制字符串表示形式)。如果用户从未从控制面板更改过此设置,则最里面的两个键 (Calendars\TwoDigitYearMax) 尚不存在。有关与注册表混合的常见警告适用。

一旦您在控制面板中更改了年份,在您进行这些更改后 启动 的每个 .NET 进程都会在 TwoDigitYearMax 属性 通过 InvarantCulture!

达成

因此,如果您希望跨 OS 个版本和用户偏好保持一致的行为,我认为您不能使用 InvariantCulture。相反,这样的事情可能会起作用:

var tmp = (CultureInfo)(CultureInfo.InvariantCulture.Clone());
tmp.DateTimeFormat.Calendar.TwoDigitYearMax = 2039; // any cutoff you need
 // incorrect: tmp.Calendar.TwoDigitYearMax = 2039
var newInvariantCulture = CultureInfo.ReadOnly(tmp);

然后在解析具有 2 位数年份的日期时使用该 newInvariantCulture 实例(您可以将其放在某些 static readonly 字段中)。

警告:每个CultureInfo x带有两个不同的Calendar可能有不同的两位数年份最大值,即:

x.DateTimeFormat.Calendar.TwoDigitYearMax
  !=
x.Calendar.TwoDigitYearMax