DateTime.TryParse 世纪控件 C#

发布于 2024-08-11 06:12:30 字数 905 浏览 9 评论 0原文

以下代码片段的结果是“12/06/1930 12:00:00”。如何控制隐含的世纪,使“12 Jun 30”变成 2030?

string dateString = "12 Jun 30"; //from user input
DateTime result;
DateTime.TryParse(dateString, new System.Globalization.CultureInfo("en-GB"),System.Globalization.DateTimeStyles.None,out result);
Console.WriteLine(result.ToString());

请暂时搁置以下事实:正确的解决方案是首先正确指定日期。

注意:结果与运行代码的电脑的系统日期时间无关。

回答:谢谢德克西

for (int i = 0; i <= 9; i++)
{
    string dateString = "12 Jun " + ((int)i * 10).ToString();
    Console.WriteLine("Parsing " + dateString);
    DateTime result;
    System.Globalization.CultureInfo cultureInfo = new System.Globalization.CultureInfo("en-GB");
    cultureInfo.Calendar.TwoDigitYearMax = 2099;
    DateTime.TryParse(dateString, cultureInfo , System.Globalization.DateTimeStyles.None, out result);
    Console.WriteLine(result.ToString());
}

The result of the following snippet is "12/06/1930 12:00:00". How do I control the implied century so that "12 Jun 30" becomes 2030 instead?

string dateString = "12 Jun 30"; //from user input
DateTime result;
DateTime.TryParse(dateString, new System.Globalization.CultureInfo("en-GB"),System.Globalization.DateTimeStyles.None,out result);
Console.WriteLine(result.ToString());

Please set aside, for the moment, the fact that a correct solution is to specify the date correctly in the first place.

Note: The result is independant of the system datetime for the pc running the code.

Answer: Thanks Deeksy

