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