65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 日期时间解析器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (53投票s)

2009年2月11日

公共领域

4分钟阅读

viewsIcon

259009

downloadIcon

2519

从字符串解析日期和(或)时间。

引言

我曾需要检测和识别互联网消息中包含的日期和/或时间。这些消息由不同的用户发送,因此无法遵循特定的格式。它们通常由一两句话组成,无法预测日期和/或时间在其中的位置。因此,.NET 内置的 DateTime.Parse() 方法无法提供帮助,因为该方法只能解析完全由日期/时间表示组成的 string,它无法在文本中查找日期/时间。此外,DateTime.Parse() 无法识别一些仍然普遍存在的日期表示。

我需要一个 C# 函数,类似于 Perl 的通用 str2time() 或 PHP 的 strtotime()。经过一番谷歌搜索,我惊讶地发现在 C# 中找不到这样的代码。因此,我编写了此处呈现的日期/时间解析类。

描述

DateTimeRoutines 类公开了几个日期/时间解析方法。基本思想是在 string 中查找日期和/或时间的第一个实例,并将其转换为 DateTime

方法 描述
TryParseDateTime() 尝试在传入的 string 中查找日期和时间。如果未找到日期或时间,则返回 false
TryParseDate() 尝试在传入的 string 中查找日期。它始终返回时间 0:0:0。如果未找到日期的年份,则默认接受当前年份;此规则可以通过指定 DefaultDate 来更改。如果未找到日期,则返回 false
TryParseTime() 尝试在传入的 string 中查找时间。如果已在 string 中找到日期并将其作为参数传递,则它会在该日期附近查找时间。它始终返回日期 1/1/1。如果未找到时间,则返回 false
TryParseDateOrTime() 尝试在传入的 string 中查找日期和/或时间。如果仅找到时间,则默认情况下,日期设置为当天的日期;此规则可以通过指定 DefaultDate 来更改。如果未找到日期或时间,则返回 false

这些方法接受 DateTimeFormat 参数,该参数指定在歧义情况下首选的识别格式。

这些方法返回一个 ParsedDateTime 对象。该对象描述了是否在 string 中找到日期(或时间),以及(如果找到)其位置,并且还包含一个 DateTime 结构作为解析结果。

此外,这些方法还有一些变体,它们直接返回 DateTime 而不是 ParsedDateTime。不过,更推荐使用原始方法,因为它们的输出允许了解日期(或时间)是否真的被找到,还是由默认值设置的。

请注意,在 string 包含多个时间的情况下,TryParseDateTime()TryParseTime() 可能会返回不同的时间。TryParseDateTime() 会查找日期附近的时间,而 TryParseTime() 返回找到的第一个时间。

本地时间和绝对时间

ParsedDateTime.DateTime 始终被视为本地时间,即它直接反映了所解析的 string。如果时间字符串中包含表示时间是绝对时间的 UTC 偏移量或时区缩写,则 ParsedDateTime.IsUtcOffsetFoundtrue,并且 ParsedDateTime.UtcDateTime 为 UTC 日期和时间。如果 ParsedDateTime.IsUtcOffsetFoundfalse,则 ParsedDateTime.UtcDateTime 应被忽略,因为它未定义。

请注意,TryParseDate() 不会检测时区。

用法

DateTimeRoutines 可以识别的日期格式可以在下面的测试字符串中看到(完整的解析格式列表可以在随代码提供的 Test 项目中找到)

@"Member since:      10-Feb-2008"
@"Last Update: 18:16 11 Feb '08 "
@"date    Tue, Feb 10, 2008 at 11:06 AM"
@"see at 12/31/2007 14:16:32"
@"sack finish 14:16:32 November 15 2008, 1-144 app"
@"Genesis Message - Wed 04 Feb 08 - 19:40"
@"The day 07/31/07 14:16:32 is "
@"Shipping is on us until December 24, 2008 within the U.S." 
@" 2008 within the U.S. at 14:16:32"
@"5th November, 1994, 8:15:30 pm"
@"7 boxes January 31 , 14:16:32."
@"the blue sky of Sept  30th  2008 14:16:32"
@" e.g. 1997-07-16T19:20:30+01:00"
@"Apr 1st, 2008 14:16:32 tufa 6767"
@"wait for 07/31/07 14:16:32"
@"later 12.31.08 and before 1.01.09"
@"Expires: Sept  30th  2008 14:16:32"
@"Offer expires Apr 1st, 2007, 14:16:32"
@"Expires  14:16:32 January 31."
@"Expires  14:16:32 January 31-st."
@"Expires 23rd January 2010."
@"Expires January 22nd, 2010."
@"Expires DEC 22, 2010."

