--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.util.CheapDateFormatter\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.util;\r
+\r
+/**\r
+ * This class contains static methods for formatting dates into Strings.\r
+ * It can be used where standard Date formatting is judged to be too\r
+ * expensive.\r
+ */\r
+public class CheapDateFormatter {\r
+ static final long SECONDS = 1000L;\r
+ static final long MINUTES = SECONDS * 60L;\r
+ static final long HOURS = MINUTES * 60L;\r
+ static final long DAYS = HOURS * 24L;\r
+ static final long NORMAL_YEAR = DAYS * 365L;\r
+ static final long LEAP_YEAR = NORMAL_YEAR + DAYS;\r
+ static final long FOURYEARS = (NORMAL_YEAR * 3L) + LEAP_YEAR;\r
+ static final long END_OF_FIRST_YEAR = NORMAL_YEAR;\r
+ static final long END_OF_SECOND_YEAR = END_OF_FIRST_YEAR + LEAP_YEAR;\r
+ static final long END_OF_THIRD_YEAR = END_OF_SECOND_YEAR + NORMAL_YEAR;\r
+ static final int[] DAYS_IN_MONTH = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\r
+ static final int FEBRUARY = 1;\r
+\r
+ /**\r
+ * This method formats the current date into a String. The input is\r
+ * a long representing the number of milliseconds since Jan. 1, 1970.\r
+ * The output is a String in the form yyyy/mm/dd hh:mm:ss.ddd GMT.\r
+ *\r
+ * The purpose of this class is to format date strings without paying\r
+ * the price of instantiating ResourceBundles and Locales, which the\r
+ * java.util.Date class does whenever you format a date string.\r
+ * As a result, the output of this class is not localized, it does\r
+ * not take the local time zone into account, and it is possible that\r
+ * it will not be as accurate as the standard Date class. It is OK\r
+ * to use this method when, for example, formatting timestamps to\r
+ * write to db2j.LOG, but not for manipulating dates in language\r
+ * processing.\r
+ *\r
+ * @param time The current time in milliseconds since Jan. 1, 1970\r
+ *\r
+ * @return The date formatted as yyyy/mm/dd hh:mm:ss.ddd GMT.\r
+ */\r
+ public static String formatDate(long time) {\r
+ // Assume not a leap year until we know otherwise\r
+ boolean leapYear = false;\r
+\r
+ // How many four year periods since Jan. 1, 1970?\r
+ long year = ((time / FOURYEARS) * 4L);\r
+\r
+ // How much time is left over after the four-year periods?\r
+ long leftover = time % FOURYEARS;\r
+ time -= (year / 4L) * FOURYEARS;\r
+\r
+ year += 1970L;\r
+\r
+ // Does time extend past end of first year in four-year period?\r
+ if (leftover >= END_OF_FIRST_YEAR) {\r
+ year++;\r
+ time -= NORMAL_YEAR;\r
+ }\r
+\r
+ // Does time extend past end of second year in four-year period?\r
+ if (leftover >= END_OF_SECOND_YEAR) {\r
+ year++;\r
+ time -= NORMAL_YEAR;\r
+ }\r
+\r
+ // Does time extend past end of third year in four-year period?\r
+ if (leftover >= END_OF_THIRD_YEAR) {\r
+ year++;\r
+ time -= LEAP_YEAR;\r
+ }\r
+\r
+ // It's a leap year if divisible by 4, unless divisible by 100,\r
+ // unless divisible by 400.\r
+ if ((year % 4L) == 0) {\r
+ if ((year % 100L) == 0) {\r
+ if ((year % 400L) == 0) {\r
+ leapYear = true;\r
+ }\r
+ }\r
+ leapYear = true;\r
+ }\r
+\r
+ // What day of the year is this, starting at 1?\r
+ long days = (time / DAYS) + 1;\r
+\r
+ // What month is this, starting at 1?\r
+ int month = 1;\r
+ for (int i = 0; i < DAYS_IN_MONTH.length; i++) {\r
+ int daysInMonth;\r
+\r
+ if (leapYear && (i == FEBRUARY)) {\r
+ // February has 29 days in a leap year\r
+ daysInMonth = 29;\r
+ } else {\r
+ // Get number of days in next month\r
+ daysInMonth = DAYS_IN_MONTH[i];\r
+ }\r
+\r
+ // Is date after the month we are looking at?\r
+ if (days > daysInMonth) {\r
+ // Count number of months\r
+ month++;\r
+\r
+ // Subtract number of days in month\r
+ days -= daysInMonth;\r
+ } else {\r
+ // Don't bother to look any more - the date is within\r
+ // the current month.\r
+ break;\r
+ }\r
+ }\r
+\r
+ // How much time is left after days are accounted for?\r
+ time %= DAYS;\r
+\r
+ long hours = time / HOURS;\r
+\r
+ // How much time is left after hours are accounted for?\r
+ time %= HOURS;\r
+\r
+ long minutes = time / MINUTES;\r
+\r
+ // How much time is left after minutes are accounted for?\r
+ time %= MINUTES;\r
+\r
+ long seconds = time / SECONDS;\r
+\r
+ // How much time is left after seconds are accounted for?\r
+ time %= SECONDS;\r
+\r
+ return year + "-" +\r
+ twoDigits(month) + "-" +\r
+ twoDigits(days) + " " +\r
+ twoDigits(hours) + ":" +\r
+ twoDigits(minutes) + ":" +\r
+ twoDigits(seconds) + "." +\r
+ threeDigits(time) + " GMT";\r
+ }\r
+\r
+ private static String twoDigits(long val) {\r
+ String retval;\r
+\r
+ if (val < 10) {\r
+ retval = "0" + val;\r
+ } else {\r
+ retval = Long.toString(val);\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ private static String threeDigits(long val) {\r
+ String retval;\r
+\r
+ if (val < 10) {\r
+ retval = "00" + val;\r
+ } else if (val < 100) {\r
+ retval = "0" + val;\r
+ } else {\r
+ retval = Long.toString(val);\r
+ }\r
+\r
+ return retval;\r
+ }\r
+}\r