Skip to content

Commit 88a67b0

Browse files
pekingmedsn5ft
authored andcommitted
Fixed getDayCopy utility function in UtcDates for DatePicker.
- was copying year/month/date fields between Calendar objects in different time zones. - convert input Calendar object into a Calendar object in UTC, then copy year/month/date fields to the return Calendar object. PiperOrigin-RevId: 284597830 (cherry picked from commit 6694175)
1 parent dbd7079 commit 88a67b0

File tree

11 files changed

+69
-35
lines changed

11 files changed

+69
-35
lines changed

lib/java/com/google/android/material/datepicker/DateStrings.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static String getDateString(long timeInMillis) {
111111
*/
112112
static String getDateString(long timeInMillis, @Nullable SimpleDateFormat userDefinedDateFormat) {
113113
Calendar currentCalendar = UtcDates.getTodayCalendar();
114-
Calendar calendarDate = UtcDates.getCalendar();
114+
Calendar calendarDate = UtcDates.getUtcCalendar();
115115
calendarDate.setTimeInMillis(timeInMillis);
116116

117117
if (userDefinedDateFormat != null) {
@@ -154,9 +154,9 @@ static Pair<String, String> getDateRangeString(
154154
}
155155

156156
Calendar currentCalendar = UtcDates.getTodayCalendar();
157-
Calendar startCalendar = UtcDates.getCalendar();
157+
Calendar startCalendar = UtcDates.getUtcCalendar();
158158
startCalendar.setTimeInMillis(start);
159-
Calendar endCalendar = UtcDates.getCalendar();
159+
Calendar endCalendar = UtcDates.getUtcCalendar();
160160
endCalendar.setTimeInMillis(end);
161161

162162
if (userDefinedDateFormat != null) {

lib/java/com/google/android/material/datepicker/DaysOfWeekAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class DaysOfWeekAdapter extends BaseAdapter {
5050
VERSION.SDK_INT >= VERSION_CODES.O ? NARROW_FORMAT : Calendar.SHORT;
5151

5252
public DaysOfWeekAdapter() {
53-
calendar = UtcDates.getCalendar();
53+
calendar = UtcDates.getUtcCalendar();
5454
daysInWeek = calendar.getMaximum(Calendar.DAY_OF_WEEK);
5555
firstDayOfWeek = calendar.getFirstDayOfWeek();
5656
}

lib/java/com/google/android/material/datepicker/MaterialCalendar.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ public void onDayClick(long day) {
230230
private ItemDecoration createItemDecoration() {
231231
return new ItemDecoration() {
232232

233-
private final Calendar startItem = UtcDates.getCalendar();
234-
private final Calendar endItem = UtcDates.getCalendar();
233+
private final Calendar startItem = UtcDates.getUtcCalendar();
234+
private final Calendar endItem = UtcDates.getUtcCalendar();
235235

236236
@Override
237237
public void onDraw(

lib/java/com/google/android/material/datepicker/MaterialCalendarGridView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
final class MaterialCalendarGridView extends GridView {
3737

38-
private final Calendar dayCompute = UtcDates.getCalendar();
38+
private final Calendar dayCompute = UtcDates.getUtcCalendar();
3939

4040
public MaterialCalendarGridView(Context context) {
4141
this(context, null);

lib/java/com/google/android/material/datepicker/Month.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private Month(@NonNull Calendar rawCalendar) {
7171
*/
7272
@NonNull
7373
static Month create(long timeInMillis) {
74-
Calendar calendar = UtcDates.getCalendar();
74+
Calendar calendar = UtcDates.getUtcCalendar();
7575
calendar.setTimeInMillis(timeInMillis);
7676
return new Month(calendar);
7777
}
@@ -86,7 +86,7 @@ static Month create(long timeInMillis) {
8686
*/
8787
@NonNull
8888
static Month create(int year, @Months int month) {
89-
Calendar calendar = UtcDates.getCalendar();
89+
Calendar calendar = UtcDates.getUtcCalendar();
9090
calendar.set(Calendar.YEAR, year);
9191
calendar.set(Calendar.MONTH, month);
9292
return new Month(calendar);

lib/java/com/google/android/material/datepicker/MonthAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class MonthAdapter extends BaseAdapter {
3838
/**
3939
* The maximum number of weeks possible in any month. 6 for {@link java.util.GregorianCalendar}.
4040
*/
41-
static final int MAXIMUM_WEEKS = UtcDates.getCalendar().getMaximum(Calendar.WEEK_OF_MONTH);
41+
static final int MAXIMUM_WEEKS = UtcDates.getUtcCalendar().getMaximum(Calendar.WEEK_OF_MONTH);
4242

4343
final Month month;
4444
/**

lib/java/com/google/android/material/datepicker/UtcDates.java

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.content.res.Resources;
2222
import android.os.Build.VERSION_CODES;
2323
import androidx.annotation.NonNull;
24+
import androidx.annotation.Nullable;
2425
import java.text.DateFormat;
2526
import java.text.SimpleDateFormat;
2627
import java.util.Calendar;
@@ -37,32 +38,64 @@ class UtcDates {
3738

3839
private UtcDates() {}
3940

40-
static TimeZone getTimeZone() {
41+
private static TimeZone getTimeZone() {
4142
return TimeZone.getTimeZone(UTC);
4243
}
4344

4445
@TargetApi(VERSION_CODES.N)
45-
private static android.icu.util.TimeZone getAndroidTimeZone() {
46+
private static android.icu.util.TimeZone getUtcAndroidTimeZone() {
4647
return android.icu.util.TimeZone.getTimeZone(UTC);
4748
}
4849

4950
static Calendar getTodayCalendar() {
5051
return getDayCopy(Calendar.getInstance());
5152
}
5253

53-
static Calendar getCalendar() {
54+
/**
55+
* Returns an empty Calendar in UTC time zone.
56+
*
57+
* @return An empty Calendar in UTC time zone.
58+
* @see {@link #getUtcCalendarOf(Calendar)}
59+
* @see Calendar#clear()
60+
*/
61+
static Calendar getUtcCalendar() {
62+
return getUtcCalendarOf(null);
63+
}
64+
65+
/**
66+
* Returns a Calendar object in UTC time zone representing the moment in input Calendar object. An
67+
* empty Calendar object in UTC will be return if input is null.
68+
*
69+
* @param rawCalendar the Calendar object representing the moment to process.
70+
* @return A Calendar object in UTC time zone.
71+
* @see @see Calendar#clear()
72+
*/
73+
static Calendar getUtcCalendarOf(@Nullable Calendar rawCalendar) {
5474
Calendar utc = Calendar.getInstance(getTimeZone());
55-
utc.clear();
75+
if (rawCalendar == null) {
76+
utc.clear();
77+
} else {
78+
utc.setTimeInMillis(rawCalendar.getTimeInMillis());
79+
}
5680
return utc;
5781
}
5882

83+
/**
84+
* Returns a Calendar object in UTC time zone representing the start of day in UTC represented in
85+
* the input Calendar object, i.e., the time (fields smaller than a day) is stripped based on the
86+
* UTC time zone.
87+
*
88+
* @param rawCalendar the Calendar object representing the moment to process.
89+
* @return A Calendar object representing the start of day in UTC time zone.
90+
*/
5991
static Calendar getDayCopy(Calendar rawCalendar) {
60-
Calendar safe = getCalendar();
61-
safe.set(
62-
rawCalendar.get(Calendar.YEAR),
63-
rawCalendar.get(Calendar.MONTH),
64-
rawCalendar.get(Calendar.DAY_OF_MONTH));
65-
return safe;
92+
Calendar rawCalendarInUtc = getUtcCalendarOf(rawCalendar);
93+
Calendar utcCalendar = getUtcCalendar();
94+
utcCalendar.set(
95+
rawCalendarInUtc.get(Calendar.YEAR),
96+
rawCalendarInUtc.get(Calendar.MONTH),
97+
rawCalendarInUtc.get(Calendar.DAY_OF_MONTH));
98+
return utcCalendar;
6699
}
67100

68101
/**
@@ -73,7 +106,7 @@ static Calendar getDayCopy(Calendar rawCalendar) {
73106
* @return A canonical long representing the time as UTC milliseconds for the represented day.
74107
*/
75108
static long canonicalYearMonthDay(long rawDate) {
76-
Calendar rawCalendar = getCalendar();
109+
Calendar rawCalendar = getUtcCalendar();
77110
rawCalendar.setTimeInMillis(rawDate);
78111
Calendar sanitizedStartItem = getDayCopy(rawCalendar);
79112
return sanitizedStartItem.getTimeInMillis();
@@ -83,7 +116,7 @@ static long canonicalYearMonthDay(long rawDate) {
83116
private static android.icu.text.DateFormat getAndroidFormat(String pattern, Locale locale) {
84117
android.icu.text.DateFormat format =
85118
android.icu.text.DateFormat.getInstanceForSkeleton(pattern, locale);
86-
format.setTimeZone(getAndroidTimeZone());
119+
format.setTimeZone(getUtcAndroidTimeZone());
87120
return format;
88121
}
89122

lib/javatests/com/google/android/material/datepicker/MaterialDatePickerTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.time.Duration;
2222
import java.util.Calendar;
23+
import java.util.TimeZone;
2324
import org.junit.Test;
2425
import org.junit.runner.RunWith;
2526
import org.robolectric.RobolectricTestRunner;
@@ -33,9 +34,9 @@ public class MaterialDatePickerTest {
3334
@Test
3435
public void testTodayInUtcMilliseconds() {
3536
long todayUtcMS = MaterialDatePicker.todayInUtcMilliseconds();
36-
Calendar outputUtcTodayInCalendar = Calendar.getInstance(UtcDates.getTimeZone());
37+
Calendar outputUtcTodayInCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
3738
outputUtcTodayInCalendar.setTimeInMillis(todayUtcMS);
38-
Calendar expectedUtcTodayInCalendar = Calendar.getInstance(UtcDates.getTimeZone());
39+
Calendar expectedUtcTodayInCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
3940

4041
// Assert fields finer than a day are stripped.
4142
assertThat(todayUtcMS % ONE_DAY_MILLIS).isEqualTo(0);
@@ -51,9 +52,9 @@ public void testTodayInUtcMilliseconds() {
5152
@Test
5253
public void testThisMonthInUtcMilliseconds() {
5354
long thisMonthUtcMS = MaterialDatePicker.thisMonthInUtcMilliseconds();
54-
Calendar outputUtcThisMonthInCalendar = Calendar.getInstance(UtcDates.getTimeZone());
55+
Calendar outputUtcThisMonthInCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
5556
outputUtcThisMonthInCalendar.setTimeInMillis(thisMonthUtcMS);
56-
Calendar expectedUtcThisMonthInCalendar = Calendar.getInstance(UtcDates.getTimeZone());
57+
Calendar expectedUtcThisMonthInCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
5758

5859
// Assert fields finer than a day are stripped.
5960
assertThat(thisMonthUtcMS % ONE_DAY_MILLIS).isEqualTo(0);

lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ public void ilDaysOfPositions() {
254254

255255
private void assertDaysOfPositions(Map<Integer, Integer> localizedDaysOfPositionsInFebruary2019) {
256256
for (int day : localizedDaysOfPositionsInFebruary2019.keySet()) {
257-
Calendar testCalendar = UtcDates.getCalendar();
257+
Calendar testCalendar = UtcDates.getUtcCalendar();
258258
testCalendar.setTimeInMillis(monthFeb2019.getItem(day));
259259
assertEquals(
260260
(int) localizedDaysOfPositionsInFebruary2019.get(day),

lib/javatests/com/google/android/material/datepicker/RangeDateSelectorTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,15 @@ public void nullDateSelectionFromParcel() {
161161

162162
@Test
163163
public void setSelectionDirectly() {
164-
Calendar setToStart = UtcDates.getCalendar();
164+
Calendar setToStart = UtcDates.getUtcCalendar();
165165
setToStart.set(2004, Calendar.MARCH, 5);
166-
Calendar setToEnd = UtcDates.getCalendar();
166+
Calendar setToEnd = UtcDates.getUtcCalendar();
167167
setToEnd.set(2005, Calendar.FEBRUARY, 1);
168168

169169
rangeDateSelector.setSelection(
170170
new Pair<>(setToStart.getTimeInMillis(), setToEnd.getTimeInMillis()));
171-
Calendar resultCalendarStart = UtcDates.getCalendar();
172-
Calendar resultCalendarEnd = UtcDates.getCalendar();
171+
Calendar resultCalendarStart = UtcDates.getUtcCalendar();
172+
Calendar resultCalendarEnd = UtcDates.getUtcCalendar();
173173
resultCalendarStart.setTimeInMillis(rangeDateSelector.getSelection().first);
174174
resultCalendarEnd.setTimeInMillis(rangeDateSelector.getSelection().second);
175175

@@ -195,9 +195,9 @@ public void setSelectionDirectly() {
195195

196196
@Test
197197
public void invalidSetThrowsException() {
198-
Calendar setToStart = UtcDates.getCalendar();
198+
Calendar setToStart = UtcDates.getUtcCalendar();
199199
setToStart.set(2005, Calendar.FEBRUARY, 1);
200-
Calendar setToEnd = UtcDates.getCalendar();
200+
Calendar setToEnd = UtcDates.getUtcCalendar();
201201
;
202202
setToEnd.set(2004, Calendar.MARCH, 5);
203203

0 commit comments

Comments
 (0)