57 lines
2.4 KiB
C#
57 lines
2.4 KiB
C#
using System.Globalization;
|
|||
|
|
|
||
|
|
namespace decePubClient.Components.Nerd;
|
||
|
|
|
||
|
|
/// <summary>One line of a NerdTip; a row without a value is not shown.</summary>
|
||
|
|
public sealed record NerdRow(string Label, string Value)
|
||
|
|
{
|
||
|
|
public static NerdRow Of(string label, object value) => new(label, value switch
|
||
|
|
{
|
||
|
|
null => null,
|
||
|
|
DateTime time => Time(time),
|
||
|
|
double number => number.ToString("0.###", CultureInfo.InvariantCulture),
|
||
|
|
bool flag => flag ? "yes" : "no",
|
||
|
|
IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture),
|
||
|
|
_ => value.ToString()
|
||
|
|
});
|
||
|
|
|
||
|
|
/// <summary>A UTC time to the millisecond, as PrivaPub records it.</summary>
|
||
|
|
public static string Time(DateTime time) =>
|
||
|
|
DateTime.SpecifyKind(time, time.Kind == DateTimeKind.Unspecified ? DateTimeKind.Utc : time.Kind).ToUniversalTime()
|
||
|
|
.ToString("yyyy-MM-dd HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture);
|
||
|
|
|
||
|
|
/// <summary>A duration the way a person reads it: 850 ms, 12.4 s, 3 min 5 s, 2 h 10 min, 4 d 3 h.</summary>
|
||
|
|
public static string Duration(TimeSpan span)
|
||
|
|
{
|
||
|
|
var sign = span < TimeSpan.Zero ? "-" : string.Empty;
|
||
|
|
span = span.Duration();
|
||
|
|
return sign + (span.TotalSeconds switch
|
||
|
|
{
|
||
|
|
< 1 => $"{span.TotalMilliseconds:0} ms",
|
||
|
|
< 60 => $"{span.TotalSeconds.ToString("0.0", CultureInfo.InvariantCulture)} s",
|
||
|
|
< 3600 => $"{span.Minutes} min {span.Seconds} s",
|
||
|
|
< 86400 => $"{(int)span.TotalHours} h {span.Minutes} min",
|
||
|
|
_ => $"{(int)span.TotalDays} d {span.Hours} h"
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>A byte count: 912 B, 14.2 KiB, 3.1 MiB.</summary>
|
||
|
|
public static string Bytes(long? bytes) => bytes switch
|
||
|
|
{
|
||
|
|
null => null,
|
||
|
|
< 1024 => $"{bytes} B",
|
||
|
|
< 1024 * 1024 => $"{(bytes.Value / 1024d).ToString("0.0", CultureInfo.InvariantCulture)} KiB",
|
||
|
|
_ => $"{(bytes.Value / 1048576d).ToString("0.0", CultureInfo.InvariantCulture)} MiB"
|
||
|
|
};
|
||
|
|
|
||
|
|
/// <summary>The great-circle distance between two points in kilometres (haversine, Earth radius 6371 km).</summary>
|
||
|
|
public static double Kilometres(double latitude1, double longitude1, double latitude2, double longitude2)
|
||
|
|
{
|
||
|
|
const double radius = 6371;
|
||
|
|
double Radians(double degrees) => degrees * Math.PI / 180;
|
||
|
|
var dLatitude = Radians(latitude2 - latitude1);
|
||
|
|
var dLongitude = Radians(longitude2 - longitude1);
|
||
|
|
var a = Math.Pow(Math.Sin(dLatitude / 2), 2) + Math.Cos(Radians(latitude1)) * Math.Cos(Radians(latitude2)) * Math.Pow(Math.Sin(dLongitude / 2), 2);
|
||
|
|
return 2 * radius * Math.Asin(Math.Min(1, Math.Sqrt(a)));
|
||
|
|
}
|
||
|
|
}
|