public final class SimpleTime6 {

   public final int hour, minute;

   public static final int HOURS_IN_DAY = 24;
   public static final int MINUTES_IN_HOUR = 60;
   public static final int MINUTES_IN_DAY = HOURS_IN_DAY*MINUTES_IN_HOUR;

   public SimpleTime6 (final int h)              { this (h, 0); }
   public SimpleTime6 (final int h, final int m) {
      assert 0<=h && h<HOURS_IN_DAY;
      assert 0<=m && m<MINUTES_IN_DAY;
      hour=h; minute=m;
   }

   @java.lang.Override
   public String toString () {
      if (hour==0 && minute==0) {
         return ("midnight");
      } else if (hour==12 && minute==0) {
         return ("noon");
      } else {
         return String.format ("%02d:%02d", hour, minute);
      }
   }

   /*
     Design for immutabililty.
   */
   public SimpleTime6 add (final int m) {
      // Wrap around to the next day.
      final int totalMinutes = Math.floorMod (MINUTES_IN_HOUR*hour + minute + m, MINUTES_IN_DAY);
      assert 0<=totalMinutes && totalMinutes<MINUTES_IN_DAY;
      // Integer division truncates
      return new SimpleTime6 (totalMinutes/MINUTES_IN_HOUR, totalMinutes%MINUTES_IN_HOUR);
   }


   public boolean before (final SimpleTime6 t) {
      return ((this.hour < t.hour)
         || ((this.hour == t.hour) && (this.minute < t.minute)));
   }

   /*
     An object really ought to have a proper equals method.  This
     requires consistency with hashing.  Several subtle issues arise
     in fullfiling the Java language expectations for these methods.
   */
   @java.lang.Override
   public boolean equals (final Object other) {
      if (this == other) return true;
      if (other == null) return false;
      if (this.getClass() != other.getClass()) return false;
      final SimpleTime6 time = (SimpleTime6) other;
      return this.hour==time.hour && this.minute==time.minute;
   }

   // Lazy initialization requires proper synchronization
   private volatile int hashCode = 0;  // unsigned, mod 2^32 number

   @java.lang.Override
   public int hashCode () {
      if (hashCode==0) {
         int result = 17;
         result = 37*result + hour;
         result = 37*result + minute;
         hashCode = result;
      }
      return hashCode;
   }

   /*
      It is a common (and often deserved) complaint that "Java is too
      verbose" or has too much "ceremony." A significant contributor
      to this is that while classes can flexibly model a variety of
      programming paradigms, this invariably comes with modeling
      overheads -- and in the case of classes that are nothing more
      than "plain data carriers", these modeling overhead can be out
      of line with their value. To write a simple data carrier class
      responsibly, we have to write a lot of low-value, repetitive
      code: constructors, accessors, equals(), hashCode(), toString(),
      etc. And developers are sometimes tempted to cut corners such as
      omitting these important methods, leading to surprising behavior
      or poor debuggability, or pressing an alternate but not entirely
      appropriate class into service because it has the "right shape"
      and they don't want to define yet another class.

      Brian Goetz
      https://cr.openjdk.java.net/~briangoetz/amber/datum.html
    */
}