blob: d14e685f38a5b33a3eec4a74b33769c9187b464a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.util.calendar;
27
28import java.util.TimeZone;
29
30/**
31 * Julian calendar implementation.
32 *
33 * @author Masayoshi Okutsu
34 * @since 1.5
35 */
36public 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 {
48 protected Date() {
49 super();
50 setCache(1, -1L, 365); // January 1, 1 CE (Julian)
51 }
52
53 protected Date(TimeZone zone) {
54 super(zone);
55 setCache(1, -1L, 365); // January 1, 1 CE (Julian)
56 }
57
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
69 protected void setKnownEra(Era era) {
70 super.setEra(era);
71 }
72
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 // ...
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
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
113 JulianCalendar() {
114 setEras(eras);
115 }
116
117 public String getName() {
118 return "julian";
119 }
120
121 public Date getCalendarDate() {
122 return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
123 }
124
125 public Date getCalendarDate(long millis) {
126 return getCalendarDate(millis, newCalendarDate());
127 }
128
129 public Date getCalendarDate(long millis, CalendarDate date) {
130 return (Date) super.getCalendarDate(millis, date);
131 }
132
133 public Date getCalendarDate(long millis, TimeZone zone) {
134 return getCalendarDate(millis, newCalendarDate(zone));
135 }
136
137 public Date newCalendarDate() {
138 return new Date();
139 }
140
141 public Date newCalendarDate(TimeZone zone) {
142 return new Date(zone);
143 }
144
145 /**
146 * @param jyear normalized Julian year
147 */
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
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 */
219 public int getYearFromFixedDate(long fixedDate) {
220 int year = (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461);
221 return year;
222 }
223
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
231 boolean isLeapYear(int jyear) {
232 return CalendarUtils.isJulianLeapYear(jyear);
233 }
234}