Format durée supérieure à 24 heures
dites que je convertis quelques secondes en l'objet TimeSpan comme ceci:
Dim sec = 1254234568
Dim t As TimeSpan = TimeSpan.FromSeconds(sec)
comment formater l'objet TimeSpan dans le format suivant:
>105hr 56mn 47sec
Est-il une fonction intégrée ou dois-je écrire une fonction personnalisée?
10 réponses
Eh bien, la chose la plus simple à faire est de formater 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 le formatage TimeSpan
dans .NET 4 simplifierait les choses.
Microsoft n'a pas (actuellement) un raccourci simple 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);
cependant, une option trop complète est de mettre en œuvre votre propre ICustomFormatter
pour TimeSpan
. Je ne le recommande que si vous l'utilisez si souvent que cela vous fera gagner du temps à long terme. Cependant, il y a des fois où vous écrivez un cours où écrire votre propre ICustomFormatter
est approprié, donc j'ai écrit ceci comme un 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);
}
}
Note, Comme dans les remarques dans le code, TimeSpan.ToString(format, myTimeSpanFormatter)
ne fonctionnera pas en raison d'une bizarrerie du .net Framework, donc vous devrez toujours utiliser string.Format (format, myTimeSpanFormatter) pour utiliser cette classe. Voir comment créer et utiliser un Formatprovider personnalisé pour DateTime? .
EDIT :
Si vous avez vraiment, et je veux dire really , si vous voulez que cela fonctionne avec TimeSpan.ToString(string, TimeSpanFormatter)
, vous pouvez ajouter ce qui suit à la classe ci-dessus TimeSpanFormatter
:
/// <remarks>
/// Update this as needed.
/// </remarks>
internal static string[] GetRecognizedFormats()
{
return new string[] { "td", "th", "tm", "ts", "tf", "TD", "TH", "TM", "TS", "TF" };
}
et ajouter 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 le total des heures int ou double soit formaté. Notez les attaches qui ne devraient pas être là dans chaîne.Format () case. Note: formatter
doit être déclaré (ou moulé) comme ICustomFormatter
plutôt que TimeSpanFormatter
.
excessif? Oui. Génial? Euh....
string.Format("{0}hr {1}mn {2}sec", (int) t.TotalHours, t.Minutes, t.Seconds);
vous pourriez avoir besoin de calculer les heures. La gamme pour des heures dans le temps.ToString est seulement 0-23.
le pire dont vous aurez besoin, c'est de faire du format raw string un Skeet de la Jon.
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");
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
vous pouvez envisager d'utiliser le type Noda Time 's Duration
.
par exemple:
Duration d = Duration.FromSeconds(sec);
ou
Duration d = Duration.FromTimeSpan(ts);
vous pouvez alors simplement le formater comme une chaîne de caractères, comme ceci:
string result = d.ToString("H'hr' m'mn' s'sec'", CultureInfo.InvariantCulture);
alternativement, vous pouvez utiliser le API pattern-based à la place:
DurationPattern p = DurationPattern.CreateWithInvariantCulture("H'hr' m'mn' s'sec'");
string result = p.Format(d);
l'avantage de l'API pattern est que vous n'avez besoin de créer le modèle qu'une seule fois. Si vous avez beaucoup de valeurs à analyser ou à formater, il peut y avoir un avantage significatif de performance.
ma solution est:
string text = Math.Floor(timeUsed.TotalHours) + "h " + ((int)timeUsed.TotalMinutes) % 60 + "min";
MS Excel a un autre format différent .NET.
vérifier ce lien http://www.paragon-inc.com/resources/blogs-posts/easy_excel_interaction_pt8
je crée une fonction simple qui convertit un temps dans un DateTime avec le 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";
selon ( https://msdn.microsoft.com/en-us/library/1ecy8h51 (v=V110).aspx ), la méthode par défaut ToString () pour un objet TimeSpan utilise le formatage" c", ce qui signifie que par défaut, un temps plus long que 24 heures ressemble à quelque chose comme" 1.03:14:56 " quand la sortie à une vue de rasoir. Cela a causé une certaine confusion avec mes clients qui ne comprennent pas que la "1."représente un jour.
donc, si vous pouvez utiliser des chaînes interpolées (C#6+), un la manière simple que j'ai trouvée pour préserver le formatage par défaut autant que possible, tout en utilisant TotalHours au lieu de jours+heures est de fournir une propriété get pour afficher le temps comme une chaîne formatée, comme ceci:
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 du même temps que ci-dessus sera"27:14:56".