View Javadoc

1   package edu.iris.Fissures.model;
2   
3   import java.io.Serializable;
4   import java.sql.Timestamp;
5   import java.text.SimpleDateFormat;
6   import java.util.Date;
7   import java.util.TimeZone;
8   import edu.iris.Fissures.Time;
9   
10  /***
11   * subclass of the java.util.Date class to extend the precision to microseconds
12   * and to eventually handle leap seconds.
13   * 
14   * @author H. Philip Crotwell
15   */
16  public class MicroSecondDate extends Date implements Serializable {
17  
18      protected long microseconds;
19  
20      protected int leapSecondVersion;
21  
22      protected LeapSecondHistory leapHistory;
23  
24      public MicroSecondDate() {
25          super();
26          this.leapSecondVersion = 0;
27          this.microseconds = 0;
28      }
29  
30      public MicroSecondDate(long microseconds) {
31          this(microseconds, 0);
32      }
33  
34      public MicroSecondDate(long microseconds, int leapSeconds) {
35          super(microseconds / 1000);
36          this.microseconds = microseconds % 1000;
37          this.leapSecondVersion = leapSeconds;
38      }
39  
40      public MicroSecondDate(Date d) {
41          this(d.getTime() * 1000, 0);
42      }
43  
44      public MicroSecondDate(MicroSecondDate d) {
45          this(d.getMicroSecondTime());
46      }
47  
48      public MicroSecondDate(Timestamp ts, int leapSeconds) {
49          // convert getTime from milliseconds to microseconds and add
50          // nanos div by 1000 to get microseconds and modulo 1000 to
51          // remove milliseconds that are already in the getTime
52          // do timestamp and nanos have duplicate info
53          this(fixTimestamp(ts), leapSeconds);
54      }
55  
56      /***
57       * fixBadJavaDatabaseTimestampNanos13Vs14Bug
58       * 
59       * @returns microseconds from the timestamp
60       */
61      static long fixTimestamp(Timestamp ts) {
62          long tsFracSeconds = ts.getTime() % 1000;
63          if(tsFracSeconds == 0) {
64              // trust nanos for all frac seconds including millis
65              return ts.getTime() * 1000 + ts.getNanos() / 1000;
66          } else {
67              // ts has millis, nanos has micro and nano but no millis
68              return ts.getTime() * 1000 + (ts.getNanos() / 1000) % 1000;
69          }
70      }
71  
72      public MicroSecondDate(Timestamp ts) {
73          this(ts, 0);
74      }
75  
76      public MicroSecondDate(Time t) {
77          this(new ISOTime(t.date_time).getDate().getMicroSecondTime(),
78               t.leap_seconds_version);
79      }
80  
81      public long getMicroSecondTime() {
82          return super.getTime() * 1000 + microseconds;
83      }
84  
85      /***
86       * Returns the microseconds as a number between 0 and 999, the milliseconds
87       * are kept in the Date superclass.
88       * 
89       * @return the microseconds as a number between 0 and 999.
90       */
91      public long getMicroSeconds() {
92          return microseconds;
93      }
94  
95      public Timestamp getTimestamp() {
96          Timestamp t = new Timestamp(getTime());
97          int nanos = t.getNanos();
98          nanos += microseconds * 1000;
99          t.setNanos(nanos);
100         return t;
101     }
102 
103     public edu.iris.Fissures.Time getFissuresTime() {
104         return new Time(ISOTime.getISOString(this), this.leapSecondVersion);
105     }
106 
107     public MicroSecondDate add(TimeInterval interval) {
108         if(interval == null) { throw new IllegalArgumentException("Cannot add() a null TimeInterval"); }
109         return new MicroSecondDate(getMicroSecondTime()
110                 + Math.round(interval.convertTo(UnitImpl.MICROSECOND)
111                         .getValue()));
112     }
113 
114     public MicroSecondDate subtract(TimeInterval interval) {
115         if(interval == null) { throw new IllegalArgumentException("Cannot subtract() a null TimeInterval"); }
116         return new MicroSecondDate(getMicroSecondTime()
117                 - Math.round(interval.convertTo(UnitImpl.MICROSECOND)
118                         .getValue()));
119     }
120 
121     /***
122      * Returns the timewidth of this - otherDate.
123      */
124     public TimeInterval subtract(MicroSecondDate otherDate) {
125         if(otherDate == null) { throw new IllegalArgumentException("Cannot difference() a null MicroSecondDate"); }
126         return new TimeInterval(getMicroSecondTime()
127                 - otherDate.getMicroSecondTime(), UnitImpl.MICROSECOND);
128     }
129 
130     /***
131      * Returns the TimeInterval between the two times. It is always positive
132      * regardless of which time comes before the other.
133      */
134     public TimeInterval difference(MicroSecondDate otherDate) {
135         if(otherDate == null) { throw new IllegalArgumentException("Cannot difference() a null MicroSecondDate"); }
136         long otherTime = otherDate.getMicroSecondTime();
137         long myTime = getMicroSecondTime();
138         if(before(otherDate)) { return new TimeInterval(otherTime - myTime,
139                                                         UnitImpl.MICROSECOND); }
140         return new TimeInterval(myTime - otherTime, UnitImpl.MICROSECOND);
141     }
142 
143     public boolean equals(Object otherDate) {
144         if(otherDate == this) { return true; }
145         if(super.equals(otherDate)) { //Date portion is equal
146             //If MicroSecondDate, compare microseconds
147             if(otherDate instanceof MicroSecondDate) {
148                 MicroSecondDate oMSD = (MicroSecondDate)otherDate;
149                 return getMicroSecondTime() == oMSD.getMicroSecondTime()
150                         && leapSecondVersion == oMSD.leapSecondVersion;
151             }
152             //otherwise, just return true since it's just a date and we need to
153             // be symmetric
154             return true;
155         }
156         return false;
157     }
158 
159     //We use Date's implementation of hashCode since MicroSecondDates are
160     // always equal to Dates and must return the same hash value according to
161     // the contract in Object. super.hashCode() is explicitly invoked here just
162     // to make the relationship clear
163     public int hashCode() {
164         return super.hashCode();
165     }
166 
167     public boolean after(Date otherDate) {
168         if(super.after(otherDate)) { return true; }
169         if(super.equals(otherDate) && otherDate instanceof MicroSecondDate) {
170             if(getMicroSecondTime() > ((MicroSecondDate)otherDate).getMicroSecondTime()) return true;
171         }
172         return false;
173     }
174 
175     public boolean before(Date otherDate) {
176         if(super.before(otherDate)) { return true; }
177         if(super.equals(otherDate) && otherDate instanceof MicroSecondDate) {
178             if(getMicroSecondTime() < ((MicroSecondDate)otherDate).getMicroSecondTime()) return true;
179         }
180         return false;
181     }
182 
183     public String toString() {
184         SimpleDateFormat df = new SimpleDateFormat("G yyyy.MM.dd HH:mm:ss.SSS zzz");
185         // SimpleDateFormat df
186         //   = new SimpleDateFormat ("hh:mm:ss.SSS");
187         df.setTimeZone(TimeZone.getTimeZone("GMT"));
188         return df.format(this);
189     }
190 }