我创建了一个API端点。调用者可以使用传递相关参数的POST
方法调用API。在参数中,有一个参数为datetime
格式。
问题是,在调用此API时,调用者可以以3种不同的格式传递datetime
:
long int
- 例如1374755180 string
)string
)我必须解析datetime
值并将其转换为时间戳格式的DateTime
或string
。
我尝试过使用DateTime.TryParse()
,DateTime.Parse()
,Convert.ToDateTime()
和Convert.ToDouble()
,但没有一个能为我确定。
所需的输出必须为en-GB
格式。
我原本想要if-else if-else
块与TryParse
一起使用3次,只有一个else
表示无法解析字符串。这是最好的解决方案吗?或者有更好的解决方案吗?
请帮忙!
答案 0 :(得分:26)
你应该考虑要求一个时区。 1不需要它,但#2和#3都需要它。
public DateTime ParseRequestDate()
{
// https://stackoverflow.com/questions/2883576/how-do-you-convert-epoch-time-in-c
CultureInfo enUS = new CultureInfo("en-US");
var dt = "1374755180";
//var dt = "7/25/2013 6:37:31 PM";
//var dt = "2013-07-25 14:26:00";
DateTime dateValue;
long dtLong;
// Scenario #1
if (long.TryParse(dt, out dtLong))
return dtLong.FromUnixTime();
// Scenario #2
if (DateTime.TryParseExact(dt, "MM/dd/yyyy hh:mm:ss tt", enUS, DateTimeStyles.None, out dateValue))
return dateValue;
// Scenario #3
if (DateTime.TryParseExact(dt, "yyyy-MM-dd hh:mm:ss", enUS, DateTimeStyles.None, out dateValue))
return dateValue;
throw new SomeException("Don't know how to parse...");
}
修改强> 正如Matt Johnson指出的那样,DateTime.TryParseExact接受一个格式字符串数组。 2& 3可以浓缩。
public DateTime ParseRequestDate()
{
// https://stackoverflow.com/questions/2883576/how-do-you-convert-epoch-time-in-c
CultureInfo enUS = new CultureInfo("en-US");
var dt = "1374755180";
//var dt = "7/25/2013 6:37:31 PM";
//var dt = "2013-07-25 14:26:00";
DateTime dateValue;
long dtLong;
// Scenario #1
if (long.TryParse(dt, out dtLong))
return dtLong.FromUnixTime();
// Scenario #2 & #3
var formatStrings = new string[] { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" };
if (DateTime.TryParseExact(dt, formatStrings, enUS, DateTimeStyles.None, out dateValue))
return dateValue;
throw new SomeException("Don't know how to parse...");
}
The epoch conversion I borrowed from another question. (扩展方法)
public static class MyExtensions
{
public static DateTime FromUnixTime(this long unixTime)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(unixTime);
}
}
答案 1 :(得分:19)
您正在寻找DateTime.ParseExact
(MSDN Article)
您将在以下情况中使用:
string[] formats= { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" }
var dateTime = DateTime.ParseExact("7/25/2013 6:37:31 PM", formats, new CultureInfo("en-GB"), DateTimeStyles.None);
这允许您根据需要向DateTime
添加尽可能多的array
格式,并且该方法将在没有if
... else
语句的情况下进行转换。
如果你的整数是以Unix Epoch为单位的秒数,你可以在纪元的日期时间(1970年1月1日)中添加秒数(.Net没有开箱即用的方法,但逻辑是'Epoch'以来的秒数:
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);
答案 2 :(得分:2)
解决此问题的一种方法是设置一种“理解”不同格式的工厂方法,并相应地解析它们。
您可以创建一个if
- then
- else
链来处理这个问题,但您也可以进行“表驱动”实施:您需要的是一个带字符串的委托数组,并告诉你两件事:
DateTime
以下是一个示例实现:
private static readonly DateParsers = new Func<string,Tuple<DateTime,bool>>[] {
(s) => {
long res;
if (long.TryParse(s, out res)) {
// The format was correct - make a DateTime,
// and return true to indicate a successful parse
return Tuple.Create(new DateTime(res), true);
} else {
// It does not matter what you put in the Item1
// when Item2 of the tuple is set to false
return Tuple.Create(DateTime.MinValue, false);
}
}
...
// Add similar delegates for other formats here
};
现在您的工厂方法可以按如下方式实施:
private static bool TryParseMultiformat(string s, out DateTime res) {
// Check all parsers in turn, looking for one returning success
foreach (var p in DateParsers) {
var tmp = p(s);
if (tmp.Item2) {
res = tmp.Item1;
return true;
}
}
res = DateTime.MinValue;
return false;
}
答案 3 :(得分:1)
如果修复了可能的格式,则可以使用TryParseExact
可能的解决方案是使用TryParse,如果无法获得正确的日期,则回退到已知格式并使用TryPraseExact
答案 4 :(得分:1)
我在一个项目中面临同样的问题,我的代码将运行在具有各种文化格式的不同环境中。
Google showed me this hidden gem。无论文化格式如何,帮助函数对于自动解析日期时间都是必不可少的
用法示例:
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());
根据作者的说法,该代码能够解析各种情况:
@"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."
答案 5 :(得分:0)
感谢您的回答。我尝试了几个答案中提出的选项,并找到了一个非常简单的方法,对我有用。
public static bool ParseDate(string dateString, out DateTime dateValue)
{
long dtLong = 0L;
bool result = false;
if (long.TryParse(dateString, out dtLong))
{
// I copied the epoch code here for simplicity
dateValue = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(dtLong);
result = true;
}
// Working for US and Timestamp formats
else if (DateTime.TryParse(dateString, out dateValue))
result = true;
return result;
}
早些时候,我试图将TryParse
用于所有3种无法正常工作的格式。
不知何故,TryParseExact
不适用于时间戳格式。它适用于美国格式。这就是我必须自己编写的原因。
答案 6 :(得分:0)
如果您使用TryParseExact
,则只有G-O-D和Microsoft开发人员知道在放弃之前它将尝试解析多少可能的日期时间格式。也许更好的解决方案是使用快速正则表达式然后使用适当的解析器。我试图使正则表达式尽可能简单,你可能需要稍微调整一下
private static readonly Regex R1
= new Regex(@"^\d+$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex R2
= new Regex(@"M$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex R3
= new Regex(@"^\d{4}-", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static void Main(string[] args)
{
string[] stringDates = new[]
{
"1374755180",
"2013-07-25 14:26:00",
"7/25/2013 6:37:31 PM"
};
foreach (var s in stringDates)
{
DateTime date = default(DateTime);
if (R1.IsMatch(s))
date = new DateTime(long.Parse(s));
else if (R2.IsMatch(s))
date = DateTime.Parse(s);
else if (R3.IsMatch(s))
date = DateTime.Parse(s);
if (date != default(DateTime))
Console.WriteLine("{0}", date);
}
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}