如果您只需要获取日期,可以使用以下代码示例:

string str = @"The last round was June 10, 2005; this time the unbroken record was held.";
DateTimeRoutines.ParsedDateTime pdt;
if (DateTimeRoutines.TryParseDate(str, DateTimeRoutines.DateTimeFormat.USA_DATE, out pdt))
    Console.WriteLine("Date was found: " + pdt.DateTime.ToString());

如果您想获取日期,并在可能的情况下获取时间,可以使用以下代码示例:

string str = @"The last round was June 10, 2005; this time the unbroken record was held.";
DateTimeRoutines.ParsedDateTime pdt;
if (DateTimeRoutines.TryParse(str, DateTimeRoutines.DateTimeFormat.USA_DATE, out pdt)
    && pdt.IsDateFound
    )
    Console.WriteLine("Date was found: " + pdt.DateTime.ToString());

如果您想获取完全指定的日期和时间,可以使用以下代码示例:

string str = @"The last round was June 10, 2005 10:30AM; this time the unbroken record was held.";
DateTimeRoutines.ParsedDateTime pdt;
if(str.TryParseDateTime(DateTimeRoutines.DateTimeFormat.USA_DATE, out pdt))
    Console.WriteLine("Date&time was found: " + pdt.DateTime.ToString());

如果您想获取 UTC 日期和时间,可以使用以下代码示例:

string str = @"Your program recognizes string : 21 Jun 2010 04:20:19 -0430 blah blah.";
DateTimeRoutines.ParsedDateTime pdt;
if(str.TryParseDateTime(DateTimeRoutines.DateTimeFormat.USA_DATE, out pdt) && pdt.IsUtcOffsetFound) 
Console.WriteLine("UTC date&time was found: " + pdt.UtcDateTime.ToString());

.NET 版本一致性

DateTimeRoutines 被构建为一个 .NET 4 DLL,它将解析方法作为 string 类的扩展公开。该 DLL 也可以被 .NET 2 代码调用。但是,如果您想将 DateTimeRoutines 的源代码嵌入到您的 .NET 2 项目中,则需要从方法参数中删除 this 关键字。

结论

这段代码满足了我的需求。我不想实现过于宽泛的识别能力,例如 Perl 的 str2time() 所提供的能力,因为更宽泛的识别能力会导致解析器在尝试检测 string 的任何部分中的日期/时间时产生更高的错误率。

尽管如此,DateTimeRoutines 能够识别通信中常用的格式。如果您发现任何未被识别的普遍日期/时间格式,请告知我,我将更新代码。

代码

在附加的代码中,您可以找到包含以下内容的 DateTimeRoutines 项目:

  • 一个被编译为 DLL 的 DateTimeRoutines
  • Test 项目

代码以公共域代码的形式获得许可。

最新版本可以在 SourceForge 上找到。

祝您开心!

历史

  • 2009 年 2 月 11 日
    • 初次发布
  • 2009 年 2 月 14 日
    • 添加了 TryParseDateTime()
  • 2009 年 12 月 18 日
    • 更新了 TryParseDate()
  • 2010 年 3 月 3 日
    • 更新了 TryParseDate()
  • 2010 年 3 月 12 日
    • 移除了 locks
  • 2010 年 3 月 13 日
    • 编译为 DLL
    • 方法编译为 string 类的扩展
    • TryParse() 重命名为 TryParseDateOrTime()
  • 2010 年 7 月 13 日
    • 更新了源代码
  • 2011 年 5 月 15 日
    • 修复了 12pm 和 12am 的问题
    • 升级到 C# 4.0
  • 2012 年 4 月 18 日
    • 添加了另一种日期格式
  • 2012 年 6 月 28 日
    • 添加了 UTC 识别;
© . All rights reserved.