Disons que je convertis quelques secondes en objet TimeSpan comme ceci:
Dim sec = 1254234568
Dim t As TimeSpan = TimeSpan.FromSeconds(sec)
Comment formater l'objet TimeSpan dans un format tel que celui-ci:
>105hr 56mn 47sec
Existe-t-il une fonction intégrée ou dois-je écrire une fonction personnalisée?
Eh bien, la chose la plus simple à faire est de formater cela vous-même, par exemple.
return string.Format("{0}hr {1}mn {2}sec",
(int) span.TotalHours,
span.Minutes,
span.Seconds);
En 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
Je ne sais pas si un des formats TimeSpan
dans .NET 4 simplifierait les choses.
Edit: C # 6/VB 14 introduit chaînes interpolées qui peuvent ou non être plus simples que le premier segment de code de ma réponse originale. Heureusement, la syntaxe pour l'interpolation est identique: un $
précédent.
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")
Voir un exemple rapide de C # ici incluant la ValueTuple
s fonctionnalité introduite en C # 7. Hélas, le seul compilateur en ligne C # 7 que je pouvais trouver fonctionnait .NET Core, ce qui est fastidieux pour de petits exemples, soyez assurés que cela fonctionne exactement de la même manière dans un projet .NET Framework.
Microsoft n'a pas (actuellement) un simple raccourci de chaîne de format pour cela. Les options les plus faciles ont déjà été partagées.
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)
Cependant, une option trop approfondie consiste à implémenter votre propre ICustomFormatter
pour TimeSpan
. Je ne le recommanderais pas, à moins que vous n'utilisiez ceci souvent, cela vous ferait gagner du temps à long terme. Cependant, il y a des moments où vous écrivez une classe dans laquelle écrire votre propre variable ICustomFormatter
est approprié, aussi ai-je écrit celui-ci à titre d'exemple.
/// <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);
}
}
Notez que, comme dans les remarques dans le code, TimeSpan.ToString(format, myTimeSpanFormatter)
ne fonctionnera pas en raison d'une bizarrerie du .NET Framework, vous devrez donc toujours utiliser string.Format (format, myTimeSpanFormatter) pour utiliser cette classe. Voir Comment créer et utiliser un IFormatProvider personnalisé pour DateTime? .
EDIT: Si vous voulez vraiment, et je veux dire, vraiment, voulez que cela fonctionne avec TimeSpan.ToString(string, TimeSpanFormatter)
, vous pouvez ajouter ce qui suit à la classe TimeSpanFormatter
ci-dessus:
/// <remarks>
/// Update this as needed.
/// </remarks>
internal static string[] GetRecognizedFormats()
{
return new string[] { "td", "th", "tm", "ts", "tf", "TD", "TH", "TM", "TS", "TF" };
}
Et ajoutez la classe suivante quelque part dans le même espace de noms:
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()));
}
}
Après cela, vous pouvez utiliser
ICustomFormatter formatter = new TimeSpanFormatter();
string myStr = myTimeSpan.ToString(@"TH,{000.00}h\:tm\m\:ss\s", formatter);
où {000.00}
est cependant vous voulez que TotalHours int ou double soit formaté. Notez les accolades englobantes, qui ne devraient pas être là dans le cas string.Format (). Notez également que formatter
doit être déclaré (ou converti) sous la forme ICustomFormatter
plutôt que TimeSpanFormatter
.
Excessif? Oui. Impressionnant? Uhhh ....
Vous pouvez essayer ceci:
TimeSpan ts = TimeSpan.FromSeconds(1254234568);
Console.WriteLine($"{((int)ts.TotalHours).ToString("d2")}hr {ts.Minutes.ToString("d2")}mm {ts.Seconds.ToString("d2")}sec");
Vous devrez peut-être calculer les heures. La plage d'heures dans TimeSpan.ToString est uniquement comprise entre 0 et 23.
Le pire dont vous aurez besoin est de formater la chaîne brute à la Jon Skeet.
Vous voudrez peut-être envisager d'utiliser le type Duration
de Noda Time .
Par exemple:
Duration d = Duration.FromSeconds(sec);
Ou
Duration d = Duration.FromTimeSpan(ts);
Vous pouvez alors simplement le formater en chaîne, comme ceci:
string result = d.ToString("H'hr' m'mn' s'sec'", CultureInfo.InvariantCulture);
Vous pouvez également utiliser l'API basée sur pattern à la place:
DurationPattern p = DurationPattern.CreateWithInvariantCulture("H'hr' m'mn' s'sec'");
string result = p.Format(d);
L’avantage de l’API de modèle est qu’il n’est nécessaire de créer le modèle qu’une seule fois. Si vous avez beaucoup de valeurs à analyser ou à formater, les performances peuvent être considérablement améliorées.
Conformément à ( https://msdn.Microsoft.com/en-us/library/1ecy8h51(v=vs.110).aspx ), la méthode ToString () par défaut d'un objet TimeSpan utilise le "c". le formatage, ce qui signifie que par défaut, une durée supérieure à 24 heures ressemble à "1.03: 14: 56" lors de la sortie dans une vue rasoir. Cela a créé une certaine confusion avec mes clients qui ne comprennent pas que le "1" représente un jour.
Donc, si vous pouvez utiliser des chaînes interpolées (C # 6 +), un moyen simple de conserver le formatage par défaut autant que possible, tout en utilisant TotalHours au lieu de Days + Hours, est de fournir une propriété get pour afficher le temps comme une chaîne formatée dans, comme suit:
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")}";
}
}
Le résultat de cette utilisation en utilisant le même temps que ci-dessus sera "27:14:56".
Ma solution est:
string text = Math.Floor(timeUsed.TotalHours) + "h " + ((int)timeUsed.TotalMinutes) % 60 + "min";
MS Excel a un autre format différent de .NET.
Vérifiez ce lien http://www.paragon-inc.com/resources/blogs-posts/easy_Excel_interaction_pt8
Je crée une fonction simple qui convertit TimeSpan en DateTime au format MS Excel
public static DateTime MyApproach(TimeSpan time)
{
return new DateTime(1900, 1, 1).Add(time).AddDays(-2);
}
et vous devez formater la cellule comme ceci:
col.Style.Numberformat.Format = "[H]:mm:ss";
Essayez cette fonction:
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