for (int i = 0; i <= 9; i++)
{
    string dateString = "12 Jun " + ((int)i * 10).ToString();
    Console.WriteLine("Parsing " + dateString);
    DateTime result;
    System.Globalization.CultureInfo cultureInfo = new System.Globalization.CultureInfo("en-GB");
    cultureInfo.Calendar.TwoDigitYearMax = 2099;
    DateTime.TryParse(dateString, cultureInfo , System.Globalization.DateTimeStyles.None, out result);
    Console.WriteLine(result.ToString());
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

乖乖哒 2024-08-18 06:12:30

这很棘手,因为 TryParse 中两位数年份的工作方式基于您正在使用的 CultureInfo 对象的 Calendar 属性的 TwoDigitYearMax 属性。 (CultureInfo->Calendar->TwoDigitYearMax)

为了使两位数年份前面加上 20,您需要手动创建一个 CultureInfo 对象,该对象具有将 2099 设置为 TwoDigitYearMax 属性的 Calendar 对象。不幸的是,这意味着解析的任何两位数日期都将在前面添加 20(包括 98、99 等),这可能不是您想要的。

我怀疑您最好的选择是使用第三方日期解析库,而不是使用 +50/-50 年规则表示 2 位数年份的标准 tryparse。 (两位数年份应转换为今年之前 50 年和比今年大 50 年之间的范围)。

或者,您可以重写日历对象(它是虚拟的)上的 ToFourDigitYear 方法,并使用它来实现 -50/+50 规则。

It's tricky, because the way two digit years work with TryParse is based on the TwoDigitYearMax property of the Calendar property of the CultureInfo object that you are using. (CultureInfo->Calendar->TwoDigitYearMax)

In order to make two digit years have 20 prepended, you'll need to manually create a CultureInfo object which has a Calendar object with 2099 set as the TwoDigitYearMax property. Unfortunately, this means that any two digit date parsed will have 20 prepended (including 98, 99 etc.) which is probably not what you want.

I suspect that your best option is to use a 3rd party date parsing library instead of the standard tryparse that will use the +50/-50 year rule for 2 digit years. (that a 2 digit year should be translated into a range between 50 years before this year and 50 years greater than this year).

Alternatively, you could override the ToFourDigitYear method on the calendar object (it's virtual) and use that to implement the -50/+50 rule.

不爱素颜 2024-08-18 06:12:30

我会编写一个可重用的函数:

public static object ConvertCustomDate(string input)
{
    //Create a new culture based on our current one but override the two
    //digit year max.
    CultureInfo ci = new CultureInfo(CultureInfo.CurrentCulture.LCID);
    ci.Calendar.TwoDigitYearMax = 2099;
    //Parse the date using our custom culture.
    DateTime dt = DateTime.ParseExact(input, "MMM-yy", ci);
    return new { Month=dt.ToString("MMMM"), Year=dt.ToString("yyyy") };
}

这是我的准日期字符串列表

List<string> dates = new List<string>(new []{
    "May-10",
    "Jun-30",
    "Jul-10",
    "Apr-08",
    "Mar-07"
});

像这样扫描它:

foreach(object obj in dates.Select(d => ConvertCustomDate(d)))
{
    Console.WriteLine(obj);
}

请注意,它现在处理 30 作为 2030 年而不是 1930...

I'd write a re-usable function:

public static object ConvertCustomDate(string input)
{
    //Create a new culture based on our current one but override the two
    //digit year max.
    CultureInfo ci = new CultureInfo(CultureInfo.CurrentCulture.LCID);
    ci.Calendar.TwoDigitYearMax = 2099;
    //Parse the date using our custom culture.
    DateTime dt = DateTime.ParseExact(input, "MMM-yy", ci);
    return new { Month=dt.ToString("MMMM"), Year=dt.ToString("yyyy") };
}

Here's my list of quasi-date strings

List<string> dates = new List<string>(new []{
    "May-10",
    "Jun-30",
    "Jul-10",
    "Apr-08",
    "Mar-07"
});

Scan over it like so:

foreach(object obj in dates.Select(d => ConvertCustomDate(d)))
{
    Console.WriteLine(obj);
}

Notice that it handles 30 as 2030 now instead of 1930...

城歌 2024-08-18 06:12:30

您正在寻找 Calendar.TwoDigitYearMax 属性。

Jon Skeet 发布了一些您可能会发现有用的内容。

You're looking for the Calendar.TwoDigitYearMax Property.

Jon Skeet has posted something on this you will likely find useful.

撕心裂肺的伤痛 2024-08-18 06:12:30

我有一个类似的问题,我用正则表达式解决了它。在你的情况下,它看起来像这样:

private static readonly Regex DateRegex = new Regex(
@"^[0-9][0-9] (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9][0-9]$",
RegexOptions.Compiled | RegexOptions.ExplicitCapture);

private static string Beautify(string date)
{
    var match = DateRegex.Match(date);
    if (match.Success)
    {
        // Maybe further checks for correct day
        return date.Insert("dd-MMM-".Length, "20");
    }

    return date;
}

I had a similar problem and I solved it with a Regex. In your case it would look like that:

private static readonly Regex DateRegex = new Regex(
@"^[0-9][0-9] (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9][0-9]$",
RegexOptions.Compiled | RegexOptions.ExplicitCapture);

private static string Beautify(string date)
{
    var match = DateRegex.Match(date);
    if (match.Success)
    {
        // Maybe further checks for correct day
        return date.Insert("dd-MMM-".Length, "20");
    }

    return date;
}
神爱温柔 2024-08-18 06:12:30

恭喜,您遇到了 Y2K bug。

此行为的文档以 自定义日期和时间格式字符串,其中包括 yy 格式说明符的说明。具体来说,我们有这样的摘录:

在解析操作中,使用“yy”自定义格式说明符解析的两位数年份将根据格式提供程序当前日历的 Calendar.TwoDigitYearMax 属性进行解释。

按照Calendar.TwoDigitYearMax 文档,我们发现:

此属性允许将 2 位数年份正确转换为 4 位数年份。例如,如果此属性设置为 2029,则 100 年范围为 1930 到 2029。因此,2 位值 30 将解释为 1930,而 2 位值 29 将解释为 2029。< /p>

此属性的初始值源自控制面板的区域和语言选项部分中的设置。

如果您只有两位数字表示年份,您将需要猜测当前和上一个世纪或当前和下一个世纪之间的临界点。微软做出了他们的猜测,但也选择使其可配置,不同的系统可能有不同的配置方式。这意味着依赖两位数的年份值是危险的,正如我们在 1999 年之前就知道的那样。自 1999 年以来,没有人再使用两位数来表示年份。

顺便说一句,自从第一次决定以来已经有一段时间了;微软可能已经到了更新默认猜测的时候了(也许是 2079 年,或者完全是一种新的方法,也许基于与当前年份的偏移量)。不幸的是,从统计上来说,有些程序依赖于默认值不改变,因此微软很难更新它。这会导致他们所谓的“重大变化”,而且他们非常善于避免对人们这样做......尽管有 一些关于更改 .Net 8 的讨论。

因此,这种情况可能会在不久的将来开始更频繁地出现,并且在这里找到了我的方法,因为它确实出现在在另一个地方,我觉得值得为这个较旧的问题添加更新的答案。除了确认情况尚未改变之外,这个答案并没有什么真正的新内容。也许 Windows 11 版本会有新的默认设置?

Congratulations, you have a Y2K bug.

The documentation for this behavior starts with the Custom Date and Time Format strings, which includes a description of the yy format specifier. Specifically, we have this excerpt:

In a parsing operation, a two-digit year that is parsed using the "yy" custom format specifier is interpreted based on the Calendar.TwoDigitYearMax property of the format provider's current calendar.

Follow that to the Calendar.TwoDigitYearMax documentation and we find this:

This property allows a 2-digit year to be properly translated to a 4-digit year. For example, if this property is set to 2029, the 100-year range is from 1930 to 2029. Therefore, a 2-digit value of 30 is interpreted as 1930, while a 2-digit value of 29 is interpreted as 2029.

The initial value of this property is derived from the settings in the regional and language options portion of Control Panel.

If you only have two digits for the year you're gonna need to guess at the tipping point between the current and previous or current and next centuries. Microsoft made their guess, but also chose to make it configurable, where different systems may have it configured different ways. This implies it's dangerous to rely on two-digit year values, as we've known since before 1999. Since 1999, no one sane uses two digits for the year anymore.

As a side note, it's been some time since this was first decided; it's probably past time for Microsoft to update that default guess (maybe 2079, or a new approach entirely, perhaps based on an offset from the current year). Unfortunately, it's a statistical certainty there are programs out there which rely on the default not changing, such that it's difficult for Microsoft to update this. It would cause what they call a "breaking change", and they are pretty good about avoiding doing that to people... though there is some discussion on changing this for .Net 8.

This situation is therefore likely to start coming up more often in the near future, and having found my way here because it indeed had come up in another place I felt it worthwhile to add a more-recent answer to this older question. There's nothing really new in this answer, except to confirm the situation hasn't (yet) changed. Maybe a Windows 11 release will have a new default?

厌倦 2024-08-18 06:12:30
result = year.ToString().Length == 1 
      || year.ToString().Length == 2 ? "1" 
       : (Convert.ToInt32(year.ToString()
          .Substring(0, (year.ToString().Length - 2))) + 1).ToString();
result = year.ToString().Length == 1 
      || year.ToString().Length == 2 ? "1" 
       : (Convert.ToInt32(year.ToString()
          .Substring(0, (year.ToString().Length - 2))) + 1).ToString();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文