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?

32
demandé sur Mark Hurd 2010-08-17 21:33:40

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.

50
répondu Jon Skeet 2010-08-17 19:24:10

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);

{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....

7
répondu dfoverdx 2017-05-23 12:26:15

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

4
répondu Jason Williams 2010-08-17 18:13:25

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.

1
répondu John 2010-08-17 17:39:47

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");
1
répondu daniell89 2017-04-05 14:36:23

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       

Convertir Un Temps En Heures Et Minutes

0
répondu Angkor Wat 2010-08-17 17:45:26

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.

0
répondu Matt Johnson 2014-11-05 17:09:58

ma solution est:

string text = Math.Floor(timeUsed.TotalHours) + "h " + ((int)timeUsed.TotalMinutes) % 60 + "min";
0
répondu alansiqueira27 2014-11-18 19:35:49

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";
0
répondu oaamados 2014-11-19 22:58:44

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".

0
répondu Michael Villere 2018-03-30 19:39:10