提交 f6e531cd authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Reimplement dateValueFromDate() and nanosFromDate() without a Calendar

上级 b3f66155
......@@ -85,6 +85,11 @@ public class DateTimeUtils {
private static final ThreadLocal<GregorianCalendar> CACHED_CALENDAR_NON_DEFAULT_TIMEZONE =
new ThreadLocal<>();
/**
* Cached local time zone.
*/
private static volatile TimeZone timeZone;
/**
* Observed JVM behaviour is that if the timezone of the host computer is
* changed while the JVM is running, the zone offset does not change but
......@@ -100,12 +105,26 @@ public class DateTimeUtils {
// utility class
}
/**
* Returns local time zone.
*
* @return local time zone
*/
private static TimeZone getTimeZone() {
TimeZone tz = timeZone;
if (tz == null) {
timeZone = tz = TimeZone.getDefault();
}
return tz;
}
/**
* Reset the cached calendar for default timezone, for example after
* changing the default timezone.
*/
public static void resetCalendar() {
CACHED_CALENDAR.remove();
timeZone = null;
zoneOffsetMillis = DateTimeUtils.createGregorianCalendar().get(Calendar.ZONE_OFFSET);
}
......@@ -1043,9 +1062,12 @@ public class DateTimeUtils {
* @return the date value
*/
public static long dateValueFromDate(long ms) {
Calendar cal = getCalendar();
cal.setTimeInMillis(ms);
return dateValueFromCalendar(cal);
ms += getTimeZone().getOffset(ms);
long absoluteDay = ms / 86_400_000;
if (ms < 0 && (absoluteDay * 86_400_000 != ms)) {
absoluteDay--;
}
return dateValueFromAbsoluteDay(absoluteDay);
}
/**
......@@ -1072,9 +1094,12 @@ public class DateTimeUtils {
* @return the nanoseconds
*/
public static long nanosFromDate(long ms) {
Calendar cal = getCalendar();
cal.setTimeInMillis(ms);
return nanosFromCalendar(cal);
ms += getTimeZone().getOffset(ms);
long absoluteDay = ms / 86_400_000;
if (ms < 0 && (absoluteDay * 86_400_000 != ms)) {
absoluteDay--;
}
return (ms - absoluteDay * 86_400_000) * 1_000_000;
}
/**
......
......@@ -6,10 +6,15 @@
package org.h2.test.unit;
import static org.h2.util.DateTimeUtils.dateValue;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.h2.test.TestBase;
import org.h2.util.DateTimeUtils;
import org.h2.value.ValueTimestamp;
/**
* Unit tests for the DateTimeUtils class
......@@ -22,6 +27,12 @@ public class TestDateTimeUtils extends TestBase {
* @param a ignored
*/
public static void main(String... a) throws Exception {
if (a.length == 1) {
if ("testUtc2Value".equals(a[0])) {
new TestDateTimeUtils().testUTC2Value(true);
return;
}
}
TestBase.createCaller().init().test();
}
......@@ -31,6 +42,7 @@ public class TestDateTimeUtils extends TestBase {
testDayOfWeek();
testWeekOfYear();
testDateValueFromDenormalizedDate();
testUTC2Value(false);
}
private void testParseTimeNanosDB2Format() {
......@@ -104,4 +116,45 @@ public class TestDateTimeUtils extends TestBase {
assertEquals(dateValue(-100, 2, 29), DateTimeUtils.dateValueFromDenormalizedDate(-100, 2, 30));
}
private void testUTC2Value(boolean allTimeZones) {
TimeZone def = TimeZone.getDefault();
GregorianCalendar gc = new GregorianCalendar();
if (allTimeZones) {
try {
for (String id : TimeZone.getAvailableIDs()) {
System.out.println(id);
TimeZone tz = TimeZone.getTimeZone(id);
TimeZone.setDefault(tz);
DateTimeUtils.resetCalendar();
testUTC2ValueImpl(tz, gc);
}
} finally {
TimeZone.setDefault(def);
DateTimeUtils.resetCalendar();
}
} else {
testUTC2ValueImpl(def, gc);
}
}
private void testUTC2ValueImpl(TimeZone tz, GregorianCalendar gc) {
gc.setTimeZone(tz);
gc.set(Calendar.MILLISECOND, 0);
long absoluteStart = DateTimeUtils.absoluteDayFromDateValue(DateTimeUtils.dateValue(1950, 01, 01));
long absoluteEnd = DateTimeUtils.absoluteDayFromDateValue(DateTimeUtils.dateValue(2050, 01, 01));
for (long i = absoluteStart; i < absoluteEnd; i++) {
long dateValue = DateTimeUtils.dateValueFromAbsoluteDay(i);
int year = DateTimeUtils.yearFromDateValue(dateValue);
int month = DateTimeUtils.monthFromDateValue(dateValue);
int day = DateTimeUtils.dayFromDateValue(dateValue);
for (int j = 0; j < 48; j++) {
gc.set(year, month - 1, day, j / 2, (j & 1) * 30, 0);
long timeMillis = gc.getTimeInMillis();
ValueTimestamp ts = DateTimeUtils.convertTimestamp(new Timestamp(timeMillis), gc);
assertEquals(ts.getDateValue(), DateTimeUtils.dateValueFromDate(timeMillis));
assertEquals(ts.getTimeNanos(), DateTimeUtils.nanosFromDate(timeMillis));
}
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论