// Timekeeper class, October 2001
//
// A non-instantiatable (?) class I whipped up to give me the time. Java makes
// simple things like telling the time incredibly complicated.
//
// There are also some nifty time-related methods for figuring out hours,
// minutes, and seconds from the number of seconds since midnight (for digital
// clocks and such). Another cool method gives the digit in any position in a
// time written in hh:mm:ss format.

import java.util.*;

public class Timekeeper {

  /*
   * CLASS CONSTANTS
   */

  private static final int secsInDay = 86400;
  // A useful constant: the number of seconds in one day.

  /*
   * CONSTRUCTOR
   */

  private Timekeeper() {}
  // The constructor is declared private because we don't want this class to
  // be able to be instantiated. It's kind of like java.lang.Math.

  /*
   * CLASS FUNCTIONS
   */

  public static long currentMillis() {
  // Returns the number of milliseconds since midnight. This incredibly useful
  // function is, surprisingly, not found in the Java API, as far as I can tell.
  //
  // Preconditions:
  //   none.
  //
  // Postcondition:
  //   The number of milliseconds since midnight is returned.

    GregorianCalendar thisInstant = new GregorianCalendar();
    // We instantiate a new GregorianCalendar. By giving no arguments to the
    // constructor, we create a GregorianCalendar corresponding to the current
    // time ("with millisecond precision").

    return thisInstant.get(Calendar.MILLISECOND) +
           1000 * thisInstant.get(Calendar.SECOND) +
           60000 * thisInstant.get(Calendar.MINUTE) +
           3600000 * thisInstant.get(Calendar.HOUR_OF_DAY);
    // Now figure out how many milliseconds this thing has.

  }

  public static int hours(double time) {
  // Returns the hours implied by a number of seconds since midnight.
  //
  // Precondition:
  //   0 <= time < 86400
  //
  // Postcondition:
  //   The number of whole hours since midnight is returned.

    return (int)(time / 3600);

  }

  public static int minutes(double time) {
  // Returns the minutes implied by a number of seconds since midnight.
  //
  // Precondition:
  //   0 <= time < 86400
  //
  // Postcondition:
  //   The number of whole minutes since the last hour change is returned.

    return (int)(time / 60) % 60;

  }

  public static int seconds(double time) {
  // Returns the seconds implied by a number of seconds since midnight.
  //
  // Precondition:
  //   0 <= time < 86400
  //
  // Postcondition:
  //   The number of whole seconds since the last minute change is returned.

    return (int)(time) % 60;

  }

  public static int getDigit(double time, int pos, boolean as24hr) {
  // Computes the digit at position pos when the time is written as hh:mm:ss.
  // time is given in seconds since midnight.
  //
  // Preconditions:
  //   0 <= time < 86400
  //   0 <= pos <= 5
  //
  // Postconditions:
  //   Returns a digit such that 0 <= result <= 9. Certain other restrictions
  //     on output will apply (for example, if pos == 2, 0 <= result <= 5).
  //
  // Note: Midnight in 24-hour time is interpreted as 00:00:00.

    int modulo = 1, divisor = 1, thisDigit;

    switch (pos) {
      case 5:  // Seconds: units place
        modulo = 10;
        divisor = 1;
        break;
      case 4:  // Seconds: tens place
        modulo = 6;
        divisor = 10;
        break;
      case 3:  // Minutes: units place
        modulo = 10;
        divisor = 60;
        break;
      case 2:  // Minutes: tens place
        modulo = 6;
        divisor = 600;
        break;
      case 1:  // Hours: units place           // Some of this hours stuff
        modulo = as24hr ? 10 : 12;             // gets really weird. 24-hour
        divisor = 3600;                        // time works great, but when
        break;                                 // you lose your mind and decide
      case 0:  // Hours: tens place            // to start mucking around with
        modulo = as24hr ? 10 : 12;             // 12-hour time, you get some
        divisor = as24hr ? 36000 : 3600;       // crazy stuff going on.
    }

    thisDigit = (int)(time / divisor) % modulo;

    if (pos < 3 && !as24hr)  // This is where it gets weird.
    // Assert: at this point, if we're looking at the hours in 12-hour time,
    // then thisDigit holds an integer from 0 to 11. Now we have to split it
    // apart and get the digit we want.
      if (pos == 0)  // Hours: tens place
        thisDigit = (thisDigit == 0) ? 1 : thisDigit / 10;
      else           // Hours: units place
        thisDigit = (thisDigit == 0) ? 2 : thisDigit % 10;

    return thisDigit;

  }

}