dealing with Excel dates : UNIX Win32 « Development Class « Java






dealing with Excel dates

   
/**
 * 
 * LibFormula : a free Java formula library
 * 
 *
 * Project Info:  http://reporting.pentaho.org/libformula/
 *
 * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
 *
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 *
 * ------------
 * $Id: HSSFDateUtil.java 3522 2007-10-16 10:56:57Z tmorgner $
 * ------------
 * (C) Copyright 2006-2007, by Pentaho Corporation.
 */

/*
 * DateUtil.java
 *
 * Created on January 19, 2002, 9:30 AM
 */

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Contains methods for dealing with Excel dates. <br/> Modified by Cedric
 * Pronzato
 * 
 * @author Michael Harhen
 * @author Glen Stampoultzis (glens at apache.org)
 * @author Dan Sherman (dsherman at isisph.com)
 * @author Hack Kampbjorn (hak at 2mba.dk)
 */

public class HSSFDateUtil {
  private HSSFDateUtil() {
  }

  private static final int BAD_DATE = -1; // used to specify that date is
                                          // invalid

  private static final long DAY_MILLISECONDS = 24 * 60 * 60 * 1000;

  private static final double CAL_1900_ABSOLUTE = (double) absoluteDay(new GregorianCalendar(1900,
      Calendar.JANUARY, 1)) - 2.0;

  /**
   * Given a Date, converts it into a double representing its internal Excel
   * representation, which is the number of days since 1/1/1900. Fractional days
   * represent hours, minutes, and seconds.
   * 
   * @return Excel representation of Date (-1 if error - test for error by
   *         checking for less than 0.1)
   * @param date
   *          the Date
   */

  public static double getExcelDate(final Date date) {
    Calendar calStart = new GregorianCalendar();

    calStart.setTime(date); // If date includes hours, minutes, and seconds, set
                            // them to 0
    // if (calStart.get(Calendar.YEAR) < 1900)
    // {
    // return BAD_DATE;
    // }
    // else
    // {
    // Because of daylight time saving we cannot use
    // date.getTime() - calStart.getTimeInMillis()
    // as the difference in milliseconds between 00:00 and 04:00
    // can be 3, 4 or 5 hours but Excel expects it to always
    // be 4 hours.
    // E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours
    // and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours
    final double fraction = (((calStart.get(Calendar.HOUR_OF_DAY) * 60 + calStart
        .get(Calendar.MINUTE)) * 60 + calStart.get(Calendar.SECOND)) * 1000 + calStart
        .get(Calendar.MILLISECOND))
        / (double) DAY_MILLISECONDS;
    calStart = dayStart(calStart);

    return fraction + (double) absoluteDay(calStart) - CAL_1900_ABSOLUTE;
  }

  // }

  /**
   * Given a excel date, converts it into a Date. Assumes 1900 date windowing.
   * 
   * @param date
   *          the Excel Date
   * 
   * @return Java representation of a date (null if error)
   * @see #getJavaDate(double,boolean)
   */

  public static Date getJavaDate(final double date) {

    return getJavaDate(date, true);
  }

