Вычитание TimeSpan из даты - PullRequest
       23

Вычитание TimeSpan из даты

0 голосов
/ 24 декабря 2010

Я хочу вычесть временной интервал из объекта даты-времени, используя 30-дневный месяц и игнорируя високосные годы и т. Д.

Date is 1983/5/1 13:0:0 (y/m/d-h:m:s)
Time span is 2/4/28-2:51:0 (y/m/d-h:m:s)

Я могу использовать объекты DateTime и TimeSpan для этого после преобразования лет и месяцев промежутка времени в дни (при условии 30-дневного месяца и ~ 364-дневного года).

new DateTime(1981,5,1,13,0,0).Subtract(new TimeSpan(878,13,51,0));

С этим я получаю результат:

{12/4/1978 11:09:00 PM}

Приведенный выше ответ, очевидно, не игнорирует факторы, которые я хочу игнорировать, и дает мне точный ответ. Но в данном случае это не то, что я хочу, поэтому я написал следующий код.

public static CustomDateTime operator -(CustomDateTime DT1,CustomDateTime DT2)
{
    CustomDateTime retVal = new CustomDateTime();
    try
    {
        const int daysPerYear = 364.25;
        const int monthsPerYear = 12;
        const int daysPerMonth = 30;
        const int hoursPerDay = 24;
        const int minutesPerHour = 60;

        retVal.Minute = DT1.Minute - DT2.Minute;
        if (retVal.Minute < 0)
        {
            retVal.Minute += minutesPerHour;
            DT1.Hour -= 1;
        }
        retVal.Hour = DT1.Hour - DT2.Hour;
        if (retVal.Hour < 0)
        {
            retVal.Hour += hoursPerDay;
            DT1.Day -= 1;
        }
        retVal.Day = DT1.Day - DT2.Day;
        if (retVal.Day < 0)
        {
            retVal.Day += daysPerMonth;
            DT1.Month -= 1;
        }
        retVal.Month = DT1.Month - DT2.Month;
        if (retVal.Month < 0)
        {
            retVal.Month += monthsPerYear;
            DT1.Year -= 1;
        }
        retVal.Year = DT1.Year - DT2.Year;                
    }
    catch (Exception ex) { }
    return retVal;
}

Тогда я получу:

1981/0/3-10:9:0

Это довольно близко к тому, к чему я стремлюсь, за исключением того, что я не получу 0 за месяц, а год должен быть 1980. Любая помощь приветствуется.


Просто чтобы прояснить ситуацию снова; в этом контексте я должен использовать 30-дневный месяц и игнорировать високосные годы, различное количество месяцев и т. д. Это странная вещь, я знаю. Так что я в значительной степени за «неправильный ответ», а не за точный ответ, данный управляемыми классами.

Ответы [ 2 ]

2 голосов
/ 24 декабря 2010

Если вы рассчитываете месяц на 30 дней, конечно, ваша математика будет отключена. Когда вы вычитаете 878 дней с 01.05.1981 г., .Net дает вам точную разницу, а не оценку, и эта разница учитывает високосные годы, если они есть. Ошибка не в методе Subtract (...), а в ваших собственных «ручных» вычислениях.

DateTime dt = new DateTime(1981, 5, 1, 13, 0, 0);
TimeSpan t = new TimeSpan(878, 13, 51, 0);

dt.Ticks
    624931668000000000

t.Ticks
    759090600000000

dt.Ticks - t.Ticks
    624172577400000000

new DateTime(dt2)
    {12/4/1978 11:09:00 PM}
    Date: {12/4/1978 12:00:00 AM}
    Day: 4
    DayOfWeek: Monday
    DayOfYear: 338
    Hour: 23
    Kind: Unspecified
    Millisecond: 0
    Minute: 9
    Month: 12
    Second: 0
    Ticks: 624172577400000000
    TimeOfDay: {23:09:00}
    Year: 1978

Это общее количество тиков с эпохи. Сделайте эту математику, затем конвертируйте обратно в дату и время.

Также: исправьте свою математику. 878 дней - это 2 года и 148 дней. 01.05.1981 - 121-й день в году, поэтому вычтите 120, чтобы получить 1 января 1979 года. Это оставляет 28 дней. Начните считать в обратном направлении с конца 1978 года, и вы получите очень близко к ответу .Net. Ваш собственный ответ не близко.

РЕДАКТИРОВАТЬ на основе обратной связи

// zh-Hans is a chinese culture
CultureInfo ci = CultureInfo.GetCultureInfo("zh-Hans");
DateTime dt = new DateTime(1981, 5, 1, 13, 0, 0, ci.Calendar);
TimeSpan t = new TimeSpan(878, 13, 51, 0);

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

Помимо этого, я не уверен, как еще сделать математику. Если вы можете предоставить ссылку на то, как вы это делаете вручную, я могу помочь вам написать код.

РЕДАКТИРОВАТЬ 2

Теперь я понимаю. Попробуйте это:

DateTime dt = new DateTime(1981, 5, 1, 13, 0, 0, ci.Calendar);

int years = 878 / 365;
int remainingDays = 878 % 365;
int months = remainingDays / 30;
remainingDays = remainingDays % 30;
TimeSpan t = new TimeSpan(years * 365 + months * 30 + remainingDays);
DateTime newdate = dt.Subtract(t);
1 голос
/ 24 декабря 2010

Вы не можете предполагать 30-дневный месяц. Вы указываете, что вы хотите вычесть 878 дней. Управляемые классы (я предполагаю, что вы имеете в виду управляемый, когда говорите «родной») предназначены для учета високосных лет, разного количества месяцев и т. Д.

Использование управляемых классов не даст вам 0 за месяц.

...