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

Changeset 3059

Show
Ignore:
Timestamp:
12/20/07 11:10:58 (1 year ago)
Author:
schveiguy
Message:

Added BC date capability to Gregorian Calendar.
Added some unit tests to Gregorian Calendar.

Files:

Legend:

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

    r3040 r3059  
    135135        Time toTime (Date d)  
    136136        { 
    137                 return toTime (d.year, d.month, d.day, 0, 0, 0, 0, CURRENT_ERA); 
     137                return toTime (d.year, d.month, d.day, 0, 0, 0, 0, d.era); 
    138138        } 
    139139 
     
    145145        Time toTime (Date d, TimeOfDay t)  
    146146        { 
    147                 return toTime (d.year, d.month, d.day, t.hours, t.minutes, t.seconds, t.millis, CURRENT_ERA); 
     147                return toTime (d.year, d.month, d.day, t.hours, t.minutes, t.seconds, t.millis, d.era); 
    148148        } 
    149149 
  • trunk/tango/time/chrono/Gregorian.d

    r3040 r3059  
    88                        Apr 2007: reshaped                         
    99 
    10         author:         John Chapman, Kris 
     10        author:         John Chapman, Kris, schveiguy 
    1111 
    1212******************************************************************************/ 
     
    1515 
    1616private import tango.time.chrono.Calendar; 
    17  
    1817 
    1918/** 
    2019 * $(ANCHOR _Gregorian) 
    2120 * Represents the Gregorian calendar. 
    22 */ 
     21 * 
     22 * Note that this is the Proleptic Gregorian calendar.  Most calendars assume 
     23 * that dates before 9/14/1752 were Julian Dates.  Julian differs from 
     24 * Gregorian in that leap years occur every 4 years, even on 100 year 
     25 * increments.  The Proleptic Gregorian calendar applies the Gregorian leap 
     26 * year rules to dates before 9/14/1752, making the calculation of dates much 
     27 * easier. 
     28 */ 
    2329class Gregorian : Calendar  
    2430{ 
     
    4450        * Represents the current era. 
    4551        */ 
    46         enum {AD_ERA = 1, MAX_YEAR = 9999}; 
     52        enum {AD_ERA = 1, BC_ERA = 2, MAX_YEAR = 9999}; 
    4753 
    4854        private static final uint[] DaysToMonthCommon = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; 
     
    8288        override Time toTime (uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era) 
    8389        { 
    84                 return Time (getDateTicks(year, month, day) + getTimeTicks(hour, minute, second)) + TimeSpan.millis(millisecond); 
     90                return Time (getDateTicks(year, month, day, era) + getTimeTicks(hour, minute, second)) + TimeSpan.millis(millisecond); 
    8591        } 
    8692 
     
    9298        override DayOfWeek getDayOfWeek(Time time)  
    9399        { 
    94                 return cast(DayOfWeek)((time.ticks / TimeSpan.TicksPerDay + 1) % 7); 
     100                int dow; 
     101                if(time.ticks < 0) 
     102                { 
     103                        dow = ((time.ticks + 1) / TimeSpan.TicksPerDay) % 7; 
     104                        if(dow < 0) 
     105                                dow += 7; 
     106                } 
     107                else 
     108                        dow = (time.ticks / TimeSpan.TicksPerDay + 1) % 7; 
     109                return cast(DayOfWeek)dow; 
    95110        } 
    96111 
     
    138153        * Overridden. Returns the era in the specified Time. 
    139154        * Params: time = A Time value. 
    140         * Returns: An integer representing the ear in time. 
     155        * Returns: An integer representing the era in time. 
    141156        */ 
    142157        override uint getEra(Time time)  
    143158        { 
    144                 return AD_ERA; 
     159                if(time < time.epoch) 
     160                        return BC_ERA; 
     161                else 
     162                        return AD_ERA; 
    145163        } 
    146164 
     
    155173        override uint getDaysInMonth(uint year, uint month, uint era)  
    156174        { 
    157                 auto monthDays = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonthLeap : DaysToMonthCommon; 
     175                auto monthDays = isLeapYear(year, era) ? DaysToMonthLeap : DaysToMonthCommon; 
    158176                return monthDays[month] - monthDays[month - 1]; 
    159177        } 
     
    191209        override bool isLeapYear(uint year, uint era)  
    192210        { 
    193                 return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); 
     211                return staticIsLeapYear(year, era); 
    194212        } 
    195213 
     
    209227        override uint[] eras()  
    210228        {        
    211                 uint[] tmp = [AD_ERA]; 
     229                uint[] tmp = [AD_ERA, BC_ERA]; 
    212230                return tmp.dup; 
    213231        } 
     
    224242        override void split(Time time, ref uint year, ref uint month, ref uint day, ref uint doy, ref uint dow, ref uint era) 
    225243        { 
    226             splitDate(time.ticks, year, month, day, doy); 
    227             era = AD_ERA; 
     244            splitDate(time.ticks, year, month, day, doy, era); 
    228245            dow = getDayOfWeek(time); 
    229246        } 
    230247 
    231         package static void splitDate (long ticks, ref uint year, ref uint month, ref uint day, ref uint dayOfYear)  
    232         { 
    233                 auto numDays = cast(int)(ticks / TimeSpan.TicksPerDay); 
    234                 auto whole400Years = numDays / cast(int) TimeSpan.DaysPer400Years; 
    235                 numDays -= whole400Years * cast(int) TimeSpan.DaysPer400Years; 
    236                 auto whole100Years = numDays / cast(int) TimeSpan.DaysPer100Years; 
    237                 if (whole100Years == 4) 
    238                     whole100Years = 3; 
    239  
    240                 numDays -= whole100Years * cast(int) TimeSpan.DaysPer100Years; 
    241                 auto whole4Years = numDays / cast(int) TimeSpan.DaysPer4Years; 
    242                 numDays -= whole4Years * cast(int) TimeSpan.DaysPer4Years; 
    243                 auto wholeYears = numDays / cast(int) TimeSpan.DaysPerYear; 
    244                 if (wholeYears == 4) 
    245                     wholeYears = 3; 
    246  
    247                 year = whole400Years * 400 + whole100Years * 100 + whole4Years * 4 + wholeYears + 1; 
    248                 numDays -= wholeYears * TimeSpan.DaysPerYear; 
     248        package static void splitDate (long ticks, ref uint year, ref uint month, ref uint day, ref uint dayOfYear, ref uint era)  
     249        { 
     250                int numDays; 
     251 
     252                void calculateYear() 
     253                { 
     254                        auto whole400Years = numDays / cast(int) TimeSpan.DaysPer400Years; 
     255                        numDays -= whole400Years * cast(int) TimeSpan.DaysPer400Years; 
     256                        auto whole100Years = numDays / cast(int) TimeSpan.DaysPer100Years; 
     257                        if (whole100Years == 4) 
     258                                whole100Years = 3; 
     259 
     260                        numDays -= whole100Years * cast(int) TimeSpan.DaysPer100Years; 
     261                        auto whole4Years = numDays / cast(int) TimeSpan.DaysPer4Years; 
     262                        numDays -= whole4Years * cast(int) TimeSpan.DaysPer4Years; 
     263                        auto wholeYears = numDays / cast(int) TimeSpan.DaysPerYear; 
     264                        if (wholeYears == 4) 
     265                                wholeYears = 3; 
     266 
     267                        year = whole400Years * 400 + whole100Years * 100 + whole4Years * 4 + wholeYears + era; 
     268                        numDays -= wholeYears * TimeSpan.DaysPerYear; 
     269                } 
     270 
     271                if(ticks < 0) 
     272                { 
     273                        // in the BC era 
     274                        era = BC_ERA; 
     275                        // 
     276                        // set up numDays to be like AD.  AD days start at 
     277                        // year 1.  However, in BC, year 1 is like AD year 0, 
     278                        // so we must subtract one year. 
     279                        // 
     280                        numDays = cast(int)((-ticks - 1) / TimeSpan.TicksPerDay); 
     281                        if(numDays < 366) 
     282                        { 
     283                                // in the year 1 B.C.  This is a special case 
     284                                // leap year 
     285                                year = 1; 
     286                        } 
     287                        else 
     288                        { 
     289                                numDays -= 366; 
     290                                calculateYear; 
     291                        } 
     292                        // 
     293                        // numDays is the number of days back from the end of 
     294                        // the year, because the original ticks were negative 
     295                        // 
     296                        numDays = (staticIsLeapYear(year, era) ? 366 : 365) - numDays - 1; 
     297                } 
     298                else 
     299                { 
     300                        era = AD_ERA; 
     301                        numDays = cast(int)(ticks / TimeSpan.TicksPerDay); 
     302                        calculateYear; 
     303                } 
    249304                dayOfYear = numDays + 1; 
    250305 
    251                 auto monthDays = (wholeYears == 3 && (whole4Years != 24 || whole100Years == 3)) ? DaysToMonthLeap : DaysToMonthCommon; 
     306                auto monthDays = staticIsLeapYear(year, era) ? DaysToMonthLeap : DaysToMonthCommon; 
    252307                month = numDays >> 5 + 1; 
    253308                while (numDays >= monthDays[month]) 
     
    259314        package static uint extractPart (long ticks, DatePart part)  
    260315        { 
    261                 uint year, month, day, dayOfYear
    262  
    263                 splitDate(ticks, year, month, day, dayOfYear); 
     316                uint year, month, day, dayOfYear, era
     317 
     318                splitDate(ticks, year, month, day, dayOfYear, era); 
    264319 
    265320                if (part is DatePart.Year) 
     
    275330        } 
    276331 
    277         package long getDateTicks (uint year, uint month, uint day)  
    278         { 
    279                 auto monthDays = isLeapYear(year, AD_ERA) ? DaysToMonthLeap : DaysToMonthCommon; 
    280                 year--; 
    281                 return (year * 365 + year / 4 - year / 100 + year / 400 + monthDays[month - 1] + day - 1) * TimeSpan.TicksPerDay; 
     332        package static long getDateTicks (uint year, uint month, uint day, uint era)  
     333        { 
     334                auto monthDays = staticIsLeapYear(year, era) ? DaysToMonthLeap : DaysToMonthCommon; 
     335                if(era == BC_ERA) 
     336                { 
     337                        year += 2; 
     338                        return -cast(long)( (year - 3) * 365 + year / 4 - year / 100 + year / 400 + monthDays[12] - (monthDays[month - 1] + day - 1)) * TimeSpan.TicksPerDay; 
     339                } 
     340                else 
     341                { 
     342                        year--; 
     343                        return (year * 365 + year / 4 - year / 100 + year / 400 + monthDays[month - 1] + day - 1) * TimeSpan.TicksPerDay; 
     344                } 
     345        } 
     346 
     347        package static bool staticIsLeapYear(uint year, uint era) 
     348        { 
     349                if(era == BC_ERA) 
     350                        return staticIsLeapYear(year - 1, AD_ERA); 
     351                if(era == AD_ERA) 
     352                        return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); 
     353                return false; 
    282354        } 
    283355} 
     356 
     357debug(Gregorian) 
     358{ 
     359        import tango.io.Stdout; 
     360 
     361        void output(Time t) 
     362        { 
     363                Date d = Gregorian.generic.toDate(t); 
     364                TimeOfDay tod = t.time; 
     365                Stdout.format("{}/{}/{:d4} {} {}:{:d2}:{:d2}.{:d3} dow:{}", 
     366                                d.month, d.day, d.year, d.era == Gregorian.AD_ERA ? "AD" : "BC", 
     367                                tod.hours, tod.minutes, tod.seconds, tod.millis, d.dow).newline; 
     368        } 
     369 
     370        void main() 
     371        { 
     372                Time t = Time(365 * TimeSpan.TicksPerDay); 
     373                output(t); 
     374                for(int i = 0; i < 366 + 365; i++) 
     375                { 
     376                        t -= TimeSpan.days(1); 
     377                        output(t); 
     378                } 
     379        } 
     380} 
     381 
     382debug(UnitTest) 
     383{ 
     384        debug(Gregorian) 
     385        { 
     386        } 
     387        else 
     388        { 
     389                void main() {} 
     390        } 
     391 
     392        unittest 
     393        { 
     394                // 
     395                // check Gregorian date handles positive time. 
     396                // 
     397                Time t = Time.epoch + TimeSpan.days(365); 
     398                Date d = Gregorian.generic.toDate(t); 
     399                assert(d.year == 2); 
     400                assert(d.month == 1); 
     401                assert(d.day == 1); 
     402                assert(d.era == Gregorian.AD_ERA); 
     403                assert(d.doy == 1); 
     404                // 
     405                // note that this is in disagreement with the Julian Calendar 
     406                // 
     407                assert(d.dow == Gregorian.DayOfWeek.Tuesday); 
     408 
     409                // 
     410                // check that it handles negative time 
     411                // 
     412                t = Time.epoch - TimeSpan.days(366); 
     413                d = Gregorian.generic.toDate(t); 
     414                assert(d.year == 1); 
     415                assert(d.month == 1); 
     416                assert(d.day == 1); 
     417                assert(d.era == Gregorian.BC_ERA); 
     418                assert(d.doy == 1); 
     419                assert(d.dow == Gregorian.DayOfWeek.Saturday); 
     420 
     421        } 
     422} 
  • trunk/tango/time/chrono/GregorianBased.d

    r3040 r3059  
    103103      long getTicks(uint year, uint month, uint day) 
    104104      { 
    105         return Gregorian.generic.getDateTicks(year, month, day); 
     105        return Gregorian.generic.getDateTicks(year, month, day, Gregorian.AD_ERA); 
    106106      } 
    107107      eraRanges[Gregorian.JAPAN] ~= EraRange(4, getTicks(1989, 1, 8), 1988, 1, Gregorian.MAX_YEAR);