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