Как преобразовать каждый формат в секунды в С#

Мое приложение находится на С#, я пытаюсь создать метод, который будет преобразовывать переданное значение в секунды (время), формат, который будет приходить, не фиксирован, он предоставляется пользователем, поэтому он будет динамическим. Это может быть чч:мм или мм:сс или чч:мм:сс, это может быть любой допустимый формат времени. Значение, которое я получу из определенного файла, всегда будет частью времени. Форматы будут передаваться пользователем в зависимости от условия/требования. Это может быть любой допустимый формат времени.

Я пытался

  1. Используя Timespan.Parse, но он не принимает формат.
  2. Используя Timespan.ParseExact, но мой компилятор выдает ошибку, что временной интервал не содержит определения ParseExact.

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

как преобразовать секунды в формат мин:сек


person The JOKER    schedule 03.10.2016    source источник
comment
Как бы вы различили чч:мм и мм:сс? Это основная причина, по которой я думаю, что хороший общий пример будет невероятно сложно придумать.   -  person Callum Bradbury    schedule 03.10.2016
comment
@CallumBradbury да, его трудно идентифицировать без написания какой-либо дополнительной логики, вот что я хотел спросить, возможно ли это сделать без написания длинных строк кода.   -  person The JOKER    schedule 03.10.2016
comment
Представьте, что у вас есть 10:20 в качестве входных данных. Это 10 часов 20 минут или 10 минут 20 секунд? Неоднозначность делает вашу задачу (в общем случае) невыполнимой.   -  person Dmitry Bychenko    schedule 03.10.2016
comment
Никакая дополнительная логика не поможет вам читать мысли пользователя   -  person Ňɏssa Pøngjǣrdenlarp    schedule 03.10.2016
comment
Вы говорите, что пользователь предоставит значение И формат или только значение?   -  person DoctorMick    schedule 03.10.2016
comment
@DoctorMick да, значение и формат будут доступны. У нас также есть доступный формат, но в зависимости от требований пользователь может указать любой допустимый формат времени, возможно, когда-то чч: мм или мм: сс или чч: мм: сс   -  person The JOKER    schedule 03.10.2016
comment
это то, что я ищу, если это возможно var convert_Seconds=ConversionMethod(myValue, myformat); Есть ли какой-либо метод или какой-либо источник для этого   -  person The JOKER    schedule 03.10.2016


Ответы (3)


Что ж, неоднозначность делает задачу неразрешимой в общем случае, т.е. посмотри на

  10:20

