2010-08-17 4 views
31

Say преобразовать несколько секунд в объект TimeSpan, как это:Формат TimeSpan больше чем 24 часа

Dim sec = 1254234568 
Dim t As TimeSpan = TimeSpan.FromSeconds(sec) 

Как отформатировать объект TimeSpan в формат, как следующее:

>105hr 56mn 47sec 

ли есть встроенная функция или мне нужно написать пользовательскую функцию?

ответ

47

Ну, простейшая вещь, чтобы сделать это, чтобы отформатировать это самостоятельно, например.

return string.Format("{0}hr {1}mn {2}sec", 
        (int) span.TotalHours, 
        span.Minutes, 
        span.Seconds); 

В VB:

Public Shared Function FormatTimeSpan(span As TimeSpan) As String 
    Return String.Format("{0}hr {1}mn {2}sec", _ 
         CInt(Math.Truncate(span.TotalHours)), _ 
         span.Minutes, _ 
         span.Seconds) 
End Function 

Я не знаю, является ли какой-либо из TimeSpan форматирования в .NET 4 будет сделать это проще.

+1

Возможно, вы захотите дать код VB, поскольку код в вопросе выглядит так :-) – Joey

+2

Я что-то упустил?Я нервничаю, когда мой ответ не согласен с Джоном Скитом :-) –

+3

'((int) span.TotalMinutes)% 60' можно заменить на' span.Minutes'. То же самое с секундами. –

3

string.Format("{0}hr {1}mn {2}sec", (int) t.TotalHours, t.Minutes, t.Seconds);

+1

Это только для TimeSpan <24 hr. И t, секунды должны быть t.Seconds –

+2

Вы должны изменить это на '{0: f0} ..., t.TotalHours, ...' – SLaks

+0

@Angkor: Хорошая точка. Tweaked, чтобы справиться с> 24 часа –

1

Вам может понадобиться для расчета часов. Диапазон в часах в TimeSpan.ToString равен только 0-23.

Худшее, что вам нужно, это сделать форматирование форматирования a la Jon Skeet.

0

Попробуйте эту функцию:

Public Shared Function GetTimeSpanString(ByVal ts As TimeSpan) As String 
     Dim output As New StringBuilder() 

     Dim needsComma As Boolean = False 

     If ts = Nothing Then 

      Return "00:00:00" 

     End If 

     If ts.TotalHours >= 1 Then 
      output.AppendFormat("{0} hr", Math.Truncate(ts.TotalHours)) 
      If ts.TotalHours > 1 Then 
       output.Append("s") 
      End If 
      needsComma = True 
     End If 

     If ts.Minutes > 0 Then 
      If needsComma Then 
       output.Append(", ") 
      End If 
      output.AppendFormat("{0} m", ts.Minutes) 
      'If ts.Minutes > 1 Then 
      ' output.Append("s") 
      'End If 
      needsComma = True 
     End If 

     Return output.ToString() 

End Function  

Convert A Timespan To Hours And Minutes

6

Microsoft не (в настоящее время) имеют простой формат строки ярлыка для этого. Самые простые варианты уже предоставлены.

string.Format("{0}hr {1:mm}mn {1:ss}sec", (int)t.TotalHours, t); 

Однако чрезмерно тщательный вариант реализовать свой собственный ICustomFormatter для TimeSpan. Я бы не рекомендовал его, если вы так часто используете его, что это сэкономит вам время в долгосрочной перспективе. Тем не менее, бывают случаи, когда вы пишете класс, где написано ваше собственное ICustomFormatter, поэтому я написал это в качестве примера.

/// <summary> 
/// Custom string formatter for TimeSpan that allows easy retrieval of Total segments. 
/// </summary> 
/// <example> 
/// TimeSpan myTimeSpan = new TimeSpan(27, 13, 5); 
/// string.Format("{0:th,###}h {0:mm}m {0:ss}s", myTimeSpan) -> "27h 13m 05s" 
/// string.Format("{0:TH}", myTimeSpan) -> "27.2180555555556" 
/// 
/// NOTE: myTimeSpan.ToString("TH") does not work. See Remarks. 
/// </example> 
/// <remarks> 
/// Due to a quirk of .NET Framework (up through version 4.5.1), 
/// <code>TimeSpan.ToString(format, new TimeSpanFormatter())</code> will not work; it will always call 
/// TimeSpanFormat.FormatCustomized() which takes a DateTimeFormatInfo rather than an 
/// IFormatProvider/ICustomFormatter. DateTimeFormatInfo, unfortunately, is a sealed class. 
/// </remarks> 
public class TimeSpanFormatter : IFormatProvider, ICustomFormatter 
{ 
    /// <summary> 
    /// Used to create a wrapper format string with the specified format. 
    /// </summary> 
    private const string DefaultFormat = "{{0:{0}}}"; 

