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