使用 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()).TwoDigitYearMax
。 Documentation of GregorianCalendar.TwoDigitYearMax
override.
在 Windows 10 版本 1809(“2018 年 10 月更新”,“Redstone 5”)机器上,用户未更改区域设置(更多信息见下文),属性 TwoDigitYearMax
是 2029
,因此您得到 12 月 25 日,1935.
但在 Windows 10 版本 1903(“2019 年 5 月更新”,“19H1”)上,相同 属性 returns 2049
,因此您的结果是12 月 25 日,2035.
然而,该值不仅取决于Windows版本。用户在区域设置中输入的内容也很重要。所以这并不是真正的“不变”。
您可以通过以下方式在控制面板中更改截止年份:
- 单击开始,单击左侧的“齿轮”图标(设置),然后单击时间和语言。
- 单击左侧的区域。
- 在相关设置下,单击其他日期、时间和区域设置。
- (您在控制面板中。)单击区域。
- (在新的区域 window。)单击页面底部附近的按钮其他设置...,然后在新 window 单击 日期 选项卡。
- 在日历组中,调整输入两位数年份时,将其解释为介于.[=95之间的年份=]
在较旧的 Windows 版本中,它可能是(从 microsoft.com
粘贴):
- 单击开始,指向设置,然后单击控制面板。
- 双击 区域设置 图标。
- 单击日期 选项卡。
- 在 输入两位数年份时,解释年份介于 框中,键入所需的截止年份,然后单击 确定.
或者您可以直接使用 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
当我使用 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()).TwoDigitYearMax
。 Documentation of GregorianCalendar.TwoDigitYearMax
override.
在 Windows 10 版本 1809(“2018 年 10 月更新”,“Redstone 5”)机器上,用户未更改区域设置(更多信息见下文),属性 TwoDigitYearMax
是 2029
,因此您得到 12 月 25 日,1935.
但在 Windows 10 版本 1903(“2019 年 5 月更新”,“19H1”)上,相同 属性 returns 2049
,因此您的结果是12 月 25 日,2035.
然而,该值不仅取决于Windows版本。用户在区域设置中输入的内容也很重要。所以这并不是真正的“不变”。
您可以通过以下方式在控制面板中更改截止年份:
- 单击开始,单击左侧的“齿轮”图标(设置),然后单击时间和语言。
- 单击左侧的区域。
- 在相关设置下,单击其他日期、时间和区域设置。
- (您在控制面板中。)单击区域。
- (在新的区域 window。)单击页面底部附近的按钮其他设置...,然后在新 window 单击 日期 选项卡。
- 在日历组中,调整输入两位数年份时,将其解释为介于.[=95之间的年份=]
在较旧的 Windows 版本中,它可能是(从 microsoft.com
粘贴):
- 单击开始,指向设置,然后单击控制面板。
- 双击 区域设置 图标。
- 单击日期 选项卡。
- 在 输入两位数年份时,解释年份介于 框中,键入所需的截止年份,然后单击 确定.
或者您可以直接使用 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