1 /******************************************************************************* 2 3 copyright: Copyright (c) 2005 John Chapman. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Mid 2005: Initial release 8 Apr 2007: reshaped 9 10 author: John Chapman, Kris 11 12 ******************************************************************************/ 13 14 module tango.time.chrono.GregorianBased; 15 16 private import tango.core.Exception; 17 18 private import tango.time.Time; 19 20 private import tango.time.chrono.Gregorian; 21 22 23 24 class GregorianBased : Gregorian { 25 26 private EraRange[] eraRanges_; 27 private int maxYear_, minYear_; 28 private int currentEra_ = -1; 29 30 this() 31 { 32 eraRanges_ = EraRange.getEraRanges(id); 33 maxYear_ = eraRanges_[0].maxEraYear; 34 minYear_ = eraRanges_[0].minEraYear; 35 currentEra_ = EraRange.getCurrentEra(id); 36 } 37 38 public override const Time toTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era) { 39 year = getGregorianYear(year, era); 40 return super.toTime(year, month, day, hour, minute, second, millisecond, era); 41 } 42 public override const uint getYear(const(Time) time) { 43 auto ticks = time.ticks; 44 auto year = extractPart(time.ticks, DatePart.Year); 45 foreach (EraRange eraRange; eraRanges_) { 46 if (ticks >= eraRange.ticks) 47 return year - eraRange.yearOffset; 48 } 49 throw new IllegalArgumentException("Value was out of range."); 50 } 51 52 public override const uint getEra(const(Time) time) { 53 auto ticks = time.ticks; 54 foreach (EraRange eraRange; eraRanges_) { 55 if (ticks >= eraRange.ticks) 56 return eraRange.era; 57 } 58 throw new IllegalArgumentException("Value was out of range."); 59 } 60 61 public override const uint[] eras() { 62 uint[] result; 63 foreach (EraRange eraRange; eraRanges_) 64 result ~= eraRange.era; 65 return result; 66 } 67 68 private const uint getGregorianYear(uint year, uint era) { 69 if (era == 0) 70 era = currentEra; 71 foreach (EraRange eraRange; eraRanges_) { 72 if (era == eraRange.era) { 73 if (year >= eraRange.minEraYear && year <= eraRange.maxEraYear) 74 return eraRange.yearOffset + year; 75 throw new IllegalArgumentException("Value was out of range."); 76 } 77 } 78 throw new IllegalArgumentException("Era value was not valid."); 79 } 80 81 @property protected const uint currentEra() { 82 return currentEra_; 83 } 84 } 85 86 87 88 package struct EraRange { 89 90 private static EraRange[][uint] eraRanges; 91 private static uint[uint] currentEras; 92 private static bool initialized_; 93 94 package uint era; 95 package long ticks; 96 package uint yearOffset; 97 package uint minEraYear; 98 package uint maxEraYear; 99 100 private static void initialize() { 101 if (!initialized_) { 102 long getTicks(uint year, uint month, uint day) 103 { 104 return Gregorian.generic.getDateTicks(year, month, day, Gregorian.AD_ERA); 105 } 106 eraRanges[Gregorian.JAPAN] ~= EraRange(4, getTicks(1989, 1, 8), 1988, 1, Gregorian.MAX_YEAR); 107 eraRanges[Gregorian.JAPAN] ~= EraRange(3, getTicks(1926, 12, 25), 1925, 1, 1989); 108 eraRanges[Gregorian.JAPAN] ~= EraRange(2, getTicks(1912, 7, 30), 1911, 1, 1926); 109 eraRanges[Gregorian.JAPAN] ~= EraRange(1, getTicks(1868, 9, 8), 1867, 1, 1912); 110 eraRanges[Gregorian.TAIWAN] ~= EraRange(1, getTicks(1912, 1, 1), 1911, 1, Gregorian.MAX_YEAR); 111 eraRanges[Gregorian.KOREA] ~= EraRange(1, getTicks(1, 1, 1), -2333, 2334, Gregorian.MAX_YEAR); 112 eraRanges[Gregorian.THAI] ~= EraRange(1, getTicks(1, 1, 1), -543, 544, Gregorian.MAX_YEAR); 113 currentEras[Gregorian.JAPAN] = 4; 114 currentEras[Gregorian.TAIWAN] = 1; 115 currentEras[Gregorian.KOREA] = 1; 116 currentEras[Gregorian.THAI] = 1; 117 initialized_ = true; 118 } 119 } 120 121 package static EraRange[] getEraRanges(uint calID) { 122 if (!initialized_) 123 initialize(); 124 return eraRanges[calID]; 125 } 126 127 package static uint getCurrentEra(uint calID) { 128 if (!initialized_) 129 initialize(); 130 return currentEras[calID]; 131 } 132 133 private static EraRange opCall(uint era, long ticks, uint yearOffset, uint minEraYear, uint prevEraYear) { 134 EraRange eraRange; 135 eraRange.era = era; 136 eraRange.ticks = ticks; 137 eraRange.yearOffset = yearOffset; 138 eraRange.minEraYear = minEraYear; 139 eraRange.maxEraYear = prevEraYear - yearOffset; 140 return eraRange; 141 } 142 143 } 144