001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003: package jodd.datetime;
004:
005: /**
006: * Date time calculations and utilities. <code>TimeUtil</code> is used by
007: * {@link JDateTime} and it contains few utilities that may be used
008: * elswhere, although {@link JDateTime} is recomended for all time
009: * manipulation.
010: */
011: public class TimeUtil {
012:
013: public static final long MILLIS_IN_DAY = 1000L * 60 * 60 * 24;
014:
015: // ---------------------------------------------------------------- misc calc
016:
017: /**
018: * Calculates day of year from given time stamp.
019: * It may not work for some dates in 1582.
020: *
021: * @return day of year in range: [1-366]
022: */
023: public static int dayOfYear(int year, int month, int day) {
024: int day_of_year;
025: if (isLeapYear(year)) {
026: day_of_year = ((275 * month) / 9) - ((month + 9) / 12)
027: + day - 30;
028: } else {
029: day_of_year = ((275 * month) / 9)
030: - (((month + 9) / 12) << 1) + day - 30;
031: }
032: return day_of_year;
033: }
034:
035: /**
036: * Check if the given year is leap year.
037: *
038: * @return <code>true</code> if the year is a leap year
039: */
040: public static boolean isLeapYear(int y) {
041: boolean result = false;
042:
043: if (((y % 4) == 0) && // must be divisible by 4...
044: ((y < 1582) || // and either before reform year...
045: ((y % 100) != 0) || // or not a century...
046: ((y % 400) == 0))) { // or a multiple of 400...
047: result = true; // for leap year.
048: }
049: return result;
050: }
051:
052: private static final int[] MONTH_LENGTH = { 0, 31, 28, 31, 30, 31,
053: 30, 31, 31, 30, 31, 30, 31 };
054: private static final int[] LEAP_MONTH_LENGTH = { 0, 31, 29, 31, 30,
055: 31, 30, 31, 31, 30, 31, 30, 31 };
056:
057: /**
058: * Returns the length of the specified month in days. Month is 1 for January
059: * and 12 for December.
060: *
061: * @return length of the specified month in days
062: */
063: public static int getMonthLength(int year, int m) {
064: if ((m < 1) || (m > 12)) {
065: return -1;
066: }
067: if (isLeapYear(year)) {
068: return LEAP_MONTH_LENGTH[m];
069: }
070: return MONTH_LENGTH[m];
071: }
072:
073: // ---------------------------------------------------------------- valid
074:
075: /**
076: * Checks if date is valid.
077: *
078: * @return <code>true</code> if date is valid, otherwise <code>false</code>
079: */
080: public static boolean isValidDate(int year, int month, int day) {
081: if ((month < 1) || (month > 12)) {
082: return false;
083: }
084: int ml = getMonthLength(year, month);
085: //noinspection RedundantIfStatement
086: if ((day < 1) || (day > ml)) {
087: return false;
088: }
089: return true;
090: }
091:
092: /**
093: * Checks if time is valid.
094: *
095: * @param hour hour to check
096: * @param minute minute to check
097: * @param second second to check
098: *
099: * @return <code>true</code> if time is valid, otherwise <code>false</code>
100: */
101: public static boolean isValidTime(int hour, int minute,
102: double second) {
103: if ((hour < 0) || (hour >= 24)) {
104: return false;
105: }
106: if ((minute < 0) || (minute >= 60)) {
107: return false;
108: }
109: //noinspection RedundantIfStatement
110: if ((second < 0) || (second >= 60)) {
111: return false;
112: }
113: return true;
114: }
115:
116: /**
117: * Checks if date and time are valid.
118: *
119: * @param year year to check
120: * @param month month to check
121: * @param day day to check
122: * @param hour hour to check
123: * @param minute minute to check
124: * @param second second to check
125: *
126: * @return <code>true</code> if date and time are valid, otherwise <code>false</code>
127: */
128: public static boolean isValidDateTime(int year, int month, int day,
129: int hour, int minute, double second) {
130: return (isValidDate(year, month, day) && isValidTime(hour,
131: minute, second));
132: }
133:
134: /**
135: * Checks if date and time are valid.
136: *
137: * @param dts date/time stamp
138: *
139: * @return <code>true</code> if date and time are valid, otherwise <code>false</code>
140: */
141: public static boolean isValidDateTime(DateTimeStamp dts) {
142: return (isValidDate(dts.year, dts.month, dts.day) && isValidTime(
143: dts.hour, dts.minute, dts.second));
144: }
145:
146: // ---------------------------------------------------------------- julian date
147:
148: /**
149: * Calculates Astronomical Julian Date from given time stamp.
150: *
151: * @return Julian Date stamp
152: */
153: public static JulianDateStamp toJulianDate(DateTimeStamp time) {
154: return toJulianDate(time.year, time.month, time.day, time.hour,
155: time.minute, time.second);
156: }
157:
158: /**
159: * Calculates Astronomical Julian Date from given time.<p>
160: *
161: * Astronomical Julian Dates are counting from noon of the January 1st, -4712
162: * (julian date 0 is -4712/01/01 12:00:00). Zero year exist. Julian Date
163: * is always GMT, there are no timezones.
164: * <p>
165: *
166: * Algorithm based on Numerical Recipesin C, 2nd ed., Cambridge University
167: * Press 1992, modified and enhanced by Igor Spasic.
168: *
169: * @param year year
170: * @param month month
171: * @param day day
172: * @param hour hour
173: * @param minute minute
174: * @param second second
175: *
176: * @return julian time stamp
177: */
178: public static JulianDateStamp toJulianDate(int year, int month,
179: int day, int hour, int minute, double second) {
180: //double JD;
181: JulianDateStamp jds = new JulianDateStamp();
182:
183: // month range fix
184: if ((month > 12) || (month < -12)) {
185: month--;
186: int delta = month / 12;
187: year += delta;
188: month -= delta * 12;
189: month++;
190: }
191: if (month < 0) {
192: year--;
193: month += 12;
194: }
195:
196: // decimal day fraction
197: double frac = (hour / 24.0) + (minute / 1440.0)
198: + (second / 86400.0);
199: if (frac < 0) { // negative time fix
200: int delta = ((int) (-frac)) + 1;
201: frac += delta;
202: day -= delta;
203: }
204: double gyr = year + (0.01 * month) + (0.0001 * day)
205: + (0.0001 * frac) + 1.0e-9;
206:
207: // conversion factors
208: int iy0;
209: int im0;
210: if (month <= 2) {
211: iy0 = year - 1;
212: im0 = month + 12;
213: } else {
214: iy0 = year;
215: im0 = month;
216: }
217: int ia = iy0 / 100;
218: int ib = 2 - ia + (ia >> 2);
219:
220: // calculate julian date
221: int jd;
222: if (year <= 0) {
223: jd = (int) ((365.25 * iy0) - 0.75)
224: + (int) (30.6001 * (im0 + 1)) + day + 1720994;
225: } else {
226: jd = (int) (365.25 * iy0) + (int) (30.6001 * (im0 + 1))
227: + day + 1720994;
228: }
229: if (gyr >= 1582.1015) { // on or after 15 October 1582
230: jd += ib;
231: }
232: //JD = jd + frac + 0.5;
233: // return JD
234:
235: jds.integer = jd;
236: jds.fraction = frac + 0.5;
237: return jds;
238: }
239:
240: /**
241: * Calculates time stamp from Astronomical Julian Date.
242: *
243: * @param JD julian date
244: *
245: * @return time stamp
246: */
247: public static DateTimeStamp fromJulianDate(double JD) {
248: return fromJulianDate(new JulianDateStamp(JD));
249: }
250:
251: /**
252: * Calculates time stamp from Astronomical Julian Date.
253: * Algorithm based on Numerical Recipesin C, 2nd ed., Cambridge University
254: * Press 1992.
255: *
256: * @param jds julian date stamp
257: *
258: * @return time stamp
259: */
260: public static DateTimeStamp fromJulianDate(JulianDateStamp jds) {
261: DateTimeStamp time = new DateTimeStamp();
262: int year, month, day;
263: double frac;
264: int jd, ka, kb, kc, kd, ke, ialp;
265: double d_hour, d_minute;
266:
267: //double JD = jds.doubleValue();//jdate;
268: //jd = (int)(JD + 0.5); // integer julian date
269: //frac = JD + 0.5 - (double)jd + 1.0e-10; // day fraction
270:
271: ka = (int) (jds.fraction + 0.5);
272: jd = jds.integer + ka;
273: frac = jds.fraction + 0.5 - ka + 1e-10;
274:
275: ka = jd;
276: if (jd >= 2299161) {
277: ialp = (int) (((double) jd - 1867216.25) / (36524.25));
278: ka = jd + 1 + ialp - (ialp >> 2);
279: }
280: kb = ka + 1524;
281: kc = (int) (((double) kb - 122.1) / 365.25);
282: kd = (int) ((double) kc * 365.25);
283: ke = (int) ((double) (kb - kd) / 30.6001);
284: day = kb - kd - ((int) ((double) ke * 30.6001));
285: if (ke > 13) {
286: month = ke - 13;
287: } else {
288: month = ke - 1;
289: }
290: if ((month == 2) && (day > 28)) {
291: day = 29;
292: }
293: if ((month == 2) && (day == 29) && (ke == 3)) {
294: year = kc - 4716;
295: } else if (month > 2) {
296: year = kc - 4716;
297: } else {
298: year = kc - 4715;
299: }
300: time.year = year;
301: time.month = month;
302: time.day = day;
303:
304: // hour with minute and second included as fraction
305: d_hour = frac * 24.0;
306: time.hour = (int) d_hour; // integer hour
307:
308: // minute with second included as a fraction
309: d_minute = (d_hour - (double) time.hour) * 60.0;
310: time.minute = (int) d_minute; // integer minute
311:
312: time.second = (d_minute - (double) time.minute) * 60.0;
313:
314: // fix calculation errors
315: time.second = ((int) (time.second * 10000) + 0.5) / 10000.0;
316: return time;
317: }
318:
319: }
|