4

我需要允许接受 UTC 日期时间:http ://www.w3.org/TR/NOTE-datetime

如:

 - Year:
         YYYY (eg 1997)    Year and month:
         YYYY-MM (eg 1997-07)    Complete date:
         YYYY-MM-DD (eg 1997-07-16)    Complete date plus hours and minutes:
         YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)    Complete date plus hours, minutes and seconds:
         YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)    Complete date plus hours, minutes, seconds and a decimal fraction of
   a second
         YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) where:

        YYYY = four-digit year
        MM   = two-digit month (01=January, etc.)
        DD   = two-digit day of month (01 through 31)
        hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
        mm   = two digits of minute (00 through 59)
        ss   = two digits of second (00 through 59)
        s    = one or more digits representing a decimal fraction of a second
        TZD  = time zone designator (Z or +hh:mm or -hh:mm)

如何将字符串转换为具有特定格式的 DateTime?

我写了下面的代码:

 private const string Format = "YYYY-MM-DDThh:mm:ssZ";

        public DateTime? Parse(string modifiedSince)
        {
            // how to know whether it's a valid DateTime in UTC format?
        }

但它总是返回 null,这意味着它无法解析为 DateTime。

它应该成功验证低于 UTC 值,但它没有:

2013-05-10
2013-05-10T05:04:10
2013-05-10T05:04:10.40
013-05-10T05:04:10.4Z

(Z 通常是可选的)

如何使用 DateTime.Parse 或 .Parsexact 以便成功返回上述格式的日期?

所有其他日期格式都应该失败,例如 20130510

我可以写一个正则表达式吗?

4

4 回答 4

10

你错过了一些重要的东西。 UTC 不是一种格式

UTC 指的是“协调世界时”(是的,缩写是故意乱序的)。这是本初子午线的固定时钟,在所有实际用途中都相当于 GMT。它不会因“夏令时”或“夏令时”而改变,当我们谈论其他时区的偏移时,它就是我们放置零的地方。

您描述的格式称为ISO8601。从技术上讲,ISO8601 标准定义了几种格式,但最常用的一种也在RFC3339中定义,仅涵盖您列出的最后两种格式。换句话说,ISO8601 允许以不同的精度对时间进行多种表示,但 RFC3339 要求的值最多为second

现在,当谈到 .Net 时,您又错过了另外几个重要的概念。具体来说,您需要了解DateTime.KindDateTimeOffset

当您有一个以Zor+00:00结尾的字符串值时,您知道它表示 UTC 时间,并且可以存储在DateTime具有DateTime.Kind == DateTimeKind.Utc.

如果您有一些其他偏移量,例如+01:00or -04:00,那么您应该将它们存储在一个DateTimeOffset对象中。如果您尝试将其存储在 a 中DateTime,那么您必须选择是忽略偏移量,还是应用它并将时间存储为 UTC。

如果你最后什么都没有那么你就有歧义。您可以将其存储在DateTimewhereDatetime.Kind == DateTimeKind.Unspecified但您必须非常小心地处理它。它没有关于该值源自哪个时区或偏移量的任何信息——因此任何数学运算都可能不正确。例如,您永远不DateTime应该通过减去两个未指定(或本地)种类的值来获得持续时间。有关其他详细信息,请参阅此博客文章

最后一件事,了解.Net 没有表示没有时间的日期的内置类。为此,我们通常DateTime在午夜使用 a - 但您无法将其与实际在午夜获得时间的值区分开来。在其他更糟糕的情况下,解析后2013-05-102013-05-10T00:00:00- 它们是等价的。

这是一些帮助您入门的代码。

public DateTime? Parse(string s)
{
    // you may want to add a few more formats here
    var formats = new[] { "yyyy-MM-dd",
                          "yyyy-MM-ddThh:mm:ss",
                          "yyyy-MM-ddThh:mm:ssZ" };

    DateTime dt;
    if (DateTime.TryParseExact(s, formats,
                               CultureInfo.InvariantCulture, // ISO is invariant
                               DateTimeStyles.RoundtripKind, // this is important
                               out dt))
        return dt;

    return null;
}

DateTimeOffset.TryParseExact如果您打算沿着这条路线走,您还应该考虑一下。

于 2013-05-23T17:32:47.110 回答
2

TryParseExact,顾名思义,只会成功解析与指定格式精确匹配的字符串。从文档中:

字符串表示的格式必须与指定的格式完全匹配。

您给出的所有示例都与您指定的格式字符串不匹配。如果您希望接受某些格式(例如 UTC 标准定义的格式)并拒绝所有其他格式,请使用接受可能格式数组的 TryParseExact重载

如问题中所述,这种重载非常适合您拥有一小组可接受格式(例如 UTC 标准指定的格式)的情况。

于 2013-05-23T16:05:09.870 回答
1

实际上,您需要的只是由TryParseExact(string input, string[] formats, ....).

  • 您定义一个可接受格式的数组,然后将其传递给上面的 TryParseExact

string[] acceptableFormats =
{
"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"
};

if (DateTime.TryParseExact(dateString, acceptableFormats,  
new CultureInfo("en-US"),   
DateTimeStyles.None,   
out dateValue))  
{  
// Do something useful  
}

这是该构造函数的 MSDN 链接

于 2013-05-23T16:29:39.927 回答
0

尝试这个;

bool validDate = false;
DateTime dt = new DateTime();
try
{
    dt = Convert.ToDateTime(modifiedSince);
    validDate = true;
}
catch(FormatException) { string message = "Not a valid date..."; }

if (validDate)
{
    //Do whatever else you need to do with the validated date.
}

这是否包含所有已知的日期格式尚不清楚,但这是我使用的方法,希望它对您有用。

于 2013-05-23T20:46:41.747 回答