C# calculate / display relative time

Date: 2020-11-18
namespace Domain.Helpers
{
    public static class RelativeTimeHelper
    {
        public static List<Threshold> Thresholds = new()
        {
            new Threshold((d) => d.AddMinutes(-1), "{0} seconden", x => x.Seconds),
            new Threshold((d) => d.AddMinutes(-2), "één minuut ", x => x.Minutes),
            new Threshold((d) => d.AddMinutes(-60), "{0} minuten", x => x.Minutes),
            new Threshold((d) => d.AddMinutes(-120), "één uur", x => x.Hours),
            new Threshold((d) => d.AddDays(-1), "{0} uur", x => x.Hours),
            new Threshold((d) => d.AddDays(-2), "gisteren", x => x.Days),
            new Threshold((d) => d.AddMonths(-1), "{0} dagen", x => x.Days),
            new Threshold((d) => d.AddMonths(-2), "{0} maand", x => x.Months),
            new Threshold((d) => d.AddYears(-1), "{0} maanden", x => x.Months),
            new Threshold((d) => DateTime.MaxValue, "{0} jaar", x => x.Years)
        };

        public static string RelativeDateTime(DateTime theDate) => FriendlyTimespan(theDate);
        public static string FriendlyTimespan(DateTime date, DateTime? now = null)
        {
            var current = now ?? DateTime.Now;
            var threshold = Thresholds.OrderByDescending(x => x.Condition(current)).FirstOrDefault(x => x.Condition(current) < date) ?? Thresholds.Last();
            var tresholdRelativeValues = TresholdRelativeValues.Get(date, current);
            return string.Format(threshold.Description, threshold.Converter(tresholdRelativeValues));
        }
    }

    public record TresholdRelativeValues(int Seconds, int Minutes, int Hours, int Days, int Months, int Years)
    {
        internal static TresholdRelativeValues Get(DateTime date, DateTime now)
        {
            var d = now - date;
            (var totalYears, var totalMonths )= GetYearAndMonthDifference(date, now);
            //= GetMonthDifference(date, now);
            return new TresholdRelativeValues((int)Math.Ceiling(d.TotalSeconds), (int)Math.Ceiling(d.TotalMinutes), (int)Math.Ceiling(d.TotalHours), (int)Math.Ceiling(d.TotalDays), totalMonths, totalYears);
        }

        static (int Years, int Months) GetYearAndMonthDifference(DateTime start, DateTime end)
        {
            // Bereken het aantal jaren en maanden verschil
            int yearsDifference = end.Year - start.Year;
            int monthsDifference = end.Month - start.Month;

            // Als de maand van de einddatum vóór de maand van de startdatum valt, betekent dat dat er nog geen volledig jaar is verstreken
            if (monthsDifference < 0)
            {
                yearsDifference--;
                monthsDifference += 12; // Correctie voor negatieve maandverschillen
            }

            // Controleer of de einddatum vóór de dag van de startdatum in de huidige maand valt
            if (end.Day < start.Day)
            {
                monthsDifference--;

                // Als het maandverschil nu negatief is, trek dan ook één jaar af en corrigeer het maandverschil
                if (monthsDifference < 0)
                {
                    yearsDifference--;
                    monthsDifference += 12;
                }
            }

            return (yearsDifference, monthsDifference);
        }
    }
    public class Threshold
    {
        public Threshold(Func<DateTime, DateTime> condition, string description, Func<TresholdRelativeValues, int> converter)
        {
            Condition = condition;
            Description = description;
            Converter = converter;
        }
        public Func<DateTime, DateTime> Condition { get; }
        public string Description { get; }
        public Func<TresholdRelativeValues, int> Converter { get; }
    }
}

42910cookie-checkC# calculate / display relative time