1
0
Files
common/AMWD.Common/Extensions/DateTimeExtensions.cs

196 lines
6.6 KiB
C#

using System.Text;
namespace System
{
/// <summary>
/// Provides extension methods for date and time manipulation.
/// </summary>
public static class DateTimeExtensions
{
#region Kind
/// <summary>
/// Specifies the <see cref="DateTime.Kind"/> as UTC.
/// </summary>
/// <param name="dt">The <see cref="DateTime"/> instance.</param>
/// <returns>A <see cref="DateTime"/> with correct <see cref="DateTime.Kind"/>.</returns>
public static DateTime AsUtc(this DateTime dt)
{
return dt.Kind switch
{
DateTimeKind.Local => dt.ToUniversalTime(),
DateTimeKind.Utc => dt,
_ => DateTime.SpecifyKind(dt, DateTimeKind.Utc),
};
}
/// <summary>
/// Specifies the <see cref="DateTime.Kind"/> as local time.
/// </summary>
/// <param name="dt">The <see cref="DateTime"/> instance.</param>
/// <returns>A <see cref="DateTime"/> with correct <see cref="DateTime.Kind"/>.</returns>
public static DateTime AsLocal(this DateTime dt)
{
return dt.Kind switch
{
DateTimeKind.Local => dt,
DateTimeKind.Utc => dt.ToLocalTime(),
_ => DateTime.SpecifyKind(dt, DateTimeKind.Local),
};
}
#endregion Kind
#region Aligned Interval
/// <summary>
/// Aligns the <see cref="TimeSpan"/> to the UTC clock.
/// </summary>
/// <param name="timeSpan">The timespan to align.</param>
/// <param name="offset">A specific offset to the timespan.</param>
/// <returns>The timespan until the aligned time.</returns>
public static TimeSpan GetAlignedIntervalUtc(this TimeSpan timeSpan, TimeSpan offset = default)
=> timeSpan.GetAlignedInterval(DateTime.UtcNow, offset);
/// <summary>
/// Aligns the <see cref="TimeSpan"/> to the local clock and respects daylight saving time.
/// </summary>
/// <param name="timeSpan">The timespan to align.</param>
/// <param name="offset">A specific offset to the timespan.</param>
/// <returns>The timespan until the aligned time.</returns>
public static TimeSpan GetAlignedIntervalLocal(this TimeSpan timeSpan, TimeSpan offset = default)
=> timeSpan.GetAlignedInterval(DateTime.Now, offset);
/// <summary>
/// Aligns the <see cref="TimeSpan"/> to the specified time.
/// </summary>
/// <param name="timeSpan">The timespan to align.</param>
/// <param name="now">A timestamp to align with.</param>
/// <param name="offset">A specific offset to the timespan.</param>
/// <returns>The timespan until the aligned time.</returns>
public static TimeSpan GetAlignedInterval(this TimeSpan timeSpan, DateTime now, TimeSpan offset = default)
{
var dtOffsetNow = new DateTimeOffset(now);
var nextTime = new DateTime(dtOffsetNow.Ticks / timeSpan.Ticks * timeSpan.Ticks, now.Kind).Add(offset);
var dtOffsetNext = new DateTimeOffset(nextTime);
if (dtOffsetNext <= dtOffsetNow)
dtOffsetNext = dtOffsetNext.Add(timeSpan);
if (now.Kind == DateTimeKind.Local)
return dtOffsetNext.LocalDateTime - dtOffsetNow.LocalDateTime;
return dtOffsetNext - dtOffsetNow;
}
#endregion Aligned Interval
/// <summary>
/// Prints the timespan as shortended string.
/// </summary>
/// <param name="timeSpan">The timespan</param>
/// <param name="withMilliseconds">A value indicating whether to show milliseconds.</param>
/// <returns>The timespan as string.</returns>
public static string ToShortString(this TimeSpan timeSpan, bool withMilliseconds = false)
{
var sb = new StringBuilder();
if (timeSpan < TimeSpan.Zero)
sb.Append("-");
if (timeSpan.TotalDays != 0)
sb.Append(Math.Abs(timeSpan.Days)).Append("d ");
if (timeSpan.TotalHours != 0)
sb.Append(Math.Abs(timeSpan.Hours)).Append("h ");
if (timeSpan.TotalMinutes != 0)
sb.Append(Math.Abs(timeSpan.Minutes)).Append("m ");
sb.Append(Math.Abs(timeSpan.Seconds)).Append("s ");
if (withMilliseconds)
sb.Append(Math.Abs(timeSpan.Milliseconds)).Append("ms");
return sb.ToString().Trim();
}
#region Round DateTime
/// <summary>
/// Rounds the <see cref="DateTime"/> to full seconds.
/// </summary>
/// <param name="dt">The time value to round.</param>
/// <returns></returns>
public static DateTime RoundToSecond(this DateTime dt)
=> new(RoundTicks(dt.Ticks, TimeSpan.TicksPerSecond), dt.Kind);
/// <summary>
/// Rounds the <see cref="DateTime"/> to full minutes.
/// </summary>
/// <param name="dt">The time value to round.</param>
/// <returns></returns>
public static DateTime RoundToMinute(this DateTime dt)
=> new(RoundTicks(dt.Ticks, TimeSpan.TicksPerMinute), dt.Kind);
/// <summary>
/// Rounds the <see cref="DateTime"/> to full hours.
/// </summary>
/// <param name="dt">The time value to round.</param>
/// <returns></returns>
public static DateTime RoundToHour(this DateTime dt)
=> new(RoundTicks(dt.Ticks, TimeSpan.TicksPerHour), dt.Kind);
/// <summary>
/// Rounds the <see cref="DateTime"/> to full days.
/// </summary>
/// <param name="dt">The time value to round.</param>
/// <returns></returns>
public static DateTime RoundToDay(this DateTime dt)
=> new(RoundTicks(dt.Ticks, TimeSpan.TicksPerDay), dt.Kind);
#endregion Round DateTime
#region Round TimeSpan
/// <summary>
/// Rounds the <see cref="TimeSpan"/> to full seconds.
/// </summary>
/// <param name="timeSpan">The time value to round.</param>
/// <returns></returns>
public static TimeSpan RoundToSecond(this TimeSpan timeSpan)
=> new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerSecond));
/// <summary>
/// Rounds the <see cref="TimeSpan"/> to full minutes.
/// </summary>
/// <param name="timeSpan">The time value to round.</param>
/// <returns></returns>
public static TimeSpan RoundToMinute(this TimeSpan timeSpan)
=> new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerMinute));
/// <summary>
/// Rounds the <see cref="TimeSpan"/> to full hours.
/// </summary>
/// <param name="timeSpan">The time value to round.</param>
/// <returns></returns>
public static TimeSpan RoundToHour(this TimeSpan timeSpan)
=> new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerHour));
/// <summary>
/// Rounds the <see cref="TimeSpan"/> to full days.
/// </summary>
/// <param name="timeSpan">The time value to round.</param>
/// <returns></returns>
public static TimeSpan RoundToDay(this TimeSpan timeSpan)
=> new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerDay));
#endregion Round TimeSpan
private static long RoundTicks(long ticks, long value)
=> (ticks + value / 2) / value * value;
}
}