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

Merge pull request #847 from katzyn/datetime

Reimplement remaining parts of EXTRACT, ISO_YEAR, etc without a Calendar
...@@ -108,6 +108,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -108,6 +108,11 @@ public class Function extends Expression implements FunctionCall {
FORMATDATETIME = 121, PARSEDATETIME = 122, ISO_YEAR = 123, FORMATDATETIME = 121, PARSEDATETIME = 122, ISO_YEAR = 123,
ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125; ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125;
/**
* Pseudo function for {@code EXTRACT(MILLISECOND FROM ...)}.
*/
public static final int MILLISECOND = 126;
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155, IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158, READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158,
...@@ -158,39 +163,39 @@ public class Function extends Expression implements FunctionCall { ...@@ -158,39 +163,39 @@ public class Function extends Expression implements FunctionCall {
static { static {
// DATE_PART // DATE_PART
DATE_PART.put("SQL_TSI_YEAR", Calendar.YEAR); DATE_PART.put("SQL_TSI_YEAR", YEAR);
DATE_PART.put("YEAR", Calendar.YEAR); DATE_PART.put("YEAR", YEAR);
DATE_PART.put("YYYY", Calendar.YEAR); DATE_PART.put("YYYY", YEAR);
DATE_PART.put("YY", Calendar.YEAR); DATE_PART.put("YY", YEAR);
DATE_PART.put("SQL_TSI_MONTH", Calendar.MONTH); DATE_PART.put("SQL_TSI_MONTH", MONTH);
DATE_PART.put("MONTH", Calendar.MONTH); DATE_PART.put("MONTH", MONTH);
DATE_PART.put("MM", Calendar.MONTH); DATE_PART.put("MM", MONTH);
DATE_PART.put("M", Calendar.MONTH); DATE_PART.put("M", MONTH);
DATE_PART.put("SQL_TSI_WEEK", Calendar.WEEK_OF_YEAR); DATE_PART.put("SQL_TSI_WEEK", WEEK);
DATE_PART.put("WW", Calendar.WEEK_OF_YEAR); DATE_PART.put("WW", WEEK);
DATE_PART.put("WK", Calendar.WEEK_OF_YEAR); DATE_PART.put("WK", WEEK);
DATE_PART.put("WEEK", Calendar.WEEK_OF_YEAR); DATE_PART.put("WEEK", WEEK);
DATE_PART.put("DAY", Calendar.DAY_OF_MONTH); DATE_PART.put("DAY", DAY_OF_MONTH);
DATE_PART.put("DD", Calendar.DAY_OF_MONTH); DATE_PART.put("DD", DAY_OF_MONTH);
DATE_PART.put("D", Calendar.DAY_OF_MONTH); DATE_PART.put("D", DAY_OF_MONTH);
DATE_PART.put("SQL_TSI_DAY", Calendar.DAY_OF_MONTH); DATE_PART.put("SQL_TSI_DAY", DAY_OF_MONTH);
DATE_PART.put("DAYOFYEAR", Calendar.DAY_OF_YEAR); DATE_PART.put("DAYOFYEAR", DAY_OF_YEAR);
DATE_PART.put("DAY_OF_YEAR", Calendar.DAY_OF_YEAR); DATE_PART.put("DAY_OF_YEAR", DAY_OF_YEAR);
DATE_PART.put("DY", Calendar.DAY_OF_YEAR); DATE_PART.put("DY", DAY_OF_YEAR);
DATE_PART.put("DOY", Calendar.DAY_OF_YEAR); DATE_PART.put("DOY", DAY_OF_YEAR);
DATE_PART.put("SQL_TSI_HOUR", Calendar.HOUR_OF_DAY); DATE_PART.put("SQL_TSI_HOUR", HOUR);
DATE_PART.put("HOUR", Calendar.HOUR_OF_DAY); DATE_PART.put("HOUR", HOUR);
DATE_PART.put("HH", Calendar.HOUR_OF_DAY); DATE_PART.put("HH", HOUR);
DATE_PART.put("SQL_TSI_MINUTE", Calendar.MINUTE); DATE_PART.put("SQL_TSI_MINUTE", MINUTE);
DATE_PART.put("MINUTE", Calendar.MINUTE); DATE_PART.put("MINUTE", MINUTE);
DATE_PART.put("MI", Calendar.MINUTE); DATE_PART.put("MI", MINUTE);
DATE_PART.put("N", Calendar.MINUTE); DATE_PART.put("N", MINUTE);
DATE_PART.put("SQL_TSI_SECOND", Calendar.SECOND); DATE_PART.put("SQL_TSI_SECOND", SECOND);
DATE_PART.put("SECOND", Calendar.SECOND); DATE_PART.put("SECOND", SECOND);
DATE_PART.put("SS", Calendar.SECOND); DATE_PART.put("SS", SECOND);
DATE_PART.put("S", Calendar.SECOND); DATE_PART.put("S", SECOND);
DATE_PART.put("MILLISECOND", Calendar.MILLISECOND); DATE_PART.put("MILLISECOND", MILLISECOND);
DATE_PART.put("MS", Calendar.MILLISECOND); DATE_PART.put("MS", MILLISECOND);
// SOUNDEX_INDEX // SOUNDEX_INDEX
String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"; String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
...@@ -837,22 +842,19 @@ public class Function extends Expression implements FunctionCall { ...@@ -837,22 +842,19 @@ public class Function extends Expression implements FunctionCall {
break; break;
} }
case DAY_OF_MONTH: case DAY_OF_MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.DAY_OF_MONTH));
break;
case DAY_OF_WEEK: case DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.DAY_OF_WEEK));
break;
case DAY_OF_YEAR: case DAY_OF_YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.DAY_OF_YEAR));
break;
case HOUR: case HOUR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.HOUR_OF_DAY));
break;
case MINUTE: case MINUTE:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.MINUTE));
break;
case MONTH: case MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.MONTH)); case QUARTER:
case ISO_YEAR:
case ISO_WEEK:
case ISO_DAY_OF_WEEK:
case SECOND:
case WEEK:
case YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, info.type));
break; break;
case MONTH_NAME: { case MONTH_NAME: {
SimpleDateFormat monthName = new SimpleDateFormat("MMMM", SimpleDateFormat monthName = new SimpleDateFormat("MMMM",
...@@ -861,27 +863,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -861,27 +863,6 @@ public class Function extends Expression implements FunctionCall {
database.getMode().treatEmptyStringsAsNull); database.getMode().treatEmptyStringsAsNull);
break; break;
} }
case QUARTER:
result = ValueInt.get((DateTimeUtils.getDatePart(v0, Calendar.MONTH) - 1) / 3 + 1);
break;
case SECOND:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.SECOND));
break;
case WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.WEEK_OF_YEAR));
break;
case YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0, Calendar.YEAR));
break;
case ISO_YEAR:
result = ValueInt.get(DateTimeUtils.getIsoYear(v0));
break;
case ISO_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoWeek(v0));
break;
case ISO_DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoDayOfWeek(v0));
break;
case CURDATE: case CURDATE:
case CURRENT_DATE: { case CURRENT_DATE: {
long now = session.getTransactionStart(); long now = session.getTransactionStart();
...@@ -1827,11 +1808,39 @@ public class Function extends Expression implements FunctionCall { ...@@ -1827,11 +1808,39 @@ public class Function extends Expression implements FunctionCall {
private static Timestamp dateadd(String part, long count, Timestamp d) { private static Timestamp dateadd(String part, long count, Timestamp d) {
int field = getDatePart(part); int field = getDatePart(part);
if (field == Calendar.MILLISECOND) { switch (field) {
case YEAR:
field = Calendar.YEAR;
break;
case MONTH:
field = Calendar.MONTH;
break;
case DAY_OF_MONTH:
field = Calendar.DAY_OF_MONTH;
break;
case DAY_OF_YEAR:
field = Calendar.DAY_OF_YEAR;
break;
case WEEK:
field = Calendar.WEEK_OF_YEAR;
break;
case HOUR:
field = Calendar.HOUR_OF_DAY;
break;
case MINUTE:
field = Calendar.MINUTE;
break;
case SECOND:
field = Calendar.SECOND;
break;
case MILLISECOND: {
Timestamp ts = new Timestamp(d.getTime() + count); Timestamp ts = new Timestamp(d.getTime() + count);
ts.setNanos(ts.getNanos() + (d.getNanos() % 1000000)); ts.setNanos(ts.getNanos() + (d.getNanos() % 1000000));
return ts; return ts;
} }
default:
throw DbException.getUnsupportedException("DATEADD " + part);
}
// We allow long for manipulating the millisecond component, // We allow long for manipulating the millisecond component,
// for the rest we only allow int. // for the rest we only allow int.
if (count > Integer.MAX_VALUE) { if (count > Integer.MAX_VALUE) {
...@@ -1878,34 +1887,34 @@ public class Function extends Expression implements FunctionCall { ...@@ -1878,34 +1887,34 @@ public class Function extends Expression implements FunctionCall {
calendar.get(Calendar.DAY_OF_WEEK), calendar.get(Calendar.DAY_OF_WEEK),
calendar.get(Calendar.MILLISECOND)); calendar.get(Calendar.MILLISECOND));
switch (field) { switch (field) {
case Calendar.MILLISECOND: case MILLISECOND:
return t2 - t1; return t2 - t1;
case Calendar.SECOND: case SECOND:
case Calendar.MINUTE: case MINUTE:
case Calendar.HOUR_OF_DAY: case HOUR:
case Calendar.DAY_OF_YEAR: case DAY_OF_YEAR:
case Calendar.WEEK_OF_YEAR: { case WEEK: {
// first 'normalize' the numbers so both are not negative // first 'normalize' the numbers so both are not negative
long hour = 60 * 60 * 1000; long hour = 60 * 60 * 1000;
long add = Math.min(t1 / hour * hour, t2 / hour * hour); long add = Math.min(t1 / hour * hour, t2 / hour * hour);
t1 -= add; t1 -= add;
t2 -= add; t2 -= add;
switch (field) { switch (field) {
case Calendar.SECOND: case SECOND:
return t2 / 1000 - t1 / 1000; return t2 / 1000 - t1 / 1000;
case Calendar.MINUTE: case MINUTE:
return t2 / (60 * 1000) - t1 / (60 * 1000); return t2 / (60 * 1000) - t1 / (60 * 1000);
case Calendar.HOUR_OF_DAY: case HOUR:
return t2 / hour - t1 / hour; return t2 / hour - t1 / hour;
case Calendar.DAY_OF_YEAR: case DAY_OF_YEAR:
return t2 / (hour * 24) - t1 / (hour * 24); return t2 / (hour * 24) - t1 / (hour * 24);
case Calendar.WEEK_OF_YEAR: case WEEK:
return t2 / (hour * 24 * 7) - t1 / (hour * 24 * 7); return t2 / (hour * 24 * 7) - t1 / (hour * 24 * 7);
default: default:
throw DbException.throwInternalError("field:" + field); throw DbException.throwInternalError("field:" + field);
} }
} }
case Calendar.DATE: case DAY_OF_MONTH:
return t2 / (24 * 60 * 60 * 1000) - t1 / (24 * 60 * 60 * 1000); return t2 / (24 * 60 * 60 * 1000) - t1 / (24 * 60 * 60 * 1000);
default: default:
break; break;
...@@ -1918,9 +1927,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -1918,9 +1927,9 @@ public class Function extends Expression implements FunctionCall {
int year2 = calendar.get(Calendar.YEAR); int year2 = calendar.get(Calendar.YEAR);
int month2 = calendar.get(Calendar.MONTH); int month2 = calendar.get(Calendar.MONTH);
int result = year2 - year1; int result = year2 - year1;
if (field == Calendar.MONTH) { if (field == MONTH) {
return 12 * result + (month2 - month1); return 12 * result + (month2 - month1);
} else if (field == Calendar.YEAR) { } else if (field == YEAR) {
return result; return result;
} else { } else {
throw DbException.getUnsupportedException("DATEDIFF " + part); throw DbException.getUnsupportedException("DATEDIFF " + part);
......
...@@ -16,6 +16,7 @@ import java.util.Locale; ...@@ -16,6 +16,7 @@ import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.expression.Function;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
...@@ -24,6 +25,7 @@ import org.h2.value.ValueTime; ...@@ -24,6 +25,7 @@ import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone; import org.h2.value.ValueTimestampTimeZone;
/** /**
* This utility class contains time conversion functions. * This utility class contains time conversion functions.
* <p> * <p>
...@@ -298,30 +300,6 @@ public class DateTimeUtils { ...@@ -298,30 +300,6 @@ public class DateTimeUtils {
return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos); return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos);
} }
private static Calendar valueToCalendar(Value value) {
Calendar cal;
if (value instanceof ValueTimestamp) {
cal = createGregorianCalendar();
cal.setTime(value.getTimestamp());
} else if (value instanceof ValueDate) {
cal = createGregorianCalendar();
cal.setTime(value.getDate());
} else if (value instanceof ValueTime) {
cal = createGregorianCalendar();
cal.setTime(value.getTime());
} else if (value instanceof ValueTimestampTimeZone) {
ValueTimestampTimeZone v = (ValueTimestampTimeZone) value;
cal = createGregorianCalendar(v.getTimeZone());
cal.setTimeInMillis(DateTimeUtils.convertDateValueToMillis(DateTimeUtils.UTC, v.getDateValue())
+ v.getTimeNanos() / 1000000L
- v.getTimeZoneOffsetMins() * 60000);
} else {
cal = createGregorianCalendar();
cal.setTime(value.getTimestamp());
}
return cal;
}
/** /**
* Parse a date string. The format is: [+|-]year-month-day * Parse a date string. The format is: [+|-]year-month-day
* *
...@@ -588,7 +566,7 @@ public class DateTimeUtils { ...@@ -588,7 +566,7 @@ public class DateTimeUtils {
* positive or negative, and month starting with 1. * positive or negative, and month starting with 1.
* *
* @param date the date value * @param date the date value
* @param field the field type * @param field the field type, see {@link Function} for constants
* @return the value * @return the value
*/ */
public static int getDatePart(Value date, int field) { public static int getDatePart(Value date, int field) {
...@@ -608,27 +586,41 @@ public class DateTimeUtils { ...@@ -608,27 +586,41 @@ public class DateTimeUtils {
timeNanos = v.getTimeNanos(); timeNanos = v.getTimeNanos();
} else { } else {
ValueTimestamp v = (ValueTimestamp) date.convertTo(Value.TIMESTAMP); ValueTimestamp v = (ValueTimestamp) date.convertTo(Value.TIMESTAMP);
date = v; // For valueToCalendar() to avoid second convertTo() call
dateValue = v.getDateValue(); dateValue = v.getDateValue();
timeNanos = v.getTimeNanos(); timeNanos = v.getTimeNanos();
} }
switch (field) { switch (field) {
case Calendar.YEAR: case Function.YEAR:
return yearFromDateValue(dateValue); return yearFromDateValue(dateValue);
case Calendar.MONTH: case Function.MONTH:
return monthFromDateValue(dateValue); return monthFromDateValue(dateValue);
case Calendar.DAY_OF_MONTH: case Function.DAY_OF_MONTH:
return dayFromDateValue(dateValue); return dayFromDateValue(dateValue);
case Calendar.HOUR_OF_DAY: case Function.HOUR:
return (int) (timeNanos / 3_600_000_000_000L % 24); return (int) (timeNanos / 3_600_000_000_000L % 24);
case Calendar.MINUTE: case Function.MINUTE:
return (int) (timeNanos / 60_000_000_000L % 60); return (int) (timeNanos / 60_000_000_000L % 60);
case Calendar.SECOND: case Function.SECOND:
return (int) (timeNanos / 1_000_000_000 % 60); return (int) (timeNanos / 1_000_000_000 % 60);
case Calendar.MILLISECOND: case Function.MILLISECOND:
return (int) (timeNanos / 1_000_000 % 1_000); return (int) (timeNanos / 1_000_000 % 1_000);
} case Function.DAY_OF_YEAR:
return valueToCalendar(date).get(field); return getDayOfYear(dateValue);
case Function.DAY_OF_WEEK:
return getSundayDayOfWeek(dateValue);
case Function.WEEK:
GregorianCalendar gc = getCalendar();
return getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1, gc.getMinimalDaysInFirstWeek());
case Function.QUARTER:
return (monthFromDateValue(dateValue) - 1) / 3 + 1;
case Function.ISO_YEAR:
return getIsoWeekYear(dateValue);
case Function.ISO_WEEK:
return getIsoWeekOfYear(dateValue);
case Function.ISO_DAY_OF_WEEK:
return getIsoDayOfWeek(dateValue);
}
throw DbException.getUnsupportedException("getDatePart(" + date + ", " + field + ')');
} }
/** /**
...@@ -668,57 +660,144 @@ public class DateTimeUtils { ...@@ -668,57 +660,144 @@ public class DateTimeUtils {
} }
/** /**
* Return the day of week according to the ISO 8601 specification. Week * Returns day of week.
* starts at Monday. See also http://en.wikipedia.org/wiki/ISO_8601
* *
* @author Robert Rathsack * @param dateValue
* @param value the date object which day of week should be calculated * the date value
* @return the day of the week, Monday as 1 to Sunday as 7 * @param firstDayOfWeek
* first day of week, Monday as 1, Sunday as 7 or 0
* @return day of week
* @see #getIsoDayOfWeek(long)
*/ */
public static int getIsoDayOfWeek(Value value) { public static int getDayOfWeek(long dateValue, int firstDayOfWeek) {
int val = valueToCalendar(value).get(Calendar.DAY_OF_WEEK) - 1; return getDayOfWeekFromAbsolute(absoluteDayFromDateValue(dateValue), firstDayOfWeek);
return val == 0 ? 7 : val; }
private static int getDayOfWeekFromAbsolute(long absoluteValue, int firstDayOfWeek) {
return absoluteValue >= 0 ? (int) ((absoluteValue - firstDayOfWeek + 11) % 7) + 1
: (int) ((absoluteValue - firstDayOfWeek - 2) % 7) + 7;
} }
/** /**
* Returns the week of the year according to the ISO 8601 specification. The * Returns number of day in year.
* spec defines the first week of the year as the week which contains at
* least 4 days of the new year. The week starts at Monday. Therefore
* December 29th - 31th could belong to the next year and January 1st - 3th
* could belong to the previous year. If January 1st is on Thursday (or
* earlier) it belongs to the first week, otherwise to the last week of the
* previous year. Hence January 4th always belongs to the first week while
* the December 28th always belongs to the last week.
* *
* @author Robert Rathsack * @param dateValue
* @param value the date object which week of year should be calculated * the date value
* @return the week of the year * @return number of day in year
*/ */
public static int getIsoWeek(Value value) { public static int getDayOfYear(long dateValue) {
Calendar c = valueToCalendar(value); int year = yearFromDateValue(dateValue);
c.setFirstDayOfWeek(Calendar.MONDAY); return (int) (absoluteDayFromDateValue(dateValue) - absoluteDayFromDateValue(dateValue(year, 1, 1))) + 1;
c.setMinimalDaysInFirstWeek(4);
return c.get(Calendar.WEEK_OF_YEAR);
} }
/** /**
* Returns the year according to the ISO week definition. * Returns ISO day of week.
* *
* @author Robert Rathsack * @param dateValue
* @param value the date object which year should be calculated * the date value
* @return the year * @return ISO day of week, Monday as 1 to Sunday as 7
* @see #getSundayDayOfWeek(long)
*/
public static int getIsoDayOfWeek(long dateValue) {
return getDayOfWeek(dateValue, 1);
}
/**
* Returns ISO number of week in year.
*
* @param dateValue
* the date value
* @return number of week in year
* @see #getIsoWeekYear(long)
* @see #getWeekOfYear(long, int, int)
*/
public static int getIsoWeekOfYear(long dateValue) {
return getWeekOfYear(dateValue, 1, 4);
}
/**
* Returns ISO week year.
*
* @param dateValue
* the date value
* @return ISO week year
* @see #getIsoWeekOfYear(long)
* @see #getWeekYear(long, int, int)
*/
public static int getIsoWeekYear(long dateValue) {
return getWeekYear(dateValue, 1, 4);
}
/**
* Returns day of week with Sunday as 1.
*
* @param dateValue
* the date value
* @return day of week, Sunday as 1 to Monday as 7
* @see #getIsoDayOfWeek(long)
*/
public static int getSundayDayOfWeek(long dateValue) {
return getDayOfWeek(dateValue, 0);
}
/**
* Returns number of week in year.
*
* @param dateValue
* the date value
* @param firstDayOfWeek
* first day of week, Monday as 1, Sunday as 7 or 0
* @param minimalDaysInFirstWeek
* minimal days in first week of year
* @return number of week in year
* @see #getIsoWeekOfYear(long)
*/
public static int getWeekOfYear(long dateValue, int firstDayOfWeek, int minimalDaysInFirstWeek) {
long abs = absoluteDayFromDateValue(dateValue);
int year = yearFromDateValue(dateValue);
long base = getWeekOfYearBase(year, firstDayOfWeek, minimalDaysInFirstWeek);
if (abs - base < 0) {
base = getWeekOfYearBase(year - 1, firstDayOfWeek, minimalDaysInFirstWeek);
} else if (monthFromDateValue(dateValue) == 12 && 24 + minimalDaysInFirstWeek < dayFromDateValue(dateValue)) {
if (abs >= getWeekOfYearBase(year + 1, firstDayOfWeek, minimalDaysInFirstWeek)) {
return 1;
}
}
return (int) ((abs - base) / 7) + 1;
}
private static long getWeekOfYearBase(int year, int firstDayOfWeek, int minimalDaysInFirstWeek) {
long first = absoluteDayFromDateValue(dateValue(year, 1, 1));
int daysInFirstWeek = 8 - getDayOfWeekFromAbsolute(first, firstDayOfWeek);
long base = first + daysInFirstWeek;
if (daysInFirstWeek >= minimalDaysInFirstWeek) {
base -= 7;
}
return base;
}
/**
* Returns week year.
*
* @param dateValue
* the date value
* @param firstDayOfWeek
* first day of week, Monday as 1, Sunday as 7 or 0
* @param minimalDaysInFirstWeek
* minimal days in first week of year
* @return week year
* @see #getIsoWeekYear(long)
*/ */
public static int getIsoYear(Value value) { public static int getWeekYear(long dateValue, int firstDayOfWeek, int minimalDaysInFirstWeek) {
Calendar cal = valueToCalendar(value); long abs = absoluteDayFromDateValue(dateValue);
cal.setFirstDayOfWeek(Calendar.MONDAY); int year = yearFromDateValue(dateValue);
cal.setMinimalDaysInFirstWeek(4); long base = getWeekOfYearBase(year, firstDayOfWeek, minimalDaysInFirstWeek);
int year = getYear(cal); if (abs - base < 0) {
int month = cal.get(Calendar.MONTH); return year - 1;
int week = cal.get(Calendar.WEEK_OF_YEAR); } else if (monthFromDateValue(dateValue) == 12 && 24 + minimalDaysInFirstWeek < dayFromDateValue(dateValue)) {
if (month == 0 && week > 51) { if (abs >= getWeekOfYearBase(year + 1, firstDayOfWeek, minimalDaysInFirstWeek)) {
year--; return year + 1;
} else if (month == 11 && week == 1) { }
year++;
} }
return year; return year;
} }
......
...@@ -6,11 +6,10 @@ ...@@ -6,11 +6,10 @@
package org.h2.test.unit; package org.h2.test.unit;
import static org.h2.util.DateTimeUtils.getIsoDayOfWeek; import static org.h2.util.DateTimeUtils.getIsoDayOfWeek;
import static org.h2.util.DateTimeUtils.getIsoWeek; import static org.h2.util.DateTimeUtils.getIsoWeekOfYear;
import static org.h2.util.DateTimeUtils.getIsoYear; import static org.h2.util.DateTimeUtils.getIsoWeekYear;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.value.Value;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone; import org.h2.value.ValueTimestampTimeZone;
...@@ -35,21 +34,21 @@ public class TestDateIso8601 extends TestBase { ...@@ -35,21 +34,21 @@ public class TestDateIso8601 extends TestBase {
TestBase.createCaller().init().test(); TestBase.createCaller().init().test();
} }
private static Value parse(String s) { private static long parse(String s) {
if (type == null) { if (type == null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
switch (type) { switch (type) {
case DATE: case DATE:
return ValueDate.parse(s); return ValueDate.parse(s).getDateValue();
case TIMESTAMP: case TIMESTAMP:
return ValueTimestamp.parse(s); return ValueTimestamp.parse(s).getDateValue();
case TIMESTAMP_TIMEZONE_0: case TIMESTAMP_TIMEZONE_0:
return ValueTimestampTimeZone.parse(s + " 00:00:00.0Z"); return ValueTimestampTimeZone.parse(s + " 00:00:00.0Z").getDateValue();
case TIMESTAMP_TIMEZONE_PLUS_18: case TIMESTAMP_TIMEZONE_PLUS_18:
return ValueTimestampTimeZone.parse(s + " 00:00:00+18:00"); return ValueTimestampTimeZone.parse(s + " 00:00:00+18:00").getDateValue();
case TIMESTAMP_TIMEZONE_MINUS_18: case TIMESTAMP_TIMEZONE_MINUS_18:
return ValueTimestampTimeZone.parse(s + " 00:00:00-18:00"); return ValueTimestampTimeZone.parse(s + " 00:00:00-18:00").getDateValue();
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
...@@ -104,57 +103,57 @@ public class TestDateIso8601 extends TestBase { ...@@ -104,57 +103,57 @@ public class TestDateIso8601 extends TestBase {
* January 1st is a Monday therefore the week belongs to the next year. * January 1st is a Monday therefore the week belongs to the next year.
*/ */
private void testIsoWeekJanuary1thMonday() throws Exception { private void testIsoWeekJanuary1thMonday() throws Exception {
assertEquals(52, getIsoWeek(parse("2006-12-31"))); assertEquals(52, getIsoWeekOfYear(parse("2006-12-31")));
assertEquals(1, getIsoWeek(parse("2007-01-01"))); assertEquals(1, getIsoWeekOfYear(parse("2007-01-01")));
assertEquals(1, getIsoWeek(parse("2007-01-07"))); assertEquals(1, getIsoWeekOfYear(parse("2007-01-07")));
assertEquals(2, getIsoWeek(parse("2007-01-08"))); assertEquals(2, getIsoWeekOfYear(parse("2007-01-08")));
} }
/** /**
* January 1st is a Tuesday therefore the week belongs to the next year. * January 1st is a Tuesday therefore the week belongs to the next year.
*/ */
private void testIsoWeekJanuary1thTuesday() throws Exception { private void testIsoWeekJanuary1thTuesday() throws Exception {
assertEquals(52, getIsoWeek(parse("2007-12-30"))); assertEquals(52, getIsoWeekOfYear(parse("2007-12-30")));
assertEquals(1, getIsoWeek(parse("2007-12-31"))); assertEquals(1, getIsoWeekOfYear(parse("2007-12-31")));
assertEquals(1, getIsoWeek(parse("2008-01-01"))); assertEquals(1, getIsoWeekOfYear(parse("2008-01-01")));
assertEquals(1, getIsoWeek(parse("2008-01-06"))); assertEquals(1, getIsoWeekOfYear(parse("2008-01-06")));
assertEquals(2, getIsoWeek(parse("2008-01-07"))); assertEquals(2, getIsoWeekOfYear(parse("2008-01-07")));
} }
/** /**
* January1th is a Wednesday therefore the week belongs to the next year. * January1th is a Wednesday therefore the week belongs to the next year.
*/ */
private void testIsoWeekJanuary1thWednesday() throws Exception { private void testIsoWeekJanuary1thWednesday() throws Exception {
assertEquals(52, getIsoWeek(parse("2002-12-28"))); assertEquals(52, getIsoWeekOfYear(parse("2002-12-28")));
assertEquals(52, getIsoWeek(parse("2002-12-29"))); assertEquals(52, getIsoWeekOfYear(parse("2002-12-29")));
assertEquals(1, getIsoWeek(parse("2002-12-30"))); assertEquals(1, getIsoWeekOfYear(parse("2002-12-30")));
assertEquals(1, getIsoWeek(parse("2002-12-31"))); assertEquals(1, getIsoWeekOfYear(parse("2002-12-31")));
assertEquals(1, getIsoWeek(parse("2003-01-01"))); assertEquals(1, getIsoWeekOfYear(parse("2003-01-01")));
assertEquals(1, getIsoWeek(parse("2003-01-05"))); assertEquals(1, getIsoWeekOfYear(parse("2003-01-05")));
assertEquals(2, getIsoWeek(parse("2003-01-06"))); assertEquals(2, getIsoWeekOfYear(parse("2003-01-06")));
} }
/** /**
* January 1st is a Thursday therefore the week belongs to the next year. * January 1st is a Thursday therefore the week belongs to the next year.
*/ */
private void testIsoWeekJanuary1thThursday() throws Exception { private void testIsoWeekJanuary1thThursday() throws Exception {
assertEquals(52, getIsoWeek(parse("2008-12-28"))); assertEquals(52, getIsoWeekOfYear(parse("2008-12-28")));
assertEquals(1, getIsoWeek(parse("2008-12-29"))); assertEquals(1, getIsoWeekOfYear(parse("2008-12-29")));
assertEquals(1, getIsoWeek(parse("2008-12-30"))); assertEquals(1, getIsoWeekOfYear(parse("2008-12-30")));
assertEquals(1, getIsoWeek(parse("2008-12-31"))); assertEquals(1, getIsoWeekOfYear(parse("2008-12-31")));
assertEquals(1, getIsoWeek(parse("2009-01-01"))); assertEquals(1, getIsoWeekOfYear(parse("2009-01-01")));
assertEquals(1, getIsoWeek(parse("2009-01-04"))); assertEquals(1, getIsoWeekOfYear(parse("2009-01-04")));
assertEquals(2, getIsoWeek(parse("2009-01-09"))); assertEquals(2, getIsoWeekOfYear(parse("2009-01-09")));
} }
/** /**
* January 1st is a Friday therefore the week belongs to the previous year. * January 1st is a Friday therefore the week belongs to the previous year.
*/ */
private void testIsoWeekJanuary1thFriday() throws Exception { private void testIsoWeekJanuary1thFriday() throws Exception {
assertEquals(53, getIsoWeek(parse("2009-12-31"))); assertEquals(53, getIsoWeekOfYear(parse("2009-12-31")));
assertEquals(53, getIsoWeek(parse("2010-01-01"))); assertEquals(53, getIsoWeekOfYear(parse("2010-01-01")));
assertEquals(53, getIsoWeek(parse("2010-01-03"))); assertEquals(53, getIsoWeekOfYear(parse("2010-01-03")));
assertEquals(1, getIsoWeek(parse("2010-01-04"))); assertEquals(1, getIsoWeekOfYear(parse("2010-01-04")));
} }
/** /**
...@@ -162,34 +161,34 @@ public class TestDateIso8601 extends TestBase { ...@@ -162,34 +161,34 @@ public class TestDateIso8601 extends TestBase {
* year. * year.
*/ */
private void testIsoWeekJanuary1thSaturday() throws Exception { private void testIsoWeekJanuary1thSaturday() throws Exception {
assertEquals(52, getIsoWeek(parse("2010-12-31"))); assertEquals(52, getIsoWeekOfYear(parse("2010-12-31")));
assertEquals(52, getIsoWeek(parse("2011-01-01"))); assertEquals(52, getIsoWeekOfYear(parse("2011-01-01")));
assertEquals(52, getIsoWeek(parse("2011-01-02"))); assertEquals(52, getIsoWeekOfYear(parse("2011-01-02")));
assertEquals(1, getIsoWeek(parse("2011-01-03"))); assertEquals(1, getIsoWeekOfYear(parse("2011-01-03")));
} }
/** /**
* January 1st is a Sunday therefore the week belongs to the previous year. * January 1st is a Sunday therefore the week belongs to the previous year.
*/ */
private void testIsoWeekJanuary1thSunday() throws Exception { private void testIsoWeekJanuary1thSunday() throws Exception {
assertEquals(52, getIsoWeek(parse("2011-12-31"))); assertEquals(52, getIsoWeekOfYear(parse("2011-12-31")));
assertEquals(52, getIsoWeek(parse("2012-01-01"))); assertEquals(52, getIsoWeekOfYear(parse("2012-01-01")));
assertEquals(1, getIsoWeek(parse("2012-01-02"))); assertEquals(1, getIsoWeekOfYear(parse("2012-01-02")));
assertEquals(1, getIsoWeek(parse("2012-01-08"))); assertEquals(1, getIsoWeekOfYear(parse("2012-01-08")));
assertEquals(2, getIsoWeek(parse("2012-01-09"))); assertEquals(2, getIsoWeekOfYear(parse("2012-01-09")));
} }
/** /**
* January 1st is a Monday therefore year is equal to isoYear. * January 1st is a Monday therefore year is equal to isoYear.
*/ */
private void testIsoYearJanuary1thMonday() throws Exception { private void testIsoYearJanuary1thMonday() throws Exception {
assertEquals(2006, getIsoYear(parse("2006-12-28"))); assertEquals(2006, getIsoWeekYear(parse("2006-12-28")));
assertEquals(2006, getIsoYear(parse("2006-12-29"))); assertEquals(2006, getIsoWeekYear(parse("2006-12-29")));
assertEquals(2006, getIsoYear(parse("2006-12-30"))); assertEquals(2006, getIsoWeekYear(parse("2006-12-30")));
assertEquals(2006, getIsoYear(parse("2006-12-31"))); assertEquals(2006, getIsoWeekYear(parse("2006-12-31")));
assertEquals(2007, getIsoYear(parse("2007-01-01"))); assertEquals(2007, getIsoWeekYear(parse("2007-01-01")));
assertEquals(2007, getIsoYear(parse("2007-01-02"))); assertEquals(2007, getIsoWeekYear(parse("2007-01-02")));
assertEquals(2007, getIsoYear(parse("2007-01-03"))); assertEquals(2007, getIsoWeekYear(parse("2007-01-03")));
} }
/** /**
...@@ -197,14 +196,14 @@ public class TestDateIso8601 extends TestBase { ...@@ -197,14 +196,14 @@ public class TestDateIso8601 extends TestBase {
* year. * year.
*/ */
private void testIsoYearJanuary1thTuesday() throws Exception { private void testIsoYearJanuary1thTuesday() throws Exception {
assertEquals(2007, getIsoYear(parse("2007-12-28"))); assertEquals(2007, getIsoWeekYear(parse("2007-12-28")));
assertEquals(2007, getIsoYear(parse("2007-12-29"))); assertEquals(2007, getIsoWeekYear(parse("2007-12-29")));
assertEquals(2007, getIsoYear(parse("2007-12-30"))); assertEquals(2007, getIsoWeekYear(parse("2007-12-30")));
assertEquals(2008, getIsoYear(parse("2007-12-31"))); assertEquals(2008, getIsoWeekYear(parse("2007-12-31")));
assertEquals(2008, getIsoYear(parse("2008-01-01"))); assertEquals(2008, getIsoWeekYear(parse("2008-01-01")));
assertEquals(2008, getIsoYear(parse("2008-01-02"))); assertEquals(2008, getIsoWeekYear(parse("2008-01-02")));
assertEquals(2008, getIsoYear(parse("2008-01-03"))); assertEquals(2008, getIsoWeekYear(parse("2008-01-03")));
assertEquals(2008, getIsoYear(parse("2008-01-04"))); assertEquals(2008, getIsoWeekYear(parse("2008-01-04")));
} }
/** /**
...@@ -212,13 +211,13 @@ public class TestDateIso8601 extends TestBase { ...@@ -212,13 +211,13 @@ public class TestDateIso8601 extends TestBase {
* the next year. * the next year.
*/ */
private void testIsoYearJanuary1thWednesday() throws Exception { private void testIsoYearJanuary1thWednesday() throws Exception {
assertEquals(2002, getIsoYear(parse("2002-12-28"))); assertEquals(2002, getIsoWeekYear(parse("2002-12-28")));
assertEquals(2002, getIsoYear(parse("2002-12-29"))); assertEquals(2002, getIsoWeekYear(parse("2002-12-29")));
assertEquals(2003, getIsoYear(parse("2002-12-30"))); assertEquals(2003, getIsoWeekYear(parse("2002-12-30")));
assertEquals(2003, getIsoYear(parse("2002-12-31"))); assertEquals(2003, getIsoWeekYear(parse("2002-12-31")));
assertEquals(2003, getIsoYear(parse("2003-01-01"))); assertEquals(2003, getIsoWeekYear(parse("2003-01-01")));
assertEquals(2003, getIsoYear(parse("2003-01-02"))); assertEquals(2003, getIsoWeekYear(parse("2003-01-02")));
assertEquals(2003, getIsoYear(parse("2003-12-02"))); assertEquals(2003, getIsoWeekYear(parse("2003-12-02")));
} }
/** /**
...@@ -226,14 +225,14 @@ public class TestDateIso8601 extends TestBase { ...@@ -226,14 +225,14 @@ public class TestDateIso8601 extends TestBase {
* next year. * next year.
*/ */
private void testIsoYearJanuary1thThursday() throws Exception { private void testIsoYearJanuary1thThursday() throws Exception {
assertEquals(2008, getIsoYear(parse("2008-12-28"))); assertEquals(2008, getIsoWeekYear(parse("2008-12-28")));
assertEquals(2009, getIsoYear(parse("2008-12-29"))); assertEquals(2009, getIsoWeekYear(parse("2008-12-29")));
assertEquals(2009, getIsoYear(parse("2008-12-30"))); assertEquals(2009, getIsoWeekYear(parse("2008-12-30")));
assertEquals(2009, getIsoYear(parse("2008-12-31"))); assertEquals(2009, getIsoWeekYear(parse("2008-12-31")));
assertEquals(2009, getIsoYear(parse("2009-01-01"))); assertEquals(2009, getIsoWeekYear(parse("2009-01-01")));
assertEquals(2009, getIsoYear(parse("2009-01-02"))); assertEquals(2009, getIsoWeekYear(parse("2009-01-02")));
assertEquals(2009, getIsoYear(parse("2009-01-03"))); assertEquals(2009, getIsoWeekYear(parse("2009-01-03")));
assertEquals(2009, getIsoYear(parse("2009-01-04"))); assertEquals(2009, getIsoWeekYear(parse("2009-01-04")));
} }
/** /**
...@@ -241,14 +240,14 @@ public class TestDateIso8601 extends TestBase { ...@@ -241,14 +240,14 @@ public class TestDateIso8601 extends TestBase {
* previous year. * previous year.
*/ */
private void testIsoYearJanuary1thFriday() throws Exception { private void testIsoYearJanuary1thFriday() throws Exception {
assertEquals(2009, getIsoYear(parse("2009-12-28"))); assertEquals(2009, getIsoWeekYear(parse("2009-12-28")));
assertEquals(2009, getIsoYear(parse("2009-12-29"))); assertEquals(2009, getIsoWeekYear(parse("2009-12-29")));
assertEquals(2009, getIsoYear(parse("2009-12-30"))); assertEquals(2009, getIsoWeekYear(parse("2009-12-30")));
assertEquals(2009, getIsoYear(parse("2009-12-31"))); assertEquals(2009, getIsoWeekYear(parse("2009-12-31")));
assertEquals(2009, getIsoYear(parse("2010-01-01"))); assertEquals(2009, getIsoWeekYear(parse("2010-01-01")));
assertEquals(2009, getIsoYear(parse("2010-01-02"))); assertEquals(2009, getIsoWeekYear(parse("2010-01-02")));
assertEquals(2009, getIsoYear(parse("2010-01-03"))); assertEquals(2009, getIsoWeekYear(parse("2010-01-03")));
assertEquals(2010, getIsoYear(parse("2010-01-04"))); assertEquals(2010, getIsoWeekYear(parse("2010-01-04")));
} }
/** /**
...@@ -256,28 +255,28 @@ public class TestDateIso8601 extends TestBase { ...@@ -256,28 +255,28 @@ public class TestDateIso8601 extends TestBase {
* previous year. * previous year.
*/ */
private void testIsoYearJanuary1thSaturday() throws Exception { private void testIsoYearJanuary1thSaturday() throws Exception {
assertEquals(2010, getIsoYear(parse("2010-12-28"))); assertEquals(2010, getIsoWeekYear(parse("2010-12-28")));
assertEquals(2010, getIsoYear(parse("2010-12-29"))); assertEquals(2010, getIsoWeekYear(parse("2010-12-29")));
assertEquals(2010, getIsoYear(parse("2010-12-30"))); assertEquals(2010, getIsoWeekYear(parse("2010-12-30")));
assertEquals(2010, getIsoYear(parse("2010-12-31"))); assertEquals(2010, getIsoWeekYear(parse("2010-12-31")));
assertEquals(2010, getIsoYear(parse("2011-01-01"))); assertEquals(2010, getIsoWeekYear(parse("2011-01-01")));
assertEquals(2010, getIsoYear(parse("2011-01-02"))); assertEquals(2010, getIsoWeekYear(parse("2011-01-02")));
assertEquals(2011, getIsoYear(parse("2011-01-03"))); assertEquals(2011, getIsoWeekYear(parse("2011-01-03")));
assertEquals(2011, getIsoYear(parse("2011-01-04"))); assertEquals(2011, getIsoWeekYear(parse("2011-01-04")));
} }
/** /**
* January 1st is a Sunday therefore this day belong to the previous year. * January 1st is a Sunday therefore this day belong to the previous year.
*/ */
private void testIsoYearJanuary1thSunday() throws Exception { private void testIsoYearJanuary1thSunday() throws Exception {
assertEquals(2011, getIsoYear(parse("2011-12-28"))); assertEquals(2011, getIsoWeekYear(parse("2011-12-28")));
assertEquals(2011, getIsoYear(parse("2011-12-29"))); assertEquals(2011, getIsoWeekYear(parse("2011-12-29")));
assertEquals(2011, getIsoYear(parse("2011-12-30"))); assertEquals(2011, getIsoWeekYear(parse("2011-12-30")));
assertEquals(2011, getIsoYear(parse("2011-12-31"))); assertEquals(2011, getIsoWeekYear(parse("2011-12-31")));
assertEquals(2011, getIsoYear(parse("2012-01-01"))); assertEquals(2011, getIsoWeekYear(parse("2012-01-01")));
assertEquals(2012, getIsoYear(parse("2012-01-02"))); assertEquals(2012, getIsoWeekYear(parse("2012-01-02")));
assertEquals(2012, getIsoYear(parse("2012-01-03"))); assertEquals(2012, getIsoWeekYear(parse("2012-01-03")));
assertEquals(2012, getIsoYear(parse("2012-01-04"))); assertEquals(2012, getIsoWeekYear(parse("2012-01-04")));
} }
} }
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
...@@ -25,6 +28,8 @@ public class TestDateTimeUtils extends TestBase { ...@@ -25,6 +28,8 @@ public class TestDateTimeUtils extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
testParseTimeNanosDB2Format(); testParseTimeNanosDB2Format();
testDayOfWeek();
testWeekOfYear();
} }
private void testParseTimeNanosDB2Format() { private void testParseTimeNanosDB2Format() {
...@@ -34,4 +39,55 @@ public class TestDateTimeUtils extends TestBase { ...@@ -34,4 +39,55 @@ public class TestDateTimeUtils extends TestBase {
assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01:02:03", 0, 8, true)); assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01:02:03", 0, 8, true));
assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01.02.03", 0, 8, true)); assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01.02.03", 0, 8, true));
} }
/**
* Test for {@link DateTimeUtils#getSundayDayOfWeek()} and
* {@link DateTimeUtils#getIsoDayOfWeek(long)}.
*/
private void testDayOfWeek() {
GregorianCalendar gc = DateTimeUtils.createGregorianCalendar();
for (int i = -1_000_000; i <= 1_000_000; i++) {
gc.clear();
gc.setTimeInMillis(i * 86400000L);
int year = gc.get(Calendar.YEAR);
if (gc.get(Calendar.ERA) == GregorianCalendar.BC) {
year = 1 - year;
}
long expectedDateValue = DateTimeUtils.dateValue(year, gc.get(Calendar.MONTH) + 1,
gc.get(Calendar.DAY_OF_MONTH));
long dateValue = DateTimeUtils.dateValueFromAbsoluteDay(i);
assertEquals(expectedDateValue, dateValue);
assertEquals(i, DateTimeUtils.absoluteDayFromDateValue(dateValue));
int dow = gc.get(Calendar.DAY_OF_WEEK);
assertEquals(dow, DateTimeUtils.getSundayDayOfWeek(dateValue));
int isoDow = (dow + 5) % 7 + 1;
assertEquals(isoDow, DateTimeUtils.getIsoDayOfWeek(dateValue));
assertEquals(gc.get(Calendar.WEEK_OF_YEAR),
DateTimeUtils.getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1, gc.getMinimalDaysInFirstWeek()));
}
}
/**
* Test for {@link DateTimeUtils#getDayOfYear(long)},
* {@link DateTimeUtils#getWeekOfYear(long, int, int)} and
* {@link DateTimeUtils#getWeekYear(long, int, int)}.
*/
private void testWeekOfYear() {
GregorianCalendar gc = new GregorianCalendar(DateTimeUtils.UTC);
for (int firstDay = 1; firstDay <= 7; firstDay++) {
gc.setFirstDayOfWeek(firstDay);
for (int minimalDays = 1; minimalDays <= 7; minimalDays++) {
gc.setMinimalDaysInFirstWeek(minimalDays);
for (int i = 0; i < 150_000; i++) {
long dateValue = DateTimeUtils.dateValueFromAbsoluteDay(i);
gc.clear();
gc.setTimeInMillis(i * 86400000L);
assertEquals(gc.get(Calendar.DAY_OF_YEAR), DateTimeUtils.getDayOfYear(dateValue));
assertEquals(gc.get(Calendar.WEEK_OF_YEAR), DateTimeUtils.getWeekOfYear(dateValue, firstDay - 1, minimalDays));
assertEquals(gc.getWeekYear(), DateTimeUtils.getWeekYear(dateValue, firstDay - 1, minimalDays));
}
}
}
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论