/*********************************************************************
*
* Copyright (C) 2001 Andrew Khan
*
* 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
***************************************************************************/
package jxl.write.biff;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import jxl.common.Logger;
import jxl.CellType;
import jxl.DateCell;
import jxl.biff.DoubleHelper;
import jxl.biff.Type;
import jxl.format.CellFormat;
import jxl.write.DateFormats;
import jxl.write.WritableCellFormat;
/**
* A date stored in the database
*/
public abstract class DateRecord extends CellValue
{
/**
* The logger
*/
private static Logger logger = Logger.getLogger(DateRecord.class);
/**
* The excel value of the date
*/
private double value;
/**
* The java representation of the date
*/
private Date date;
/**
* Indicates whether this is a full date, or just a time only
*/
private boolean time;
// The number of days between 01 Jan 1900 and 01 Jan 1970 - this gives
// the UTC offset
/**
*/
private final static int utcOffsetDays = 25569;
// The number of milliseconds in a day
/**
*/
private final static long msInADay = 24 * 60 * 60 * 1000;
/**
* This is package protected so that the worksheet might detect
* whether or not to override it with the column cell format
*/
static final WritableCellFormat defaultDateFormat =
new WritableCellFormat(DateFormats.DEFAULT);
// The number of days between 1 Jan 1900 and 1 March 1900. Excel thinks
// the day before this was 29th Feb 1900, but it was 28th Feb 19000.
// I guess the programmers thought nobody would notice that they
// couldn't be bothered to program this dating anomaly properly
/**
*/
private final static int nonLeapDay = 61;
/**
* Class definition for a dummy variable
*/
protected static final class GMTDate
{
public GMTDate(){}
};
/**
* Constructor invoked by the user API
*
* @param c the column
* @param r the row
* @param d the date
*/
protected DateRecord(int c, int r, Date d)
{
this(c, r, d, defaultDateFormat, false);
}
/**
* Constructor invoked by the user API
*
* @param c the column
* @param r the row
* @param d the date
* @param a adjust timezone
*/
protected DateRecord(int c, int r, Date d, GMTDate a)
{
this(c, r, d, defaultDateFormat, false);
}
/**
* Constructor invoked from the user API
*
* @param c the column
* @param r the row
* @param st the format for the date
* @param d the date
*/
protected DateRecord(int c, int r, Date d, CellFormat st)
{
super(Type.NUMBER, c, r,st);
date = d;
calculateValue(true);
}
/**
* Constructor invoked from the user API
*
* @param c the column
* @param r the row
* @param st the format for the date
* @param d the date
* @param a adjust for the timezone
*/
protected DateRecord(int c, int r, Date d, CellFormat st, GMTDate a)
{
super(Type.NUMBER, c, r, st);
date = d;
calculateValue(false);
}
/**
* Constructor invoked from the API
*
* @param c the column
* @param r the row
* @param st the date format
* @param tim time indicator
* @param d the date
*/
protected DateRecord(int c, int r, Date d, CellFormat st, boolean tim)
{
super(Type.NUMBER, c, r, st);
date = d;
time = tim;
calculateValue(false);
}
/**
* Constructor invoked when copying a readable spreadsheet
*
* @param dc the date to copy
*/
protected DateRecord(DateCell dc)
{
super(Type.NUMBER, dc);
date = dc.getDate();
time = dc.isTime();
calculateValue(false);
}
/**
* Copy constructor
*
* @param c the column
* @param r the row
* @param dr the record to copy
*/
protected DateRecord(int c, int r, DateRecord dr)
{
super(Type.NUMBER, c, r, dr);
value = dr.value;
time = dr.time;
date = dr.date;
}
/**
* Calculates the 1900 based numerical value based upon the utc value held
* in the date object
*
* @param adjust TRUE if we want to incorporate timezone information
* into the raw UTC date eg. when copying from a spreadsheet
*/
private void calculateValue(boolean adjust)
{
// Offsets for current time zone
long zoneOffset = 0;
long dstOffset = 0;
// Get the timezone and dst offsets if we want to take these into
// account
if (adjust)
{
// Get the current calender, replete with timezone information
Calendar cal = Calendar.getInstance();
cal.setTime(date);
zoneOffset = cal.get(Calendar.ZONE_OFFSET);
dstOffset = cal.get(Calendar.DST_OFFSET);
}
long utcValue = date.getTime() + zoneOffset + dstOffset;
// Convert this to the number of days, plus fractions of a day since
// 01 Jan 1970
double utcDays = (double) utcValue / (double) msInADay;
// Add in the offset to get the number of days since 01 Jan 1900
value = utcDays + utcOffsetDays;
// Work round a bug in excel. Excel seems to think there is a date
// called the 29th Feb, 1900 - but this was not a leap year.
// Therefore for values less than 61, we must subtract 1. Only do
// this for full dates, not times
if (!time && value < nonLeapDay)
{
value -= 1;
}
// If this refers to a time, then get rid of the integer part
if (time)
{
value = value - (int) value;
}
}
/**
* Returns the content type of this cell
*
* @return the content type for this cell
*/
public CellType getType()
{
return CellType.DATE;
}
/**
* Gets the binary data for writing
*
* @return the binary data
*/
public byte[] getData()
{
byte[] celldata = super.getData();
byte[] data = new byte[celldata.length + 8];
System.arraycopy(celldata, 0, data, 0, celldata.length);
DoubleHelper.getIEEEBytes(value, data, celldata.length);
return data;
}
/**
* Quick and dirty function to return the contents of this cell as a string.
* For more complex manipulation of the contents, it is necessary to cast
* this interface to correct subinterface
*
* @return the contents of this cell as a string
*/
public String getContents()
{
return date.toString();
}
/**
* Sets the date in this cell
*
* @param d the date
*/
protected void setDate(Date d)
{
date = d;
calculateValue(true);
}
/**
* Sets the date in this cell, taking the timezone into account
*
* @param d the date
* @param a adjust for timezone
*/
protected void setDate(Date d, GMTDate a)
{
date = d;
calculateValue(false);
}
/**
* Gets the date contained in this cell
*
* @return the cell contents
*/
public Date getDate()
{
return date;
}
/**
* Indicates whether the date value contained in this cell refers to a date,
* or merely a time. When writing a cell, all dates are fully defined,
* even if they refer to a time
*
* @return FALSE if this is full date, TRUE if a time
*/
public boolean isTime()
{
return time;
}
/**
* Gets the DateFormat used to format the cell. This will normally be
* the format specified in the excel spreadsheet, but in the event of any
* difficulty parsing this, it will revert to the default date/time format.
*
* @return the DateFormat object used to format the date in the original
* excel cell
*/
public DateFormat getDateFormat()
{
return null;
}
}
|