Merge "Convert some users of Time.format() to an alt."
This commit is contained in:
@@ -40,7 +40,7 @@ import android.database.DatabaseUtils;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Time;
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.util.Preconditions;
|
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
|
* <h3>Writing to Events</h3> There are further restrictions on all Updates
|
||||||
* and Inserts in the Events table:
|
* and Inserts in the Events table:
|
||||||
* <ul>
|
* <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>
|
* and the time must correspond to a midnight boundary.</li>
|
||||||
* <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
|
* <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
|
||||||
* original_id and original_sync_id must be empty.</li>
|
* original_id and original_sync_id must be empty.</li>
|
||||||
@@ -2609,9 +2609,7 @@ public final class CalendarContract {
|
|||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
|
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Time time = new Time();
|
String schedTime = TimeMigrationUtils.formatMillisWithFixedFormat(alarmTime);
|
||||||
time.set(alarmTime);
|
|
||||||
String schedTime = time.format(" %a, %b %d, %Y %I:%M%P");
|
|
||||||
Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
|
Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ import libcore.icu.LocaleData;
|
|||||||
import libcore.util.ZoneInfo;
|
import libcore.util.ZoneInfo;
|
||||||
|
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
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.
|
* Format the specified {@code wallTime} using {@code pattern}. The output is returned.
|
||||||
*/
|
*/
|
||||||
@@ -99,12 +155,9 @@ class TimeFormatter {
|
|||||||
|
|
||||||
formatInternal(pattern, wallTime, zoneInfo);
|
formatInternal(pattern, wallTime, zoneInfo);
|
||||||
String result = stringBuilder.toString();
|
String result = stringBuilder.toString();
|
||||||
// This behavior is the source of a bug since some formats are defined as being
|
// The localizeDigits() behavior is the source of a bug since some formats are defined
|
||||||
// in ASCII and not localized.
|
// as being in ASCII and not localized.
|
||||||
if (localeData.zeroDigit != '0') {
|
return localizeDigits(result);
|
||||||
result = localizeDigits(result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} finally {
|
} finally {
|
||||||
outputBuilder = null;
|
outputBuilder = null;
|
||||||
numberFormatter = null;
|
numberFormatter = null;
|
||||||
@@ -112,6 +165,10 @@ class TimeFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String localizeDigits(String s) {
|
private String localizeDigits(String s) {
|
||||||
|
if (localeData.zeroDigit == '0') {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
int length = s.length();
|
int length = s.length();
|
||||||
int offsetToLocalizedDigits = localeData.zeroDigit - '0';
|
int offsetToLocalizedDigits = localeData.zeroDigit - '0';
|
||||||
StringBuilder result = new StringBuilder(length);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@Presubmit
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TimeMigrationUtilsTest {
|
||||||
|
|
||||||
|
private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
|
||||||
|
|
||||||
|
private Locale mDefaultLocale;
|
||||||
|
private TimeZone mDefaultTimeZone;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mDefaultLocale = Locale.getDefault();
|
||||||
|
mDefaultTimeZone = TimeZone.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
Locale.setDefault(mDefaultLocale);
|
||||||
|
TimeZone.setDefault(mDefaultTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatMillisWithFixedFormat_fixes2038Issue() {
|
||||||
|
Locale.setDefault(Locale.UK);
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||||
|
|
||||||
|
// The following cannot be represented properly using Time because they are outside of the
|
||||||
|
// supported range.
|
||||||
|
long y2038Issue1 = (((long) Integer.MIN_VALUE) - ONE_DAY_IN_SECONDS) * 1000L;
|
||||||
|
assertEquals(
|
||||||
|
"1901-12-12 20:45:52", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue1));
|
||||||
|
long y2038Issue2 = (((long) Integer.MAX_VALUE) + ONE_DAY_IN_SECONDS) * 1000L;
|
||||||
|
assertEquals(
|
||||||
|
"2038-01-20 03:14:07", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares TimeMigrationUtils.formatSimpleDateTime() with the code it is replacing.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void formatMillisAsDateTime_matchesOldBehavior() {
|
||||||
|
// A selection of interesting locales.
|
||||||
|
Locale[] locales = new Locale[] {
|
||||||
|
Locale.US,
|
||||||
|
Locale.UK,
|
||||||
|
Locale.FRANCE,
|
||||||
|
Locale.JAPAN,
|
||||||
|
Locale.CHINA,
|
||||||
|
// Android supports RTL locales like arabic and arabic with latin numbers.
|
||||||
|
Locale.forLanguageTag("ar-AE"),
|
||||||
|
Locale.forLanguageTag("ar-AE-u-nu-latn"),
|
||||||
|
};
|
||||||
|
// A selection of interesting time zones.
|
||||||
|
String[] timeZoneIds = new String[] {
|
||||||
|
"UTC", "Europe/London", "America/New_York", "America/Los_Angeles", "Asia/Shanghai",
|
||||||
|
};
|
||||||
|
// Some arbitrary times when the two formatters should agree.
|
||||||
|
long[] timesMillis = new long[] {
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
0,
|
||||||
|
// The Time class only works in 32-bit range, the replacement works beyond that. To
|
||||||
|
// avoid messing around with offsets and complicating the test, below there are a
|
||||||
|
// day after / before the known limits.
|
||||||
|
(Integer.MIN_VALUE + ONE_DAY_IN_SECONDS) * 1000L,
|
||||||
|
(Integer.MAX_VALUE - ONE_DAY_IN_SECONDS) * 1000L,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Locale locale : locales) {
|
||||||
|
Locale.setDefault(locale);
|
||||||
|
for (String timeZoneId : timeZoneIds) {
|
||||||
|
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
|
||||||
|
TimeZone.setDefault(timeZone);
|
||||||
|
for (long timeMillis : timesMillis) {
|
||||||
|
Time time = new Time();
|
||||||
|
time.set(timeMillis);
|
||||||
|
String oldResult = time.format("%Y-%m-%d %H:%M:%S");
|
||||||
|
String newResult = TimeMigrationUtils.formatMillisWithFixedFormat(timeMillis);
|
||||||
|
assertEquals(
|
||||||
|
"locale=" + locale + ", timeZoneId=" + timeZoneId
|
||||||
|
+ ", timeMillis=" + timeMillis,
|
||||||
|
oldResult, newResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ import android.os.SystemClock;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.Time;
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
@@ -582,11 +582,9 @@ public final class DropBoxManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int numFound = 0, numArgs = searchArgs.size();
|
int numFound = 0, numArgs = searchArgs.size();
|
||||||
Time time = new Time();
|
|
||||||
out.append("\n");
|
out.append("\n");
|
||||||
for (EntryFile entry : mAllFiles.contents) {
|
for (EntryFile entry : mAllFiles.contents) {
|
||||||
time.set(entry.timestampMillis);
|
String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
|
||||||
String date = time.format("%Y-%m-%d %H:%M:%S");
|
|
||||||
boolean match = true;
|
boolean match = true;
|
||||||
for (int i = 0; i < numArgs && match; i++) {
|
for (int i = 0; i < numArgs && match; i++) {
|
||||||
String arg = searchArgs.get(i);
|
String arg = searchArgs.get(i);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ import android.os.UserHandle;
|
|||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.os.WorkSource;
|
import android.os.WorkSource;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.format.Time;
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.EventLog;
|
import android.util.EventLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -1987,9 +1987,7 @@ public class SyncManager {
|
|||||||
if (time == 0) {
|
if (time == 0) {
|
||||||
return "N/A";
|
return "N/A";
|
||||||
}
|
}
|
||||||
Time tobj = new Time();
|
return TimeMigrationUtils.formatMillisWithFixedFormat(time);
|
||||||
tobj.set(time);
|
|
||||||
return tobj.format("%Y-%m-%d %H:%M:%S");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
|
private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
|
||||||
@@ -2555,9 +2553,7 @@ public class SyncManager {
|
|||||||
accountKey = "Unknown";
|
accountKey = "Unknown";
|
||||||
}
|
}
|
||||||
final long elapsedTime = item.elapsedTime;
|
final long elapsedTime = item.elapsedTime;
|
||||||
final Time time = new Time();
|
|
||||||
final long eventTime = item.eventTime;
|
final long eventTime = item.eventTime;
|
||||||
time.set(eventTime);
|
|
||||||
|
|
||||||
final String key = authorityName + "/" + accountKey;
|
final String key = authorityName + "/" + accountKey;
|
||||||
final Long lastEventTime = lastTimeMap.get(key);
|
final Long lastEventTime = lastTimeMap.get(key);
|
||||||
@@ -2622,9 +2618,7 @@ public class SyncManager {
|
|||||||
authorityName = "Unknown";
|
authorityName = "Unknown";
|
||||||
accountKey = "Unknown";
|
accountKey = "Unknown";
|
||||||
}
|
}
|
||||||
final Time time = new Time();
|
|
||||||
final long eventTime = item.eventTime;
|
final long eventTime = item.eventTime;
|
||||||
time.set(eventTime);
|
|
||||||
|
|
||||||
pw.printf(" #%-3d: %s %8s ",
|
pw.printf(" #%-3d: %s %8s ",
|
||||||
i + 1,
|
i + 1,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import android.net.Network;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.text.format.Time;
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
@@ -1643,17 +1643,13 @@ public final class JobStatus {
|
|||||||
if (numFailures != 0) {
|
if (numFailures != 0) {
|
||||||
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
|
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
|
||||||
}
|
}
|
||||||
final Time t = new Time();
|
|
||||||
final String format = "%Y-%m-%d %H:%M:%S";
|
|
||||||
if (mLastSuccessfulRunTime != 0) {
|
if (mLastSuccessfulRunTime != 0) {
|
||||||
pw.print(prefix); pw.print("Last successful run: ");
|
pw.print(prefix); pw.print("Last successful run: ");
|
||||||
t.set(mLastSuccessfulRunTime);
|
pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastSuccessfulRunTime));
|
||||||
pw.println(t.format(format));
|
|
||||||
}
|
}
|
||||||
if (mLastFailedRunTime != 0) {
|
if (mLastFailedRunTime != 0) {
|
||||||
pw.print(prefix); pw.print("Last failed run: ");
|
pw.print(prefix); pw.print("Last failed run: ");
|
||||||
t.set(mLastFailedRunTime);
|
pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastFailedRunTime));
|
||||||
pw.println(t.format(format));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ import android.os.SystemClock;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManagerInternal;
|
import android.os.UserManagerInternal;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.Time;
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.AtomicFile;
|
import android.util.AtomicFile;
|
||||||
import android.util.KeyValueListParser;
|
import android.util.KeyValueListParser;
|
||||||
@@ -3981,9 +3981,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String formatTime(long time) {
|
static String formatTime(long time) {
|
||||||
Time tobj = new Time();
|
return TimeMigrationUtils.formatMillisWithFixedFormat(time);
|
||||||
tobj.set(time);
|
|
||||||
return tobj.format("%Y-%m-%d %H:%M:%S");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpCurrentTime(PrintWriter pw) {
|
private void dumpCurrentTime(PrintWriter pw) {
|
||||||
|
|||||||
Reference in New Issue
Block a user