以多种格式解析日期时间

时间:2013-07-25 13:28:15

标签: c# datetime

我创建了一个API端点。调用者可以使用传递相关参数的POST方法调用API。在参数中,有一个参数为datetime格式。

问题是,在调用此API时,调用者可以以3种不同的格式传递datetime

  1. long int - 例如1374755180
  2. 美国格式 - 例如“2013年7月25日下午6:37:31”(作为string
  3. 时间戳格式 - 例如“2013-07-25 14:26:00”(作为string
  4. 我必须解析datetime值并将其转换为时间戳格式的DateTimestring

    我尝试过使用DateTime.TryParse()DateTime.Parse()Convert.ToDateTime()Convert.ToDouble(),但没有一个能为我确定。

    所需的输出必须为en-GB格式。

    编辑:

    我原本想要if-else if-else块与TryParse一起使用3次,只有一个else表示无法解析字符串。这是最好的解决方案吗?或者有更好的解决方案吗?

    请帮忙!

7 个答案:

答案 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.ParseExactMSDN 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);

来自this question

答案 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();
    }