001: /*
002:
003: Derby - Class org.apache.derby.iapi.util.CheapDateFormatter
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.iapi.util;
023:
024: /**
025: * This class contains static methods for formatting dates into Strings.
026: * It can be used where standard Date formatting is judged to be too
027: * expensive.
028: */
029: public class CheapDateFormatter {
030: static final long SECONDS = 1000L;
031: static final long MINUTES = SECONDS * 60L;
032: static final long HOURS = MINUTES * 60L;
033: static final long DAYS = HOURS * 24L;
034: static final long NORMAL_YEAR = DAYS * 365L;
035: static final long LEAP_YEAR = NORMAL_YEAR + DAYS;
036: static final long FOURYEARS = (NORMAL_YEAR * 3L) + LEAP_YEAR;
037: static final long END_OF_FIRST_YEAR = NORMAL_YEAR;
038: static final long END_OF_SECOND_YEAR = END_OF_FIRST_YEAR
039: + LEAP_YEAR;
040: static final long END_OF_THIRD_YEAR = END_OF_SECOND_YEAR
041: + NORMAL_YEAR;
042: static final int[] DAYS_IN_MONTH = { 31, 28, 31, 30, 31, 30, 31,
043: 31, 30, 31, 30, 31 };
044: static final int FEBRUARY = 1;
045:
046: /**
047: * This method formats the current date into a String. The input is
048: * a long representing the number of milliseconds since Jan. 1, 1970.
049: * The output is a String in the form yyyy/mm/dd hh:mm:ss.ddd GMT.
050: *
051: * The purpose of this class is to format date strings without paying
052: * the price of instantiating ResourceBundles and Locales, which the
053: * java.util.Date class does whenever you format a date string.
054: * As a result, the output of this class is not localized, it does
055: * not take the local time zone into account, and it is possible that
056: * it will not be as accurate as the standard Date class. It is OK
057: * to use this method when, for example, formatting timestamps to
058: * write to db2j.LOG, but not for manipulating dates in language
059: * processing.
060: *
061: * @param time The current time in milliseconds since Jan. 1, 1970
062: *
063: * @return The date formatted as yyyy/mm/dd hh:mm:ss.ddd GMT.
064: */
065: public static String formatDate(long time) {
066: // Assume not a leap year until we know otherwise
067: boolean leapYear = false;
068:
069: // How many four year periods since Jan. 1, 1970?
070: long year = ((time / FOURYEARS) * 4L);
071:
072: // How much time is left over after the four-year periods?
073: long leftover = time % FOURYEARS;
074: time -= (year / 4L) * FOURYEARS;
075:
076: year += 1970L;
077:
078: // Does time extend past end of first year in four-year period?
079: if (leftover >= END_OF_FIRST_YEAR) {
080: year++;
081: time -= NORMAL_YEAR;
082: }
083:
084: // Does time extend past end of second year in four-year period?
085: if (leftover >= END_OF_SECOND_YEAR) {
086: year++;
087: time -= NORMAL_YEAR;
088: }
089:
090: // Does time extend past end of third year in four-year period?
091: if (leftover >= END_OF_THIRD_YEAR) {
092: year++;
093: time -= LEAP_YEAR;
094: }
095:
096: // It's a leap year if divisible by 4, unless divisible by 100,
097: // unless divisible by 400.
098: if ((year % 4L) == 0) {
099: if ((year % 100L) == 0) {
100: if ((year % 400L) == 0) {
101: leapYear = true;
102: }
103: }
104: leapYear = true;
105: }
106:
107: // What day of the year is this, starting at 1?
108: long days = (time / DAYS) + 1;
109:
110: // What month is this, starting at 1?
111: int month = 1;
112: for (int i = 0; i < DAYS_IN_MONTH.length; i++) {
113: int daysInMonth;
114:
115: if (leapYear && (i == FEBRUARY)) {
116: // February has 29 days in a leap year
117: daysInMonth = 29;
118: } else {
119: // Get number of days in next month
120: daysInMonth = DAYS_IN_MONTH[i];
121: }
122:
123: // Is date after the month we are looking at?
124: if (days > daysInMonth) {
125: // Count number of months
126: month++;
127:
128: // Subtract number of days in month
129: days -= daysInMonth;
130: } else {
131: // Don't bother to look any more - the date is within
132: // the current month.
133: break;
134: }
135: }
136:
137: // How much time is left after days are accounted for?
138: time %= DAYS;
139:
140: long hours = time / HOURS;
141:
142: // How much time is left after hours are accounted for?
143: time %= HOURS;
144:
145: long minutes = time / MINUTES;
146:
147: // How much time is left after minutes are accounted for?
148: time %= MINUTES;
149:
150: long seconds = time / SECONDS;
151:
152: // How much time is left after seconds are accounted for?
153: time %= SECONDS;
154:
155: return year + "-" + twoDigits(month) + "-" + twoDigits(days)
156: + " " + twoDigits(hours) + ":" + twoDigits(minutes)
157: + ":" + twoDigits(seconds) + "." + threeDigits(time)
158: + " GMT";
159: }
160:
161: private static String twoDigits(long val) {
162: String retval;
163:
164: if (val < 10) {
165: retval = "0" + val;
166: } else {
167: retval = Long.toString(val);
168: }
169:
170: return retval;
171: }
172:
173: private static String threeDigits(long val) {
174: String retval;
175:
176: if (val < 10) {
177: retval = "00" + val;
178: } else if (val < 100) {
179: retval = "0" + val;
180: } else {
181: retval = Long.toString(val);
182: }
183:
184: return retval;
185: }
186: }
|