【问题标题】:Parsing "12/25/35" to a date using InvariantCulture (2-digit year)使用 InvariantCulture(2 位数年份)将“12/25/35”解析为日期
【发布时间】:2019-10-22 16:34:20
【问题描述】:

当我使用InvariantCulture 解析字符串时,两者都有:

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

和:

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

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

12 月 25 日,2035

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

12 月 25 日,1935

发生了什么事?

【问题讨论】:

    标签: .net windows datetime locale regional-settings


    【解决方案1】:

    所谓的不变文化在这种情况下并不是那么不变。这取决于您的操作系统版本和操作系统中当前用户的区域设置。

    在 .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”)上,相同的属性返回 2049,因此您的结果是 12 月 25 日,2035。

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

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

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

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

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

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

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

    因此,如果您希望跨操作系统版本和用户偏好的行为保持一致,我认为您不能使用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 带有两个不同的Calendars,可能有不同的 2 位数年份最大值,即:

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

    【讨论】:

    • 是的。依靠特定的机器(及其特定的区域设置)来使其正确是危险的。最好强制转换在所有服务器上以相同的方式工作,基本上忽略所有区域设置。
    • @DavidRTribble 人们普遍认为,当您使用CultureInfo.InvariantInfo 时,您是安全的。但在这种情况下,区域设置(和 Windows 版本)确实会影响结果,即使传递了“不变信息”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多