Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3099

Show
Ignore:
Timestamp:
01/15/08 20:19:00 (10 months ago)
Author:
schveiguy
Message:

Fixed bug in getDayOfWeek in Gregorian
Added addMonths and addYears to Calendar/Gregorian. Fixes #825

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tango/time/chrono/Calendar.d

    r3059 r3099  
    346346        } 
    347347 
     348        /** 
     349         * Returns a new Time with the specified number of months added.  If 
     350         * the months are negative, the months are subtracted. 
     351         * 
     352         * The default implementation uses information provided by the 
     353         * calendar to calculate the correct time to add.  Derived classes may 
     354         * override if there is a more optimized method. 
     355         * 
     356         * Note that the generic method does not take into account crossing 
     357         * era boundaries.  Derived classes may support this. 
     358         * 
     359         * Params: t = A time to add the months to 
     360         * Params: nMonths = The number of months to add.  This can be 
     361         * negative. 
     362         * 
     363         * Returns: A Time that represents the provided time with the number 
     364         * of months added. 
     365         */ 
     366        Time addMonths(Time t, int nMonths) 
     367        { 
     368                uint era = getEra(t); 
     369                uint year = getYear(t); 
     370                uint month = getMonth(t); 
     371 
     372                // 
     373                // Assume we go back to day 1 of the current year, taking 
     374                // into account that offset using the nMonths and nDays 
     375                // offsets. 
     376                // 
     377                nMonths += month - 1; 
     378                long nDays = cast(int)getDayOfMonth(t) - cast(int)getDayOfYear(t); 
     379                if(nMonths > 0) 
     380                { 
     381                        // 
     382                        // Adding, add all the years until the year we want to 
     383                        // be in. 
     384                        // 
     385                        auto miy = getMonthsInYear(year, era); 
     386                        while(nMonths >= miy) 
     387                        { 
     388                                // 
     389                                // skip a whole year 
     390                                // 
     391                                nDays += getDaysInYear(year, era); 
     392                                nMonths -= miy; 
     393                                year++; 
     394 
     395                                // 
     396                                // update miy 
     397                                // 
     398                                miy = getMonthsInYear(year, era); 
     399                        } 
     400                } 
     401                else if(nMonths < 0) 
     402                { 
     403                        // 
     404                        // subtracting months 
     405                        // 
     406                        while(nMonths < 0) 
     407                        { 
     408                                auto miy = getMonthsInYear(--year, era); 
     409                                nDays -= getDaysInYear(year, era); 
     410                                nMonths += miy; 
     411                        } 
     412                } 
     413 
     414                // 
     415                // we now are offset to the resulting year. 
     416                // Add the rest of the months to get to the day we want. 
     417                // 
     418                for(int m = 0; m < nMonths; m++) 
     419                        nDays += getDaysInMonth(year, m + 1, era); 
     420                return t + TimeSpan.days(nDays); 
     421        } 
     422 
     423        /** 
     424         * Add the specified number of years to the given Time. 
     425         * 
     426         * The generic algorithm uses information provided by the abstract 
     427         * methods.  Derived classes may re-implement this in order to 
     428         * optimize the algorithm 
     429         * 
     430         * Note that the generic algorithm does not take into account crossing 
     431         * era boundaries.  Derived classes may support this. 
     432         * 
     433         * Params: t = A time to add the years to 
     434         * Params: nYears = The number of years to add.  This can be negative. 
     435         * 
     436         * Returns: A Time that represents the provided time with the number 
     437         * of years added. 
     438         */ 
     439        Time addYears(Time t, int nYears) 
     440        { 
     441                auto date = toDate(t); 
     442                auto tod = t.ticks % TimeSpan.TicksPerDay; 
     443                if(tod < 0) 
     444                        tod += TimeSpan.TicksPerDay; 
     445                date.year += nYears; 
     446                return toTime(date) + TimeSpan(tod); 
     447        } 
     448 
    348449        package static long getTimeTicks (uint hour, uint minute, uint second)  
    349450        { 
  • trunk/tango/time/chrono/Gregorian.d

    r3089 r3099  
    9999        { 
    100100                auto ticks = time.ticks; 
     101                int offset = 1; 
    101102                if (ticks < 0) 
     103                { 
    102104                    ++ticks; 
     105                    offset = 0; 
     106                } 
    103107        
    104                 auto dow = cast(int) ((ticks / TimeSpan.TicksPerDay) % 7); 
     108                auto dow = cast(int) ((ticks / TimeSpan.TicksPerDay + offset) % 7); 
    105109                if (dow < 0) 
    106110                    dow += 7; 
     
    242246            splitDate(time.ticks, year, month, day, doy, era); 
    243247            dow = getDayOfWeek(time); 
     248        } 
     249 
     250        override Time addMonths(Time t, int nMonths) 
     251        { 
     252                // 
     253                // We know all years are 12 months, so use the to/from date 
     254                // methods to make the calculation an O(1) operation 
     255                // 
     256                auto date = toDate(t); 
     257                nMonths += date.month - 1; 
     258                int nYears = nMonths / 12; 
     259                nMonths %= 12; 
     260                if(nMonths < 0) 
     261                { 
     262                        nYears--; 
     263                        nMonths += 12; 
     264                } 
     265                int realYear = date.year; 
     266                if(date.era == BC_ERA) 
     267                        realYear = -realYear + 1; 
     268                realYear += nYears; 
     269                if(realYear < 1) 
     270                { 
     271                        date.year = -realYear + 1; 
     272                        date.era = BC_ERA; 
     273                } 
     274                else 
     275                { 
     276                        date.year = realYear; 
     277                        date.era = AD_ERA; 
     278                } 
     279                date.month = nMonths + 1; 
     280                auto tod = t.ticks % TimeSpan.TicksPerDay; 
     281                if(tod < 0) 
     282                        tod += TimeSpan.TicksPerDay; 
     283                return toTime(date) + TimeSpan(tod); 
     284        } 
     285 
     286        override Time addYears(Time t, int nYears) 
     287        { 
     288                return addMonths(t, nYears * 12); 
    244289        } 
    245290 
     
    347392                if(era == BC_ERA) 
    348393                        return staticIsLeapYear(year - 1, AD_ERA); 
    349                 if(era == AD_ERA
     394                if(era == AD_ERA || era == CURRENT_ERA
    350395                        return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); 
    351396                return false; 
     
    409454                assert(d.dow == Gregorian.DayOfWeek.Saturday); 
    410455 
     456                // 
     457                // check that addMonths works properly, add 15 months to 
     458                // 2/3/2004, 04:05:06.007008, then subtract 15 months again. 
     459                // 
     460                t = Gregorian.generic.toTime(2004, 2, 3, 4, 5, 6, 7) + TimeSpan.micros(8); 
     461                d = Gregorian.generic.toDate(t); 
     462                assert(d.year == 2004); 
     463                assert(d.month == 2); 
     464                assert(d.day == 3); 
     465                assert(d.era == Gregorian.AD_ERA); 
     466                assert(d.doy == 34); 
     467                assert(d.dow == Gregorian.DayOfWeek.Tuesday); 
     468 
     469                auto t2 = Gregorian.generic.addMonths(t, 15); 
     470                d = Gregorian.generic.toDate(t2); 
     471                assert(d.year == 2005); 
     472                assert(d.month == 5); 
     473                assert(d.day == 3); 
     474                assert(d.era == Gregorian.AD_ERA); 
     475                assert(d.doy == 123); 
     476                assert(d.dow == Gregorian.DayOfWeek.Tuesday); 
     477 
     478                t2 = Gregorian.generic.addMonths(t2, -15); 
     479                d = Gregorian.generic.toDate(t2); 
     480                assert(d.year == 2004); 
     481                assert(d.month == 2); 
     482                assert(d.day == 3); 
     483                assert(d.era == Gregorian.AD_ERA); 
     484                assert(d.doy == 34); 
     485                assert(d.dow == Gregorian.DayOfWeek.Tuesday); 
     486 
     487                assert(t == t2); 
    411488        } 
    412489}