Можно ли в C # проверить, содержит ли данная строка формата даты только формат даты или время? - PullRequest
3 голосов
/ 25 сентября 2019

Например.У меня есть несколько строк формата даты и времени ..

"date1": "dd/MM/yyyy",
"date2": "yyyy MM yyyy",
"date3": "h:mmtt",
"date4": "h:mmtt"

Мне нужно проверить, является ли каждая из них форматом времени или даты.Я знаю, что могу выполнить некоторые операции с проверкой строк, если они содержат «гггг» и т. Д., Но это кажется неправильным и может привести к ошибке.Есть ли способ проверить, приводит ли данный формат DateTime только к отображаемому времени или только к дате?

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

Большое спасибо

Стюарт

Ответы [ 3 ]

4 голосов
/ 25 сентября 2019

Я хотел бы пойти с чем-то вроде:

[Flags]
public enum DateFormatStringKind
{
    HasNone = 0,
    HasDate = 1 << 0,
    HasTime = 1 << 1,
    HasBoth = HasDate | HasTime
}

public static DateFormatStringKind DescribeFormatString(string s, IFormatProvider provider)
{
    DateTime d = new DateTime(2, 2, 2, 1, 1, 1, 1); // DateTime will all non-default values
    DateTime d2 = DateTime.ParseExact(d.ToString(s, provider), s, provider, System.Globalization.DateTimeStyles.NoCurrentDateDefault);

    DateFormatStringKind result = DateFormatStringKind.HasNone;

    if (d2.Date.Ticks != 0)
        result |= DateFormatStringKind.HasDate;

    if (d2.TimeOfDay != TimeSpan.Zero)
        result |= DateFormatStringKind.HasTime;

    return result;
}
var culture = System.Globalization.CultureInfo.InvariantCulture;

Console.WriteLine(DescribeFormatString("dd/MM/yyyy", culture));
Console.WriteLine(DescribeFormatString("yyyy MM yyyy", culture));
Console.WriteLine(DescribeFormatString("h:mmtt", culture));
Console.WriteLine(DescribeFormatString("dd h:mmtt", culture));
Console.WriteLine(DescribeFormatString("'literal'", culture));
HasDate
HasDate
HasTime
HasBoth
HasNone

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

Если в шаблоне не было компонента даты, часть «дата» будет иметь значение 0001-01-01, что является нулевой датой (нулевые отметки източка 0).Флаг NoCurrentDateDefault гарантирует, что текущая дата не используется вместо этого.

Если в шаблоне не было компонента времени, время будет сброшено до полуночи (TimeSpan.Zero с полуночи).

Если в шаблоне даты был хотя бы один компонент (год, месяц или день), соответствующее поле станет 2, что больше значения по умолчанию 1 для полей даты, поэтому оно будет обнаружено независимокакого компонента это было.

Если в шаблоне времени был хотя бы один компонент (часы, минуты, секунды, миллисекунды), он станет 1, что больше значения по умолчанию 0 дляполя времени, поэтому он снова будет обнаружен независимо от того, каким компонентом он был.

0 голосов
/ 25 сентября 2019

Есть 864 000 000 000 ticks in a day.Вы можете проверить свойство DateTime.Ticks, чтобы увидеть, делится ли оно на это число.Если Ticks% ticks in a day равно 0, то временная часть отсутствует.Аналогично, если Ticks / ticks in a day равно 0, дневная часть отсутствует.Используйте Math.DivRem для одновременного выполнения операции деления и модуля.

