001/*
002 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
003 *
004 * Based in London, we are world leaders in the design and development
005 * of bespoke applications for the securities financing markets.
006 *
007 * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
008 *           ___  _     _           _   _          _
009 *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
010 *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
011 *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
012 *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
013 *                   |__/
014 *
015 *                     www.ObjectLab.co.uk
016 *
017 * $Id$
018 *
019 * Copyright 2006 the original author or authors.
020 *
021 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
022 * use this file except in compliance with the License. You may obtain a copy of
023 * the License at
024 *
025 * http://www.apache.org/licenses/LICENSE-2.0
026 *
027 * Unless required by applicable law or agreed to in writing, software
028 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
029 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
030 * License for the specific language governing permissions and limitations under
031 * the License.
032 */
033package net.objectlab.kit.datecalc.common;
034
035import java.util.Calendar;
036import java.util.Date;
037import java.util.GregorianCalendar;
038
039/**
040 * Convert Excel Date to Jdk <code>Date</code> or <code>Calendar</code>.
041 *
042 * @author Benoit Xhenseval
043 *
044 */
045public final class ExcelDateUtil {
046    private static final double HALF_MILLISEC = 0.5;
047
048    private static final int EXCEL_FUDGE_19000229 = 61;
049
050    private static final int EXCEL_WINDOWING_1904 = 1904;
051
052    private static final int EXCEL_BASE_YEAR = 1900;
053
054    private static final long DAY_MILLISECONDS = 24 * 60 * 60 * 1000L;
055
056    private ExcelDateUtil() {
057    }
058
059    /**
060     * Given an Excel date with either 1900 or 1904 date windowing, converts it
061     * to a java.util.Date.
062     *
063     * @param excelDate
064     *            The Excel date.
065     * @param use1904windowing
066     *            true if date uses 1904 windowing, or false if using 1900 date
067     *            windowing.
068     * @return Java representation of the date without any time.
069     *
070     * @see java.util.TimeZone
071     */
072    public static Calendar getJavaCalendar(final double excelDate, final boolean use1904windowing) {
073        if (isValidExcelDate(excelDate)) {
074            int startYear = EXCEL_BASE_YEAR;
075            int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which
076            // it isn't
077            final int wholeDays = (int) Math.floor(excelDate);
078            if (use1904windowing) {
079                startYear = EXCEL_WINDOWING_1904;
080                dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the
081                // first day
082            } else if (wholeDays < EXCEL_FUDGE_19000229) {
083                // Date is prior to 3/1/1900, so adjust because Excel thinks
084                // 2/29/1900 exists
085                // If Excel date == 2/29/1900, will become 3/1/1900 in Java
086                // representation
087                dayAdjust = 0;
088            }
089            final GregorianCalendar calendar = new GregorianCalendar(startYear, 0, wholeDays + dayAdjust);
090            final int millisecondsInDay = (int) ((excelDate - Math.floor(excelDate)) * DAY_MILLISECONDS + HALF_MILLISEC);
091            calendar.set(Calendar.MILLISECOND, millisecondsInDay);
092            return calendar;
093        } else {
094            return null;
095        }
096
097    }
098
099    // -----------------------------------------------------------------------
100    //
101    // ObjectLab, world leaders in the design and development of bespoke
102    // applications for the securities financing markets.
103    // www.ObjectLab.co.uk
104    //
105    // -----------------------------------------------------------------------
106
107    /**
108     * Given an Excel date with either 1900 or 1904 date windowing, converts it
109     * to a java.util.Date.
110     *
111     * @param excelDate
112     *            The Excel date.
113     * @param use1904windowing
114     *            true if date uses 1904 windowing, or false if using 1900 date
115     *            windowing.
116     * @return Java representation of the date without any time.
117     *
118     * @see java.util.TimeZone
119     */
120    public static Date getJavaDateOnly(final double excelDate, final boolean use1904windowing) {
121        final Calendar javaCalendar = getJavaCalendar(excelDate, use1904windowing);
122        if (javaCalendar == null) {
123            return null;
124        }
125        return Utils.blastTime(javaCalendar).getTime();
126    }
127
128    /**
129     * Given an Excel date with either 1900 or 1904 date windowing, converts it
130     * to a java.util.Date.
131     *
132     * NOTE: If the default <code>TimeZone</code> in Java uses Daylight Saving
133     * Time then the conversion back to an Excel date may not give the same
134     * value, that is the comparison <CODE>excelDate ==
135     * getExcelDate(getJavaDate(excelDate,false))</CODE> is not always true.
136     * For example if default timezone is <code>Europe/Copenhagen</code>, on
137     * 2004-03-28 the minute after 01:59 CET is 03:00 CEST, if the excel date
138     * represents a time between 02:00 and 03:00 then it is converted to past
139     * 03:00 summer time
140     *
141     * @param excelDate
142     *            The Excel date.
143     * @param use1904windowing
144     *            true if date uses 1904 windowing, or false if using 1900 date
145     *            windowing.
146     * @return Java representation of the date, or null if date is not a valid
147     *         Excel date
148     * @see java.util.TimeZone
149     */
150    public static Date getJavaDate(final double excelDate, final boolean use1904windowing) {
151        final Calendar cal = getJavaCalendar(excelDate, use1904windowing);
152        return cal == null ? null : cal.getTime();
153    }
154
155    /**
156     * Given a double, checks if it is a valid Excel date.
157     *
158     * @return true if valid
159     * @param excelDate
160     *            the double value
161     */
162    public static boolean isValidExcelDate(final double excelDate) {
163        return excelDate > -Double.MIN_VALUE;
164    }
165}
166
167/*
168 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
169 *
170 * Based in London, we are world leaders in the design and development
171 * of bespoke applications for the securities financing markets.
172 *
173 * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
174 *           ___  _     _           _   _          _
175 *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
176 *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
177 *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
178 *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
179 *                   |__/
180 *
181 *                     www.ObjectLab.co.uk
182 */