@@ -59,8 +59,9 @@ public enum DateTimeUnit {
59
59
WEEK_OF_WEEKYEAR ((byte ) 1 , "week" , IsoFields .WEEK_OF_WEEK_BASED_YEAR , true , TimeUnit .DAYS .toMillis (7 )) {
60
60
private final long extraLocalOffsetLookup = TimeUnit .DAYS .toMillis (7 );
61
61
62
- long roundFloor (long utcMillis ) {
63
- return DateUtils .roundWeekOfWeekYear (utcMillis );
62
+ @ Override
63
+ long roundFloor (long utcMillis , int multiplier ) {
64
+ return DateUtils .roundWeekIntervalOfWeekYear (utcMillis , multiplier );
64
65
}
65
66
66
67
@ Override
@@ -71,50 +72,62 @@ long extraLocalOffsetLookup() {
71
72
YEAR_OF_CENTURY ((byte ) 2 , "year" , ChronoField .YEAR_OF_ERA , false , 12 ) {
72
73
private final long extraLocalOffsetLookup = TimeUnit .DAYS .toMillis (366 );
73
74
74
- long roundFloor (long utcMillis ) {
75
- return DateUtils .roundYear (utcMillis );
75
+ @ Override
76
+ long roundFloor (long utcMillis , int multiplier ) {
77
+ return multiplier == 1 ? DateUtils .roundYear (utcMillis ) : DateUtils .roundYearInterval (utcMillis , multiplier );
76
78
}
77
79
80
+ @ Override
78
81
long extraLocalOffsetLookup () {
79
82
return extraLocalOffsetLookup ;
80
83
}
81
84
},
82
85
QUARTER_OF_YEAR ((byte ) 3 , "quarter" , IsoFields .QUARTER_OF_YEAR , false , 3 ) {
83
86
private final long extraLocalOffsetLookup = TimeUnit .DAYS .toMillis (92 );
84
87
85
- long roundFloor (long utcMillis ) {
86
- return DateUtils .roundQuarterOfYear (utcMillis );
88
+ @ Override
89
+ long roundFloor (long utcMillis , int multiplier ) {
90
+ return multiplier == 1
91
+ ? DateUtils .roundQuarterOfYear (utcMillis )
92
+ : DateUtils .roundIntervalMonthOfYear (utcMillis , multiplier * 3 );
87
93
}
88
94
95
+ @ Override
89
96
long extraLocalOffsetLookup () {
90
97
return extraLocalOffsetLookup ;
91
98
}
92
99
},
93
100
MONTH_OF_YEAR ((byte ) 4 , "month" , ChronoField .MONTH_OF_YEAR , false , 1 ) {
94
101
private final long extraLocalOffsetLookup = TimeUnit .DAYS .toMillis (31 );
95
102
96
- long roundFloor (long utcMillis ) {
97
- return DateUtils .roundMonthOfYear (utcMillis );
103
+ @ Override
104
+ long roundFloor (long utcMillis , int multiplier ) {
105
+ return multiplier == 1 ? DateUtils .roundMonthOfYear (utcMillis ) : DateUtils .roundIntervalMonthOfYear (utcMillis , multiplier );
98
106
}
99
107
108
+ @ Override
100
109
long extraLocalOffsetLookup () {
101
110
return extraLocalOffsetLookup ;
102
111
}
103
112
},
104
113
DAY_OF_MONTH ((byte ) 5 , "day" , ChronoField .DAY_OF_MONTH , true , ChronoField .DAY_OF_MONTH .getBaseUnit ().getDuration ().toMillis ()) {
105
- long roundFloor (long utcMillis ) {
106
- return DateUtils .roundFloor (utcMillis , this .ratio );
114
+ @ Override
115
+ long roundFloor (long utcMillis , int multiplier ) {
116
+ return DateUtils .roundFloor (utcMillis , this .ratio * multiplier );
107
117
}
108
118
119
+ @ Override
109
120
long extraLocalOffsetLookup () {
110
121
return ratio ;
111
122
}
112
123
},
113
124
HOUR_OF_DAY ((byte ) 6 , "hour" , ChronoField .HOUR_OF_DAY , true , ChronoField .HOUR_OF_DAY .getBaseUnit ().getDuration ().toMillis ()) {
114
- long roundFloor (long utcMillis ) {
115
- return DateUtils .roundFloor (utcMillis , ratio );
125
+ @ Override
126
+ long roundFloor (long utcMillis , int multiplier ) {
127
+ return DateUtils .roundFloor (utcMillis , ratio * multiplier );
116
128
}
117
129
130
+ @ Override
118
131
long extraLocalOffsetLookup () {
119
132
return ratio ;
120
133
}
@@ -126,10 +139,12 @@ long extraLocalOffsetLookup() {
126
139
true ,
127
140
ChronoField .MINUTE_OF_HOUR .getBaseUnit ().getDuration ().toMillis ()
128
141
) {
129
- long roundFloor (long utcMillis ) {
130
- return DateUtils .roundFloor (utcMillis , ratio );
142
+ @ Override
143
+ long roundFloor (long utcMillis , int multiplier ) {
144
+ return DateUtils .roundFloor (utcMillis , ratio * multiplier );
131
145
}
132
146
147
+ @ Override
133
148
long extraLocalOffsetLookup () {
134
149
return ratio ;
135
150
}
@@ -141,10 +156,12 @@ long extraLocalOffsetLookup() {
141
156
true ,
142
157
ChronoField .SECOND_OF_MINUTE .getBaseUnit ().getDuration ().toMillis ()
143
158
) {
144
- long roundFloor (long utcMillis ) {
145
- return DateUtils .roundFloor (utcMillis , ratio );
159
+ @ Override
160
+ long roundFloor (long utcMillis , int multiplier ) {
161
+ return DateUtils .roundFloor (utcMillis , ratio * multiplier );
146
162
}
147
163
164
+ @ Override
148
165
long extraLocalOffsetLookup () {
149
166
return ratio ;
150
167
}
@@ -171,10 +188,11 @@ long extraLocalOffsetLookup() {
171
188
* This rounds down the supplied milliseconds since the epoch down to the next unit. In order to retain performance this method
172
189
* should be as fast as possible and not try to convert dates to java-time objects if possible
173
190
*
174
- * @param utcMillis the milliseconds since the epoch
175
- * @return the rounded down milliseconds since the epoch
191
+ * @param utcMillis the milliseconds since the epoch
192
+ * @param multiplier the factor by which the unit is multiplied
193
+ * @return the rounded down milliseconds since the epoch
176
194
*/
177
- abstract long roundFloor (long utcMillis );
195
+ abstract long roundFloor (long utcMillis , int multiplier );
178
196
179
197
/**
180
198
* When looking up {@link LocalTimeOffset} go this many milliseconds
@@ -329,17 +347,24 @@ public static class Builder {
329
347
330
348
private final DateTimeUnit unit ;
331
349
private final long interval ;
350
+ private final int multiplier ;
332
351
333
352
private ZoneId timeZone = ZoneOffset .UTC ;
334
353
private long offset = 0 ;
335
354
336
355
public Builder (DateTimeUnit unit ) {
356
+ this (unit , 1 );
357
+ }
358
+
359
+ public Builder (DateTimeUnit unit , int multiplier ) {
337
360
this .unit = unit ;
361
+ this .multiplier = multiplier ;
338
362
this .interval = -1 ;
339
363
}
340
364
341
365
public Builder (TimeValue interval ) {
342
366
this .unit = null ;
367
+ this .multiplier = -1 ;
343
368
if (interval .millis () < 1 ) throw new IllegalArgumentException ("Zero or negative time interval not supported" );
344
369
this .interval = interval .millis ();
345
370
}
@@ -365,7 +390,7 @@ public Builder offset(long offset) {
365
390
public Rounding build () {
366
391
Rounding rounding ;
367
392
if (unit != null ) {
368
- rounding = new TimeUnitRounding (unit , timeZone );
393
+ rounding = new TimeUnitRounding (unit , multiplier , timeZone );
369
394
} else {
370
395
rounding = new TimeIntervalRounding (interval , timeZone );
371
396
}
@@ -422,11 +447,17 @@ static class TimeUnitRounding extends Rounding {
422
447
private final DateTimeUnit unit ;
423
448
private final ZoneId timeZone ;
424
449
private final boolean unitRoundsToMidnight ;
450
+ private final int multiplier ;
425
451
426
452
TimeUnitRounding (DateTimeUnit unit , ZoneId timeZone ) {
453
+ this (unit , 1 , timeZone );
454
+ }
455
+
456
+ TimeUnitRounding (DateTimeUnit unit , int multiplier , ZoneId timeZone ) {
427
457
this .unit = unit ;
428
458
this .timeZone = timeZone ;
429
459
this .unitRoundsToMidnight = this .unit .field .getBaseUnit ().getDuration ().toMillis () > 3600000L ;
460
+ this .multiplier = multiplier ;
430
461
}
431
462
432
463
TimeUnitRounding (StreamInput in ) throws IOException {
@@ -660,7 +691,7 @@ private class FixedToMidnightRounding extends TimeUnitPreparedRounding {
660
691
661
692
@ Override
662
693
public long round (long utcMillis ) {
663
- return offset .localToUtcInThisOffset (unit .roundFloor (offset .utcToLocalTime (utcMillis )));
694
+ return offset .localToUtcInThisOffset (unit .roundFloor (offset .utcToLocalTime (utcMillis ), multiplier ));
664
695
}
665
696
666
697
@ Override
@@ -686,7 +717,7 @@ private class FixedNotToMidnightRounding extends TimeUnitPreparedRounding {
686
717
687
718
@ Override
688
719
public long round (long utcMillis ) {
689
- return offset .localToUtcInThisOffset (unit .roundFloor (offset .utcToLocalTime (utcMillis )));
720
+ return offset .localToUtcInThisOffset (unit .roundFloor (offset .utcToLocalTime (utcMillis ), multiplier ));
690
721
}
691
722
692
723
@ Override
@@ -710,7 +741,7 @@ private class ToMidnightRounding extends TimeUnitPreparedRounding implements Loc
710
741
@ Override
711
742
public long round (long utcMillis ) {
712
743
LocalTimeOffset offset = lookup .lookup (utcMillis );
713
- return offset .localToUtc (unit .roundFloor (offset .utcToLocalTime (utcMillis )), this );
744
+ return offset .localToUtc (unit .roundFloor (offset .utcToLocalTime (utcMillis ), multiplier ), this );
714
745
}
715
746
716
747
@ Override
@@ -764,14 +795,14 @@ private class NotToMidnightRounding extends AbstractNotToMidnightRounding implem
764
795
@ Override
765
796
public long round (long utcMillis ) {
766
797
LocalTimeOffset offset = lookup .lookup (utcMillis );
767
- long roundedLocalMillis = unit .roundFloor (offset .utcToLocalTime (utcMillis ));
798
+ long roundedLocalMillis = unit .roundFloor (offset .utcToLocalTime (utcMillis ), multiplier );
768
799
return offset .localToUtc (roundedLocalMillis , this );
769
800
}
770
801
771
802
@ Override
772
803
public long inGap (long localMillis , Gap gap ) {
773
804
// Round from just before the start of the gap
774
- return gap .previous ().localToUtc (unit .roundFloor (gap .firstMissingLocalTime () - 1 ), this );
805
+ return gap .previous ().localToUtc (unit .roundFloor (gap .firstMissingLocalTime () - 1 , multiplier ), this );
775
806
}
776
807
777
808
@ Override
0 commit comments