Почему TimeSpan не обладает свойством Years?

Я писал конвертер, который принимает человека на дату рождения и производит их возраст в годах. Я написал что-то вроде:

public class DateOfBirthToAgeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var date = value as DateTime?;
        if (date == null) return null;
        return (DateTime.Now - date).Years;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Я обнаружил, что на TimeSpan нет свойства Years, которое является результатом вычитания двух объектов DateTime. Я был несколько удивлен этим. Я думал о том, почему не может быть Years. Я понял, что это может быть из-за високосного дня, но по этой логике не должно быть Days из-за дневного сбережения.

Отсутствие Months имело смысл, поскольку нет стандартной длины месяца.

Мне удалось написать какой-то другой код, чтобы получить правильный возраст, но я все еще очень хочу знать, почему в TimeSpan нет свойства Years или Weeks. Кто-нибудь знает причину?

Ответ 1

Жизнь программиста действительно тяжелая.

Длина года является переменной. Некоторые годы имеют 365 дней, а некоторые - 366 дней. Согласно календарю, у некоторых лет могут быть даже пропущенные дни. Если говорить о культуре, то это становится сложнее, поскольку китайский лунный календарь может иметь 13 месяцев в году.

Длина месяца является переменной, и это хорошо известно. Это также означает, что в других календарях все может ухудшиться.

Продолжительность дня является переменной из-за экономии летнего времени, и это зависит не только от культуры, но и от географии.

Длина часа и минуты являются переменными, из-за високосных секунд с.

Кажется, единственное, что заслуживает доверия, это длина секунды. Таким образом, внутреннее время хранится в секундах (или миллисекундах, что то же самое).

Но изменчивость единиц времени дает ответ "сколько (лет/месяцев/дней/часов/минут) за n секунд?" быть всегда неточным.

Вот почему разработчики получают решение, которое полезно на практике, но не является точным. Они просто игнорируют переход на летнее время и дополнительные секунды. Однако, поскольку люди почти не задают вопросы о годах и месяцах, они просто решили не отвечать на эти вопросы.

Ответ 2

TimeSpan содержит только разницу между двумя значениями DateTime. Неизвестно, в каком году этот TimeSpan. Это также то, почему у него нет свойства Months.

Пример:

TimeSpan.FromDays(60)

Сколько месяцев это? 1 или 2?


Отсутствие месяцев имело смысл, поскольку нет стандартной продолжительности месяца.

Также нет стандартной продолжительности года из-за високосных лет.

Обходной путь: Если вы действительно хотите отобразить приблизительное значение, тогда выполнение TimeSpan.TotalDays/365 подойдет.

Изменение: Но только для приблизительных оценок, а не для дней рождения. В расчете дня рождения високосные дни будут накапливаться каждые 4 года, как отметил Хенк Холтерман в комментариях. Посмотрите здесь для расчета дней рождения.

Ответ 3

Риторический вопрос: без точки отсчета, как долго проходит год?

Поскольку TimeSpan не имеет фиксированной точки во времени, невозможно однозначно сказать, как долго будет длиться год в неизвестное время. В простейшем случае это может быть 365 или 366 дней. Значительно больше случаев, которые повлияют на результат.

Ответ 4

Я понял, что это может быть из-за високосного дня, но по этой логике, не должно быть Дней из-за летнего сбережения.

У вас есть точка; вычитание двух дат идеально подходит для экономии дневного света. Если даты являются местным временем, вы можете получить неожиданный результат.

Изменение летнего времени означает пробел или перекрытие в локальное время, и это игнорируется, если вы выполняете расчеты с датами. Итак, если вы хотите получить точную разницу между двумя значениями DateTime, которые являются местным временем, вы должны сначала преобразовать их в UTC, так как это имеет линейное время:

TimeSpan diff = date1.ToUniversalTime() - date2.ToUniversalTime();

Причина, по которой TimeSpan не имеет лет, состоит в том, что годы различаются по длине. Проблема с дневным сбережением является следствием того, как вы вычисляете TimeSpan, и ее можно обойти, но нет "линейных лет", которые вы можете использовать, чтобы обойти високосные годы.

Ответ 5

Timespan просто сохраняет количество миллисекунд. Если у вас есть (1000 * 60 * 60 * 24 * 365,5) 365,5 дней в миллисекундах, невозможно узнать, охватывает ли это количество миллисекундов целый год и в следующем, если это просто меньше года, или если оно охватывает три года. То же самое с 30,5 днями в миллисекундах, может занять второй месяц, может быть меньше месяца, может охватывать три месяца.