    /// <remarks> 
    /// IFormatProvider.GetFormat implementation. 
    /// </remarks> 
    public object GetFormat(Type formatType) 
    { 
     // Determine whether custom formatting object is requested. 
     if (formatType == typeof(ICustomFormatter)) 
     { 
      return this; 
     } 

     return null; 
    } 

    /// <summary> 
    /// Determines whether the specified format is looking for a total, and formats it accordingly. 
    /// If not, returns the default format for the given <para>format</para> of a TimeSpan. 
    /// </summary> 
    /// <returns> 
    /// The formatted string for the given TimeSpan. 
    /// </returns> 
    /// <remarks> 
    /// ICustomFormatter.Format implementation. 
    /// </remarks> 
    public string Format(string format, object arg, IFormatProvider formatProvider) 
    { 
     // only apply our format if there is a format and if the argument is a TimeSpan 
     if (string.IsNullOrWhiteSpace(format) || 
      formatProvider != this || // this should always be true, but just in case... 
      !(arg is TimeSpan) || 
      arg == null) 
     { 
      // return the default for whatever our format and argument are 
      return GetDefault(format, arg); 
     } 

     TimeSpan span = (TimeSpan)arg; 

     string[] formatSegments = format.Split(new char[] { ',' }, 2); 
     string tsFormat = formatSegments[0]; 

     // Get inner formatting which will be applied to the int or double value of the requested total. 
     // Default number format is just to return the number plainly. 
     string numberFormat = "{0}"; 
     if (formatSegments.Length > 1) 
     { 
      numberFormat = string.Format(DefaultFormat, formatSegments[1]); 
     } 

     // We only handle two-character formats, and only when those characters' capitalization match 
     // (e.g. 'TH' and 'th', but not 'tH'). Feel free to change this to suit your needs. 
     if (tsFormat.Length != 2 || 
      char.IsUpper(tsFormat[0]) != char.IsUpper(tsFormat[1])) 
     { 
      return GetDefault(format, arg); 
     } 

     // get the specified time segment from the TimeSpan as a double 
     double valAsDouble; 
     switch (char.ToLower(tsFormat[1])) 
     { 
      case 'd': 
       valAsDouble = span.TotalDays; 
       break; 
      case 'h': 
       valAsDouble = span.TotalHours; 
       break; 
      case 'm': 
       valAsDouble = span.TotalMinutes; 
       break; 
      case 's': 
       valAsDouble = span.TotalSeconds; 
       break; 
      case 'f': 
       valAsDouble = span.TotalMilliseconds; 
       break; 
      default: 
       return GetDefault(format, arg); 
     } 

     // figure out if we want a double or an integer 
     switch (tsFormat[0]) 
     { 
      case 'T': 
       // format Total as double 
       return string.Format(numberFormat, valAsDouble); 

      case 't': 
       // format Total as int (rounded down) 
       return string.Format(numberFormat, (int)valAsDouble); 

      default: 
       return GetDefault(format, arg); 
     } 
    } 

    /// <summary> 
    /// Returns the formatted value when we don't know what to do with their specified format. 
    /// </summary> 
    private string GetDefault(string format, object arg) 
    { 
     return string.Format(string.Format(DefaultFormat, format), arg); 
    } 
} 

Обратите внимание, как в слове в коде, TimeSpan.ToString(format, myTimeSpanFormatter) не будет работать из-за причуда .NET Framework, так что вы всегда будете использовать string.Format (формат, myTimeSpanFormatter), чтобы использовать эту функцию класс. См. How to create and use a custom IFormatProvider for DateTime?.


EDIT: Если вы на самом деле, и я имею в виду действительно, хотят, чтобы это работало с TimeSpan.ToString(string, TimeSpanFormatter), вы можете добавить следующие строки в вышеприведенном TimeSpanFormatter класса:

/// <remarks> 
/// Update this as needed. 
/// </remarks> 
internal static string[] GetRecognizedFormats() 
{ 
    return new string[] { "td", "th", "tm", "ts", "tf", "TD", "TH", "TM", "TS", "TF" }; 
} 

