31

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

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

  1. long int- 例如 1374755180
  2. 美国格式 - 例如“7/25/2013 6:37:31 PM”(as string
  3. 时间戳格式 - 例如“2013-07-25 14:26:00”(as string

我必须解析该datetime值并将其转换为DateTime时间戳string格式。

我曾尝试使用DateTime.TryParse(), DateTime.Parse()Convert.ToDateTime()Convert.ToDouble()没有一个对我来说确实有效。

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

编辑:

我曾想过有一个if-else if-else块可以使用TryParse3 次,其中一个else表示无法解析字符串。这是最好的解决方案吗?还是有比这更好的解决方案?

请帮忙!

4

7 回答 7

32

您应该考虑需要一个时区。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...");
}

编辑 正如马特约翰逊指出的那样, 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...");
}

我从另一个问题中借来的时代转换。 (一种扩展方法)

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);
    }
}
于 2013-07-25T13:51:03.113 回答
27

您正在寻找DateTime.ParseExactMSDN 文章

你会在这样的情况下使用它:

string[] formats= { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" }
var dateTime = DateTime.ParseExact("07/25/2013 6:37:31 PM", formats, new CultureInfo("en-GB"), DateTimeStyles.None);

这允许您根据需要添加任意DateTime数量的格式,array并且该方法将在没有if...else语句的情况下进行转换。

如果您的整数是自Unix 纪元以来的秒数,则将秒数添加到纪元 (01/01/1970) 的 DateTime 中(.Net 对此没有开箱即用的方法,但逻辑是自'时代'):

new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);

这个问题

于 2013-07-25T13:49:56.857 回答
2

解决这个问题的一种方法是设置一个工厂方法来“理解”不同的格式,并相应地解析它们。

你可以创建一个--s 链if来处理这个问题thenelse但你也可以做一个“表驱动”的实现:你需要的是一个接受字符串的委托数组,并告诉你两件事:

  • 此委托是否可以解析传入的字符串,以及
  • 如果是,那么该解析的结果是什么,表示为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;
}
于 2013-07-25T13:47:40.670 回答
2

我在一个项目中遇到了同样的问题,我的代码将在具有各种文化格式的不同环境中运行。

谷歌向我展示了这个隐藏的宝石。无论文化格式如何,帮助函数对于正确地自动解析日期时间都是必不可少的

用法示例:

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."
于 2015-04-01T14:39:55.750 回答
1

如果可能的格式是固定的,那么您可以使用TryParseExact

一种可能的解决方案是使用TryParse,如果它无法获得正确的日期,则回退到已知格式并使用TryPraseExact

于 2013-07-25T13:33:50.403 回答
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不适用于时间戳格式。它适用于美国格式。这就是我必须自己写的原因。

于 2013-07-25T14:28:51.873 回答
0

如果您使用TryParseExact,只有 GOD 和 Microsoft 开发人员知道它会在放弃之前尝试解析多少种可能的日期时间格式。也许更好的解决方案是使用快速正则表达式,然后使用适当的解析器。我试图让正则表达式像 possibke 一样简单,你可能需要稍微调整一下

    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();
    }
于 2013-07-25T14:33:02.777 回答