Вот вспомогательный класс.

    public class DateInfo
    {
        private const long ticksPerDay = 864000000000;
        public bool HasDate { get; private set; }
        public bool HasTime { get; private set; }
        public DateInfo(DateTime date)
        {
            long timeTicks = 0;
            var dayticks = Math.DivRem(date.Ticks, ticksPerDay, out timeTicks);
            HasDate = dayticks > 0;
            HasTime = timeTicks > 0;
        }
        public override string ToString()
        {
            return $"{{{nameof(HasDate)}:{HasDate}, {nameof(HasTime)}:{HasTime}}}";
        }
        private static readonly DateTime testDate = DateTime.Parse("2/2/2 1:11");
        public static DateInfo GetDateInfo(string format)
        {
            var formatted = testDate.ToString(format);
            var dt = DateTime.ParseExact(formatted, format, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
            return new DateInfo(dt);
        }
    }

Тесты:

        var MinDate = DateTime.MinValue;
        var OneHour = MinDate.AddHours(1);
        var OneDay = MinDate.AddDays(1);

        var tests = new Dictionary<string, DateTime>
        {
            { nameof(MinDate), DateTime.MinValue },
            { nameof(OneDay), OneDay },
            { nameof(OneHour), OneHour },
            { nameof(DateTime.Now), DateTime.Now },
            { nameof(DateTime.Today), DateTime.Today },
        };

        var infos = tests.Select(x =>
        {
            var dateInfo = new DateInfo(x.Value);
            return new { x.Key, dateInfo.HasDate, dateInfo.HasTime };
        });

        tests.ToList().ForEach(test =>
        {
            var dateInfo = new DateInfo(test.Value);
            System.Diagnostics.Debug.WriteLine($"{test.Key}: {dateInfo}");
        });
        var formatTests = new Dictionary<string, string>
        {
            { "date1", "dd/MM/yyyy" },
            { "date2", "yyyy MM dd" },
            { "date3", "h:mmtt" },
            { "date4", "hh:mmtt" }
        };
        formatTests.ToList().ForEach(test =>
        {
            var dateInfo = DateInfo.GetDateInfo(test.Value);
            System.Diagnostics.Debug.WriteLine($"{test.Key}: {dateInfo}");
        });

Результат:

MinDate: {HasDate:False, HasTime:False}
OneDay: {HasDate:True, HasTime:False}
OneHour: {HasDate:False, HasTime:True}
Now: {HasDate:True, HasTime:True}
Today: {HasDate:True, HasTime:False}
date1: {HasDate:True, HasTime:False}
date2: {HasDate:True, HasTime:False}
date3: {HasDate:False, HasTime:True}
date4: {HasDate:False, HasTime:True}
0 голосов
/ 25 сентября 2019

Для этого нет встроенного, который я знаю.

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

Первый - это анализпроизвольная дата-время теста.Это было отражено в ответе GSerg, но вкратце вы создаете фиктивную дату, а затем анализируете ее в строку и обратно, используя строку формата.Очевидно, что у вас должно быть время, отличное от 00:00, иначе вы все равно не сможете определить;и она также должна иметь дату, отличную от «сегодня» или «1 января 0001 года» (см. Документация ).

Второй вариант - проверка по полному набору даты и времени.строковые переменные формата (см. Документация ) - так, что-то вроде этого (хотя это может измениться в будущих реализациях .NET Framework):

Элементы, связанные с датой, следующие:

"d" "dd" "ddd" "dddd" "g" "gg" "M" "MM" "MMM" "MMMM" "y" "yy" "yyy" "yyyy"" ггггг "" / "

Элементы, относящиеся ко времени:

" f "" ff "" fff "" ffff "" fffff ""ffffff "" fffffff "" F "" FF "" FFF "" FFFF "" FFFFF "" FFFFFF "" FFFFFFF "" h "" hh "" H "" HH "" s "" ss "" t "" tt ""m" "mm" ":"

Следующее является неоднозначным, может быть и так - поэтому мы проигнорируем это:

"K" "z" "zz "" zzz "

это дает нам следующий псевдокод:

If date1 contains any of (d,g,M,y,/) then date = true
If date1 contains any of (f,F,h,H,s,t,m,:) then time = true
If date && time then date-time

Обратите внимание, что это не учитывает возможности ESзаглавные (\) символы или строковые литералы ('...'), содержащие один из вышеуказанных символов.Чтобы решить эту проблему, вы можете сначала удалить любой символ, который следует после обратной косой черты или между одинарными кавычками, из строки формата - но вы также можете использовать регулярное выражение в этой точке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...