Unverified 提交 ecafdea5 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #981 from katzyn/datetime

Reorganize date-time functions
...@@ -147,6 +147,7 @@ import org.h2.table.Table; ...@@ -147,6 +147,7 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableFilter.TableFilterVisitor; import org.h2.table.TableFilter.TableFilterVisitor;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.DateTimeFunctions;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.ParserUtil; import org.h2.util.ParserUtil;
...@@ -2798,7 +2799,7 @@ public class Parser { ...@@ -2798,7 +2799,7 @@ public class Parser {
} }
case Function.DATE_ADD: case Function.DATE_ADD:
case Function.DATE_DIFF: { case Function.DATE_DIFF: {
if (Function.isDatePart(currentToken)) { if (DateTimeFunctions.isDatePart(currentToken)) {
function.setParameter(0, function.setParameter(0,
ValueExpression.get(ValueString.get(currentToken))); ValueExpression.get(ValueString.get(currentToken)));
read(); read();
......
差异被折叠。
...@@ -9,12 +9,9 @@ package org.h2.util; ...@@ -9,12 +9,9 @@ package org.h2.util;
import java.sql.Date; import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -58,7 +55,7 @@ public class DateTimeUtils { ...@@ -58,7 +55,7 @@ public class DateTimeUtils {
/** /**
* Date value for 1970-01-01. * Date value for 1970-01-01.
*/ */
private static final int EPOCH_DATE_VALUE = (1970 << SHIFT_YEAR) + (1 << SHIFT_MONTH) + 1; public static final int EPOCH_DATE_VALUE = (1970 << SHIFT_YEAR) + (1 << SHIFT_MONTH) + 1;
private static final int[] NORMAL_DAYS_PER_MONTH = { 0, 31, 28, 31, 30, 31, private static final int[] NORMAL_DAYS_PER_MONTH = { 0, 31, 28, 31, 30, 31,
30, 31, 31, 30, 31, 30, 31 }; 30, 31, 31, 30, 31, 30, 31 };
...@@ -744,8 +741,7 @@ public class DateTimeUtils { ...@@ -744,8 +741,7 @@ public class DateTimeUtils {
* @return number of day in year * @return number of day in year
*/ */
public static int getDayOfYear(long dateValue) { public static int getDayOfYear(long dateValue) {
int year = yearFromDateValue(dateValue); return (int) (absoluteDayFromDateValue(dateValue) - absoluteDayFromYear(yearFromDateValue(dateValue))) + 1;
return (int) (absoluteDayFromDateValue(dateValue) - absoluteDayFromDateValue(dateValue(year, 1, 1))) + 1;
} }
/** /**
...@@ -825,7 +821,7 @@ public class DateTimeUtils { ...@@ -825,7 +821,7 @@ public class DateTimeUtils {
} }
private static long getWeekOfYearBase(int year, int firstDayOfWeek, int minimalDaysInFirstWeek) { private static long getWeekOfYearBase(int year, int firstDayOfWeek, int minimalDaysInFirstWeek) {
long first = absoluteDayFromDateValue(dateValue(year, 1, 1)); long first = absoluteDayFromYear(year);
int daysInFirstWeek = 8 - getDayOfWeekFromAbsolute(first, firstDayOfWeek); int daysInFirstWeek = 8 - getDayOfWeekFromAbsolute(first, firstDayOfWeek);
long base = first + daysInFirstWeek; long base = first + daysInFirstWeek;
if (daysInFirstWeek >= minimalDaysInFirstWeek) { if (daysInFirstWeek >= minimalDaysInFirstWeek) {
...@@ -860,67 +856,6 @@ public class DateTimeUtils { ...@@ -860,67 +856,6 @@ public class DateTimeUtils {
return year; return year;
} }
/**
* Formats a date using a format string.
*
* @param date the date to format
* @param format the format string
* @param locale the locale
* @param timeZone the timezone
* @return the formatted date
*/
public static String formatDateTime(java.util.Date date, String format,
String locale, String timeZone) {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
synchronized (dateFormat) {
return dateFormat.format(date);
}
}
/**
* Parses a date using a format string.
*
* @param date the date to parse
* @param format the parsing format
* @param locale the locale
* @param timeZone the timeZone
* @return the parsed date
*/
public static java.util.Date parseDateTime(String date, String format,
String locale, String timeZone) {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
try {
synchronized (dateFormat) {
return dateFormat.parse(date);
}
} catch (Exception e) {
// ParseException
throw DbException.get(ErrorCode.PARSE_ERROR_1, e, date);
}
}
private static SimpleDateFormat getDateFormat(String format, String locale,
String timeZone) {
try {
// currently, a new instance is create for each call
// however, could cache the last few instances
SimpleDateFormat df;
if (locale == null) {
df = new SimpleDateFormat(format);
} else {
Locale l = new Locale(locale);
df = new SimpleDateFormat(format, l);
}
if (timeZone != null) {
df.setTimeZone(TimeZone.getTimeZone(timeZone));
}
return df;
} catch (Exception e) {
throw DbException.get(ErrorCode.PARSE_ERROR_1, e,
format + "/" + locale + "/" + timeZone);
}
}
/** /**
* Returns number of days in month. * Returns number of days in month.
* *
...@@ -1230,6 +1165,26 @@ public class DateTimeUtils { ...@@ -1230,6 +1165,26 @@ public class DateTimeUtils {
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, (short) offsetMins); return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, (short) offsetMins);
} }
/**
* Calculate the absolute day for a January, 1 of the specified year.
*
* @param year
* the year
* @return the absolute day
*/
public static long absoluteDayFromYear(long year) {
year--;
long a = ((year * 1461L) >> 2) - 719_177;
if (year < 1582) {
// Julian calendar
a += 13;
} else if (year < 1900 || year > 2099) {
// Gregorian calendar (slow mode)
a += (year / 400) - (year / 100) + 15;
}
return a;
}
/** /**
* Calculate the absolute day from an encoded date value. * Calculate the absolute day from an encoded date value.
* *
...@@ -1244,11 +1199,11 @@ public class DateTimeUtils { ...@@ -1244,11 +1199,11 @@ public class DateTimeUtils {
y--; y--;
m += 12; m += 12;
} }
long a = ((y * 2922L) >> 3) + DAYS_OFFSET[m - 3] + d - 719_484; long a = ((y * 1461L) >> 2) + DAYS_OFFSET[m - 3] + d - 719_484;
if (y <= 1582 && ((y < 1582) || (m * 100 + d < 1015))) { if (y <= 1582 && ((y < 1582) || (m * 100 + d < 10_15))) {
// Julian calendar (cutover at 1582-10-04 / 1582-10-15) // Julian calendar (cutover at 1582-10-04 / 1582-10-15)
a += 13; a += 13;
} else if (y < 1901 || y > 2099) { } else if (y < 1900 || y > 2099) {
// Gregorian calendar (slow mode) // Gregorian calendar (slow mode)
a += (y / 400) - (y / 100) + 15; a += (y / 400) - (y / 100) + 15;
} }
...@@ -1270,8 +1225,8 @@ public class DateTimeUtils { ...@@ -1270,8 +1225,8 @@ public class DateTimeUtils {
y--; y--;
m += 12; m += 12;
} }
long a = ((y * 2922L) >> 3) + DAYS_OFFSET[m - 3] + d - 719_484; long a = ((y * 1461L) >> 2) + DAYS_OFFSET[m - 3] + d - 719_484;
if (y < 1901 || y > 2099) { if (y < 1900 || y > 2099) {
// Slow mode // Slow mode
a += (y / 400) - (y / 100) + 15; a += (y / 400) - (y / 100) + 15;
} }
...@@ -1286,7 +1241,7 @@ public class DateTimeUtils { ...@@ -1286,7 +1241,7 @@ public class DateTimeUtils {
*/ */
public static long dateValueFromAbsoluteDay(long absoluteDay) { public static long dateValueFromAbsoluteDay(long absoluteDay) {
long d = absoluteDay + 719_468; long d = absoluteDay + 719_468;
long y100 = 0, offset; long y100, offset;
if (d > 578_040) { if (d > 578_040) {
// Gregorian calendar // Gregorian calendar
long y400 = d / 146_097; long y400 = d / 146_097;
...@@ -1296,6 +1251,7 @@ public class DateTimeUtils { ...@@ -1296,6 +1251,7 @@ public class DateTimeUtils {
offset = y400 * 400 + y100 * 100; offset = y400 * 400 + y100 * 100;
} else { } else {
// Julian calendar // Julian calendar
y100 = 0;
d += 292_200_000_002L; d += 292_200_000_002L;
offset = -800_000_000; offset = -800_000_000;
} }
...@@ -1339,14 +1295,13 @@ public class DateTimeUtils { ...@@ -1339,14 +1295,13 @@ public class DateTimeUtils {
if (day < getDaysInMonth(year, month)) { if (day < getDaysInMonth(year, month)) {
return dateValue + 1; return dateValue + 1;
} }
day = 1;
if (month < 12) { if (month < 12) {
month++; month++;
} else { } else {
month = 1; month = 1;
year++; year++;
} }
return dateValue(year, month, day); return dateValue(year, month, 1);
} }
/** /**
......
...@@ -91,8 +91,7 @@ public class ToDateParser { ...@@ -91,8 +91,7 @@ public class ToDateParser {
} }
if (doyValid) { if (doyValid) {
dateValue = DateTimeUtils.dateValueFromAbsoluteDay( dateValue = DateTimeUtils.dateValueFromAbsoluteDay(
DateTimeUtils.absoluteDayFromDateValue(DateTimeUtils.dateValue(year, 1, 1)) DateTimeUtils.absoluteDayFromYear(year) + dayOfYear - 1);
+ dayOfYear - 1);
} else { } else {
int month = this.month; int month = this.month;
if (month == 0) { if (month == 0) {
......
...@@ -845,8 +845,7 @@ public abstract class Value { ...@@ -845,8 +845,7 @@ public abstract class Value {
case TIME: case TIME:
// because the time has set the date to 1970-01-01, // because the time has set the date to 1970-01-01,
// this will be the result // this will be the result
return ValueDate.fromDateValue( return ValueDate.fromDateValue(DateTimeUtils.EPOCH_DATE_VALUE);
DateTimeUtils.dateValue(1970, 1, 1));
case TIMESTAMP: case TIMESTAMP:
return ValueDate.fromDateValue( return ValueDate.fromDateValue(
((ValueTimestamp) this).getDateValue()); ((ValueTimestamp) this).getDateValue());
......
...@@ -26,7 +26,6 @@ public class TestClearReferences extends TestBase { ...@@ -26,7 +26,6 @@ public class TestClearReferences extends TestBase {
"org.h2.compress.CompressLZF.cachedHashTable", "org.h2.compress.CompressLZF.cachedHashTable",
"org.h2.engine.DbSettings.defaultSettings", "org.h2.engine.DbSettings.defaultSettings",
"org.h2.engine.SessionRemote.sessionFactory", "org.h2.engine.SessionRemote.sessionFactory",
"org.h2.expression.Function.MONTHS_AND_WEEKS",
"org.h2.jdbcx.JdbcDataSourceFactory.cachedTraceSystem", "org.h2.jdbcx.JdbcDataSourceFactory.cachedTraceSystem",
"org.h2.store.RecoverTester.instance", "org.h2.store.RecoverTester.instance",
"org.h2.store.fs.FilePath.defaultProvider", "org.h2.store.fs.FilePath.defaultProvider",
...@@ -37,6 +36,7 @@ public class TestClearReferences extends TestBase { ...@@ -37,6 +36,7 @@ public class TestClearReferences extends TestBase {
"org.h2.tools.CompressTool.cachedBuffer", "org.h2.tools.CompressTool.cachedBuffer",
"org.h2.util.CloseWatcher.queue", "org.h2.util.CloseWatcher.queue",
"org.h2.util.CloseWatcher.refs", "org.h2.util.CloseWatcher.refs",
"org.h2.util.DateTimeFunctions.MONTHS_AND_WEEKS",
"org.h2.util.DateTimeUtils.timeZone", "org.h2.util.DateTimeUtils.timeZone",
"org.h2.util.MathUtils.cachedSecureRandom", "org.h2.util.MathUtils.cachedSecureRandom",
"org.h2.util.NetUtils.cachedLocalAddress", "org.h2.util.NetUtils.cachedLocalAddress",
......
...@@ -371,6 +371,9 @@ public class TestDate extends TestBase { ...@@ -371,6 +371,9 @@ public class TestDate extends TestBase {
if (abs != next && next != Long.MIN_VALUE) { if (abs != next && next != Long.MIN_VALUE) {
assertEquals(abs, next); assertEquals(abs, next);
} }
if (m == 1 && d == 1) {
assertEquals(abs, DateTimeUtils.absoluteDayFromYear(y));
}
next = abs + 1; next = abs + 1;
long d2 = DateTimeUtils.dateValueFromAbsoluteDay(abs); long d2 = DateTimeUtils.dateValueFromAbsoluteDay(abs);
assertEquals(date, d2); assertEquals(date, d2);
......
...@@ -13,7 +13,7 @@ import java.util.Random; ...@@ -13,7 +13,7 @@ import java.util.Random;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.utils.AssertThrows; import org.h2.test.utils.AssertThrows;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeFunctions;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
/** /**
...@@ -85,7 +85,7 @@ public class TestStringUtils extends TestBase { ...@@ -85,7 +85,7 @@ public class TestStringUtils extends TestBase {
StringUtils.xmlText("Rand&Blue")); StringUtils.xmlText("Rand&Blue"));
assertEquals("&lt;&lt;[[[]]]&gt;&gt;", assertEquals("&lt;&lt;[[[]]]&gt;&gt;",
StringUtils.xmlCData("<<[[[]]]>>")); StringUtils.xmlCData("<<[[[]]]>>"));
Date dt = DateTimeUtils.parseDateTime( Date dt = DateTimeFunctions.parseDateTime(
"2001-02-03 04:05:06 GMT", "2001-02-03 04:05:06 GMT",
"yyyy-MM-dd HH:mm:ss z", "en", "GMT"); "yyyy-MM-dd HH:mm:ss z", "en", "GMT");
String s = StringUtils.xmlStartDoc() String s = StringUtils.xmlStartDoc()
...@@ -99,10 +99,10 @@ public class TestStringUtils extends TestBase { ...@@ -99,10 +99,10 @@ public class TestStringUtils extends TestBase {
+ StringUtils.xmlNode("description", null, "H2 Database Engine") + StringUtils.xmlNode("description", null, "H2 Database Engine")
+ StringUtils.xmlNode("language", null, "en-us") + StringUtils.xmlNode("language", null, "en-us")
+ StringUtils.xmlNode("pubDate", null, + StringUtils.xmlNode("pubDate", null,
DateTimeUtils.formatDateTime(dt, DateTimeFunctions.formatDateTime(dt,
"EEE, d MMM yyyy HH:mm:ss z", "en", "GMT")) "EEE, d MMM yyyy HH:mm:ss z", "en", "GMT"))
+ StringUtils.xmlNode("lastBuildDate", null, + StringUtils.xmlNode("lastBuildDate", null,
DateTimeUtils.formatDateTime(dt, DateTimeFunctions.formatDateTime(dt,
"EEE, d MMM yyyy HH:mm:ss z", "en", "GMT")) "EEE, d MMM yyyy HH:mm:ss z", "en", "GMT"))
+ StringUtils.xmlNode("item", null, + StringUtils.xmlNode("item", null,
StringUtils.xmlNode("title", null, StringUtils.xmlNode("title", null,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论