Time.java Source code

Java tutorial

Introduction

Here is the source code for Time.java

Source

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