Merge "Convert some users of Time.format() to an alt." am: 267b83e7d6 am: 1b0c2fcd3b
Change-Id: I1cb9722000898c9d1a7d479e9b0d88f717c57414
This commit is contained in:
@@ -40,7 +40,7 @@ import android.database.DatabaseUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Time;
|
||||
import android.text.format.TimeMigrationUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -1680,7 +1680,7 @@ public final class CalendarContract {
|
||||
* <h3>Writing to Events</h3> There are further restrictions on all Updates
|
||||
* and Inserts in the Events table:
|
||||
* <ul>
|
||||
* <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC}
|
||||
* <li>If allDay is set to 1 eventTimezone must be "UTC"
|
||||
* and the time must correspond to a midnight boundary.</li>
|
||||
* <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
|
||||
* original_id and original_sync_id must be empty.</li>
|
||||
@@ -2609,9 +2609,7 @@ public final class CalendarContract {
|
||||
@UnsupportedAppUsage
|
||||
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
|
||||
if (DEBUG) {
|
||||
Time time = new Time();
|
||||
time.set(alarmTime);
|
||||
String schedTime = time.format(" %a, %b %d, %Y %I:%M%P");
|
||||
String schedTime = TimeMigrationUtils.formatMillisWithFixedFormat(alarmTime);
|
||||
Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ import libcore.icu.LocaleData;
|
||||
import libcore.util.ZoneInfo;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
@@ -85,6 +88,59 @@ class TimeFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The implementation of {@link TimeMigrationUtils#formatMillisWithFixedFormat(long)} for
|
||||
* 2038-safe formatting with the pattern "%Y-%m-%d %H:%M:%S" and including the historic
|
||||
* incorrect digit localization behavior.
|
||||
*/
|
||||
String formatMillisWithFixedFormat(long timeMillis) {
|
||||
// This method is deliberately not a general purpose replacement for
|
||||
// format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the
|
||||
// pattern characters supported by Time.format() have unusual behavior which would make
|
||||
// using java.time.format or similar packages difficult. It would be a lot of work to share
|
||||
// behavior and many internal Android usecases can be covered by this common pattern
|
||||
// behavior.
|
||||
|
||||
// No need to worry about overflow / underflow: long millis is representable by Instant and
|
||||
// LocalDateTime with room to spare.
|
||||
Instant instant = Instant.ofEpochMilli(timeMillis);
|
||||
|
||||
// Date/times are calculated in the current system default time zone.
|
||||
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
|
||||
// You'd think it would be as simple as:
|
||||
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", locale);
|
||||
// return formatter.format(localDateTime);
|
||||
// but we retain Time's behavior around digits.
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder(19);
|
||||
|
||||
// This effectively uses the US locale because number localization is handled separately
|
||||
// (see below).
|
||||
stringBuilder.append(localDateTime.getYear());
|
||||
stringBuilder.append('-');
|
||||
append2DigitNumber(stringBuilder, localDateTime.getMonthValue());
|
||||
stringBuilder.append('-');
|
||||
append2DigitNumber(stringBuilder, localDateTime.getDayOfMonth());
|
||||
stringBuilder.append(' ');
|
||||
append2DigitNumber(stringBuilder, localDateTime.getHour());
|
||||
stringBuilder.append(':');
|
||||
append2DigitNumber(stringBuilder, localDateTime.getMinute());
|
||||
stringBuilder.append(':');
|
||||
append2DigitNumber(stringBuilder, localDateTime.getSecond());
|
||||
|
||||
String result = stringBuilder.toString();
|
||||
return localizeDigits(result);
|
||||
}
|
||||
|
||||
/** Zero-pads value as needed to achieve a 2-digit number. */
|
||||
private static void append2DigitNumber(StringBuilder builder, int value) {
|
||||
if (value < 10) {
|
||||
builder.append('0');
|
||||
}
|
||||
builder.append(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the specified {@code wallTime} using {@code pattern}. The output is returned.
|
||||
*/
|
||||
@@ -99,12 +155,9 @@ class TimeFormatter {
|
||||
|
||||
formatInternal(pattern, wallTime, zoneInfo);
|
||||
String result = stringBuilder.toString();
|
||||
// This behavior is the source of a bug since some formats are defined as being
|
||||
// in ASCII and not localized.
|
||||
if (localeData.zeroDigit != '0') {
|
||||
result = localizeDigits(result);
|
||||
}
|
||||
return result;
|
||||
// The localizeDigits() behavior is the source of a bug since some formats are defined
|
||||
// as being in ASCII and not localized.
|
||||
return localizeDigits(result);
|
||||
} finally {
|
||||
outputBuilder = null;
|
||||
numberFormatter = null;
|
||||
@@ -112,6 +165,10 @@ class TimeFormatter {
|
||||
}
|
||||
|
||||
private String localizeDigits(String s) {
|
||||
if (localeData.zeroDigit == '0') {
|
||||
return s;
|
||||
}
|
||||
|
||||
int length = s.length();
|
||||
int offsetToLocalizedDigits = localeData.zeroDigit - '0';
|
||||
StringBuilder result = new StringBuilder(length);
|
||||
|
||||
40
core/java/android/text/format/TimeMigrationUtils.java
Normal file
40
core/java/android/text/format/TimeMigrationUtils.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.text.format;
|
||||
|
||||
/**
|
||||
* Logic to ease migration away from {@link Time} in Android internal code. {@link Time} is
|
||||
* afflicted by the Y2038 issue and deprecated. The methods here are intended to allow minimal
|
||||
* changes to classes that use {@link Time} for common behavior.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TimeMigrationUtils {
|
||||
|
||||
private TimeMigrationUtils() {}
|
||||
|
||||
/**
|
||||
* A Y2038-safe replacement for various users of the {@link Time#format(String)} with the
|
||||
* pattern "%Y-%m-%d %H:%M:%S". Note, this method retains the unusual localization behavior
|
||||
* originally implemented by Time, which can lead to non-latin numbers being produced if the
|
||||
* default locale does not use latin numbers.
|
||||
*/
|
||||
public static String formatMillisWithFixedFormat(long timeMillis) {
|
||||
// Delegate to TimeFormatter so that the unusual localization / threading behavior can be
|
||||
// reused.
|
||||
return new TimeFormatter().formatMillisWithFixedFormat(timeMillis);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user