И добавьте следующий класс в одно и то же пространство имен:

public static class TimeSpanFormatterExtensions 
{ 
    private static readonly string CustomFormatsRegex = string.Format(@"([^\\])?({0})(?:,{{([^(\\}})]+)}})?", string.Join("|", TimeSpanFormatter.GetRecognizedFormats())); 

    public static string ToString(this TimeSpan timeSpan, string format, ICustomFormatter formatter) 
    { 
     if (formatter == null) 
     { 
      throw new ArgumentNullException(); 
     } 

     TimeSpanFormatter tsFormatter = (TimeSpanFormatter)formatter; 

     format = Regex.Replace(format, CustomFormatsRegex, new MatchEvaluator(m => MatchReplacer(m, timeSpan, tsFormatter))); 
     return timeSpan.ToString(format); 
    } 

    private static string MatchReplacer(Match m, TimeSpan timeSpan, TimeSpanFormatter formatter) 
    { 
     // the matched non-'\' char before the stuff we actually care about 
     string firstChar = m.Groups[1].Success ? m.Groups[1].Value : string.Empty; 

     string input; 
     if (m.Groups[3].Success) 
     { 
      // has additional formatting 
      input = string.Format("{0},{1}", m.Groups[2].Value, m.Groups[3].Value); 
     } 
     else 
     { 
      input = m.Groups[2].Value; 
     } 

     string replacement = formatter.Format(input, timeSpan, formatter); 
     if (string.IsNullOrEmpty(replacement)) 
     { 
      return firstChar; 
     } 

     return string.Format("{0}\\{1}", firstChar, string.Join("\\", replacement.ToCharArray())); 
    } 
} 

После этого, вы можете использовать

ICustomFormatter formatter = new TimeSpanFormatter(); 
string myStr = myTimeSpan.ToString(@"TH,{000.00}h\:tm\m\:ss\s", formatter); 

где {000.00} однако вы хотите TotalHours Int или двойной быть отформатирован. Обратите внимание на прилагаемые фигурные скобки, которых не должно быть в строке .Format(). Также обратите внимание, formatterдолжен быть объявлен (или литой) как ICustomFormatter, а не TimeSpanFormatter.

Чрезмерное? Да. Потрясающие? Uhhh ....

+0

Красивая над инженерной. Я сделал свою кепку. – BanksySan

+1

Ваш короткий и сладкий ответ учитывает ведущие нули, красивые! Застрял с подобными «47: 33: 4» на некоторое время ... лучше, чем сам Скит! – Murphybro2

+2

Мне очень нравится это решение. К сожалению, он не будет использоваться в двухстороннем сценарии привязки, потому что не существует реализации 'TimeSpan.Parse', которая бы взяла экземпляр' ICustomFormatter'. – modiX

0

Возможно, вы захотите использовать тип Noda TimeDuration.

Например:

Duration d = Duration.FromSeconds(sec); 

Или

Duration d = Duration.FromTimeSpan(ts); 

Вы можете просто отформатировать его в виде строки, например:

string result = d.ToString("H'hr' m'mn' s'sec'", CultureInfo.InvariantCulture); 

В качестве альтернативы, вы можете использовать pattern-based API вместо :

DurationPattern p = DurationPattern.CreateWithInvariantCulture("H'hr' m'mn' s'sec'"); 
string result = p.Format(d); 

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

0

Мое решение:

string text = Math.Floor(timeUsed.TotalHours) + "h " + ((int)timeUsed.TotalMinutes) % 60 + "min"; 
0

MS Excel имеет другой формат другого для .NET.

Проверить эту ссылку http://www.paragon-inc.com/resources/blogs-posts/easy_excel_interaction_pt8

Я создаю простую функцию, которая преобразовать TimeSpan в DateTime с форматом MS Excel

public static DateTime MyApproach(TimeSpan time) 
    { 
     return new DateTime(1900, 1, 1).Add(time).AddDays(-2); 
    } 

и вам нужно отформатировать ячейку, как это:

col.Style.Numberformat.Format = "[H]:mm:ss"; 
1

Вы можете попробовать:

TimeSpan ts = TimeSpan.FromSeconds(1254234568); 
Console.WriteLine($"{((int)ts.TotalHours).ToString("d2")}hr {ts.Minutes.ToString("d2")}mm {ts.Seconds.ToString("d2")}sec"); 
+0

'toString (" d2 ")' с соединением с принятым ответом получает лучший результат –

Смежные вопросы