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