KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > hssf > usermodel > HSSFDateUtil


1 /* ====================================================================
2    Copyright 2002-2004 Apache Software Foundation
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15 ==================================================================== */

16
17
18
19 /*
20  * DateUtil.java
21  *
22  * Created on January 19, 2002, 9:30 AM
23  */

24 package org.apache.poi.hssf.usermodel;
25
26 import java.util.Calendar JavaDoc;
27 import java.util.Date JavaDoc;
28 import java.util.GregorianCalendar JavaDoc;
29
30 /**
31  * Contains methods for dealing with Excel dates.
32  *
33  * @author Michael Harhen
34  * @author Glen Stampoultzis (glens at apache.org)
35  * @author Dan Sherman (dsherman at isisph.com)
36  * @author Hack Kampbjorn (hak at 2mba.dk)
37  */

38
39 public class HSSFDateUtil
40 {
41     private HSSFDateUtil()
42     {
43     }
44
45     private static final int BAD_DATE =
46         -1; // used to specify that date is invalid
47
private static final long DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
48     private static final double CAL_1900_ABSOLUTE =
49         ( double ) absoluteDay(new GregorianCalendar JavaDoc(1900, Calendar
50         .JANUARY, 1)) - 2.0;
51
52     /**
53      * Given a Date, converts it into a double representing its internal Excel representation,
54      * which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.
55      *
56      * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
57      * @param date the Date
58      */

59
60     public static double getExcelDate(Date JavaDoc date)
61     {
62         Calendar JavaDoc calStart = new GregorianCalendar JavaDoc();
63
64         calStart.setTime(
65             date); // If date includes hours, minutes, and seconds, set them to 0
66
if (calStart.get(Calendar.YEAR) < 1900)
67         {
68             return BAD_DATE;
69         }
70         else
71         {
72         // Because of daylight time saving we cannot use
73
// date.getTime() - calStart.getTimeInMillis()
74
// as the difference in milliseconds between 00:00 and 04:00
75
// can be 3, 4 or 5 hours but Excel expects it to always
76
// be 4 hours.
77
// E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours
78
// and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours
79
double fraction = (((calStart.get(Calendar.HOUR_OF_DAY) * 60
80                                  + calStart.get(Calendar.MINUTE)
81                                 ) * 60 + calStart.get(Calendar.SECOND)
82                                ) * 1000 + calStart.get(Calendar.MILLISECOND)
83                               ) / ( double ) DAY_MILLISECONDS;
84             calStart = dayStart(calStart);
85
86             return fraction + ( double ) absoluteDay(calStart)
87                    - CAL_1900_ABSOLUTE;
88         }
89     }
90
91     /**
92      * Given a excel date, converts it into a Date.
93      * Assumes 1900 date windowing.
94      *
95      * @param date the Excel Date
96      *
97      * @return Java representation of a date (null if error)
98      * @see #getJavaDate(double,boolean)
99      */

100
101     public static Date JavaDoc getJavaDate(double date)
102     {
103         return getJavaDate(date,false);
104     }
105     
106     /**
107      * Given an Excel date with either 1900 or 1904 date windowing,
108      * converts it to a java.util.Date.
109      *
110      * NOTE: If the default <code>TimeZone</code> in Java uses Daylight
111      * Saving Time then the conversion back to an Excel date may not give
112      * the same value, that is the comparison
113      * <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE>
114      * is not always true. For example if default timezone is
115      * <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after
116      * 01:59 CET is 03:00 CEST, if the excel date represents a time between
117      * 02:00 and 03:00 then it is converted to past 03:00 summer time
118      *
119      * @param date The Excel date.
120      * @param use1904windowing true if date uses 1904 windowing,
121      * or false if using 1900 date windowing.
122      * @return Java representation of the date, or null if date is not a valid Excel date
123      * @see java.util.TimeZone
124      */

125     public static Date JavaDoc getJavaDate(double date, boolean use1904windowing) {
126         if (isValidExcelDate(date)) {
127             int startYear = 1900;
128             int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
129
int wholeDays = (int)Math.floor(date);
130             if (use1904windowing) {
131                 startYear = 1904;
132                 dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
133
}
134             else if (wholeDays < 61) {
135                 // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
136
// If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
137
dayAdjust = 0;
138             }
139             GregorianCalendar JavaDoc calendar = new GregorianCalendar JavaDoc(startYear,0,
140                                                      wholeDays + dayAdjust);
141             int millisecondsInDay = (int)((date - Math.floor(date)) *
142                                           (double) DAY_MILLISECONDS + 0.5);
143             calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
144             return calendar.getTime();
145         }
146         else {
147             return null;
148         }
149     }
150
151     /**
152      * given a format ID this will check whether the format represents
153      * an internal date format or not.
154      */

155     public static boolean isInternalDateFormat(int format) {
156       boolean retval =false;
157
158             switch(format) {
159                 // Internal Date Formats as described on page 427 in
160
// Microsoft Excel Dev's Kit...
161
case 0x0e:
162                 case 0x0f:
163                 case 0x10:
164                 case 0x11:
165                 case 0x12:
166                 case 0x13:
167                 case 0x14:
168                 case 0x15:
169                 case 0x16:
170                 case 0x2d:
171                 case 0x2e:
172                 case 0x2f:
173                     retval = true;
174                     break;
175                     
176                 default:
177                     retval = false;
178                     break;
179             }
180        return retval;
181     }
182
183     /**
184      * Check if a cell contains a date
185      * Since dates are stored internally in Excel as double values
186      * we infer it is a date if it is formatted as such.
187      * @see #isInternalDateFormat(int)
188      */

189     public static boolean isCellDateFormatted(HSSFCell cell) {
190         if (cell == null) return false;
191         boolean bDate = false;
192         
193         double d = cell.getNumericCellValue();
194         if ( HSSFDateUtil.isValidExcelDate(d) ) {
195             HSSFCellStyle style = cell.getCellStyle();
196             int i = style.getDataFormat();
197             bDate = isInternalDateFormat(i);
198         }
199         return bDate;
200     }
201
202
203     /**
204      * Given a double, checks if it is a valid Excel date.
205      *
206      * @return true if valid
207      * @param value the double value
208      */

209
210     public static boolean isValidExcelDate(double value)
211     {
212         return (value > -Double.MIN_VALUE);
213     }
214
215     /**
216      * Given a Calendar, return the number of days since 1600/12/31.
217      *
218      * @return days number of days since 1600/12/31
219      * @param cal the Calendar
220      * @exception IllegalArgumentException if date is invalid
221      */

222
223     private static int absoluteDay(Calendar JavaDoc cal)
224     {
225         return cal.get(Calendar.DAY_OF_YEAR)
226                + daysInPriorYears(cal.get(Calendar.YEAR));
227     }
228
229     /**
230      * Return the number of days in prior years since 1601
231      *
232      * @return days number of days in years prior to yr.
233      * @param yr a year (1600 < yr < 4000)
234      * @exception IllegalArgumentException if year is outside of range.
235      */

236
237     private static int daysInPriorYears(int yr)
238     {
239         if (yr < 1601)
240         {
241             throw new IllegalArgumentException JavaDoc(
242                 "'year' must be 1601 or greater");
243         }
244         int y = yr - 1601;
245         int days = 365 * y // days in prior years
246
+ y / 4 // plus julian leap days in prior years
247
- y / 100 // minus prior century years
248
+ y / 400; // plus years divisible by 400
249

250         return days;
251     }
252
253     // set HH:MM:SS fields of cal to 00:00:00:000
254
private static Calendar JavaDoc dayStart(final Calendar JavaDoc cal)
255     {
256         cal.get(Calendar
257             .HOUR_OF_DAY); // force recalculation of internal fields
258
cal.set(Calendar.HOUR_OF_DAY, 0);
259         cal.set(Calendar.MINUTE, 0);
260         cal.set(Calendar.SECOND, 0);
261         cal.set(Calendar.MILLISECOND, 0);
262         cal.get(Calendar
263             .HOUR_OF_DAY); // force recalculation of internal fields
264
return cal;
265     }
266
267     // ---------------------------------------------------------------------------------------------------------
268
}
269
Popular Tags