Java tutorial
/* * 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); } } }