1 /*
2  * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.util.calendar;
27 
28 import java.util.TimeZone;
29 
30 /**
31  * Julian calendar implementation.
32  *
33  * @author Masayoshi Okutsu
34  * @since 1.5
35  */
36 public class JulianCalendar extends BaseCalendar {
37 
38     private static final int BCE = 0;
39     private static final int CE = 1;
40 
41     private static final Era[] eras = {
42         new Era("BeforeCommonEra", "B.C.E.", Long.MIN_VALUE, false),
43         new Era("CommonEra", "C.E.", -62135709175808L, true)
44     };
45     private static final int JULIAN_EPOCH = -1;
46 
47     private static class Date extends BaseCalendar.Date {
Date()48         protected Date() {
49             super();
50             setCache(1, -1L, 365); // January 1, 1 CE (Julian)
51         }
52 
Date(TimeZone zone)53         protected Date(TimeZone zone) {
54             super(zone);
55             setCache(1, -1L, 365); // January 1, 1 CE (Julian)
56         }
57 
setEra(Era era)58         public Date setEra(Era era) {
59             if (era == null) {
60                 throw new NullPointerException();
61             }
62             if (era != eras[0] || era != eras[1]) {
63                 throw new IllegalArgumentException("unknown era: " + era);
64             }
65             super.setEra(era);
66             return this;
67         }
68 
setKnownEra(Era era)69         protected void setKnownEra(Era era) {
70             super.setEra(era);
71         }
72 
getNormalizedYear()73         public int getNormalizedYear() {
74             if (getEra() == eras[BCE]) {
75                 return 1 - getYear();
76             }
77             return getYear();
78         }
79 
80         // Use the year numbering ..., -2, -1, 0, 1, 2, ... for
81         // normalized years. This differs from "Calendrical
82         // Calculations" in which the numbering is ..., -2, -1, 1, 2,
83         // ...
setNormalizedYear(int year)84         public void setNormalizedYear(int year) {
85             if (year <= 0) {
86                 setYear(1 - year);
87                 setKnownEra(eras[BCE]);
88             } else {
89                 setYear(year);
90                 setKnownEra(eras[CE]);
91             }
92         }
93 
toString()94         public String toString() {
95             String time = super.toString();
96             time = time.substring(time.indexOf('T'));
97             StringBuffer sb = new StringBuffer();
98             Era era = getEra();
99             if (era != null) {
100                 String n = era.getAbbreviation();
101                 if (n != null) {
102                     sb.append(n).append(' ');
103                 }
104             }
105             sb.append(getYear()).append('-');
106             CalendarUtils.sprintf0d(sb, getMonth(), 2).append('-');
107             CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
108             sb.append(time);
109             return sb.toString();
110         }
111     }
112 
JulianCalendar()113     JulianCalendar() {
114         setEras(eras);
115     }
116 
getName()117     public String getName() {
118         return "julian";
119     }
120 
getCalendarDate()121     public Date getCalendarDate() {
122         return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
123     }
124 
getCalendarDate(long millis)125     public Date getCalendarDate(long millis) {
126         return getCalendarDate(millis, newCalendarDate());
127     }
128 
getCalendarDate(long millis, CalendarDate date)129     public Date getCalendarDate(long millis, CalendarDate date) {
130         return (Date) super.getCalendarDate(millis, date);
131     }
132 
getCalendarDate(long millis, TimeZone zone)133     public Date getCalendarDate(long millis, TimeZone zone) {
134         return getCalendarDate(millis, newCalendarDate(zone));
135     }
136 
newCalendarDate()137     public Date newCalendarDate() {
138         return new Date();
139     }
140 
newCalendarDate(TimeZone zone)141     public Date newCalendarDate(TimeZone zone) {
142         return new Date(zone);
143     }
144 
145     /**
146      * @param jyear normalized Julian year
147      */
getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date cache)148     public long getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date cache) {
149         boolean isJan1 = month == JANUARY && dayOfMonth == 1;
150 
151         // Look up the one year cache
152         if (cache != null && cache.hit(jyear)) {
153             if (isJan1) {
154                 return cache.getCachedJan1();
155             }
156             return cache.getCachedJan1() + getDayOfYear(jyear, month, dayOfMonth) - 1;
157         }
158 
159         long y = jyear;
160         long days = JULIAN_EPOCH - 1 + (365 * (y - 1)) + dayOfMonth;
161         if (y > 0) {
162             // CE years
163             days += (y - 1) / 4;
164         } else {
165             // BCE years
166             days += CalendarUtils.floorDivide(y - 1, 4);
167         }
168         if (month > 0) {
169             days += ((367 * (long) month) - 362) / 12;
170         } else {
171             days += CalendarUtils.floorDivide((367 * (long) month) - 362, 12);
172         }
173         if (month > FEBRUARY) {
174             days -= CalendarUtils.isJulianLeapYear(jyear) ? 1 : 2;
175         }
176 
177         // If it's January 1, update the cache.
178         if (cache != null && isJan1) {
179             cache.setCache(jyear, days, CalendarUtils.isJulianLeapYear(jyear) ? 366 : 365);
180         }
181 
182         return days;
183     }
184 
getCalendarDateFromFixedDate(CalendarDate date, long fixedDate)185     public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
186         Date jdate = (Date) date;
187         long fd = 4 * (fixedDate - JULIAN_EPOCH) + 1464;
188         int year;
189         if (fd >= 0) {
190             year = (int)(fd / 1461);
191         } else {
192             year = (int) CalendarUtils.floorDivide(fd, 1461);
193         }
194         int priorDays = (int)(fixedDate - getFixedDate(year, JANUARY, 1, jdate));
195         boolean isLeap = CalendarUtils.isJulianLeapYear(year);
196         if (fixedDate >= getFixedDate(year, MARCH, 1, jdate)) {
197             priorDays += isLeap ? 1 : 2;
198         }
199         int month = 12 * priorDays + 373;
200         if (month > 0) {
201             month /= 367;
202         } else {
203             month = CalendarUtils.floorDivide(month, 367);
204         }
205         int dayOfMonth = (int)(fixedDate - getFixedDate(year, month, 1, jdate)) + 1;
206         int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
207         assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
208         jdate.setNormalizedYear(year);
209         jdate.setMonth(month);
210         jdate.setDayOfMonth(dayOfMonth);
211         jdate.setDayOfWeek(dayOfWeek);
212         jdate.setLeapYear(isLeap);
213         jdate.setNormalized(true);
214     }
215 
216     /**
217      * Returns the normalized Julian year number of the given fixed date.
218      */
getYearFromFixedDate(long fixedDate)219     public int getYearFromFixedDate(long fixedDate) {
220         int year = (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461);
221         return year;
222     }
223 
getDayOfWeek(CalendarDate date)224     public int getDayOfWeek(CalendarDate date) {
225         // TODO: should replace this with a faster calculation, such
226         // as cache table lookup
227         long fixedDate = getFixedDate(date);
228         return getDayOfWeekFromFixedDate(fixedDate);
229     }
230 
isLeapYear(int jyear)231     boolean isLeapYear(int jyear) {
232         return CalendarUtils.isJulianLeapYear(jyear);
233     }
234 }
235