/// <summary> /// Converts <paramref name="value"/> to a representation such as "in 20 minutes". /// If <paramref name="value"/> is null then returns a flag stating not scheduled / not run, depending on whether /// <paramref name="representation"/> is expected to be in the past or future. /// </summary> /// <param name="value">The value to represent.</param> /// <param name="representation">Whether the value is supposed to be last-run (past) or next-run (future).</param> /// <returns>A string in English stating when it should run.</returns> internal static string ToTimeOffset(this DateTime?value, DateTimeRepresentationOf representation) { // No value? if (null == value) { return(representation == DateTimeRepresentationOf.LastRun ? "(not since last vault start)" : "(not scheduled)"); } // Find the difference between the scheduled time and now. var universalValue = value.Value.ToUniversalTime(); var localTime = universalValue.ToLocalTime(); var diff = universalValue.Subtract(DateTime.UtcNow); var isInPast = diff < TimeSpan.Zero; if (diff.TotalSeconds == 0) { // Now! return(representation == DateTimeRepresentationOf.LastRun ? "Now" : "Due now"); } else { // Convert the diff to a string. if (isInPast) { // It's in the past. If this is a "next run" then it's overdue. diff = new TimeSpan(diff.Ticks * -1); if (representation == DateTimeRepresentationOf.NextRun) { // If it's <= 15 seconds then we may just be waiting to be notified. if (diff <= TimeSpan.FromSeconds(15)) { return("Waiting to be run"); } // It is the next run but it's in the past. return($"Overdue by {(int)diff.TotalSeconds}s"); } } // Work out the difference string ("x minutes ago"). var diffString = ""; if (diff < TimeSpan.FromSeconds(60)) { // Show the time in seconds. diffString = ((int)diff.TotalSeconds).ToString() + " seconds"; } else if (diff < TimeSpan.FromMinutes(60 * 2)) { // Show the time in minutes. diffString = ((int)diff.TotalMinutes).ToString() + " minutes"; } else if (diff < TimeSpan.FromHours(24)) { // Show the time in hours. diffString = ((int)diff.TotalHours).ToString() + " hours"; } else { // Default to the specific time. return(localTime.Date == DateTime.Now.ToLocalTime().Date ? $"At {localTime.ToString("HH:mm:ss")} server-time" : $"At {localTime.ToString("HH:mm:ss")} server-time on {localTime.ToString("yyyy-MM-dd")}"); } // Render out ago vs in. if (isInPast) { // Past. if (representation == DateTimeRepresentationOf.NextRun) { // It is the next run but it's in the past. return("Overdue (expected " + diffString + " ago)"); } return(diffString + " ago"); } else { // Future. return(localTime.Date == DateTime.Now.ToLocalTime().Date ? $"At {localTime.ToString("HH:mm:ss")} server-time (in {diffString})" : $"At {localTime.ToString("HH:mm:ss")} server-time on {localTime.ToString("yyyy-MM-dd")} (in {diffString})"); } } }
/// <summary> /// Converts <paramref name="value"/> to a representation such as "in 20 minutes". /// If <paramref name="value"/> is null then returns a flag stating not scheduled / not run, depending on whether /// <paramref name="representation"/> is expected to be in the past or future. /// </summary> /// <param name="value">The value to represent.</param> /// <param name="representation">Whether the value is supposed to be last-run (past) or next-run (future).</param> /// <returns>A string in English stating when it should run.</returns> internal static string ToTimeOffset(this DateTime value, DateTimeRepresentationOf representation) { return(((DateTime?)value).ToTimeOffset(representation)); }