在C#中没有年份的leap年解析总是失败

时间:2018-11-20 04:08:01

标签: c# datetime

我正在尝试以d/M的格式解析生日,而未指定任何年份。

大多数情况下,使用DateTime.TryParseExact(birthday, "d/M", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthdayDate)起作用,除非生日在birthday年日(又名29/2),并且解析永远不会成功,因为它默认为当前年份。自it defaults to year = 1(这不是年)以来,使用DatTimeStyles.NoCurrentDateDefault都不起作用。

我该如何进行解析,以使其不涉及破解(我不想手动解析或手动添加任意年份以将其解析为完整日期,它们都很难看并且可能很脆弱),并且还在所有可能的日期(包括leap日)上工作? Existing questions完全没有帮助,因为没有人会费心检查他们是否在leap日工作。我尝试了所有这些,但没有一个起作用。

2 个答案:

答案 0 :(得分:2)

这个问题缺少适当的细节,但是

如果您只想解析包含strong年日期的出生日期和月份,则只需在日期末尾添加a年。

我不确定您打算在这里做什么,但是您可以尝试一下

birthday = $"{birthday}/2016"; // leap year

DateTime.TryParseExact(birthday, "d/M/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthdayDate);

更新

  

我的问题是如何不让TryParseExact假定年份   通过以某种方式手动覆盖它来自动

这里是技术性的,如果您仅解析a年的月份和日期,则不必在字符串中指定the年

TryParseExact方法确实有很多检查和平衡方法,但是这里是重要的部分。

简而言之,它使用当前年份或年份1,无法告诉它专门选择a年

private static bool CheckDefaultDateTime(ref DateTimeResult result, ref Calendar cal, DateTimeStyles styles)
{
  if ((result.flags & ParseFlags.CaptureOffset) != (ParseFlags) 0 && (result.Month != -1 || result.Day != -1) && ((result.Year == -1 || (result.flags & ParseFlags.YearDefault) != (ParseFlags) 0) && (result.flags & ParseFlags.TimeZoneUsed) != (ParseFlags) 0))
  {
    result.SetFailure(ParseFailureKind.Format, "Format_MissingIncompleteDate", (object) null);
    return false;
  }
  if (result.Year == -1 || result.Month == -1 || result.Day == -1)
  {
    DateTime dateTimeNow = DateTimeParse.GetDateTimeNow(ref result, ref styles);
    if (result.Month == -1 && result.Day == -1)
    {
      if (result.Year == -1)
      {
        if ((styles & DateTimeStyles.NoCurrentDateDefault) != DateTimeStyles.None)
        {
          cal = GregorianCalendar.GetDefaultInstance();
          result.Year = result.Month = result.Day = 1;
        }
        else
        {
          result.Year = cal.GetYear(dateTimeNow);
          result.Month = cal.GetMonth(dateTimeNow);
          result.Day = cal.GetDayOfMonth(dateTimeNow);
        }
      }
      else
      {
        result.Month = 1;
        result.Day = 1;
      }
    }
    else
    {
      if (result.Year == -1)
        result.Year = cal.GetYear(dateTimeNow);
      if (result.Month == -1)
        result.Month = 1;
      if (result.Day == -1)
        result.Day = 1;
    }
  }
  if (result.Hour == -1)
    result.Hour = 0;
  if (result.Minute == -1)
    result.Minute = 0;
  if (result.Second == -1)
    result.Second = 0;
  if (result.era == -1)
    result.era = 0;
  return true;
}

答案 1 :(得分:2)

一天零一个月不算日期-因此,如果不假设年份,则不能将它们解析为DateTime值。 .NET Framework假定年份为当前年份或第一年-正是因为2/29仅在leap年才有效-这是一个非常合理的假设。

.Net框架没有提供存储日/月值的内置方式,但是Noda Time可以-看一下AnnualDate-它存储了一天零一个月但没有年份。

但是,它没有ParseTryParse方法-因此,您仍然需要手动操作输入字符串并按顺序添加年份(如2016年的leap年)使用DateTime的{​​{1}}方法。

更新

正如马特·约翰逊(Matt Johnson)在评论中所写,“野田时间”确实提供了一种使用AnnualDatePattern类将文本解析为TryParseExact的方法。
该文档有一个名为Patterns for AnnualDate values的页面,其中列出了受支持的模式。