File: src\Shared\FormatHelpers.cs
Web Access
Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using Aspire.Dashboard.Extensions;
 
namespace Aspire.Dashboard.Utils;
 
public enum MillisecondsDisplay
{
    None,
    Truncated,
    Full
}
 
public enum TimeFormat
{
    System,
    TwelveHour,
    TwentyFourHour
}
 
public interface ITimeFormatProvider
{
    TimeFormat ResolvedTimeFormat { get; }
}
 
internal static class FormatHelpers
{
    // Limit size of very long data that is written in large grids.
    public const int ColumnMaximumTextLength = 250;
    public const int TooltipMaximumTextLength = 1500;
    public const string Ellipsis = "…";
 
    /// <summary>
    /// Formats a DateTime as a local time string (HH:mm:ss.fff) for console output.
    /// </summary>
    public static string FormatConsoleTime(TimeProvider timeProvider, DateTime value)
    {
        return timeProvider.ToLocal(value)
            .ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture);
    }
 
    public static string FormatTime(TimeProvider timeProvider, DateTime value, MillisecondsDisplay millisecondsDisplay = MillisecondsDisplay.None, CultureInfo? cultureInfo = null)
    {
        cultureInfo ??= CultureInfo.CurrentCulture;
        var local = timeProvider.ToLocal(value);
        var timeFormat = GetResolvedTimeFormat(timeProvider);
        var pattern = DateFormatStringsHelpers.GetLongTimePattern(cultureInfo, timeFormat, millisecondsDisplay);
 
        return local.ToString(pattern, cultureInfo);
    }
 
    public static string FormatDateTime(TimeProvider timeProvider, DateTime value, MillisecondsDisplay millisecondsDisplay = MillisecondsDisplay.None, CultureInfo? cultureInfo = null)
    {
        cultureInfo ??= CultureInfo.CurrentCulture;
        var local = timeProvider.ToLocal(value);
        var timeFormat = GetResolvedTimeFormat(timeProvider);
        var pattern = DateFormatStringsHelpers.GetShortDateLongTimePattern(cultureInfo, timeFormat, millisecondsDisplay);
 
        return local.ToString(pattern, cultureInfo);
    }
 
    private static TimeFormat GetResolvedTimeFormat(TimeProvider timeProvider)
    {
        if (timeProvider is ITimeFormatProvider tfp)
        {
            return tfp.ResolvedTimeFormat;
        }
 
        return TimeFormat.System;
    }
 
    public static string FormatTimeWithOptionalDate(TimeProvider timeProvider, DateTime value, MillisecondsDisplay millisecondsDisplay = MillisecondsDisplay.None, CultureInfo? cultureInfo = null)
    {
        var local = timeProvider.ToLocal(value);
 
        // If the date is today then only return time, otherwise return entire date time text.
        if (local.Date == DateTime.Now.Date)
        {
            // e.g. "08:57:44" (based on user's culture and preferences)
            // Don't include milliseconds as resource server returned time stamp is second precision.
            return FormatTime(timeProvider, local, millisecondsDisplay, cultureInfo);
        }
        else
        {
            // e.g. "9/02/2024 08:57:44" (based on user's culture and preferences)
            return FormatDateTime(timeProvider, local, millisecondsDisplay, cultureInfo);
        }
    }
 
    public static string FormatNumberWithOptionalDecimalPlaces(double value, int maxDecimalPlaces, CultureInfo? provider = null)
    {
        var formatString = maxDecimalPlaces switch
        {
            1 => "##,0.#",
            2 => "##,0.##",
            3 => "##,0.###",
            4 => "##,0.####",
            5 => "##,0.#####",
            6 => "##,0.######",
            _ => throw new ArgumentException("Unexpected value.", nameof(maxDecimalPlaces))
        };
        return value.ToString(formatString, provider ?? CultureInfo.CurrentCulture);
    }
 
    public static string TruncateText(string? text, int maxLength)
    {
        if (string.IsNullOrEmpty(text))
        {
            return string.Empty;
        }
 
        if (text.Length <= maxLength)
        {
            return text;
        }
 
        return string.Concat(text.AsSpan(0, maxLength - Ellipsis.Length), Ellipsis);
    }
 
    public static string CombineWithSeparator(string separator, params string?[] parts)
    {
        return string.Join(separator, parts.Where(p => !string.IsNullOrEmpty(p)));
    }
}