001 /*
002 * Copyright 2001-2005 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.time.chrono.gj;
017
018 import org.joda.time.DateTimeField;
019
020 /**
021 * A reference Julian chronology implementation, intended for testing purposes
022 * only. Correctness is favored over performance. The key functions for date
023 * calculations are based on ones provided in "Calendrical Calculations", ISBN
024 * 0-521-77752-6.
025 *
026 * @author Brian S O'Neill
027 */
028 public final class TestJulianChronology extends TestGJChronology {
029
030 private static final long JULIAN_EPOCH;
031
032 static {
033 // Constant as defined in book.
034 JULIAN_EPOCH = new TestGregorianChronology().fixedFromGJ(0, 12, 30);
035 }
036
037 /**
038 * Constructs with an epoch of 1969-12-19.
039 */
040 public TestJulianChronology() {
041 super(1969, 12, 19);
042 }
043
044 public TestJulianChronology(int epochYear, int epochMonth, int epochDay) {
045 super(epochYear, epochMonth, epochDay);
046 }
047
048 public DateTimeField dayOfMonth() {
049 return new TestJulianDayOfMonthField(this);
050 }
051
052 public DateTimeField weekyear() {
053 return new TestJulianWeekyearField(this);
054 }
055
056 public DateTimeField monthOfYear() {
057 return new TestJulianMonthOfYearField(this);
058 }
059
060 public DateTimeField year() {
061 return new TestJulianYearField(this);
062 }
063
064 public String toString() {
065 return "TestJulianChronology";
066 }
067
068 long millisPerYear() {
069 return (long)(365.25 * MILLIS_PER_DAY);
070 }
071
072 long millisPerMonth() {
073 return (long)(365.25 * MILLIS_PER_DAY / 12);
074 }
075
076 boolean isLeapYear(int year) {
077 if (year == 0) {
078 throw new IllegalArgumentException("Illegal year: " + year);
079 }
080 return mod(year, 4) == (year > 0 ? 0 : 3);
081 }
082
083 /**
084 * @return days from 0001-01-01
085 */
086 long fixedFromGJ(int year, int monthOfYear, int dayOfMonth) {
087 if (year == 0) {
088 throw new IllegalArgumentException("Illegal year: " + year);
089 }
090 int y = (year < 0) ? year + 1 : year;
091 long y_m1 = y - 1;
092 long f = JULIAN_EPOCH - 1 + 365 * y_m1 + div(y_m1, 4)
093 + div(367 * monthOfYear - 362, 12) + dayOfMonth;
094 if (monthOfYear > 2) {
095 f += isLeapYear(year) ? -1 : -2;
096 }
097 return f;
098 }
099
100 /**
101 * @param date days from 0001-01-01
102 * @return gj year
103 */
104 int gjYearFromFixed(long date) {
105 return gjFromFixed(date)[0];
106 }
107
108 /**
109 * @param date days from 0001-01-01
110 * @return gj year, monthOfYear, dayOfMonth
111 */
112 int[] gjFromFixed(long date) {
113 long approx = div(4 * (date - JULIAN_EPOCH) + 1464, 1461);
114 long year = (approx <= 0) ? approx - 1 : approx;
115 int year_i = (int)year;
116 if (year_i != year) {
117 throw new RuntimeException("year cannot be cast to an int: " + year);
118 }
119 long priorDays = date - fixedFromGJ(year_i, 1, 1);
120 long correction;
121 if (date < fixedFromGJ(year_i, 3, 1)) {
122 correction = 0;
123 } else if (isLeapYear(year_i)) {
124 correction = 1;
125 } else {
126 correction = 2;
127 }
128 int monthOfYear = (int)div(12 * (priorDays + correction) + 373, 367);
129 int day = (int)(date - fixedFromGJ(year_i, monthOfYear, 1) + 1);
130
131 return new int[]{year_i, monthOfYear, day};
132 }
133
134 long fixedFromISO(int weekyear, int weekOfWeekyear, int dayOfWeek) {
135 if (weekyear == 0) {
136 throw new IllegalArgumentException("Illegal weekyear: " + weekyear);
137 }
138 if (weekyear == 1) {
139 weekyear = -1;
140 } else {
141 weekyear--;
142 }
143 return nthWeekday(weekOfWeekyear, 0, weekyear, 12, 28) + dayOfWeek;
144 }
145
146 /**
147 * @param date days from 0001-01-01
148 * @return iso weekyear, weekOfWeekyear, dayOfWeek (1=Monday to 7)
149 */
150 int[] isoFromFixed(long date) {
151 int weekyear = gjYearFromFixed(date - 3);
152 int nextWeekyear;
153 if (weekyear == -1) {
154 nextWeekyear = 1;
155 } else {
156 nextWeekyear = weekyear + 1;
157 }
158 if (date >= fixedFromISO(nextWeekyear, 1, 1)) {
159 weekyear = nextWeekyear;
160 }
161 int weekOfWeekyear = (int)(div(date - fixedFromISO(weekyear, 1, 1), 7) + 1);
162 int dayOfWeek = (int)amod(date, 7);
163 return new int[]{weekyear, weekOfWeekyear, dayOfWeek};
164 }
165 }