/*
* This code 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 code 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 program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
//package no.geosoft.cc.util;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* A class representing a moment in time. Extends Day which represents the day
* of the moment, and defines the time within the day to millisecond accuracy.
*
* @author Jacob Dreyer (<a
* href="mailto:jacob.dreyer@geosoft.no">jacob.dreyer@geosoft.no</a>)
*/
public class Time extends Day {
/**
* Instantiate a Time object. The time is lenient meaning that illegal day
* parameters can be specified and results in a recomputed day with legal
* month/day values.
*
* @param year
* Year of this time
* @param month
* Month of this time
* @param dayOfMonth
* Day of month of this time.
* @param hours
* Hours of this time [0-23]
* @param minutes
* Minutes of this time [0-23]
* @param seconds
* Seconds of this time [0-23]
*/
public Time(int year, int month, int dayOfMonth, int hours, int minutes, int seconds) {
super(year, month, dayOfMonth);
setHours(hours);
setMinutes(minutes);
setSeconds(seconds);
}
public Time(Day day, int hours, int minutes, int seconds) {
this(day.getYear(), day.getMonth(), day.getDayOfMonth(), hours, minutes, seconds);
}
public Time(int hours, int minutes, int seconds) {
this(new Day(), hours, minutes, seconds);
}
public Time() {
calendar_ = new GregorianCalendar(); // Now
}
public void setDay(Day day) {
setYear(day.getYear());
setMonth(day.getMonth());
setDayOfMonth(day.getDayOfMonth());
}
public void setHours(int hours) {
calendar_.set(Calendar.HOUR_OF_DAY, hours);
}
public int getHours() {
return calendar_.get(Calendar.HOUR_OF_DAY);
}
public void setMinutes(int minutes) {
calendar_.set(Calendar.MINUTE, minutes);
}
public int getMinutes() {
return calendar_.get(Calendar.MINUTE);
}
public void setSeconds(int seconds) {
calendar_.set(Calendar.SECOND, seconds);
}
public int getSeconds() {
return calendar_.get(Calendar.SECOND);
}
public void setMilliSeconds(int milliSeconds) {
calendar_.set(Calendar.MILLISECOND, milliSeconds);
}
public int getMilliSeconds() {
return calendar_.get(Calendar.MILLISECOND);
}
public boolean isAfter(Time time) {
return calendar_.after(time.calendar_);
}
public boolean isBefore(Time time) {
return calendar_.before(time.calendar_);
}
public boolean equals(Time time) {
return calendar_.equals(time.calendar_);
}
public void addHours(int nHours) {
calendar_.add(Calendar.HOUR_OF_DAY, nHours);
}
public void addMinutes(int nMinutes) {
calendar_.add(Calendar.MINUTE, nMinutes);
}
public void addSeconds(int nSeconds) {
calendar_.add(Calendar.SECOND, nSeconds);
}
public void addMilliSeconds(int nMilliSeconds) {
calendar_.add(Calendar.MILLISECOND, nMilliSeconds);
}
public long milliSecondsBetween(Time time) {
long millisBetween = calendar_.getTime().getTime() - time.calendar_.getTime().getTime();
return millisBetween;
}
public double secondsBetween(Time time) {
long millisBetween = calendar_.getTime().getTime() - time.calendar_.getTime().getTime();
return millisBetween / 1000;
}
public double minutesBetween(Time time) {
long millisBetween = calendar_.getTime().getTime() - time.calendar_.getTime().getTime();
return millisBetween / (1000 * 60);
}
public double hoursBetween(Time time) {
long millisBetween = calendar_.getTime().getTime() - time.calendar_.getTime().getTime();
return millisBetween / (1000 * 60 * 60);
}
public String toString() {
StringBuffer string = new StringBuffer();
string.append(super.toString());
string.append(' ');
if (getHours() < 10)
string.append('0');
string.append(getHours());
string.append(':');
if (getMinutes() < 10)
string.append('0');
string.append(getMinutes());
string.append(':');
if (getSeconds() < 10)
string.append('0');
string.append(getSeconds());
string.append(',');
string.append(getMilliSeconds());
return string.toString();
}
public static void main(String args[]) {
Time time = new Time(12, 00, 00);
System.out.println(time);
}
}
class Day implements Comparable, Cloneable, Serializable {
protected Calendar calendar_;
/**
* Initialize the internal calendar instance.
*
* @param year
* Year of new day.
* @param month
* Month of new day.
* @param dayOfMonth
* Day of month of new day.
*/
private void initialize(int year, int month, int dayOfMonth) {
calendar_ = Calendar.getInstance();
calendar_.setLenient(true);
calendar_.setFirstDayOfWeek(Calendar.MONDAY);
calendar_.setTimeZone(TimeZone.getTimeZone("GMT"));
set(year, month, dayOfMonth);
}
/**
* Create a new day. The day is lenient meaning that illegal day parameters
* can be specified and results in a recomputed day with legal month/day
* values.
*
* @param year
* Year of new day.
* @param month
* Month of new day (0-11)
* @param dayOfMonth
* Day of month of new day (1-31)
*/
public Day(int year, int month, int dayOfMonth) {
initialize(year, month, dayOfMonth);
}
/**
* Create a new day, specifying the year and the day of year. The day is
* lenient meaning that illegal day parameters can be specified and results in
* a recomputed day with legal month/day values.
*
* @param year
* Year of new day.
* @param dayOfYear
* 1=January 1, etc.
*/
public Day(int year, int dayOfYear) {
initialize(year, Calendar.JANUARY, 1);
calendar_.set(Calendar.DAY_OF_YEAR, dayOfYear);
}
/**
* Create a new day representing the day of creation (according to the setting
* of the current machine).
*/
public Day() {
// Now (in the currenct locale of the client machine)
Calendar calendar = Calendar.getInstance();
// Prune time part
initialize(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar
.get(Calendar.DAY_OF_MONTH));
}
/**
* Create a new day based on a java.util.Calendar instance. NOTE: The time
* component from calendar will be pruned.
*
* @param calendar
* Calendar instance to copy.
*/
public Day(Calendar calendar) {
this(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar
.get(Calendar.DAY_OF_MONTH));
}
/**
* Create a new day based on a java.util.Date instance. NOTE: The time
* component from date will be pruned.
*
* @param date
* Date instance to copy.
*/
public Day(Date date) {
// Create a calendar based on given date
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
// Extract date values and use these only
initialize(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar
.get(Calendar.DAY_OF_MONTH));
}
/**
* Create a new day based on a time value. Time is milliseconds since "the
* Epoch" (1.1.1970). NOTE: The time component from time will be pruned.
*
* @param time
* Milliseconds since "the Epoch".
*/
public Day(long time) {
this(new Date(time));
}
/**
* Create a new day as a copy of the specified day.
*
* @param day
* Day to clone.
*/
public Day(Day day) {
this(day.getYear(), day.getMonth(), day.getDayOfMonth());
}
/**
* Create a clone of this day.
*
* @return This day cloned.
*/
public Object clone() {
return new Day(this);
}
/**
* A more explicit front-end to the Day() constructor which return a day
* object representing the day of creation.
*
* @return A day instance representing today.
*/
public static Day today() {
return new Day();
}
/**
* Return a Calendar instance representing the same day as this instance. For
* use by secondary methods requiring java.util.Calendar as input.
*
* @return Calendar equivalent representing this day.
*/
public Calendar getCalendar() {
return (Calendar) calendar_.clone();
}
/**
* Return a Date instance representing the same date as this instance. For use
* by secondary methods requiring java.util.Date as input.
*
* @return Date equivalent representing this day.
*/
public Date getDate() {
return getCalendar().getTime();
}
/**
* Compare this day to the specified day. If object is not of type Day a
* ClassCastException is thrown.
*
* @param object
* Day object to compare to.
* @return
* @see Comparable#compareTo(Object)
* @throws ClassCastException
* If object is not of type Day.
*/
public int compareTo(Object object) {
Day day = (Day) object;
return calendar_.getTime().compareTo(day.calendar_.getTime());
}
/**
* Return true if this day is after the specified day.
*
* @param date
* Day to compare to.
* @return True if this is after day, false otherwise.
*/
public boolean isAfter(Day day) {
return calendar_.after(day.calendar_);
}
/**
* Return true if this day is before the specified day.
*
* @param date
* Day to compare to.
* @return True if this is before day, false otherwise.
*/
public boolean isBefore(Day day) {
return calendar_.before(day.calendar_);
}
/**
* Return true if this day equals (represent the same date) as the specified
* day.
*
* @param date
* Day to compare to.
* @return True if this equals day, false otherwise.
*/
public boolean equals(Day day) {
return calendar_.equals(day.calendar_);
}
/**
* Overload required as default definition of equals() has changed.
*
* @return A hash code value for this object.
*/
public int hashCode() {
return calendar_.hashCode();
}
/**
* Set date of this day. The day is lenient meaning that illegal day
* parameters can be specified and results in a recomputed day with legal
* month/day values.
*
* @param year
* Year of this day.
* @param month
* Month of this day (0-11).
* @param dayOfMonth
* Day of month of this day (1-31).
*/
public void set(int year, int month, int dayOfMonth) {
setYear(year);
setMonth(month);
setDayOfMonth(dayOfMonth);
}
/**
* Return year of this day.
*
* @return Year of this day.
*/
public int getYear() {
return calendar_.get(Calendar.YEAR);
}
/**
* Set year of this day.
*
* @param year
* New year of this day.
*/
public void setYear(int year) {
calendar_.set(Calendar.YEAR, year);
}
/**
* Return month of this day. The result must be compared to Calendar.JANUARY,
* Calendar.FEBRUARY, etc.
*
* @return Month of this day.
*/
public int getMonth() {
return calendar_.get(Calendar.MONTH);
}
/**
* Return the 1-based month number of the month of this day. 1 = January, 2 =
* February and so on.
*
* @return Month number of this month
*/
public int getMonthNo() {
// It is tempting to return getMonth() + 1 but this is conceptually
// wrong, as Calendar month is an enumeration and the values are tags
// only and can be anything.
switch (getMonth()) {
case Calendar.JANUARY:
return 1;
case Calendar.FEBRUARY:
return 2;
case Calendar.MARCH:
return 3;
case Calendar.APRIL:
return 4;
case Calendar.MAY:
return 5;
case Calendar.JUNE:
return 6;
case Calendar.JULY:
return 7;
case Calendar.AUGUST:
return 8;
case Calendar.SEPTEMBER:
return 9;
case Calendar.OCTOBER:
return 10;
case Calendar.NOVEMBER:
return 11;
case Calendar.DECEMBER:
return 12;
}
// This will never happen
return 0;
}
/**
* Set month of this day. January = 0, February = 1, etc. Illegal month values
* will result in a recomputation of year and a resetting of month to a valid
* value. I.e. setMonth(20), will add 1 year to day and set month to 8.
*
* @param month
* New month of this day.
*/
public void setMonth(int month) {
calendar_.set(Calendar.MONTH, month);
}
/**
* Return day of month of this day. NOTE: First day of month is 1 (not 0).
*
* @return Day of month of this day.
*/
public int getDayOfMonth() {
return calendar_.get(Calendar.DAY_OF_MONTH);
}
/**
* Set day of month of this date. 1=1st 2=2nd, etc. Illegal day values will
* result in a recomputation of month/year and a resetting of day to a valid
* value. I.e. setDayOfMonth(33), will add 1 month to date and set day to 5,
* 4, 3 or 2 depending on month/year.
*
* @param dayOfMonth
* New day of month of this day.
*/
public void setDayOfMonth(int dayOfMonth) {
calendar_.set(Calendar.DAY_OF_MONTH, dayOfMonth);
}
/**
* Return the day number of year this day represents. January 1 = 1 and so on.
*
* @return day number of year.
*/
public int getDayOfYear() {
return calendar_.get(Calendar.DAY_OF_YEAR);
}
/**
* Return the day of week of this day. NOTE: Must be compared to
* Calendar.MONDAY, TUSEDAY etc.
*
* @return Day of week of this day.
*/
public int getDayOfWeek() {
return calendar_.get(Calendar.DAY_OF_WEEK);
}
/**
* Return the day number of week of this day, where Monday=1, Tuesday=2, ...
* Sunday=7.
*
* @return Day number of week of this day.
*/
public int getDayNumberOfWeek() {
return getDayOfWeek() == Calendar.SUNDAY ? 7 : getDayOfWeek() - Calendar.SUNDAY;
}
/**
* Return the week number of year, this day belongs to. 1st=1 and so on.
*
* @return Week number of year of this day.
*/
public int getWeekOfYear() {
return calendar_.get(Calendar.WEEK_OF_YEAR);
}
/**
* Add a number of days to this day. Subtracting a number of days can be done
* by a negative argument to addDays() or calling subtractDays() explicitly.
*
* @param nDays
* Number of days to add.
*/
public void addDays(int nDays) {
calendar_.add(Calendar.DAY_OF_MONTH, nDays);
}
/**
* Subtract a number of days from this day
*
* @param nDays
* Number of days to subtract.
*/
public void subtractDays(int nDays) {
addDays(-nDays);
}
/**
* Add a number of months to this day. The actual number of days added depends
* on the staring day. Subtracting a number of months can be done by a
* negative argument to addMonths() or calling subtactMonths() explicitly.
* NOTE: addMonth(n) m times will in general give a different result than
* addMonth(m*n). Add 1 month to January 31, 2005 will give February 28, 2005.
*
* @param nMonths
* Number of months to add.
*/
public void addMonths(int nMonths) {
calendar_.add(Calendar.MONTH, nMonths);
}
/**
* Subtract a number of months from this day
*
* @see #addMonths(int).
*
* @param nDays
* Number of days to subtract.
*/
public void subtractMonths(int nMonths) {
addMonths(-nMonths);
}
/**
* Add a number of years to this day. The actual number of days added depends
* on the starting day. Subtracting a number of years can be done by a
* negative argument to addYears() or calling subtractYears explicitly.
*
* @param nYears
* Number of years to add.
*/
public void addYears(int nYears) {
calendar_.add(Calendar.YEAR, nYears);
}
/**
* Subtract a number of years from this day
*
* @see #addYears(int).
*
* @param nYears
* Number of years to subtract.
*/
public void subtractYears(int nYears) {
addYears(-nYears);
}
/**
* Return the number of days in the year of this day.
*
* @return Number of days in this year.
*/
public int getDaysInYear() {
return calendar_.getActualMaximum(Calendar.DAY_OF_YEAR);
}
/**
* Return true if the year of this day is a leap year.
*
* @return True if this year is a leap year, false otherwise.
*/
public boolean isLeapYear() {
return getDaysInYear() == calendar_.getMaximum(Calendar.DAY_OF_YEAR);
}
/**
* Return true if the specified year is a leap year.
*
* @param year
* Year to check.
* @return True if specified year is leap year, false otherwise.
*/
public static boolean isLeapYear(int year) {
return (new Day(year, Calendar.JANUARY, 1)).isLeapYear();
}
/**
* Return the number of days in the month of this day.
*
* @return Number of days in this month.
*/
public int getDaysInMonth() {
return calendar_.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* Get default locale name of this day ("Monday", "Tuesday", etc.
*
* @return Name of day.
*/
public String getDayName() {
switch (getDayOfWeek()) {
case Calendar.MONDAY:
return "Monday";
case Calendar.TUESDAY:
return "Tuesday";
case Calendar.WEDNESDAY:
return "Wednesday";
case Calendar.THURSDAY:
return "Thursday";
case Calendar.FRIDAY:
return "Friday";
case Calendar.SATURDAY:
return "Saturday";
case Calendar.SUNDAY:
return "Sunday";
}
// This will never happen
return null;
}
/**
* Return number of days between two days. The method always returns a
* positive number of days.
*
* @param date
* The day to compare to.
* @return Number of days between this and day.
*/
public int daysBetween(Day day) {
long millisBetween = Math
.abs(calendar_.getTime().getTime() - day.calendar_.getTime().getTime());
return (int) Math.round(millisBetween / (1000 * 60 * 60 * 24));
}
/**
* Find the n'th xxxxday of s specified month (for instance find 1st sunday of
* May 2006; findNthOfMonth (1, Calendar.SUNDAY, Calendar.MAY, 2006); Return
* null if the specified day doesn't exists.
*
* @param n
* Nth day to look for.
* @param dayOfWeek
* Day to look for (Calendar.XXXDAY).
* @param month
* Month to check (Calendar.XXX).
* @param year
* Year to check.
* @return Required Day (or null if non-existent)
* @throws ArrayIndexOutOfBoundsException
* if dyaOfWeek parameter doesn't represent a valid day.
*/
public static Day getNthOfMonth(int n, int dayOfWeek, int month, int year)
throws ArrayIndexOutOfBoundsException {
// Validate the dayOfWeek argument
if (dayOfWeek < 0 || dayOfWeek > 6)
throw new ArrayIndexOutOfBoundsException(dayOfWeek);
Day first = new Day(year, month, 1);
int offset = dayOfWeek - first.getDayOfWeek();
if (offset < 0)
offset = 7 + offset;
int dayNo = (n - 1) * 7 + offset + 1;
return dayNo > first.getDaysInMonth() ? null : new Day(year, month, dayNo);
}
/**
* Find the first of a specific day in a given month, for instance first
* Tuesday of May: getFirstOfMonth (Calendar.TUESDAY, Calendar.MAY, 2005);
*
* @param dayOfWeek
* Weekday to get.
* @param month
* Month of day to get.
* @param year
* Year of day to get.
* @return The requested day.
*/
public static Day getFirstOfMonth(int dayOfWeek, int month, int year) {
return Day.getNthOfMonth(1, dayOfWeek, month, year);
}
/**
* Find the last of a specific day in a given month, for instance last Tuesday
* of May: getLastOfMonth (Calendar.TUESDAY, Calendar.MAY, 2005);
*
* @param dayOfWeek
* Weekday to get.
* @param month
* Month of day to get.
* @param year
* Year of day to get.
* @return The requested day.
*/
public static Day getLastOfMonth(int dayOfWeek, int month, int year) {
Day day = Day.getNthOfMonth(5, dayOfWeek, month, year);
return day != null ? day : Day.getNthOfMonth(4, dayOfWeek, month, year);
}
/**
* Return a scratch string representation of this day. Used for debugging
* only. The format of the day is dd/mm-yyyy
*
* @return A string representation of this day.
*/
public String toString() {
StringBuffer string = new StringBuffer();
if (getDayOfMonth() < 10)
string.append('0');
string.append(getDayOfMonth());
string.append('/');
if (getMonth() < 9)
string.append('0');
string.append(getMonth() + 1);
string.append('-');
string.append(getYear());
string.append(" ");
string.append(getDayName());
return string.toString();
}
/**
* Testing this class.
*
* @param args
* Not used.
*/
public static void main(String[] args) {
// This proves that there are 912 days between the two major
// terrorist attacks, not 911 as is common knowledge.
Day september11 = new Day(2001, Calendar.SEPTEMBER, 11);
Day march11 = new Day(2004, Calendar.MARCH, 11);
System.out.println(september11.daysBetween(march11));
// This proves that Kennedy was president for 1037 days,
// not 1000 as is the popular belief nor 1036 which is the
// bluffers reply. Nerds knows when to add one...
Day precidency = new Day(1961, Calendar.JANUARY, 20);
Day assasination = new Day(1963, Calendar.NOVEMBER, 22);
System.out.println(precidency.daysBetween(assasination) + 1);
// Niel Armstrong walked the moon on a Sunday
Day nielOnMoon = new Day(1969, Calendar.JULY, 20);
System.out.println(nielOnMoon.getDayNumberOfWeek());
// Find last tuesdays for 2005
for (int i = 0; i < 12; i++) {
Day tuesday = Day.getLastOfMonth(Calendar.TUESDAY, i, 2005);
System.out.println(tuesday);
}
}
}
|