Vali-CountDown
IValiCountDown provides deadline tracking, countdown calculation, elapsed time measurement, and progress reporting. All methods accept an optional reference time parameter, allowing you to test against any point in time rather than always using DateTime.Now.
Installation
dotnet add package Vali-CountDown
Registration
builder.Services.AddValiCountDown();
// or via the meta-package:
builder.Services.AddValiTempo();
IValiCountDown API
IsExpired
Return true if the deadline has already passed:
bool expired = countdown.IsExpired(deadline);
bool expiredAt = countdown.IsExpired(deadline, reference: DateTime.Now);
Signature: bool IsExpired(DateTime deadline) / bool IsExpired(DateTime deadline, DateTime reference)
TimeUntil
Return the amount of time remaining until the deadline in the specified unit. Returns 0 if already expired:
decimal remaining = countdown.TimeUntil(deadline, TimeUnit.Hours);
// → e.g. 47.5
decimal remainingRounded = countdown.TimeUntil(deadline, TimeUnit.Days, decimalPlaces: 1);
// → e.g. 2.0
Signature: decimal TimeUntil(DateTime deadline, TimeUnit unit, int? decimalPlaces = null)
TimeElapsed
Return the amount of time that has elapsed since the given point, in the specified unit:
decimal elapsed = countdown.TimeElapsed(startDate, TimeUnit.Hours);
// → How many hours since startDate
Signature: decimal TimeElapsed(DateTime from, TimeUnit unit, int? decimalPlaces = null)
Note: When
fromis in the future, returns 0. UseIsStarted()to check whether elapsed time is meaningful.
Progress
Return the fractional progress (0.0–1.0) between start and end. Returns 0 before start; 1 at or after end:
decimal progress = countdown.Progress(startDate, deadline);
// → 0.0 at start, 1.0 at deadline
Signature: decimal Progress(DateTime start, DateTime end) / decimal Progress(DateTime start, DateTime end, DateTime reference)
ProgressPercent
Return the progress as a percentage (0–100):
decimal pct = countdown.ProgressPercent(startDate, deadline);
// → 0.0 to 100.0
Signature: decimal ProgressPercent(DateTime start, DateTime end)
Breakdown
Decompose the remaining time into component units. Returns all zeros if the deadline has expired:
var parts = countdown.Breakdown(deadline);
// → Dictionary with Days, Hours, Minutes, Seconds, Milliseconds keys
Console.WriteLine($"{parts[TimeUnit.Days]}d {parts[TimeUnit.Hours]}h {parts[TimeUnit.Minutes]}m");
Signature: Dictionary<TimeUnit, decimal> Breakdown(DateTime deadline)
Format
Format the time remaining until the deadline as a human-readable string (e.g., "5d 3h 20m"). Returns "Expired" if the deadline has already passed. Only non-zero components are included.
When between 0 and 1 second remain, returns "< 1s".
string formatted = countdown.Format(deadline);
// → "2d 3h 20m"
string withSeconds = countdown.Format(deadline, includeSeconds: true);
// → "2d 3h 20m 15s"
Signature: string Format(DateTime deadline, bool includeSeconds = false)
IsWithin
Return true if the deadline is within a given amount (expressed in the specified unit) from now. Returns false if the deadline has already expired:
bool urgent = countdown.IsWithin(deadline, 24, TimeUnit.Hours);
// → true if deadline is within the next 24 hours
bool soonWarning = countdown.IsWithin(deadline, 7, TimeUnit.Days);
Signature: bool IsWithin(DateTime deadline, decimal amount, TimeUnit unit)
IsStarted
Return true if from is in the past or present (i.e., elapsed time is meaningful):
bool started = countdown.IsStarted(projectStart);
// → true when DateTime.Now >= projectStart
Signature: bool IsStarted(DateTime from)
Complete Example
public class TaskDashboard(IValiCountDown countdown)
{
public void DisplayTaskStatus(string taskName, DateTime created, DateTime deadline)
{
bool isExpired = countdown.IsExpired(deadline);
if (isExpired)
{
decimal overdue = countdown.TimeElapsed(deadline, TimeUnit.Hours, decimalPlaces: 1);
Console.WriteLine($"[OVERDUE] {taskName} — overdue by {overdue:F1} hours");
return;
}
decimal progressPct = countdown.ProgressPercent(created, deadline);
bool isUrgent = countdown.IsWithin(deadline, 48, TimeUnit.Hours);
var parts = countdown.Breakdown(deadline);
Console.WriteLine($"Task: {taskName}");
Console.WriteLine($"Progress: {progressPct:F1}%");
Console.WriteLine($"Remaining: {parts[TimeUnit.Days]}d {parts[TimeUnit.Hours]}h {parts[TimeUnit.Minutes]}m");
Console.WriteLine($"Formatted: {countdown.Format(deadline)}");
if (isUrgent)
Console.WriteLine(" *** URGENT: less than 48 hours ***");
}
}