View | Details | Raw Unified | Return to bug 14375
Collapse All | Expand All

(-)src/java/org/apache/poi/hssf/model/Workbook.java (+17 lines)
Lines 88-93 Link Here
88
 * @author  Andrew C. Oliver (acoliver at apache dot org)
88
 * @author  Andrew C. Oliver (acoliver at apache dot org)
89
 * @author  Glen Stampoultzis (glens at apache.org)
89
 * @author  Glen Stampoultzis (glens at apache.org)
90
 * @author  Sergei Kozello (sergeikozello at mail.ru)
90
 * @author  Sergei Kozello (sergeikozello at mail.ru)
91
 * @author  Dan Sherman (dsherman at isisph.com)
91
 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
92
 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
92
 * @version 1.0-pre
93
 * @version 1.0-pre
93
 */
94
 */
Lines 155-160 Link Here
155
    0;   // holds the position of sup book
156
    0;   // holds the position of sup book
156
    private short              maxformatid  =
157
    private short              maxformatid  =
157
    -1;  // holds the max format id
158
    -1;  // holds the max format id
159
    private boolean            uses1904datewindowing  =
160
    false;  // whether 1904 date windowing is being used
158
161
159
    private static POILogger   log         =
162
    private static POILogger   log         =
160
    POILogFactory.getLogger(Workbook.class);
163
    POILogFactory.getLogger(Workbook.class);
Lines 248-253 Link Here
248
		    retval.formats.add(rec);
251
		    retval.formats.add(rec);
249
		    retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
252
		    retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
250
		    break;
253
		    break;
254
                case DateWindow1904Record.sid :
255
                    log.log(DEBUG, "found datewindow1904 record at " + k);
256
                    retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1;
257
                    break;
251
258
252
                default :
259
                default :
253
            }
260
            }
Lines 1900-1904 Link Here
1900
    public List getRecords()
1907
    public List getRecords()
1901
    {
1908
    {
1902
        return records;
1909
        return records;
1910
    }
1911
1912
    /**
1913
    * Whether date windowing is based on 1/2/1904 or 1/1/1900.
1914
    * Some versions of Excel (Mac) can save workbooks using 1904 date windowing.
1915
    *
1916
    * @return true if using 1904 date windowing
1917
    */
1918
    public boolean isUsing1904DateWindowing() {
1919
        return uses1904datewindowing;
1903
    }
1920
    }
1904
}
1921
}
(-)src/java/org/apache/poi/hssf/usermodel/HSSFCell.java (-1 / +7 lines)
Lines 94-99 Link Here
94
 * NOTE: the alpha won't be implementing formulas
94
 * NOTE: the alpha won't be implementing formulas
95
 *
95
 *
96
 * @author  Andrew C. Oliver (acoliver at apache dot org)
96
 * @author  Andrew C. Oliver (acoliver at apache dot org)
97
 * @author  Dan Sherman (dsherman at isisph.com)
97
 * @version 1.0-pre
98
 * @version 1.0-pre
98
 */
99
 */
99
100
Lines 783-789 Link Here
783
            throw new NumberFormatException(
784
            throw new NumberFormatException(
784
                "You cannot get a date value from an error cell");
785
                "You cannot get a date value from an error cell");
785
        }
786
        }
786
        return HSSFDateUtil.getJavaDate(cellValue);
787
        if (book.isUsing1904DateWindowing()) {
788
            return HSSFDateUtil.getJavaDate(cellValue,true);
789
        }
790
        else {
791
            return HSSFDateUtil.getJavaDate(cellValue,false);
792
        }
787
    }
793
    }
788
794
789
    /**
795
    /**
(-)src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java (-13 / +47 lines)
Lines 69-74 Link Here
69
 *
69
 *
70
 * @author  Michael Harhen
70
 * @author  Michael Harhen
71
 * @author  Glen Stampoultzis (glens at apache.org)
71
 * @author  Glen Stampoultzis (glens at apache.org)
72
 * @author  Dan Sherman (dsherman at isisph.com)
72
 */
73
 */
73
74
74
public class HSSFDateUtil
75
public class HSSFDateUtil
Lines 115-147 Link Here
115
116
116
    /**
117
    /**
117
     * Given a excel date, converts it into a Date.
118
     * Given a excel date, converts it into a Date.
119
     * Assumes 1900 date windowing.
118
     *
120
     *
119
     * @param  date the Excel Date
121
     * @param  date the Excel Date
120
     *
122
     *
121
     * @return Java representation of a date (null if error)
123
     * @return Java representation of a date (null if error)
124
     * @see #getJavaDate(double,boolean)
122
     */
125
     */
123
126
124
    public static Date getJavaDate(double date)
127
    public static Date getJavaDate(double date)
125
    {
128
    {
126
        if (isValidExcelDate(date))
129
        return getJavaDate(date,false);
127
        {
130
    }
128
            int               wholeDaysSince1900 = ( int ) Math.floor(date);
131
    
129
            GregorianCalendar calendar           = new GregorianCalendar(1900,
132
    /**
130
                                                       0, wholeDaysSince1900
133
     *  Given an Excel date with either 1900 or 1904 date windowing,
131
                                                       - 1);
134
     *  converts it to a java.util.Date.
132
            int               millisecondsInDay  =
135
     *
133
                ( int ) ((date - Math.floor(date))
136
     *  @param date  The Excel date.
134
                         * ( double ) DAY_MILLISECONDS + 0.5);
137
     *  @param use1904windowing  true if date uses 1904 windowing,
135
138
     *   or false if using 1900 date windowing.
139
     *  @return Java representation of the date, or null if date is not a valid Excel date
140
     */
141
    public static Date getJavaDate(double date, boolean use1904windowing) {
142
        if (isValidExcelDate(date)) {
143
            int startYear = 1900;
144
            int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
145
            int wholeDays = (int)Math.floor(date);
146
            if (use1904windowing) {
147
                startYear = 1904;
148
                dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
149
            }
150
            else if (wholeDays < 61) {
151
                // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists
152
                // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation
153
                dayAdjust = 0;
154
            }
155
            GregorianCalendar calendar = new GregorianCalendar(startYear,0,
156
                                                     wholeDays + dayAdjust);
157
            int millisecondsInDay = (int)((date - Math.floor(date)) * 
158
                                          (double) DAY_MILLISECONDS + 0.5);
136
            calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
159
            calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
137
            return calendar.getTime();
160
            return calendar.getTime();
138
        }
161
        }
139
        else
162
        else {
140
        {
141
            return null;
163
            return null;
142
        }
164
        }
143
    }
165
    }
144
    
166
145
    /**
167
    /**
146
     * given a format ID this will check whether the format represents
168
     * given a format ID this will check whether the format represents
147
     * an internal date format or not. 
169
     * an internal date format or not. 
Lines 164-169 Link Here
164
                case 0x2d:
186
                case 0x2d:
165
                case 0x2e:
187
                case 0x2e:
166
                case 0x2f:
188
                case 0x2f:
189
                // Additional internal date formats found by inspection
190
                // Using Excel v.X 10.1.0 (Mac)
191
                case 0xa4:
192
                case 0xa5:
193
                case 0xa6:
194
                case 0xa7:
195
                case 0xa8:
196
                case 0xa9:
197
                case 0xaa:
198
                case 0xab:
199
                case 0xac:
200
                case 0xad:
167
                    retval = true;
201
                    retval = true;
168
                    break;
202
                    break;
169
                    
203
                    

Return to bug 14375