次のように、数秒をTimeSpanオブジェクトに変換するとします。
Dim sec = 1254234568
Dim t As TimeSpan = TimeSpan.FromSeconds(sec)
TimeSpanオブジェクトを次のような形式にフォーマットするにはどうすればよいですか。
>105hr 56mn 47sec
組み込み関数はありますか、またはカスタム関数を作成する必要がありますか?
まあ、最も簡単なことは、これを自分でフォーマットすることです。
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
.NET 4のTimeSpan
フォーマットのいずれかでこれが簡単になるかどうかはわかりません。
編集:C#6/VB 14導入 補間文字列 これは、私の最初のコードセグメントよりも単純な場合とそうでない場合があります元の回答。ありがたいことに、補間の構文は同じです:先行する_$
_。
_TimeSpan t = new TimeSpan(105, 56, 47);
Console.WriteLine($"{(int)t.TotalHours}h {t:mm}mn {t:ss}sec");
_
_dim t As New TimeSpan(105, 56, 47)
Console.WriteLine($"{CInt(Math.Truncate(t.TotalHours))}h {t:mm}mn {t:ss}sec")
_
C#の簡単な例をご覧ください here C#7で導入された ValueTuple
s 機能を含みます。コアは小さな例では非常に扱いにくいですが、.NET Frameworkプロジェクトでもまったく同じように機能するので安心してください。
Microsoftには(現在)単純なフォーマット文字列のショートカットはありません。最も簡単なオプションはすでに共有されています。
_string.Format("{0}hr {1:mm}mn {1:ss}sec", (int)t.TotalHours, t);
_
_String.Format("{0}hr {1:mm}mn {1:ss}sec", _
CInt(Math.Truncate(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(format、myTimeSpanFormatter)を使用する必要があります。 DateTimeのカスタムIFormatProviderを作成して使用する方法 を参照してください。
[〜#〜] 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またはdoubleをフォーマットする必要があります。囲み中括弧に注意してください。括弧はstring.Format()の場合にはありません。また、formatter
はICustomFormatter
ではなくTimeSpanFormatter
として宣言(またはキャスト)する必要があることに注意してください。
過剰?はい。驚くばかり?うーん・・・.
string.Format("{0}hr {1}mn {2}sec", (int) t.TotalHours, t.Minutes, t.Seconds);
あなたはこれを試すことができます:
TimeSpan ts = TimeSpan.FromSeconds(1254234568);
Console.WriteLine($"{((int)ts.TotalHours).ToString("d2")}hr {ts.Minutes.ToString("d2")}mm {ts.Seconds.ToString("d2")}sec");
時間の計算が必要になる場合があります。 TimeSpan.ToStringでの時間の範囲は0〜23のみです。
あなたが必要とする最悪のことは、ジョン・スキートの生の文字列フォーマットを行うことです。
Noda Time のDuration
タイプの使用を検討してください。
例えば:
Duration d = Duration.FromSeconds(sec);
または
Duration d = Duration.FromTimeSpan(ts);
その後、次のように単純に文字列としてフォーマットできます。
string result = d.ToString("H'hr' m'mn' s'sec'", CultureInfo.InvariantCulture);
または、代わりに パターンベースのAPI を使用できます。
DurationPattern p = DurationPattern.CreateWithInvariantCulture("H'hr' m'mn' s'sec'");
string result = p.Format(d);
パターンAPIの利点は、パターンを一度作成するだけでよいことです。解析またはフォーマットする値が多い場合は、パフォーマンスが大幅に向上する可能性があります。
( https://msdn.Microsoft.com/en-us/library/1ecy8h51(v = vs.110).aspx )のとおり、TimeSpanオブジェクトのデフォルトのToString()メソッドは、 「c」形式。つまり、デフォルトでは、24時間より長いタイムスパンは、かみそりビューへの出力時に「1.03:14:56」のようになります。これは、「1」であることを理解していない顧客との間で混乱を引き起こしました。 1日を表します。
したがって、補間された文字列(C#6 +)を使用できる場合、デフォルトの形式をできるだけ維持するために思いついた簡単な方法は、Days + Hoursの代わりにTotalHoursを使用して、getプロパティを提供して、次のようにフォーマットされた文字列としての時間:
public TimeSpan SystemTime { get; set; }
public string SystemTimeAsString
{
get
{
// Note: ignoring fractional seconds.
return $"{(int)SystemTime.TotalHours}:SystemTime.Minutes.ToString("00")}:SystemTime.Seconds.ToString("00")}";
}
}
上記と同じ時間を使用したこの結果は、「27:14:56」になります。
私の解決策は:
string text = Math.Floor(timeUsed.TotalHours) + "h " + ((int)timeUsed.TotalMinutes) % 60 + "min";
MS Excelには、.NETとは異なる他の形式があります。
このリンクをチェック http://www.paragon-inc.com/resources/blogs-posts/easy_Excel_interaction_pt8
MS Excel形式でDateStimeのTimeSpanを変換する簡単な関数を作成します
public static DateTime MyApproach(TimeSpan time)
{
return new DateTime(1900, 1, 1).Add(time).AddDays(-2);
}
そしてあなたはこのようにセルをフォーマットする必要があります:
col.Style.Numberformat.Format = "[H]:mm:ss";
この機能を試してください:
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