Подтвердить что ты не робот

Время и время анализа в нескольких форматах

Я создал конечную точку API. Вызывающий может вызвать API с помощью метода POST, передающего соответствующие параметры. В параметрах есть один параметр, который имеет формат datetime.

Проблема заключается в том, что при вызове этого API вызывающий может передавать datetime в 3 разных форматах:

  • long int - например. 1374755180
  • Формат США - например, "7/25/2013 6:37:31 PM" (как string)
  • Формат временной отметки - например. "2013-07-25 14:26:00" (как string)

Мне нужно проанализировать значение datetime и преобразовать его в формат datetime или string в формате Timestamp.

Я пробовал использовать DateTime.TryParse(), DateTime.Parse(), Convert.ToDateTime() и Convert.ToDouble(), но никто из них не работает для меня определенно.

Требуемый вывод должен быть в формате en-GB.

Изменить:

Я думал, что есть блок if-else if-else для использования с TryParse 3 раза с одним else, чтобы сказать, что строка не может быть проанализирована. Это лучшее решение? Или есть решения лучше этого?

Пожалуйста, помогите!

4b9b3361

Ответ 1

Вам следует подумать о необходимости использования часового пояса. 1 не нуждается в ней, но # 2 и # 3 делают.

public DateTime ParseRequestDate()
{
    // /questions/26366/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()
{
    // /questions/26366/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);
    }
}

Ответ 2

Вы ищете DateTime.ParseExact (Статья MSDN)

Что вы бы использовали в такой ситуации:

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, вы добавляете количество секунд в DateTime эпохи (01/01/1970 ) (.Net не имеет метода "из коробки" для этого, но логика занимает секунды с "Эпохи" ):

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

Из этот вопрос.

Ответ 3

Одним из способов решения этой проблемы будет создание метода factory, который "понимает" разные форматы и соответственно анализирует их.

Вы можете создать цепочку 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
};

Теперь ваш метод factory может быть реализован следующим образом:

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;
}

Ответ 4

Если возможные форматы фиксированы, вы можете использовать TryParseExact

Возможным решением является использование TryParse, если ему не удастся получить правильную дату, затем вернуться к известным форматам и использовать TryPraseExact

Ответ 5

Спасибо за ваши ответы. Я попробовал варианты, предложенные в нескольких ответах, и нашел очень простой подход, который сработал у меня.

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 для всех трех форматов, которые не работали.

Как-то, TryParseExact не работал для формата timestamp. Он работал в формате США. Вот почему я должен был написать свой собственный.

Ответ 6

Если вы используете 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();
    }

Ответ 7

У меня возникла такая же проблема в проекте, где мой код будет работать в разных средах с различными форматами культуры.

Google показал мне этот скрытый камень. Вспомогательная функция незаменима для автоматического определения даты и времени независимо от форматов культуры.

Примеры использования:

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."