Normand Briere
2019-04-22 a9e12f6c508810604c8c91ee15451776b08ce1a1
timeflow/data/time/TimeUnit.java
....@@ -3,241 +3,256 @@
33 import java.util.*;
44 import java.text.*;
55
6
-public class TimeUnit {
6
+public class TimeUnit
7
+{
8
+ public static final TimeUnit YEAR = new TimeUnit("Years", Calendar.YEAR, 365 * 24 * 60 * 60 * 1000L, "yyyy", "yyyy");
9
+ public static final TimeUnit MONTH = new TimeUnit("Months", Calendar.MONTH, 30 * 24 * 60 * 60 * 1000L, "MMM", "MMM yyyy");
10
+ public static final TimeUnit WEEK = new TimeUnit("Weeks", Calendar.WEEK_OF_YEAR, 7 * 24 * 60 * 60 * 1000L, "d", "MMM d yyyy");
11
+ public static final TimeUnit DAY = new TimeUnit("Days", Calendar.DAY_OF_MONTH, 24 * 60 * 60 * 1000L, "d", "MMM d yyyy");
12
+ public static final TimeUnit DAY_OF_WEEK = new TimeUnit("Days", Calendar.DAY_OF_WEEK, 24 * 60 * 60 * 1000L, "d", "MMM d yyyy");
13
+ public static final TimeUnit HOUR = new TimeUnit("Hours", Calendar.HOUR_OF_DAY, 60 * 60 * 1000L, "HH:mm", "MMM d yyyy HH:mm");
14
+ public static final TimeUnit MINUTE = new TimeUnit("Minutes", Calendar.MINUTE, 60 * 1000L, ":mm", "MMM d yyyy HH:mm");
15
+ public static final TimeUnit SECOND = new TimeUnit("Seconds", Calendar.SECOND, 1000L, ":ss", "MMM d yyyy HH:mm:ss");
16
+ public static final TimeUnit REALTIME = new TimeUnit("Realtime", Calendar.MILLISECOND, 1L, ".SS", "HH:mm:ss.SS");
17
+
18
+ public static final TimeUnit DECADE = multipleYears(10);
19
+ public static final TimeUnit CENTURY = multipleYears(100);
20
+ private static final double DAY_SIZE = 24 * 60 * 60 * 1000L;
21
+ private int quantity;
22
+ private long roughSize;
23
+ private SimpleDateFormat format, fullFormat;
24
+ private String name;
25
+ private int calendarCode;
726
8
- public static final TimeUnit YEAR=new TimeUnit("Years", Calendar.YEAR, 365*24*60*60*1000L, "yyyy", "yyyy");
9
- public static final TimeUnit MONTH=new TimeUnit("Months", Calendar.MONTH, 30*24*60*60*1000L, "MMM", "MMM yyyy");
10
- public static final TimeUnit WEEK=new TimeUnit("Weeks", Calendar.WEEK_OF_YEAR, 7*24*60*60*1000L, "d", "MMM d yyyy");
11
- public static final TimeUnit DAY=new TimeUnit("Days", Calendar.DAY_OF_MONTH, 24*60*60*1000L, "d", "MMM d yyyy");
12
- public static final TimeUnit DAY_OF_WEEK=new TimeUnit("Days", Calendar.DAY_OF_WEEK, 24*60*60*1000L, "d", "MMM d yyyy");
13
- public static final TimeUnit HOUR=new TimeUnit("Hours", Calendar.HOUR_OF_DAY, 60*60*1000L, "kk:mm", "MMM d yyyy kk:mm");
14
- public static final TimeUnit MINUTE=new TimeUnit("Minutes", Calendar.MINUTE, 60*1000L, ":mm", "MMM d yyyy kk:mm");
15
- public static final TimeUnit SECOND=new TimeUnit("Seconds", Calendar.SECOND, 1000L, ":ss", "MMM d yyyy kk:mm:ss");
16
- public static final TimeUnit DECADE=multipleYears(10);
17
- public static final TimeUnit CENTURY=multipleYears(100);
18
-
19
- private static final double DAY_SIZE=24*60*60*1000L;
20
-
21
- private int quantity;
22
- private long roughSize;
23
- private SimpleDateFormat format, fullFormat;
24
- private String name;
25
- private int calendarCode;
26
-
27
- private TimeUnit()
28
- {
29
- }
30
-
31
- private TimeUnit(String name, int calendarCode, long roughSize, String formatPattern, String fullFormatPattern)
32
- {
33
- this.name=name;
34
- this.calendarCode=calendarCode;
35
- this.roughSize=roughSize;
36
- format=new SimpleDateFormat(formatPattern);
37
- fullFormat=new SimpleDateFormat(fullFormatPattern);
38
- quantity=1;
39
- }
40
-
41
- public String toString()
42
- {
43
- return "[TimeUnit: "+name+"]";
44
- }
27
+ private TimeUnit()
28
+ {
29
+ }
4530
46
- public static TimeUnit multipleYears(int numYears)
47
- {
48
- TimeUnit t=new TimeUnit();
49
- t.name=numYears+" Years";
50
- t.calendarCode=Calendar.YEAR;
51
- t.roughSize=YEAR.roughSize*numYears;
52
- t.format=YEAR.format;
53
- t.fullFormat=YEAR.fullFormat;
54
- t.quantity=numYears;
55
- return t;
56
- }
57
-
58
- public static TimeUnit multipleWeeks(int num)
59
- {
60
- TimeUnit t=new TimeUnit();
61
- t.name=num+" Weeks";
62
- t.calendarCode=Calendar.WEEK_OF_YEAR;
63
- t.roughSize=WEEK.roughSize*num;
64
- t.format=WEEK.format;
65
- t.fullFormat=WEEK.fullFormat;
66
- t.quantity=num;
67
- return t;
68
- }
69
-
70
- public TimeUnit times(int quantity)
71
- {
72
- TimeUnit t=new TimeUnit();
73
- t.name=quantity+" "+this.name;
74
- t.calendarCode=this.calendarCode;
75
- t.roughSize=this.roughSize*quantity;
76
- t.format=this.format;
77
- t.fullFormat=this.fullFormat;
78
- t.quantity=quantity;
79
- return t;
80
-
81
- }
31
+ private TimeUnit(String name, int calendarCode, long roughSize, String formatPattern, String fullFormatPattern)
32
+ {
33
+ this.name = name;
34
+ this.calendarCode = calendarCode;
35
+ this.roughSize = roughSize;
36
+ format = new SimpleDateFormat(formatPattern);
37
+ fullFormat = new SimpleDateFormat(fullFormatPattern);
38
+ quantity = 1;
39
+ }
8240
83
-
84
- public int numUnitsIn(TimeUnit u)
85
- {
86
- return (int)Math.round(u.getRoughSize()/(double)getRoughSize());
87
- }
88
-
89
- public boolean isDayOrLess()
90
- {
91
- return roughSize <= 24*60*60*1000L;
92
- }
93
-
94
- public RoughTime roundDown(long timestamp)
95
- {
96
- return round(timestamp, false);
97
- }
98
-
99
- public RoughTime roundUp(long timestamp)
100
- {
101
- return round(timestamp, true);
102
- }
103
-
104
- private static final int[] calendarUnits={Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR};
105
- public RoughTime round(long timestamp, boolean up)
106
- {
107
- Calendar c=TimeUtils.cal(timestamp);
108
-
109
- if (calendarCode==Calendar.WEEK_OF_YEAR )
110
- {
111
- c.set(Calendar.DAY_OF_WEEK, c.getMinimum(Calendar.DAY_OF_WEEK));
112
- }
113
- else
114
- {
115
-
116
- // set to minimum all fields of finer granularity.
117
- int roundingCode=calendarCode;
118
- if (calendarCode==Calendar.WEEK_OF_YEAR || calendarCode==Calendar.DAY_OF_WEEK)
119
- roundingCode=Calendar.DAY_OF_MONTH;
120
- for (int i=0; i<calendarUnits.length; i++)
121
- {
122
- if (calendarUnits[i]==roundingCode)
123
- break;
124
- if (i==calendarUnits.length-1)
125
- throw new IllegalArgumentException("Unsupported Calendar Unit: "+calendarCode);
126
- c.set(calendarUnits[i], c.getMinimum(calendarUnits[i]));
127
- }
128
- if (quantity>1)
129
- {
130
- c.set(calendarCode, quantity*(c.get(calendarCode)/quantity));
131
- }
132
- }
133
-
134
- // if rounding up, then add a unit at current granularity.
135
- if (up)
136
- c.add(calendarCode, quantity);
137
-
138
- return new RoughTime(c.getTimeInMillis(), this);
139
- }
140
-
141
- public int get(long timestamp)
142
- {
143
- Calendar c= TimeUtils.cal(timestamp);
144
- int n=c.get(calendarCode);
145
- return quantity==1 ? n : n%quantity;
146
- }
147
-
148
- public void addTo(RoughTime r)
149
- {
150
- addTo(r,1);
151
- }
152
-
153
- public void addTo(RoughTime r, int times)
154
- {
155
- Calendar c=TimeUtils.cal(r.getTime());
156
- c.add(calendarCode, quantity*times);
157
- r.setTime(c.getTimeInMillis());
158
- }
159
-
160
- // Finding the difference between two dates, in a given unit of time,
161
- // is much subtler than you'd think! And annoyingly, the Calendar class does not do
162
- // this for you, even though it actually "knows" how to do so since it
163
- // can add fields.
164
- //
165
- // The most vexing problem is dealing with daylight savings time,
166
- // which means that one day a year has 23 hours and one day has 25 hours.
167
- // We also have to handle the fact that months and years aren't constant lengths.
168
- //
169
- // Rather than write all this ourselves, in this code we
170
- // use the Calendar class to do the heavy lifting.
171
- public long difference(long x, long y)
172
- {
173
- // If this is not one of the hard cases,
174
- // just divide the timespan by the length of time unit.
175
- // Note that we're not worrying about hours and daylight savings time.
176
- if (calendarCode!=Calendar.YEAR && calendarCode!=Calendar.MONTH &&
177
- calendarCode!=Calendar.DAY_OF_MONTH && calendarCode!=Calendar.DAY_OF_WEEK &&
178
- calendarCode!=Calendar.WEEK_OF_YEAR)
179
- {
180
- return (x-y)/roughSize;
181
- }
182
-
183
- Calendar c1=TimeUtils.cal(x), c2=TimeUtils.cal(y);
184
- int diff=0;
185
- switch (calendarCode)
186
- {
187
- case Calendar.YEAR:
188
- return (c1.get(Calendar.YEAR)-c2.get(Calendar.YEAR))/quantity;
189
-
190
- case Calendar.MONTH:
191
- diff= 12*(c1.get(Calendar.YEAR)-c2.get(Calendar.YEAR))+
192
- c1.get(Calendar.MONTH)-c2.get(Calendar.MONTH);
193
- return diff/quantity;
194
-
195
- case Calendar.DAY_OF_MONTH:
196
- case Calendar.DAY_OF_WEEK:
197
- case Calendar.DAY_OF_YEAR:
198
- case Calendar.WEEK_OF_MONTH:
199
- case Calendar.WEEK_OF_YEAR:
200
- // This is ugly, but believe me, it beats the alternative methods :-)
201
- // We use the Calendar class's knowledge of daylight savings time.
202
- // and also the fact that if we calculate this naively, then we aren't going
203
- // to be off by more than one in either direction.
204
- int naive=(int)Math.round((x-y)/(double)roughSize);
205
- c2.add(calendarCode, naive*quantity);
206
- if (c1.get(calendarCode)==c2.get(calendarCode))
207
- return naive/quantity;
208
- c2.add(calendarCode, quantity);
209
- if (c1.get(calendarCode)==c2.get(calendarCode))
210
- return naive/quantity+1;
211
- return naive/quantity-1;
212
- }
213
- throw new IllegalArgumentException("Unexpected calendar code: "+calendarCode);
214
- }
41
+ public String toString()
42
+ {
43
+ return "[TimeUnit: " + name + "]";
44
+ }
21545
216
- public long approxNumInRange(long start, long end)
217
- {
218
- return 1+(end-start)/roughSize;
219
- }
220
-
221
- public long getRoughSize() {
222
- return roughSize;
223
- }
46
+ public static TimeUnit multipleYears(int numYears)
47
+ {
48
+ TimeUnit t = new TimeUnit();
49
+ t.name = numYears + " Years";
50
+ t.calendarCode = Calendar.YEAR;
51
+ t.roughSize = YEAR.roughSize * numYears;
52
+ t.format = YEAR.format;
53
+ t.fullFormat = YEAR.fullFormat;
54
+ t.quantity = numYears;
55
+ return t;
56
+ }
22457
225
- public String format(Date date)
226
- {
227
- return format.format(date);
228
- }
58
+ public static TimeUnit multipleWeeks(int num)
59
+ {
60
+ TimeUnit t = new TimeUnit();
61
+ t.name = num + " Weeks";
62
+ t.calendarCode = Calendar.WEEK_OF_YEAR;
63
+ t.roughSize = WEEK.roughSize * num;
64
+ t.format = WEEK.format;
65
+ t.fullFormat = WEEK.fullFormat;
66
+ t.quantity = num;
67
+ return t;
68
+ }
22969
230
- public String formatFull(Date date)
231
- {
232
- return fullFormat.format(date);
233
- }
70
+ public TimeUnit times(int quantity)
71
+ {
72
+ TimeUnit t = new TimeUnit();
73
+ t.name = quantity + " " + this.name;
74
+ t.calendarCode = this.calendarCode;
75
+ t.roughSize = this.roughSize * quantity;
76
+ t.format = this.format;
77
+ t.fullFormat = this.fullFormat;
78
+ t.quantity = quantity;
79
+ return t;
23480
235
- public String formatFull(long timestamp)
236
- {
237
- return fullFormat.format(new Date(timestamp));
238
- }
81
+ }
23982
240
- public String getName() {
241
- return name;
242
- }
83
+ public int numUnitsIn(TimeUnit u)
84
+ {
85
+ return (int) Math.round(u.getRoughSize() / (double) getRoughSize());
86
+ }
87
+
88
+ public boolean isDayOrLess()
89
+ {
90
+ return roughSize <= 24 * 60 * 60 * 1000L;
91
+ }
92
+
93
+ public RoughTime roundDown(long timestamp)
94
+ {
95
+ return round(timestamp, false);
96
+ }
97
+
98
+ public RoughTime roundUp(long timestamp)
99
+ {
100
+ return round(timestamp, true);
101
+ }
102
+ private static final int[] calendarUnits =
103
+ {
104
+ Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR
105
+ };
106
+
107
+ public RoughTime round(long timestamp, boolean up)
108
+ {
109
+ Calendar c = TimeUtils.cal(timestamp);
110
+
111
+ if (calendarCode == Calendar.WEEK_OF_YEAR)
112
+ {
113
+ c.set(Calendar.DAY_OF_WEEK, c.getMinimum(Calendar.DAY_OF_WEEK));
114
+ } else
115
+ {
116
+
117
+ // set to minimum all fields of finer granularity.
118
+ int roundingCode = calendarCode;
119
+ if (calendarCode == Calendar.WEEK_OF_YEAR || calendarCode == Calendar.DAY_OF_WEEK)
120
+ {
121
+ roundingCode = Calendar.DAY_OF_MONTH;
122
+ }
123
+ for (int i = 0; i < calendarUnits.length; i++)
124
+ {
125
+ if (calendarUnits[i] == roundingCode)
126
+ {
127
+ break;
128
+ }
129
+ if (i == calendarUnits.length - 1)
130
+ {
131
+ //throw new IllegalArgumentException("Unsupported Calendar Unit: " + calendarCode);
132
+ }
133
+ c.set(calendarUnits[i], c.getMinimum(calendarUnits[i]));
134
+ }
135
+ if (quantity > 1)
136
+ {
137
+ c.set(calendarCode, quantity * (c.get(calendarCode) / quantity));
138
+ }
139
+ }
140
+
141
+ // if rounding up, then add a unit at current granularity.
142
+ if (up)
143
+ {
144
+ c.add(calendarCode, quantity);
145
+ }
146
+
147
+ return new RoughTime(c.getTimeInMillis(), this);
148
+ }
149
+
150
+ public int get(long timestamp)
151
+ {
152
+ Calendar c = TimeUtils.cal(timestamp);
153
+ int n = c.get(calendarCode);
154
+ return quantity == 1 ? n : n % quantity;
155
+ }
156
+
157
+ public void addTo(RoughTime r)
158
+ {
159
+ addTo(r, 1);
160
+ }
161
+
162
+ public void addTo(RoughTime r, int times)
163
+ {
164
+ Calendar c = TimeUtils.cal(r.getTime());
165
+ c.add(calendarCode, quantity * times);
166
+ r.setTime(c.getTimeInMillis());
167
+ }
168
+
169
+ // Finding the difference between two dates, in a given unit of time,
170
+ // is much subtler than you'd think! And annoyingly, the Calendar class does not do
171
+ // this for you, even though it actually "knows" how to do so since it
172
+ // can add fields.
173
+ //
174
+ // The most vexing problem is dealing with daylight savings time,
175
+ // which means that one day a year has 23 hours and one day has 25 hours.
176
+ // We also have to handle the fact that months and years aren't constant lengths.
177
+ //
178
+ // Rather than write all this ourselves, in this code we
179
+ // use the Calendar class to do the heavy lifting.
180
+ public long difference(long x, long y)
181
+ {
182
+ // If this is not one of the hard cases,
183
+ // just divide the timespan by the length of time unit.
184
+ // Note that we're not worrying about hours and daylight savings time.
185
+ if (calendarCode != Calendar.YEAR && calendarCode != Calendar.MONTH
186
+ && calendarCode != Calendar.DAY_OF_MONTH && calendarCode != Calendar.DAY_OF_WEEK
187
+ && calendarCode != Calendar.WEEK_OF_YEAR)
188
+ {
189
+ return (x - y) / roughSize;
190
+ }
191
+
192
+ Calendar c1 = TimeUtils.cal(x), c2 = TimeUtils.cal(y);
193
+ int diff = 0;
194
+ switch (calendarCode)
195
+ {
196
+ case Calendar.YEAR:
197
+ return (c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR)) / quantity;
198
+
199
+ case Calendar.MONTH:
200
+ diff = 12 * (c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR))
201
+ + c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
202
+ return diff / quantity;
203
+
204
+ case Calendar.DAY_OF_MONTH:
205
+ case Calendar.DAY_OF_WEEK:
206
+ case Calendar.DAY_OF_YEAR:
207
+ case Calendar.WEEK_OF_MONTH:
208
+ case Calendar.WEEK_OF_YEAR:
209
+ // This is ugly, but believe me, it beats the alternative methods :-)
210
+ // We use the Calendar class's knowledge of daylight savings time.
211
+ // and also the fact that if we calculate this naively, then we aren't going
212
+ // to be off by more than one in either direction.
213
+ int naive = (int) Math.round((x - y) / (double) roughSize);
214
+ c2.add(calendarCode, naive * quantity);
215
+ if (c1.get(calendarCode) == c2.get(calendarCode))
216
+ {
217
+ return naive / quantity;
218
+ }
219
+ c2.add(calendarCode, quantity);
220
+ if (c1.get(calendarCode) == c2.get(calendarCode))
221
+ {
222
+ return naive / quantity + 1;
223
+ }
224
+ return naive / quantity - 1;
225
+ }
226
+ throw new IllegalArgumentException("Unexpected calendar code: " + calendarCode);
227
+ }
228
+
229
+ public long approxNumInRange(long start, long end)
230
+ {
231
+ return 1 + (end - start) / roughSize;
232
+ }
233
+
234
+ public long getRoughSize()
235
+ {
236
+ return roughSize;
237
+ }
238
+
239
+ public String format(Date date)
240
+ {
241
+ return format.format(date);
242
+ }
243
+
244
+ public String formatFull(Date date)
245
+ {
246
+ return fullFormat.format(date);
247
+ }
248
+
249
+ public String formatFull(long timestamp)
250
+ {
251
+ return fullFormat.format(new Date(timestamp));
252
+ }
253
+
254
+ public String getName()
255
+ {
256
+ return name;
257
+ }
243258 }