/* * Date.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST 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 * of the License, or (at your option) any later version. * * BEAST 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 BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evolution.util; import dr.util.Attribute; import dr.util.NumberFormatter; import java.util.Calendar; import java.util.TimeZone; /** * A data class. * * @version $Id: Date.java,v 1.26 2005/05/24 20:25:57 rambaut Exp $ * * @author Alexei Drummond * @author Andrew Rambaut */ public class Date extends TimeScale implements Attribute { public static final String DATE = "date"; private double precision = 0.0; /** * Constructor for relative to origin * @param time the time in units relative to origin * @param units the units of the given time * @param backwards true if the time is earlier than the origin * @param origin the absolute origin at a Date. */ public Date(double time, Type units, boolean backwards, java.util.Date origin) { super(units, backwards, origin); this.time = time; } /** * Constructor for an absolute date. * @param date the date */ public Date(java.util.Date date) { super(Units.Type.YEARS, false); origin = -1970.0; initUsingDate(date); } /** * Constructor for an absolute date. * @param date the date * @param units the units */ public Date(java.util.Date date, Type units) { super(units, false); initUsingDate(date); } /** * Constructor for an absolute date with origin specified * @param date the date * @param units the units * @param origin the origin as a date */ public Date(java.util.Date date, Type units, java.util.Date origin) { super(units, false, origin); initUsingDate(date); } /** * Constructor of a relative age * @param time the time relative to arbitrary zero point. * @param units the units the time is measured in * @param backwards true of the time is earlier than the zero point. */ public Date(double time, Type units, boolean backwards) { super(units, backwards); this.time = time; } /** * Constructor for time a relative to origin * @param origin the origin in given units from Jan 1st 1970 */ private Date(double time, Type units, boolean backwards, double origin) { super(units, backwards, origin); this.time = time; } //************************************************************************ // Factory methods //************************************************************************ /** * Create an age representing the given age (time ago) in the given units */ public static Date createRelativeAge(double age, Type units) { return new Date(age, units, true); } /** * Create an age representing the given age (time ago) in the given units * with an origin of the given date. * The age represents the number units back in time from the origin. */ public static Date createTimeAgoFromOrigin(double age, Type units, java.util.Date origin) { return new Date(age, units, true, origin); } /** * Create an age representing the given age (time ago) in the given units * with an origin as the given number of units since 1970. * The age represents the number units back in time from the origin. */ public static Date createTimeAgoFromOrigin(double age, Type units, double origin) { return new Date(age, units, true, origin); } /** * Create an age representing the given age (time since) in the given units * with an origin of the given date. * The age represents the number units back in time from the origin. */ public static Date createTimeSinceOrigin(double age, Type units, java.util.Date origin) { return new Date(age, units, false, origin); } /** * Create an age representing the given age (time since) in the given units * with an origin as the given number of units since 1970. * The age represents the number units forwards in time from the origin. */ public static Date createTimeSinceOrigin(double age, Type units, double origin) { return new Date(age, units, false, origin); } /** * Create a date an sets units to Units.YEARS */ public static Date createDate(java.util.Date date) { return new Date(date, Units.Type.YEARS); } //************************************************************************ // Private methods //************************************************************************ private void initUsingDate(java.util.Date date) { // get the number of milliseconds this date is after the 1st January 1970 long millisAhead = date.getTime(); double daysAhead = ((double)millisAhead)/MILLIS_PER_DAY; switch (units) { case DAYS: time = daysAhead; break; case MONTHS: time = daysAhead / DAYS_PER_MONTH; break; case YEARS: //time = daysAhead / DAYS_PER_YEAR; // more precise (so 1st Jan 2013 is 2013.0) // to avoid timezone specific differences in date calculations, all dates and calendars are // set to GMT. Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.setTime(date); int year = cal.get(Calendar.YEAR); long millis1 = cal.getTimeInMillis(); cal.set(year, Calendar.JANUARY, 1, 0, 0); long millis2 = cal.getTimeInMillis(); cal.set(year + 1, Calendar.JANUARY, 1, 0, 0); long millis3 = cal.getTimeInMillis(); double fractionalYear = ((double)(millis1 - millis2)) / (millis3 - millis2); time = fractionalYear + year - 1970; break; default: throw new IllegalArgumentException(); } if (time < getOrigin()) { time = getOrigin() - time; backwards = true; } else { time = time - getOrigin(); backwards = false; } } /** * Returns the time value that is relative to the origin */ public double getTimeValue() { return time; } /** * Returns the absolute time value (i.e., relative to zero). */ public double getAbsoluteTimeValue() { if (isBackwards()) { return getOrigin() - getTimeValue(); } return getOrigin() + getTimeValue(); } public boolean before(Date date) { double newTime = convertTime(date.getTimeValue(), date); if (isBackwards()) { return getTimeValue() > newTime; } return getTimeValue() < newTime; } public boolean after(Date date) { double newTime = convertTime(date.getTimeValue(), date); if (isBackwards()) { return getTimeValue() < newTime; } return getTimeValue() > newTime; } public boolean equals(Date date) { double newTime = convertTime(date.getTimeValue(), date); return getTimeValue() == newTime; } public String getAttributeName() { return DATE; } public Object getAttributeValue() { return this; } public String toString() { if (isBackwards()) { return formatter.format(time).trim() + " " + unitString(time) + " ago"; } else { return formatter.format(time).trim() + " " + unitString(time); } } private double time; private NumberFormatter formatter = new NumberFormatter(5); public void setPrecision(double precision) { this.precision = precision; } public double getPrecision() { return precision; } }