  /**
   * Given an Excel date with either 1900 or 1904 date windowing, converts it to
   * a java.util.Date.
   * 
   * NOTE: If the default <code>TimeZone</code> in Java uses Daylight Saving
   * Time then the conversion back to an Excel date may not give the same value,
   * that is the comparison <CODE>excelDate ==
   * getExcelDate(getJavaDate(excelDate,false))</CODE> is not always true. For
   * example if default timezone is <code>Europe/Copenhagen</code>, on
   * 2004-03-28 the minute after 01:59 CET is 03:00 CEST, if the excel date
   * represents a time between 02:00 and 03:00 then it is converted to past
   * 03:00 summer time
   * 
   * @param date
   *          The Excel date.
   * @param use1904windowing
   *          true if date uses 1904 windowing, or false if using 1900 date
   *          windowing.
   * @return Java representation of the date, or null if date is not a valid
   *         Excel date
   * @see java.util.TimeZone
   */
  public static Date getJavaDate(final double date, final boolean use1904windowing) {
    if (isValidExcelDate(date)) {
      int startYear = 1900;
      int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it
                          // isn't
      final int wholeDays = (int) Math.floor(date);
      if (use1904windowing) {
        startYear = 1904;
        dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day
      } else if (wholeDays < 61) {
        // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900
        // exists
        // If Excel date == 2/29/1900, will become 3/1/1900 in Java
        // representation
        dayAdjust = 0;
      }
      final GregorianCalendar calendar = new GregorianCalendar(startYear, 0, wholeDays + dayAdjust);
      final int millisecondsInDay = (int) ((date - Math.floor(date)) * (double) DAY_MILLISECONDS + 0.5);
      calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
      return calendar.getTime();
    } else {
      return null;
    }
  }

  /**
   * given a format ID this will check whether the format represents an internal
   * date format or not.
   */
  public static boolean isInternalDateFormat(final int format) {
    boolean retval;

    switch (format) {
    // Internal Date Formats as described on page 427 in
    // Microsoft Excel Dev's Kit...
    case 0x0e:
    case 0x0f:
    case 0x10:
    case 0x11:
    case 0x12:
    case 0x13:
    case 0x14:
    case 0x15:
    case 0x16:
    case 0x2d:
    case 0x2e:
    case 0x2f:
      retval = true;
      break;

    default:
      retval = false;
      break;
    }
    return retval;
  }

  /**
   * Given a double, checks if it is a valid Excel date.
   * 
   * @return true if valid
   * @param value
   *          the double value
   */

  public static boolean isValidExcelDate(final double value) {
    return (value > -Double.MIN_VALUE);
  }

  /**
   * Given a Calendar, return the number of days since 1600/12/31.
   * 
   * @return days number of days since 1600/12/31
   * @param cal
   *          the Calendar
   * @exception IllegalArgumentException
   *              if date is invalid
   */

  private static int absoluteDay(final Calendar cal) {
    return cal.get(Calendar.DAY_OF_YEAR) + daysInPriorYears(cal.get(Calendar.YEAR));
  }

  /**
   * Return the number of days in prior years since 1601
   * 
   * @return days number of days in years prior to yr.
   * @param yr
   *          a year (1600 < yr < 4000)
   * @exception IllegalArgumentException
   *              if year is outside of range.
   */

  private static int daysInPriorYears(final int yr) {
    if (yr < 1601) {
      throw new IllegalArgumentException("'year' must be 1601 or greater");
    }
    final int y = yr - 1601;

    return 365 * y // days in prior years
        + y / 4 // plus julian leap days in prior years
        - y / 100 // minus prior century years
        + y / 400;
  }

  // set HH:MM:SS fields of cal to 00:00:00:000
  private static Calendar dayStart(final Calendar cal) {
    cal.get(Calendar.HOUR_OF_DAY); // force recalculation of internal fields
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    cal.get(Calendar.HOUR_OF_DAY); // force recalculation of internal fields
    return cal;
  }

  // ---------------------------------------------------------------------------------------------------------
}

   
    
    
  








Related examples in the same category

1.Java 1.5 (5.0) Changes to the API: ProcessBuilder.
2.How to execute a program from within Java
3.How to execute an external program How to execute an external program
4.Show how to use exec to pass complex args
5.ExecDemo shows how to execute an external program 2
6.ExecDemo shows how to execute an external program
7.Execute an external program read its output, and print its exit status
8.Create some temp files, ls them, and rm them
9.ExecDemoHelp shows how to use the Win32 start command
10.ExecDemo shows how to execute an external program and read its output
11.ExecDemo shows how to execute an external program and read its output 3
12.UNIX getopt() system call
13.Unix Crypt
14.Handles program arguments like Unix getopt()
15.Helper method to execute shell command