Время и время анализа в нескольких форматах
Я создал конечную точку 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
, чтобы сказать, что строка не может быть проанализирована. Это лучшее решение? Или есть решения лучше этого?
Пожалуйста, помогите!
Ответы
Ответ 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."