это 10 часов и 20 минут, поэтому ответ будет 10 * 3600 + 20 * 60 == 37200 или просто 10 минут и 20 секунд, что равно 10 * 60 + 20 = 620 секундам. Однако, если вы знаете, как справиться с этой двусмысленностью, вы можете использовать TryParseExact:

  private static double InSeconds(string value, params string[] formats) {
    // if no formats provided, use default ones:
    // try these formats in this particular order:
    if ((null == formats) || (formats.Length <= 0))
      formats = new string[] { 
        @"h\:m\:s", 
        @"h\:m", 
        @"m\:s" }
    else
      // In case of unescaped formats like "h:m" (see comments below)
      // we automatically escape them
      for (int i = 0; i < formats.Length; ++i)
        if (formats[i] != null)
          formats[i] = Regex.Replace(formats[i], 
            @"(?<!\\)[^A-Za-z\\]", 
            match => @"\" + match.Value);

    TimeSpan result; 

    if (TimeSpan.TryParseExact(value, formats, CultureInfo.InvariantCulture, out result))
      return result.TotalSeconds;
    else
      return double.NaN;  
  }

Контрольная работа

  // 23 hours 53 minutes == 85980 seconds
  // Please, notice ambiguity: 23 minutes 53 seconds is also possible
  // however the routine states that h:m should be tried first  
  Console.Write(InSeconds("23:53"));
  // 47 minutes 53 seconds == 2873 seconds:
  // hour:minutes tried first, fails and minutes:seconds succeeds  
  Console.Write(InSeconds("47:53")); 
  // 99:99 == NaN
  // All three expected formats fail on such an input
  Console.Write(InSeconds("99:99")); 

  // Custom format - 45240
  Console.Write(InSeconds("12:34", @"hh\:mm")); 
  // Custom format - NAN: hh requires leading zeros (i.e. 01:34)
  Console.Write(InSeconds("1:34", @"hh\:mm")); 
  // Custom formats: 1 day 12 hours 34  minutes - 131640
  Console.Write(InSeconds("1.12:34", @"hh\:mm", @"d\.hh\:mm")); 

  // Custom format (unescaped, notice abscence of \) - 45240
  Console.Write(InSeconds("12:34", @"hh:mm")); 
person Dmitry Bychenko    schedule 03.10.2016
comment
я пытался использовать TryParse.Exact, но во время компиляции только я получаю сообщение об ошибке, поскольку System.Timespan не содержит определения для TryParse.Exact. - person The JOKER; 04.10.2016
comment
@Sam Sam: обратите внимание, TimeSpan.TryParseExact (между TryParse и Exact нет точки) - person Dmitry Bychenko; 04.10.2016
comment
Поддерживаются ли те форматы времени, которые упомянуты в ответе, или поддерживаются другие форматы, а также должны ли форматы передаваться таким же образом? поскольку я передал формат чч: мм, и он не вернул никакого результата. - person The JOKER; 04.10.2016
comment
да, я думаю, это проблема с фреймворком, мое решение находится в Framework 3.5, который не поддерживает метод TryParseExact. Я проверяю это на образце приложения с фреймворком 4.5. - person The JOKER; 04.10.2016
comment
@Sam Sam: у вас неправильная строка формата, возможно, она должна быть @"hh\:mm"i.e. hours:minutes с обязательными ведущими нулями; см. msdn.microsoft.com/en-us/ library/ee372287(v=vs.110).aspx для подробностей - person Dmitry Bychenko; 04.10.2016
comment
@Sam Sam: если у вас есть ограничение (в вашем случае .Net 3.5), укажите его в вопросе (обычно как тег в дополнение к C#, дате-времени и преобразованию данных) - person Dmitry Bychenko; 04.10.2016
comment
@Dmitrry Bychenko, могу ли я передать свои форматы, а не использовать массив строк или формат, я пытался передать, но он не конвертируется - person The JOKER; 04.10.2016
comment
это метод, который я создал приватный статический двойной InSeconds (значение строки, формат строки), и это то, что я делаю при обработке, если (TimeSpan.TryParseExact (значение, форматы, CultureInfo.InvariantCulture, результат вывода)) return result.TotalSeconds; и значение, которое я передаю в формате, равно @hh\:mm, но преобразование не происходит - person The JOKER; 04.10.2016
comment
@Sam Sam: конечно, вы можете передавать свои собственные форматы (см. Мое редактирование) - person Dmitry Bychenko; 04.10.2016
comment
@Sam Sam: @"hh\:mm" хочет начальные нули, например. "1.23" не удастся преобразовать, так как ожидается "01.23" (нулевое уведомление). Попробуйте использовать строку формата @"h\:m", которая более снисходительна. - person Dmitry Bychenko; 04.10.2016
comment
и последнее, я получаю форматы в определенном файле, и форматы, которые приходят, такие как чч: мм или мм: сс или чч: мм: сс, что я могу сделать для этого, он не конвертируется с такими форматами - person The JOKER; 04.10.2016
comment
@Sam Sam: затем измените указанные форматы: format = Regex.Replace(format, @"[^A-Za-z]", match => @"\" + match.Value); - person Dmitry Bychenko; 04.10.2016

Попробуй это:

    class TimeParser
    {
        Regex tripleReg = new Regex(@"([\d]{1,2}):([\d]{1,2}):([\d]{1,2})");
        Regex doubleReg = new Regex(@"([\d]{1,2}):([\d]{1,2})");

        public enum Format
        {
            HoursMinutesSeconds,
            HoursMinutes,
            MinutesSeconds
        }

        public TimeSpan Parse(string data)
        {
            if (tripleReg.IsMatch(data))
                return Parse(data, Format.HoursMinutesSeconds);
            else
            {
                var match = doubleReg.Match(data);

                var segment = match.Groups[1];
                var value = int.Parse(segment.Value);

                if (value < 60)
                    return Parse(data, Format.MinutesSeconds);
                else
                    return Parse(data, Format.HoursMinutes);
            }
        }

        public TimeSpan Parse(string data, Format format)
        {
            TimeSpan result;
            Match match;

            var hours = 0;
            var minutes = 0;
            var seconds = 0;

            switch (format)
            {
                case Format.HoursMinutesSeconds:
                    match = tripleReg.Match(data);
                    if (match.Success)
                    {
                        int.TryParse(match.Groups[1].Value, out hours);
                        int.TryParse(match.Groups[2].Value, out minutes);
                        int.TryParse(match.Groups[3].Value, out seconds);
                    }
                    break;
                case Format.HoursMinutes:
                    match = doubleReg.Match(data);
                    if (match.Success)
                    {
                        int.TryParse(match.Groups[1].Value, out hours);
                        int.TryParse(match.Groups[2].Value, out minutes);
                    }
                    break;
                case Format.MinutesSeconds:
                    match = doubleReg.Match(data);
                    if (match.Success)
                    {
                        int.TryParse(match.Groups[1].Value, out minutes);
                        int.TryParse(match.Groups[2].Value, out seconds);
                    }
                    break;
                default:
                    break;
            }

            result = new TimeSpan(hours, minutes, seconds);

            return result;
        }
    }

Тесты:

    static void Main(string[] args)
    {
        var parser = new TimeParser();

        Console.WriteLine(parser.Parse("60:34").TotalSeconds); //218040 seconds, hh:mm

        Console.WriteLine(parser.Parse("55:10").TotalSeconds); //3310 seconds, mm:ss

        Console.WriteLine(parser.Parse("3:33:34").TotalSeconds); //12814 seconds, hh:mm:ss

        Console.WriteLine(parser.Parse("12:34", TimeParser.Format.HoursMinutes).TotalSeconds); //45240 seconds

        Console.WriteLine(parser.Parse("55:10", TimeParser.Format.MinutesSeconds).TotalSeconds); //3310 seconds

        Console.WriteLine(parser.Parse("3:33:34", TimeParser.Format.HoursMinutesSeconds).TotalSeconds); //12814 seconds

        Console.ReadKey();
    }
person Alex Solari    schedule 04.10.2016

Я не знаю, является ли это лучшим возможным решением или я усложнил его, публикуя вопрос. Ниже приведено то, что я реализовал, и это удовлетворяет моему требованию.

После получения значения в двойном формате, например "01:30", я преобразую его в объект Datetime.

var DateObj= Convert.ToDateTime("MyValue");
DateObj.ToString("MyFormat");
var TempVariable=DateObj.TimeOfDay.TotalSeconds;

Если в этом решении есть какие-либо недостатки, прокомментируйте или улучшите мой ответ.

person The JOKER    schedule 04.10.2016