我需要允许接受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
我可以写一个正则表达式吗?
答案 0 :(得分:8)
你遗漏了一些重要的东西。 UTC不是格式。
UTC指的是“协调世界时”(是的,缩写是故意不按顺序)。这是本初子午线的固定时钟,相当于GMT用于所有实际目的。它不会因“夏令时”或“夏令时”而改变,而且在谈论其他时区的偏移时我们将零置于此处。
您描述的格式称为ISO8601。从技术上讲,ISO8601标准定义了几种格式,但最常用的格式也在RFC3339中定义,并且仅涵盖您列出的最后两种格式。换句话说,ISO8601允许在不同的精度上进行多次时间表示,但RFC3339要求值高达 second 。
现在谈到.Net,你错过了另外两个重要的概念。具体而言,您需要了解 DateTime.Kind
和 DateTimeOffset
。
当您的字符串值包含最后的Z
或+00:00
时,您知道它代表UTC时间,并且可以存储在DateTime
中{ {1}}。
如果您有其他偏移量,例如DateTime.Kind == DateTimeKind.Utc
或+01:00
,那么您应该将它们存储在-04:00
对象中。如果您尝试将其存储在DateTimeOffset
中,则必须选择是否要忽略偏移量,还是应用它并将时间存储为UTC。
如果你最后没有任何,那么你就会有歧义。您可以将其存储在DateTime
DateTime
Datetime.Kind == DateTimeKind.Unspecified
中,但您必须非常小心处理它。它没有任何关于该值来自哪个时区或偏移的信息 - 因此任何数学运算都可能不正确。例如,你应该从不通过用未指定(或本地)种类减去两个DateTime
值来获得持续时间。有关其他详细信息,请参阅this blog post。
最后一点,明白.Net没有内置类来代表没有时间的日期。为此,我们通常在午夜使用DateTime
- 但您无法将其与实际给出午夜时间的值区分开来。更糟糕的是,在解析2013-05-10
和2013-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
。
答案 1 :(得分:2)
TryParseExact,顾名思义,仅成功解析与指定格式完全匹配的字符串。来自文档:
字符串表示的格式必须与指定的格式完全匹配。
您提供的示例中没有一个符合您指定的格式字符串。如果您希望接受一些 set 格式(例如UTC标准定义的格式)并拒绝所有其他格式,请使用接受an array of possible formats的TryParseExact重载。
对于您有一小组可接受格式(例如UTC标准指定的格式)的情况,该过载非常理想。如问题中所述。
答案 2 :(得分:1)
实际上你所需要的只是由TryParseExact(string input, string[] formats, ....)
的另一个“不那么有名”的构造函数来实现。
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
}
答案 3 :(得分: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.
}
这是否包含日期的所有已知格式尚不清楚,但这是我使用的方法,并希望它适合您。