mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-08 09:35:16 +00:00
Merge
This commit is contained in:
commit
34f54b7bb3
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,7 @@ FILES_java = \
|
||||
java/text/AttributedString.java \
|
||||
java/text/BreakDictionary.java \
|
||||
java/text/BreakIterator.java \
|
||||
java/text/CalendarBuilder.java \
|
||||
java/text/CharacterIterator.java \
|
||||
java/text/CharacterIteratorFieldDelegate.java \
|
||||
java/text/ChoiceFormat.java \
|
||||
|
||||
170
jdk/src/share/classes/java/text/CalendarBuilder.java
Normal file
170
jdk/src/share/classes/java/text/CalendarBuilder.java
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Calendar;
|
||||
import static java.util.GregorianCalendar.*;
|
||||
|
||||
/**
|
||||
* {@code CalendarBuilder} keeps field-value pairs for setting
|
||||
* the calendar fields of the given {@code Calendar}. It has the
|
||||
* {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
|
||||
* support. Also {@code ISO_DAY_OF_WEEK} is used to specify
|
||||
* {@code DAY_OF_WEEK} in the ISO day of week numbering.
|
||||
*
|
||||
* <p>{@code CalendarBuilder} retains the semantic of the pseudo
|
||||
* timestamp for fields. {@code CalendarBuilder} uses a single
|
||||
* int array combining fields[] and stamp[] of {@code Calendar}.
|
||||
*
|
||||
* @author Masayoshi Okutsu
|
||||
*/
|
||||
class CalendarBuilder {
|
||||
/*
|
||||
* Pseudo time stamp constants used in java.util.Calendar
|
||||
*/
|
||||
private static final int UNSET = 0;
|
||||
private static final int COMPUTED = 1;
|
||||
private static final int MINIMUM_USER_STAMP = 2;
|
||||
|
||||
private static final int MAX_FIELD = FIELD_COUNT + 1;
|
||||
|
||||
public static final int WEEK_YEAR = FIELD_COUNT;
|
||||
public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
|
||||
|
||||
// stamp[] (lower half) and field[] (upper half) combined
|
||||
private final int[] field;
|
||||
private int nextStamp;
|
||||
private int maxFieldIndex;
|
||||
|
||||
CalendarBuilder() {
|
||||
field = new int[MAX_FIELD * 2];
|
||||
nextStamp = MINIMUM_USER_STAMP;
|
||||
maxFieldIndex = -1;
|
||||
}
|
||||
|
||||
CalendarBuilder set(int index, int value) {
|
||||
if (index == ISO_DAY_OF_WEEK) {
|
||||
index = DAY_OF_WEEK;
|
||||
value = toCalendarDayOfWeek(value);
|
||||
}
|
||||
field[index] = nextStamp++;
|
||||
field[MAX_FIELD + index] = value;
|
||||
if (index > maxFieldIndex && index < FIELD_COUNT) {
|
||||
maxFieldIndex = index;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CalendarBuilder addYear(int value) {
|
||||
field[MAX_FIELD + YEAR] += value;
|
||||
field[MAX_FIELD + WEEK_YEAR] += value;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean isSet(int index) {
|
||||
if (index == ISO_DAY_OF_WEEK) {
|
||||
index = DAY_OF_WEEK;
|
||||
}
|
||||
return field[index] > UNSET;
|
||||
}
|
||||
|
||||
Calendar establish(Calendar cal) {
|
||||
boolean weekDate = isSet(WEEK_YEAR)
|
||||
&& field[WEEK_YEAR] > field[YEAR];
|
||||
if (weekDate && !cal.isWeekDateSupported()) {
|
||||
// Use YEAR instead
|
||||
if (!isSet(YEAR)) {
|
||||
set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
|
||||
}
|
||||
weekDate = false;
|
||||
}
|
||||
|
||||
cal.clear();
|
||||
// Set the fields from the min stamp to the max stamp so that
|
||||
// the field resolution works in the Calendar.
|
||||
for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
|
||||
for (int index = 0; index <= maxFieldIndex; index++) {
|
||||
if (field[index] == stamp) {
|
||||
cal.set(index, field[MAX_FIELD + index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weekDate) {
|
||||
int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
|
||||
int dayOfWeek = isSet(DAY_OF_WEEK) ?
|
||||
field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
|
||||
if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
|
||||
if (dayOfWeek >= 8) {
|
||||
dayOfWeek--;
|
||||
weekOfYear += dayOfWeek / 7;
|
||||
dayOfWeek = (dayOfWeek % 7) + 1;
|
||||
} else {
|
||||
while (dayOfWeek <= 0) {
|
||||
dayOfWeek += 7;
|
||||
weekOfYear--;
|
||||
}
|
||||
}
|
||||
dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
|
||||
}
|
||||
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
|
||||
}
|
||||
return cal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CalendarBuilder:[");
|
||||
for (int i = 0; i < field.length; i++) {
|
||||
if (isSet(i)) {
|
||||
sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
|
||||
}
|
||||
}
|
||||
int lastIndex = sb.length() - 1;
|
||||
if (sb.charAt(lastIndex) == ',') {
|
||||
sb.setLength(lastIndex);
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static int toISODayOfWeek(int calendarDayOfWeek) {
|
||||
return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
|
||||
}
|
||||
|
||||
static int toCalendarDayOfWeek(int isoDayOfWeek) {
|
||||
if (!isValidDayOfWeek(isoDayOfWeek)) {
|
||||
// adjust later for lenient mode
|
||||
return isoDayOfWeek;
|
||||
}
|
||||
return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
|
||||
}
|
||||
|
||||
static boolean isValidDayOfWeek(int dayOfWeek) {
|
||||
return dayOfWeek > 0 && dayOfWeek <= 7;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -226,7 +226,29 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
* Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
|
||||
* All locales use the same these unlocalized pattern characters.
|
||||
*/
|
||||
static final String patternChars = "GyMdkHmsSEDFwWahKzZ";
|
||||
static final String patternChars = "GyMdkHmsSEDFwWahKzZYu";
|
||||
|
||||
static final int PATTERN_ERA = 0; // G
|
||||
static final int PATTERN_YEAR = 1; // y
|
||||
static final int PATTERN_MONTH = 2; // M
|
||||
static final int PATTERN_DAY_OF_MONTH = 3; // d
|
||||
static final int PATTERN_HOUR_OF_DAY1 = 4; // k
|
||||
static final int PATTERN_HOUR_OF_DAY0 = 5; // H
|
||||
static final int PATTERN_MINUTE = 6; // m
|
||||
static final int PATTERN_SECOND = 7; // s
|
||||
static final int PATTERN_MILLISECOND = 8; // S
|
||||
static final int PATTERN_DAY_OF_WEEK = 9; // E
|
||||
static final int PATTERN_DAY_OF_YEAR = 10; // D
|
||||
static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
|
||||
static final int PATTERN_WEEK_OF_YEAR = 12; // w
|
||||
static final int PATTERN_WEEK_OF_MONTH = 13; // W
|
||||
static final int PATTERN_AM_PM = 14; // a
|
||||
static final int PATTERN_HOUR1 = 15; // h
|
||||
static final int PATTERN_HOUR0 = 16; // K
|
||||
static final int PATTERN_ZONE_NAME = 17; // z
|
||||
static final int PATTERN_ZONE_VALUE = 18; // Z
|
||||
static final int PATTERN_WEEK_YEAR = 19; // Y
|
||||
static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
|
||||
|
||||
/**
|
||||
* Localized date-time pattern characters. For example, a locale may
|
||||
@ -505,7 +527,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
* @return the localized date-time pattern characters.
|
||||
*/
|
||||
public String getLocalPatternChars() {
|
||||
return new String(localPatternChars);
|
||||
return localPatternChars;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -514,7 +536,8 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
* pattern characters.
|
||||
*/
|
||||
public void setLocalPatternChars(String newLocalPatternChars) {
|
||||
localPatternChars = new String(newLocalPatternChars);
|
||||
// Call toString() to throw an NPE in case the argument is null
|
||||
localPatternChars = newLocalPatternChars.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,7 +722,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
||||
} else {
|
||||
dst.zoneStrings = null;
|
||||
}
|
||||
dst.localPatternChars = new String (src.localPatternChars);
|
||||
dst.localPatternChars = src.localPatternChars;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -55,6 +55,8 @@ import sun.util.calendar.CalendarUtils;
|
||||
import sun.util.calendar.ZoneInfoFile;
|
||||
import sun.util.resources.LocaleData;
|
||||
|
||||
import static java.text.DateFormatSymbols.*;
|
||||
|
||||
/**
|
||||
* <code>SimpleDateFormat</code> is a concrete class for formatting and
|
||||
* parsing dates in a locale-sensitive manner. It allows for formatting
|
||||
@ -108,40 +110,50 @@ import sun.util.resources.LocaleData;
|
||||
* <td><a href="#year">Year</a>
|
||||
* <td><code>1996</code>; <code>96</code>
|
||||
* <tr>
|
||||
* <td><code>Y</code>
|
||||
* <td>Week year
|
||||
* <td><a href="#year">Year</a>
|
||||
* <td><code>2009</code>; <code>09</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>M</code>
|
||||
* <td>Month in year
|
||||
* <td><a href="#month">Month</a>
|
||||
* <td><code>July</code>; <code>Jul</code>; <code>07</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <tr>
|
||||
* <td><code>w</code>
|
||||
* <td>Week in year
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>27</code>
|
||||
* <tr>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>W</code>
|
||||
* <td>Week in month
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>2</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <tr>
|
||||
* <td><code>D</code>
|
||||
* <td>Day in year
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>189</code>
|
||||
* <tr>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>d</code>
|
||||
* <td>Day in month
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>10</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <tr>
|
||||
* <td><code>F</code>
|
||||
* <td>Day of week in month
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>2</code>
|
||||
* <tr>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>E</code>
|
||||
* <td>Day in week
|
||||
* <td>Day name in week
|
||||
* <td><a href="#text">Text</a>
|
||||
* <td><code>Tuesday</code>; <code>Tue</code>
|
||||
* <tr>
|
||||
* <td><code>u</code>
|
||||
* <td>Day number of week (1 = Monday, ..., 7 = Sunday)
|
||||
* <td><a href="#number">Number</a>
|
||||
* <td><code>1</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>a</code>
|
||||
* <td>Am/pm marker
|
||||
@ -202,12 +214,12 @@ import sun.util.resources.LocaleData;
|
||||
* the full form is used; otherwise a short or abbreviated form
|
||||
* is used if available.
|
||||
* For parsing, both forms are accepted, independent of the number
|
||||
* of pattern letters.
|
||||
* of pattern letters.<br><br></li>
|
||||
* <li><strong><a name="number">Number:</a></strong>
|
||||
* For formatting, the number of pattern letters is the minimum
|
||||
* number of digits, and shorter numbers are zero-padded to this amount.
|
||||
* For parsing, the number of pattern letters is ignored unless
|
||||
* it's needed to separate two adjacent fields.
|
||||
* it's needed to separate two adjacent fields.<br><br></li>
|
||||
* <li><strong><a name="year">Year:</a></strong>
|
||||
* If the formatter's {@link #getCalendar() Calendar} is the Gregorian
|
||||
* calendar, the following rules are applied.<br>
|
||||
@ -239,11 +251,20 @@ import sun.util.resources.LocaleData;
|
||||
* letters is 4 or more, a calendar specific {@linkplain
|
||||
* Calendar#LONG long form} is used. Otherwise, a calendar
|
||||
* specific {@linkplain Calendar#SHORT short or abbreviated form}
|
||||
* is used.
|
||||
* is used.<br>
|
||||
* <br>
|
||||
* If week year {@code 'Y'} is specified and the {@linkplain
|
||||
* #getCalendar() calendar} doesn't support any <a
|
||||
* href="../util/GregorianCalendar.html#week_year"> week
|
||||
* years</a>, the calendar year ({@code 'y'}) is used instead. The
|
||||
* support of week years can be tested with a call to {@link
|
||||
* DateFormat#getCalendar() getCalendar()}.{@link
|
||||
* java.util.Calendar#isWeekDateSupported()
|
||||
* isWeekDateSupported()}.<br><br></li>
|
||||
* <li><strong><a name="month">Month:</a></strong>
|
||||
* If the number of pattern letters is 3 or more, the month is
|
||||
* interpreted as <a href="#text">text</a>; otherwise,
|
||||
* it is interpreted as a <a href="#number">number</a>.
|
||||
* it is interpreted as a <a href="#number">number</a>.<br><br></li>
|
||||
* <li><strong><a name="timezone">General time zone:</a></strong>
|
||||
* Time zones are interpreted as <a href="#text">text</a> if they have
|
||||
* names. For time zones representing a GMT offset value, the
|
||||
@ -264,7 +285,7 @@ import sun.util.resources.LocaleData;
|
||||
* 00 and 59. The format is locale independent and digits must be taken
|
||||
* from the Basic Latin block of the Unicode standard.
|
||||
* <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
|
||||
* accepted.
|
||||
* accepted.<br><br></li>
|
||||
* <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
|
||||
* For formatting, the RFC 822 4-digit time zone format is used:
|
||||
* <pre>
|
||||
@ -321,6 +342,9 @@ import sun.util.resources.LocaleData;
|
||||
* <tr>
|
||||
* <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
|
||||
* <td><code>2001-07-04T12:08:56.235-0700</code>
|
||||
* <tr bgcolor="#eeeeff">
|
||||
* <td><code>"YYYY-'W'ww-u"</code>
|
||||
* <td><code>2001-W27-3</code>
|
||||
* </table>
|
||||
* </blockquote>
|
||||
*
|
||||
@ -877,7 +901,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
* @param pos the formatting position. On input: an alignment field,
|
||||
* if desired. On output: the offsets of the alignment field.
|
||||
* @return the formatted date-time string.
|
||||
* @exception NullPointerException if the given date is null
|
||||
* @exception NullPointerException if the given {@code date} is {@code null}.
|
||||
*/
|
||||
public StringBuffer format(Date date, StringBuffer toAppendTo,
|
||||
FieldPosition pos)
|
||||
@ -968,7 +992,10 @@ public class SimpleDateFormat extends DateFormat {
|
||||
Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
|
||||
Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
|
||||
Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
|
||||
Calendar.ZONE_OFFSET
|
||||
Calendar.ZONE_OFFSET,
|
||||
// Pseudo Calendar fields
|
||||
CalendarBuilder.WEEK_YEAR,
|
||||
CalendarBuilder.ISO_DAY_OF_WEEK
|
||||
};
|
||||
|
||||
// Map index into pattern character string to DateFormat field number
|
||||
@ -982,6 +1009,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
|
||||
DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
|
||||
DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
|
||||
DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD
|
||||
};
|
||||
|
||||
// Maps from DecimalFormatSymbols index to Field constant
|
||||
@ -993,6 +1021,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
|
||||
Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
|
||||
Field.TIME_ZONE,
|
||||
Field.YEAR, Field.DAY_OF_WEEK
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1007,9 +1036,24 @@ public class SimpleDateFormat extends DateFormat {
|
||||
int beginOffset = buffer.length();
|
||||
|
||||
int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
|
||||
int value = calendar.get(field);
|
||||
int value;
|
||||
if (field == CalendarBuilder.WEEK_YEAR) {
|
||||
if (calendar.isWeekDateSupported()) {
|
||||
value = calendar.getWeekYear();
|
||||
} else {
|
||||
// use calendar year 'y' instead
|
||||
patternCharIndex = PATTERN_YEAR;
|
||||
field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
|
||||
value = calendar.get(field);
|
||||
}
|
||||
} else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
|
||||
value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
|
||||
} else {
|
||||
value = calendar.get(field);
|
||||
}
|
||||
|
||||
int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
|
||||
if (!useDateFormatSymbols) {
|
||||
if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
|
||||
current = calendar.getDisplayName(field, style, locale);
|
||||
}
|
||||
|
||||
@ -1018,7 +1062,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// zeroPaddingNumber() must be fixed.
|
||||
|
||||
switch (patternCharIndex) {
|
||||
case 0: // 'G' - ERA
|
||||
case PATTERN_ERA: // 'G'
|
||||
if (useDateFormatSymbols) {
|
||||
String[] eras = formatData.getEras();
|
||||
if (value < eras.length)
|
||||
@ -1028,7 +1072,8 @@ public class SimpleDateFormat extends DateFormat {
|
||||
current = "";
|
||||
break;
|
||||
|
||||
case 1: // 'y' - YEAR
|
||||
case PATTERN_WEEK_YEAR: // 'Y'
|
||||
case PATTERN_YEAR: // 'y'
|
||||
if (calendar instanceof GregorianCalendar) {
|
||||
if (count != 2)
|
||||
zeroPaddingNumber(value, count, maxIntCount, buffer);
|
||||
@ -1042,7 +1087,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 'M' - MONTH
|
||||
case PATTERN_MONTH: // 'M'
|
||||
if (useDateFormatSymbols) {
|
||||
String[] months;
|
||||
if (count >= 4) {
|
||||
@ -1062,7 +1107,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59
|
||||
case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
|
||||
if (current == null) {
|
||||
if (value == 0)
|
||||
zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
|
||||
@ -1072,7 +1117,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // 'E' - DAY_OF_WEEK
|
||||
case PATTERN_DAY_OF_WEEK: // 'E'
|
||||
if (useDateFormatSymbols) {
|
||||
String[] weekdays;
|
||||
if (count >= 4) {
|
||||
@ -1085,14 +1130,14 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 14: // 'a' - AM_PM
|
||||
case PATTERN_AM_PM: // 'a'
|
||||
if (useDateFormatSymbols) {
|
||||
String[] ampm = formatData.getAmPmStrings();
|
||||
current = ampm[value];
|
||||
}
|
||||
break;
|
||||
|
||||
case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM
|
||||
case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
|
||||
if (current == null) {
|
||||
if (value == 0)
|
||||
zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
|
||||
@ -1102,7 +1147,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 17: // 'z' - ZONE_OFFSET
|
||||
case PATTERN_ZONE_NAME: // 'z'
|
||||
if (current == null) {
|
||||
if (formatData.locale == null || formatData.isZoneStringsSet) {
|
||||
int zoneIndex =
|
||||
@ -1129,7 +1174,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break;
|
||||
|
||||
case 18: // 'Z' - ZONE_OFFSET ("-/+hhmm" form)
|
||||
case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
|
||||
value = (calendar.get(Calendar.ZONE_OFFSET) +
|
||||
calendar.get(Calendar.DST_OFFSET)) / 60000;
|
||||
|
||||
@ -1145,16 +1190,17 @@ public class SimpleDateFormat extends DateFormat {
|
||||
break;
|
||||
|
||||
default:
|
||||
// case 3: // 'd' - DATE
|
||||
// case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59
|
||||
// case 6: // 'm' - MINUTE
|
||||
// case 7: // 's' - SECOND
|
||||
// case 8: // 'S' - MILLISECOND
|
||||
// case 10: // 'D' - DAY_OF_YEAR
|
||||
// case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
|
||||
// case 12: // 'w' - WEEK_OF_YEAR
|
||||
// case 13: // 'W' - WEEK_OF_MONTH
|
||||
// case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM
|
||||
// case PATTERN_DAY_OF_MONTH: // 'd'
|
||||
// case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
|
||||
// case PATTERN_MINUTE: // 'm'
|
||||
// case PATTERN_SECOND: // 's'
|
||||
// case PATTERN_MILLISECOND: // 'S'
|
||||
// case PATTERN_DAY_OF_YEAR: // 'D'
|
||||
// case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
|
||||
// case PATTERN_WEEK_OF_YEAR: // 'w'
|
||||
// case PATTERN_WEEK_OF_MONTH: // 'W'
|
||||
// case PATTERN_HOUR0: // 'K' eg, 11PM + 1 hour =>> 0 AM
|
||||
// case PATTERN_ISO_DAY_OF_WEEK: // 'u' pseudo field, Monday = 1, ..., Sunday = 7
|
||||
if (current == null) {
|
||||
zeroPaddingNumber(value, count, maxIntCount, buffer);
|
||||
}
|
||||
@ -1264,10 +1310,9 @@ public class SimpleDateFormat extends DateFormat {
|
||||
int oldStart = start;
|
||||
int textLength = text.length();
|
||||
|
||||
calendar.clear(); // Clears all the time fields
|
||||
|
||||
boolean[] ambiguousYear = {false};
|
||||
|
||||
CalendarBuilder calb = new CalendarBuilder();
|
||||
|
||||
for (int i = 0; i < compiledPattern.length; ) {
|
||||
int tag = compiledPattern[i] >>> 8;
|
||||
@ -1340,7 +1385,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
start = subParse(text, start, tag, count, obeyCount,
|
||||
ambiguousYear, pos,
|
||||
useFollowingMinusSignAsDelimiter);
|
||||
useFollowingMinusSignAsDelimiter, calb);
|
||||
if (start < 0) {
|
||||
pos.index = oldStart;
|
||||
return null;
|
||||
@ -1354,46 +1399,16 @@ public class SimpleDateFormat extends DateFormat {
|
||||
|
||||
pos.index = start;
|
||||
|
||||
// This part is a problem: When we call parsedDate.after, we compute the time.
|
||||
// Take the date April 3 2004 at 2:30 am. When this is first set up, the year
|
||||
// will be wrong if we're parsing a 2-digit year pattern. It will be 1904.
|
||||
// April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am
|
||||
// is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
|
||||
// on that day. It is therefore parsed out to fields as 3:30 am. Then we
|
||||
// add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is
|
||||
// a Saturday, so it can have a 2:30 am -- and it should. [LIU]
|
||||
/*
|
||||
Date parsedDate = calendar.getTime();
|
||||
if( ambiguousYear[0] && !parsedDate.after(defaultCenturyStart) ) {
|
||||
calendar.add(Calendar.YEAR, 100);
|
||||
parsedDate = calendar.getTime();
|
||||
}
|
||||
*/
|
||||
// Because of the above condition, save off the fields in case we need to readjust.
|
||||
// The procedure we use here is not particularly efficient, but there is no other
|
||||
// way to do this given the API restrictions present in Calendar. We minimize
|
||||
// inefficiency by only performing this computation when it might apply, that is,
|
||||
// when the two-digit year is equal to the start year, and thus might fall at the
|
||||
// front or the back of the default century. This only works because we adjust
|
||||
// the year correctly to start with in other cases -- see subParse().
|
||||
Date parsedDate;
|
||||
try {
|
||||
if (ambiguousYear[0]) // If this is true then the two-digit year == the default start year
|
||||
{
|
||||
// We need a copy of the fields, and we need to avoid triggering a call to
|
||||
// complete(), which will recalculate the fields. Since we can't access
|
||||
// the fields[] array in Calendar, we clone the entire object. This will
|
||||
// stop working if Calendar.clone() is ever rewritten to call complete().
|
||||
Calendar savedCalendar = (Calendar)calendar.clone();
|
||||
parsedDate = calendar.getTime();
|
||||
if (parsedDate.before(defaultCenturyStart))
|
||||
{
|
||||
// We can't use add here because that does a complete() first.
|
||||
savedCalendar.set(Calendar.YEAR, defaultCenturyStartYear + 100);
|
||||
parsedDate = savedCalendar.getTime();
|
||||
parsedDate = calb.establish(calendar).getTime();
|
||||
// If the year value is ambiguous,
|
||||
// then the two-digit year == the default start year
|
||||
if (ambiguousYear[0]) {
|
||||
if (parsedDate.before(defaultCenturyStart)) {
|
||||
parsedDate = calb.addYear(100).establish(calendar).getTime();
|
||||
}
|
||||
}
|
||||
else parsedDate = calendar.getTime();
|
||||
}
|
||||
// An IllegalArgumentException will be thrown by Calendar.getTime()
|
||||
// if any fields are out of range, e.g., MONTH == 17.
|
||||
@ -1415,7 +1430,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
* @return the new start position if matching succeeded; a negative number
|
||||
* indicating matching failure, otherwise.
|
||||
*/
|
||||
private int matchString(String text, int start, int field, String[] data)
|
||||
private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
|
||||
{
|
||||
int i = 0;
|
||||
int count = data.length;
|
||||
@ -1441,7 +1456,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
if (bestMatch >= 0)
|
||||
{
|
||||
calendar.set(field, bestMatch);
|
||||
calb.set(field, bestMatch);
|
||||
return start + bestMatchLength;
|
||||
}
|
||||
return -start;
|
||||
@ -1452,7 +1467,8 @@ public class SimpleDateFormat extends DateFormat {
|
||||
* String[]). This method takes a Map<String, Integer> instead of
|
||||
* String[].
|
||||
*/
|
||||
private int matchString(String text, int start, int field, Map<String,Integer> data) {
|
||||
private int matchString(String text, int start, int field,
|
||||
Map<String,Integer> data, CalendarBuilder calb) {
|
||||
if (data != null) {
|
||||
String bestMatch = null;
|
||||
|
||||
@ -1466,7 +1482,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
|
||||
if (bestMatch != null) {
|
||||
calendar.set(field, data.get(bestMatch));
|
||||
calb.set(field, data.get(bestMatch));
|
||||
return start + bestMatch.length();
|
||||
}
|
||||
}
|
||||
@ -1486,11 +1502,22 @@ public class SimpleDateFormat extends DateFormat {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
|
||||
String[][] zoneStrings) {
|
||||
int index = standardIndex + 2;
|
||||
String zoneName = zoneStrings[zoneIndex][index];
|
||||
if (text.regionMatches(true, start,
|
||||
zoneName, 0, zoneName.length())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* find time zone 'text' matched zoneStrings and set to internal
|
||||
* calendar.
|
||||
*/
|
||||
private int subParseZoneString(String text, int start) {
|
||||
private int subParseZoneString(String text, int start, CalendarBuilder calb) {
|
||||
boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
|
||||
TimeZone currentTimeZone = getTimeZone();
|
||||
|
||||
@ -1524,6 +1551,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tz == null) {
|
||||
int len = zoneStrings.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
@ -1549,8 +1577,8 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// determine the local time. (6645292)
|
||||
int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
|
||||
if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
|
||||
calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
|
||||
calendar.set(Calendar.DST_OFFSET, dstAmount);
|
||||
calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
|
||||
.set(Calendar.DST_OFFSET, dstAmount);
|
||||
}
|
||||
return (start + zoneNames[nameIndex].length());
|
||||
}
|
||||
@ -1577,11 +1605,15 @@ public class SimpleDateFormat extends DateFormat {
|
||||
private int subParse(String text, int start, int patternCharIndex, int count,
|
||||
boolean obeyCount, boolean[] ambiguousYear,
|
||||
ParsePosition origPos,
|
||||
boolean useFollowingMinusSignAsDelimiter) {
|
||||
boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
|
||||
Number number = null;
|
||||
int value = 0;
|
||||
ParsePosition pos = new ParsePosition(0);
|
||||
pos.index = start;
|
||||
if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
|
||||
// use calendar year 'y' instead
|
||||
patternCharIndex = PATTERN_YEAR;
|
||||
}
|
||||
int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
|
||||
|
||||
// If there are any spaces here, skip over them. If we hit the end
|
||||
@ -1602,10 +1634,11 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// a number value. We handle further, more generic cases below. We need
|
||||
// to handle some of them here because some fields require extra processing on
|
||||
// the parsed value.
|
||||
if (patternCharIndex == 4 /* HOUR_OF_DAY1_FIELD */ ||
|
||||
patternCharIndex == 15 /* HOUR1_FIELD */ ||
|
||||
(patternCharIndex == 2 /* MONTH_FIELD */ && count <= 2) ||
|
||||
patternCharIndex == 1 /* YEAR_FIELD */) {
|
||||
if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
|
||||
patternCharIndex == PATTERN_HOUR1 ||
|
||||
(patternCharIndex == PATTERN_MONTH && count <= 2) ||
|
||||
patternCharIndex == PATTERN_YEAR ||
|
||||
patternCharIndex == PATTERN_WEEK_YEAR) {
|
||||
// It would be good to unify this with the obeyCount logic below,
|
||||
// but that's going to be difficult.
|
||||
if (obeyCount) {
|
||||
@ -1617,7 +1650,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
number = numberFormat.parse(text, pos);
|
||||
}
|
||||
if (number == null) {
|
||||
if (patternCharIndex != 1 || calendar instanceof GregorianCalendar) {
|
||||
if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
|
||||
break parsing;
|
||||
}
|
||||
} else {
|
||||
@ -1638,33 +1671,34 @@ public class SimpleDateFormat extends DateFormat {
|
||||
|
||||
int index;
|
||||
switch (patternCharIndex) {
|
||||
case 0: // 'G' - ERA
|
||||
case PATTERN_ERA: // 'G'
|
||||
if (useDateFormatSymbols) {
|
||||
if ((index = matchString(text, start, Calendar.ERA, formatData.getEras())) > 0) {
|
||||
if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
} else {
|
||||
Map<String, Integer> map = calendar.getDisplayNames(field,
|
||||
Calendar.ALL_STYLES,
|
||||
locale);
|
||||
if ((index = matchString(text, start, field, map)) > 0) {
|
||||
if ((index = matchString(text, start, field, map, calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
break parsing;
|
||||
|
||||
case 1: // 'y' - YEAR
|
||||
case PATTERN_WEEK_YEAR: // 'Y'
|
||||
case PATTERN_YEAR: // 'y'
|
||||
if (!(calendar instanceof GregorianCalendar)) {
|
||||
// calendar might have text representations for year values,
|
||||
// such as "\u5143" in JapaneseImperialCalendar.
|
||||
int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
|
||||
Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
|
||||
if (map != null) {
|
||||
if ((index = matchString(text, start, field, map)) > 0) {
|
||||
if ((index = matchString(text, start, field, map, calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
calendar.set(field, value);
|
||||
calb.set(field, value);
|
||||
return pos.index;
|
||||
}
|
||||
|
||||
@ -1676,8 +1710,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// is treated literally: "2250", "-1", "1", "002".
|
||||
if (count <= 2 && (pos.index - start) == 2
|
||||
&& Character.isDigit(text.charAt(start))
|
||||
&& Character.isDigit(text.charAt(start+1)))
|
||||
{
|
||||
&& Character.isDigit(text.charAt(start+1))) {
|
||||
// Assume for example that the defaultCenturyStart is 6/18/1903.
|
||||
// This means that two-digit years will be forced into the range
|
||||
// 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
|
||||
@ -1691,16 +1724,16 @@ public class SimpleDateFormat extends DateFormat {
|
||||
value += (defaultCenturyStartYear/100)*100 +
|
||||
(value < ambiguousTwoDigitYear ? 100 : 0);
|
||||
}
|
||||
calendar.set(Calendar.YEAR, value);
|
||||
calb.set(field, value);
|
||||
return pos.index;
|
||||
|
||||
case 2: // 'M' - MONTH
|
||||
case PATTERN_MONTH: // 'M'
|
||||
if (count <= 2) // i.e., M or MM.
|
||||
{
|
||||
// Don't want to parse the month if it is a string
|
||||
// while pattern uses numeric style: M or MM.
|
||||
// [We computed 'value' above.]
|
||||
calendar.set(Calendar.MONTH, value - 1);
|
||||
calb.set(Calendar.MONTH, value - 1);
|
||||
return pos.index;
|
||||
}
|
||||
|
||||
@ -1710,50 +1743,50 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// Try count == 4 first:
|
||||
int newStart = 0;
|
||||
if ((newStart = matchString(text, start, Calendar.MONTH,
|
||||
formatData.getMonths())) > 0) {
|
||||
formatData.getMonths(), calb)) > 0) {
|
||||
return newStart;
|
||||
}
|
||||
// count == 4 failed, now try count == 3
|
||||
if ((index = matchString(text, start, Calendar.MONTH,
|
||||
formatData.getShortMonths())) > 0) {
|
||||
formatData.getShortMonths(), calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
} else {
|
||||
Map<String, Integer> map = calendar.getDisplayNames(field,
|
||||
Calendar.ALL_STYLES,
|
||||
locale);
|
||||
if ((index = matchString(text, start, field, map)) > 0) {
|
||||
if ((index = matchString(text, start, field, map, calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
break parsing;
|
||||
|
||||
case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59
|
||||
case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
|
||||
// [We computed 'value' above.]
|
||||
if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1) value = 0;
|
||||
calendar.set(Calendar.HOUR_OF_DAY, value);
|
||||
calb.set(Calendar.HOUR_OF_DAY, value);
|
||||
return pos.index;
|
||||
|
||||
case 9:
|
||||
{ // 'E' - DAY_OF_WEEK
|
||||
case PATTERN_DAY_OF_WEEK: // 'E'
|
||||
{
|
||||
if (useDateFormatSymbols) {
|
||||
// Want to be able to parse both short and long forms.
|
||||
// Try count == 4 (DDDD) first:
|
||||
int newStart = 0;
|
||||
if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
|
||||
formatData.getWeekdays())) > 0) {
|
||||
formatData.getWeekdays(), calb)) > 0) {
|
||||
return newStart;
|
||||
}
|
||||
// DDDD failed, now try DDD
|
||||
if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
|
||||
formatData.getShortWeekdays())) > 0) {
|
||||
formatData.getShortWeekdays(), calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
} else {
|
||||
int[] styles = { Calendar.LONG, Calendar.SHORT };
|
||||
for (int style : styles) {
|
||||
Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
|
||||
if ((index = matchString(text, start, field, map)) > 0) {
|
||||
if ((index = matchString(text, start, field, map, calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
@ -1761,27 +1794,28 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
break parsing;
|
||||
|
||||
case 14: // 'a' - AM_PM
|
||||
case PATTERN_AM_PM: // 'a'
|
||||
if (useDateFormatSymbols) {
|
||||
if ((index = matchString(text, start, Calendar.AM_PM, formatData.getAmPmStrings())) > 0) {
|
||||
if ((index = matchString(text, start, Calendar.AM_PM,
|
||||
formatData.getAmPmStrings(), calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
} else {
|
||||
Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
|
||||
if ((index = matchString(text, start, field, map)) > 0) {
|
||||
if ((index = matchString(text, start, field, map, calb)) > 0) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
break parsing;
|
||||
|
||||
case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM
|
||||
case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
|
||||
// [We computed 'value' above.]
|
||||
if (value == calendar.getLeastMaximum(Calendar.HOUR)+1) value = 0;
|
||||
calendar.set(Calendar.HOUR, value);
|
||||
calb.set(Calendar.HOUR, value);
|
||||
return pos.index;
|
||||
|
||||
case 17: // 'z' - ZONE_OFFSET
|
||||
case 18: // 'Z' - ZONE_OFFSET
|
||||
case PATTERN_ZONE_NAME: // 'z'
|
||||
case PATTERN_ZONE_VALUE: // 'Z'
|
||||
// First try to parse generic forms such as GMT-07:00. Do this first
|
||||
// in case localized TimeZoneNames contains the string "GMT"
|
||||
// for a zone; in that case, we don't want to match the first three
|
||||
@ -1797,7 +1831,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
if ((text.length() - start) >= GMT.length() &&
|
||||
text.regionMatches(true, start, GMT, 0, GMT.length())) {
|
||||
int num;
|
||||
calendar.set(Calendar.DST_OFFSET, 0);
|
||||
calb.set(Calendar.DST_OFFSET, 0);
|
||||
pos.index = start + GMT.length();
|
||||
|
||||
try { // try-catch for "GMT" only time zone string
|
||||
@ -1810,8 +1844,8 @@ public class SimpleDateFormat extends DateFormat {
|
||||
}
|
||||
catch(StringIndexOutOfBoundsException e) {}
|
||||
|
||||
if (sign == 0) { /* "GMT" without offset */
|
||||
calendar.set(Calendar.ZONE_OFFSET, 0);
|
||||
if (sign == 0) { /* "GMT" without offset */
|
||||
calb.set(Calendar.ZONE_OFFSET, 0);
|
||||
return pos.index;
|
||||
}
|
||||
|
||||
@ -1875,7 +1909,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
sign = -1;
|
||||
} else {
|
||||
// Try parsing the text as a time zone name (abbr).
|
||||
int i = subParseZoneString(text, pos.index);
|
||||
int i = subParseZoneString(text, pos.index, calb);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
@ -1933,24 +1967,24 @@ public class SimpleDateFormat extends DateFormat {
|
||||
// arrive here if the form GMT+/-... or an RFC 822 form was seen.
|
||||
if (sign != 0) {
|
||||
offset *= MILLIS_PER_MINUTE * sign;
|
||||
calendar.set(Calendar.ZONE_OFFSET, offset);
|
||||
calendar.set(Calendar.DST_OFFSET, 0);
|
||||
calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0);
|
||||
return ++pos.index;
|
||||
}
|
||||
}
|
||||
break parsing;
|
||||
|
||||
default:
|
||||
// case 3: // 'd' - DATE
|
||||
// case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59
|
||||
// case 6: // 'm' - MINUTE
|
||||
// case 7: // 's' - SECOND
|
||||
// case 8: // 'S' - MILLISECOND
|
||||
// case 10: // 'D' - DAY_OF_YEAR
|
||||
// case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
|
||||
// case 12: // 'w' - WEEK_OF_YEAR
|
||||
// case 13: // 'W' - WEEK_OF_MONTH
|
||||
// case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM
|
||||
// case PATTERN_DAY_OF_MONTH: // 'd'
|
||||
// case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
|
||||
// case PATTERN_MINUTE: // 'm'
|
||||
// case PATTERN_SECOND: // 's'
|
||||
// case PATTERN_MILLISECOND: // 'S'
|
||||
// case PATTERN_DAY_OF_YEAR: // 'D'
|
||||
// case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
|
||||
// case PATTERN_WEEK_OF_YEAR: // 'w'
|
||||
// case PATTERN_WEEK_OF_MONTH: // 'W'
|
||||
// case PATTERN_HOUR0: // 'K' 0-based. eg, 11PM + 1 hour =>> 0 AM
|
||||
// case PATTERN_ISO_DAY_OF_WEEK: // 'u' (pseudo field);
|
||||
|
||||
// Handle "generic" fields
|
||||
if (obeyCount) {
|
||||
@ -1973,7 +2007,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
pos.index--;
|
||||
}
|
||||
|
||||
calendar.set(field, value);
|
||||
calb.set(field, value);
|
||||
return pos.index;
|
||||
}
|
||||
break parsing;
|
||||
@ -2020,11 +2054,18 @@ public class SimpleDateFormat extends DateFormat {
|
||||
inQuote = true;
|
||||
else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
int ci = from.indexOf(c);
|
||||
if (ci == -1)
|
||||
if (ci >= 0) {
|
||||
// patternChars is longer than localPatternChars due
|
||||
// to serialization compatibility. The pattern letters
|
||||
// unsupported by localPatternChars pass through.
|
||||
if (ci < to.length()) {
|
||||
c = to.charAt(ci);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal pattern " +
|
||||
" character '" +
|
||||
c + "'");
|
||||
c = to.charAt(ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.append(c);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -119,7 +119,7 @@ import sun.util.resources.LocaleData;
|
||||
* calculating its time or calendar field values if any out-of-range field
|
||||
* value has been set.
|
||||
*
|
||||
* <h4>First Week</h4>
|
||||
* <h4><a name="first_week">First Week</a></h4>
|
||||
*
|
||||
* <code>Calendar</code> defines a locale-specific seven day week using two
|
||||
* parameters: the first day of the week and the minimal days in first week
|
||||
@ -2195,6 +2195,101 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
||||
return minimalDaysInFirstWeek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this {@code Calendar} supports week dates.
|
||||
*
|
||||
* <p>The default implementation of this method returns {@code false}.
|
||||
*
|
||||
* @return {@code true} if this {@code Calendar} supports week dates;
|
||||
* {@code false} otherwise.
|
||||
* @see #getWeekYear()
|
||||
* @see #setWeekDate(int,int,int)
|
||||
* @see #getWeeksInWeekYear()
|
||||
* @since 1.7
|
||||
*/
|
||||
public boolean isWeekDateSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the week year represented by this {@code Calendar}. The
|
||||
* week year is in sync with the week cycle. The {@linkplain
|
||||
* #getFirstDayOfWeek() first day of the first week} is the first
|
||||
* day of the week year.
|
||||
*
|
||||
* <p>The default implementation of this method throws an
|
||||
* {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @return the week year of this {@code Calendar}
|
||||
* @exception UnsupportedOperationException
|
||||
* if any week year numbering isn't supported
|
||||
* in this {@code Calendar}.
|
||||
* @see #isWeekDateSupported()
|
||||
* @see #getFirstDayOfWeek()
|
||||
* @see #getMinimalDaysInFirstWeek()
|
||||
* @since 1.7
|
||||
*/
|
||||
public int getWeekYear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date of this {@code Calendar} with the the given date
|
||||
* specifiers - week year, week of year, and day of week.
|
||||
*
|
||||
* <p>Unlike the {@code set} method, all of the calendar fields
|
||||
* and {@code time} values are calculated upon return.
|
||||
*
|
||||
* <p>If {@code weekOfYear} is out of the valid week-of-year range
|
||||
* in {@code weekYear}, the {@code weekYear} and {@code
|
||||
* weekOfYear} values are adjusted in lenient mode, or an {@code
|
||||
* IllegalArgumentException} is thrown in non-lenient mode.
|
||||
*
|
||||
* <p>The default implementation of this method throws an
|
||||
* {@code UnsupportedOperationException}.
|
||||
*
|
||||
* @param weekYear the week year
|
||||
* @param weekOfYear the week number based on {@code weekYear}
|
||||
* @param dayOfWeek the day of week value: one of the constants
|
||||
* for the {@link #DAY_OF_WEEK} field: {@link
|
||||
* #SUNDAY}, ..., {@link #SATURDAY}.
|
||||
* @exception IllegalArgumentException
|
||||
* if any of the given date specifiers is invalid
|
||||
* or any of the calendar fields are inconsistent
|
||||
* with the given date specifiers in non-lenient mode
|
||||
* @exception UnsupportedOperationException
|
||||
* if any week year numbering isn't supported in this
|
||||
* {@code Calendar}.
|
||||
* @see #isWeekDateSupported()
|
||||
* @see #getFirstDayOfWeek()
|
||||
* @see #getMinimalDaysInFirstWeek()
|
||||
* @since 1.7
|
||||
*/
|
||||
public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of weeks in the week year represented by this
|
||||
* {@code Calendar}.
|
||||
*
|
||||
* <p>The default implementation of this method throws an
|
||||
* {@code UnsupportedOperationException}.
|
||||
*
|
||||
* @return the number of weeks in the week year.
|
||||
* @exception UnsupportedOperationException
|
||||
* if any week year numbering isn't supported in this
|
||||
* {@code Calendar}.
|
||||
* @see #WEEK_OF_YEAR
|
||||
* @see #isWeekDateSupported()
|
||||
* @see #getWeekYear()
|
||||
* @see #getActualMaximum(int)
|
||||
* @since 1.7
|
||||
*/
|
||||
public int getWeeksInWeekYear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum value for the given calendar field of this
|
||||
* <code>Calendar</code> instance. The minimum value is defined as
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -88,23 +88,49 @@ import sun.util.calendar.ZoneInfo;
|
||||
* adjustment may be made if desired for dates that are prior to the Gregorian
|
||||
* changeover and which fall between January 1 and March 24.
|
||||
*
|
||||
* <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
|
||||
* 53. Week 1 for a year is the earliest seven day period starting on
|
||||
* <code>getFirstDayOfWeek()</code> that contains at least
|
||||
* <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
|
||||
* depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
|
||||
* <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
|
||||
* Weeks between week 1 of one year and week 1 of the following year are
|
||||
* numbered sequentially from 2 to 52 or 53 (as needed).
|
||||
|
||||
* <p>For example, January 1, 1998 was a Thursday. If
|
||||
* <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
|
||||
* <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
|
||||
* reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
|
||||
* on December 29, 1997, and ends on January 4, 1998. If, however,
|
||||
* <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
|
||||
* starts on January 4, 1998, and ends on January 10, 1998; the first three days
|
||||
* of 1998 then are part of week 53 of 1997.
|
||||
* <h4><a name="week_and_year">Week Of Year and Week Year</a></h4>
|
||||
*
|
||||
* <p>Values calculated for the {@link Calendar#WEEK_OF_YEAR
|
||||
* WEEK_OF_YEAR} field range from 1 to 53. The first week of a
|
||||
* calendar year is the earliest seven day period starting on {@link
|
||||
* Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at
|
||||
* least {@link Calendar#getMinimalDaysInFirstWeek()
|
||||
* getMinimalDaysInFirstWeek()} days from that year. It thus depends
|
||||
* on the values of {@code getMinimalDaysInFirstWeek()}, {@code
|
||||
* getFirstDayOfWeek()}, and the day of the week of January 1. Weeks
|
||||
* between week 1 of one year and week 1 of the following year
|
||||
* (exclusive) are numbered sequentially from 2 to 52 or 53 (except
|
||||
* for year(s) involved in the Julian-Gregorian transition).
|
||||
*
|
||||
* <p>The {@code getFirstDayOfWeek()} and {@code
|
||||
* getMinimalDaysInFirstWeek()} values are initialized using
|
||||
* locale-dependent resources when constructing a {@code
|
||||
* GregorianCalendar}. <a name="iso8601_compatible_setting">The week
|
||||
* determination is compatible</a> with the ISO 8601 standard when {@code
|
||||
* getFirstDayOfWeek()} is {@code MONDAY} and {@code
|
||||
* getMinimalDaysInFirstWeek()} is 4, which values are used in locales
|
||||
* where the standard is preferred. These values can explicitly be set by
|
||||
* calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and
|
||||
* {@link Calendar#setMinimalDaysInFirstWeek(int)
|
||||
* setMinimalDaysInFirstWeek()}.
|
||||
*
|
||||
* <p>A <a name="week_year"><em>week year</em></a> is in sync with a
|
||||
* {@code WEEK_OF_YEAR} cycle. All weeks between the first and last
|
||||
* weeks (inclusive) have the same <em>week year</em> value.
|
||||
* Therefore, the first and last days of a week year may have
|
||||
* different calendar year values.
|
||||
*
|
||||
* <p>For example, January 1, 1998 is a Thursday. If {@code
|
||||
* getFirstDayOfWeek()} is {@code MONDAY} and {@code
|
||||
* getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible
|
||||
* setting), then week 1 of 1998 starts on December 29, 1997, and ends
|
||||
* on January 4, 1998. The week year is 1998 for the last three days
|
||||
* of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is
|
||||
* {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and
|
||||
* ends on January 10, 1998; the first three days of 1998 then are
|
||||
* part of week 53 of 1997 and their week year is 1997.
|
||||
*
|
||||
* <h4>Week Of Month</h4>
|
||||
*
|
||||
* <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
|
||||
* to 6. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
|
||||
@ -124,7 +150,9 @@ import sun.util.calendar.ZoneInfo;
|
||||
* <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
|
||||
* through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
|
||||
*
|
||||
* <p>The <code>clear</code> methods set calendar field(s)
|
||||
* <h4>Default Fields Values</h4>
|
||||
*
|
||||
* <p>The <code>clear</code> method sets calendar field(s)
|
||||
* undefined. <code>GregorianCalendar</code> uses the following
|
||||
* default value for each calendar field if its value is undefined.
|
||||
*
|
||||
@ -1625,6 +1653,13 @@ public class GregorianCalendar extends Calendar {
|
||||
* is 29 because 2004 is a leap year, and if the date of this
|
||||
* instance is February 1, 2005, it's 28.
|
||||
*
|
||||
* <p>This method calculates the maximum value of {@link
|
||||
* Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link
|
||||
* Calendar#YEAR YEAR} (calendar year) value, not the <a
|
||||
* href="#week_year">week year</a>. Call {@link
|
||||
* #getWeeksInWeekYear()} to get the maximum value of {@code
|
||||
* WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}.
|
||||
*
|
||||
* @param field the calendar field
|
||||
* @return the maximum of the given field for the time value of
|
||||
* this <code>GregorianCalendar</code>
|
||||
@ -1742,8 +1777,13 @@ public class GregorianCalendar extends Calendar {
|
||||
if (gc == this) {
|
||||
gc = (GregorianCalendar) gc.clone();
|
||||
}
|
||||
gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
|
||||
int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
|
||||
gc.set(DAY_OF_YEAR, maxDayOfYear);
|
||||
value = gc.get(WEEK_OF_YEAR);
|
||||
if (internalGet(YEAR) != gc.getWeekYear()) {
|
||||
gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
|
||||
value = gc.get(WEEK_OF_YEAR);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1934,46 +1974,239 @@ public class GregorianCalendar extends Calendar {
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Proposed public API
|
||||
//////////////////////
|
||||
/**
|
||||
* Returns {@code true} indicating this {@code GregorianCalendar}
|
||||
* supports week dates.
|
||||
*
|
||||
* @return {@code true} (always)
|
||||
* @see #getWeekYear()
|
||||
* @see #setWeekDate(int,int,int)
|
||||
* @see #getWeeksInWeekYear()
|
||||
* @since 1.7
|
||||
*/
|
||||
@Override
|
||||
public final boolean isWeekDateSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
|
||||
* This may be one year before or after the Gregorian or Julian year stored
|
||||
* in the <code>YEAR</code> field. For example, January 1, 1999 is considered
|
||||
* Friday of week 53 of 1998 (if minimal days in first week is
|
||||
* 2 or less, and the first day of the week is Sunday). Given
|
||||
* these same settings, the ISO year of January 1, 1999 is
|
||||
* 1998.
|
||||
* Returns the <a href="#week_year">week year</a> represented by this
|
||||
* {@code GregorianCalendar}. The dates in the weeks between 1 and the
|
||||
* maximum week number of the week year have the same week year value
|
||||
* that may be one year before or after the {@link Calendar#YEAR YEAR}
|
||||
* (calendar year) value.
|
||||
*
|
||||
* <p>This method calls {@link Calendar#complete} before
|
||||
* calculating the week-based year.
|
||||
* <p>This method calls {@link Calendar#complete()} before
|
||||
* calculating the week year.
|
||||
*
|
||||
* @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
|
||||
* may be one year before or after the <code>YEAR</code> field.
|
||||
* @see #YEAR
|
||||
* @see #WEEK_OF_YEAR
|
||||
* @return the week year represented by this {@code GregorianCalendar}.
|
||||
* If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is
|
||||
* represented by 0 or a negative number: BC 1 is 0, BC 2
|
||||
* is -1, BC 3 is -2, and so on.
|
||||
* @throws IllegalArgumentException
|
||||
* if any of the calendar fields is invalid in non-lenient mode.
|
||||
* @see #isWeekDateSupported()
|
||||
* @see #getWeeksInWeekYear()
|
||||
* @see Calendar#getFirstDayOfWeek()
|
||||
* @see Calendar#getMinimalDaysInFirstWeek()
|
||||
* @since 1.7
|
||||
*/
|
||||
/*
|
||||
public int getWeekBasedYear() {
|
||||
complete();
|
||||
// TODO: Below doesn't work for gregorian cutover...
|
||||
int weekOfYear = internalGet(WEEK_OF_YEAR);
|
||||
int year = internalGet(YEAR);
|
||||
if (internalGet(MONTH) == Calendar.JANUARY) {
|
||||
if (weekOfYear >= 52) {
|
||||
@Override
|
||||
public int getWeekYear() {
|
||||
int year = get(YEAR); // implicitly calls complete()
|
||||
if (internalGetEra() == BCE) {
|
||||
year = 1 - year;
|
||||
}
|
||||
|
||||
// Fast path for the Gregorian calendar years that are never
|
||||
// affected by the Julian-Gregorian transition
|
||||
if (year > gregorianCutoverYear + 1) {
|
||||
int weekOfYear = internalGet(WEEK_OF_YEAR);
|
||||
if (internalGet(MONTH) == JANUARY) {
|
||||
if (weekOfYear >= 52) {
|
||||
--year;
|
||||
}
|
||||
} else {
|
||||
if (weekOfYear == 1) {
|
||||
++year;
|
||||
}
|
||||
}
|
||||
return year;
|
||||
}
|
||||
|
||||
// General (slow) path
|
||||
int dayOfYear = internalGet(DAY_OF_YEAR);
|
||||
int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
|
||||
int minimalDays = getMinimalDaysInFirstWeek();
|
||||
|
||||
// Quickly check the possibility of year adjustments before
|
||||
// cloning this GregorianCalendar.
|
||||
if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
|
||||
return year;
|
||||
}
|
||||
|
||||
// Create a clone to work on the calculation
|
||||
GregorianCalendar cal = (GregorianCalendar) clone();
|
||||
cal.setLenient(true);
|
||||
// Use GMT so that intermediate date calculations won't
|
||||
// affect the time of day fields.
|
||||
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
// Go to the first day of the year, which is usually January 1.
|
||||
cal.set(DAY_OF_YEAR, 1);
|
||||
cal.complete();
|
||||
|
||||
// Get the first day of the first day-of-week in the year.
|
||||
int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
|
||||
if (delta != 0) {
|
||||
if (delta < 0) {
|
||||
delta += 7;
|
||||
}
|
||||
cal.add(DAY_OF_YEAR, delta);
|
||||
}
|
||||
int minDayOfYear = cal.get(DAY_OF_YEAR);
|
||||
if (dayOfYear < minDayOfYear) {
|
||||
if (minDayOfYear <= minimalDays) {
|
||||
--year;
|
||||
}
|
||||
} else {
|
||||
if (weekOfYear == 1) {
|
||||
++year;
|
||||
cal.set(YEAR, year + 1);
|
||||
cal.set(DAY_OF_YEAR, 1);
|
||||
cal.complete();
|
||||
int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
|
||||
if (del != 0) {
|
||||
if (del < 0) {
|
||||
del += 7;
|
||||
}
|
||||
cal.add(DAY_OF_YEAR, del);
|
||||
}
|
||||
minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
|
||||
if (minDayOfYear == 0) {
|
||||
minDayOfYear = 7;
|
||||
}
|
||||
if (minDayOfYear >= minimalDays) {
|
||||
int days = maxDayOfYear - dayOfYear + 1;
|
||||
if (days <= (7 - minDayOfYear)) {
|
||||
++year;
|
||||
}
|
||||
}
|
||||
}
|
||||
return year;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets this {@code GregorianCalendar} to the date given by the
|
||||
* date specifiers - <a href="#week_year">{@code weekYear}</a>,
|
||||
* {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
|
||||
* follows the <a href="#week_and_year">{@code WEEK_OF_YEAR}
|
||||
* numbering</a>. The {@code dayOfWeek} value must be one of the
|
||||
* {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link
|
||||
* Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}.
|
||||
*
|
||||
* <p>Note that the numeric day-of-week representation differs from
|
||||
* the ISO 8601 standard, and that the {@code weekOfYear}
|
||||
* numbering is compatible with the standard when {@code
|
||||
* getFirstDayOfWeek()} is {@code MONDAY} and {@code
|
||||
* getMinimalDaysInFirstWeek()} is 4.
|
||||
*
|
||||
* <p>Unlike the {@code set} method, all of the calendar fields
|
||||
* and the instant of time value are calculated upon return.
|
||||
*
|
||||
* <p>If {@code weekOfYear} is out of the valid week-of-year
|
||||
* range in {@code weekYear}, the {@code weekYear}
|
||||
* and {@code weekOfYear} values are adjusted in lenient
|
||||
* mode, or an {@code IllegalArgumentException} is thrown in
|
||||
* non-lenient mode.
|
||||
*
|
||||
* @param weekYear the week year
|
||||
* @param weekOfYear the week number based on {@code weekYear}
|
||||
* @param dayOfWeek the day of week value: one of the constants
|
||||
* for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field:
|
||||
* {@link Calendar#SUNDAY SUNDAY}, ...,
|
||||
* {@link Calendar#SATURDAY SATURDAY}.
|
||||
* @exception IllegalArgumentException
|
||||
* if any of the given date specifiers is invalid,
|
||||
* or if any of the calendar fields are inconsistent
|
||||
* with the given date specifiers in non-lenient mode
|
||||
* @see GregorianCalendar#isWeekDateSupported()
|
||||
* @see Calendar#getFirstDayOfWeek()
|
||||
* @see Calendar#getMinimalDaysInFirstWeek()
|
||||
* @since 1.7
|
||||
*/
|
||||
@Override
|
||||
public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
|
||||
if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
|
||||
throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
|
||||
}
|
||||
|
||||
// To avoid changing the time of day fields by date
|
||||
// calculations, use a clone with the GMT time zone.
|
||||
GregorianCalendar gc = (GregorianCalendar) clone();
|
||||
gc.setLenient(true);
|
||||
int era = gc.get(ERA);
|
||||
gc.clear();
|
||||
gc.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
gc.set(ERA, era);
|
||||
gc.set(YEAR, weekYear);
|
||||
gc.set(WEEK_OF_YEAR, 1);
|
||||
gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
|
||||
int days = dayOfWeek - getFirstDayOfWeek();
|
||||
if (days < 0) {
|
||||
days += 7;
|
||||
}
|
||||
days += 7 * (weekOfYear - 1);
|
||||
if (days != 0) {
|
||||
gc.add(DAY_OF_YEAR, days);
|
||||
} else {
|
||||
gc.complete();
|
||||
}
|
||||
|
||||
set(ERA, gc.internalGet(ERA));
|
||||
set(YEAR, gc.internalGet(YEAR));
|
||||
set(MONTH, gc.internalGet(MONTH));
|
||||
set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
|
||||
|
||||
// to avoid throwing an IllegalArgumentException in
|
||||
// non-lenient, set WEEK_OF_YEAR and DAY_OF_WEEK internally
|
||||
internalSet(WEEK_OF_YEAR, weekOfYear);
|
||||
internalSet(DAY_OF_WEEK, dayOfWeek);
|
||||
complete();
|
||||
|
||||
assert getWeekYear() == weekYear;
|
||||
assert get(WEEK_OF_YEAR) == weekOfYear;
|
||||
assert get(DAY_OF_WEEK) == dayOfWeek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of weeks in the <a href="#week_year">week year</a>
|
||||
* represented by this {@code GregorianCalendar}.
|
||||
*
|
||||
* <p>For example, if this {@code GregorianCalendar}'s date is
|
||||
* December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO
|
||||
* 8601 compatible setting</a>, this method will return 53 for the
|
||||
* period: December 29, 2008 to January 3, 2010 while {@link
|
||||
* #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return
|
||||
* 52 for the period: December 31, 2007 to December 28, 2008.
|
||||
*
|
||||
* @return the number of weeks in the week year.
|
||||
* @see Calendar#WEEK_OF_YEAR
|
||||
* @see #getWeekYear()
|
||||
* @see #getActualMaximum(int)
|
||||
* @since 1.7
|
||||
*/
|
||||
public int getWeeksInWeekYear() {
|
||||
GregorianCalendar gc = getNormalizedCalendar();
|
||||
int weekYear = gc.getWeekYear();
|
||||
if (weekYear == gc.internalGet(YEAR)) {
|
||||
return gc.getActualMaximum(WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
// Use the 2nd week for calculating the max of WEEK_OF_YEAR
|
||||
if (gc == this) {
|
||||
gc = (GregorianCalendar) gc.clone();
|
||||
}
|
||||
gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
|
||||
return gc.getActualMaximum(WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Time => Fields computation
|
||||
@ -2178,7 +2411,7 @@ public class GregorianCalendar extends Calendar {
|
||||
// If we are in the cutover year, we need some special handling.
|
||||
if (normalizedYear == cutoverYear) {
|
||||
// Need to take care of the "missing" days.
|
||||
if (getCutoverCalendarSystem() == jcal) {
|
||||
if (gregorianCutoverYearJulian <= gregorianCutoverYear) {
|
||||
// We need to find out where we are. The cutover
|
||||
// gap could even be more than one year. (One
|
||||
// year difference in ~48667 years.)
|
||||
@ -2208,27 +2441,36 @@ public class GregorianCalendar extends Calendar {
|
||||
// December 31, which is not always true in
|
||||
// GregorianCalendar.
|
||||
long fixedDec31 = fixedDateJan1 - 1;
|
||||
long prevJan1;
|
||||
long prevJan1 = fixedDateJan1 - 365;
|
||||
if (normalizedYear > (cutoverYear + 1)) {
|
||||
prevJan1 = fixedDateJan1 - 365;
|
||||
if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
|
||||
--prevJan1;
|
||||
}
|
||||
} else if (normalizedYear <= gregorianCutoverYearJulian) {
|
||||
if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) {
|
||||
--prevJan1;
|
||||
}
|
||||
} else {
|
||||
BaseCalendar calForJan1 = calsys;
|
||||
int prevYear = normalizedYear - 1;
|
||||
if (prevYear == cutoverYear) {
|
||||
//int prevYear = normalizedYear - 1;
|
||||
int prevYear = getCalendarDate(fixedDec31).getNormalizedYear();
|
||||
if (prevYear == gregorianCutoverYear) {
|
||||
calForJan1 = getCutoverCalendarSystem();
|
||||
}
|
||||
prevJan1 = calForJan1.getFixedDate(prevYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
while (prevJan1 > fixedDec31) {
|
||||
prevJan1 = getJulianCalendarSystem().getFixedDate(--prevYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
if (calForJan1 == jcal) {
|
||||
prevJan1 = calForJan1.getFixedDate(prevYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
} else {
|
||||
prevJan1 = gregorianCutoverDate;
|
||||
calForJan1 = gcal;
|
||||
}
|
||||
} else if (prevYear <= gregorianCutoverYearJulian) {
|
||||
calForJan1 = getJulianCalendarSystem();
|
||||
prevJan1 = calForJan1.getFixedDate(prevYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
}
|
||||
}
|
||||
weekOfYear = getWeekNumber(prevJan1, fixedDec31);
|
||||
@ -2260,14 +2502,20 @@ public class GregorianCalendar extends Calendar {
|
||||
if (nextYear == gregorianCutoverYear) {
|
||||
calForJan1 = getCutoverCalendarSystem();
|
||||
}
|
||||
long nextJan1 = calForJan1.getFixedDate(nextYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
if (nextJan1 < fixedDate) {
|
||||
|
||||
long nextJan1;
|
||||
if (nextYear > gregorianCutoverYear
|
||||
|| gregorianCutoverYearJulian == gregorianCutoverYear
|
||||
|| nextYear == gregorianCutoverYearJulian) {
|
||||
nextJan1 = calForJan1.getFixedDate(nextYear,
|
||||
BaseCalendar.JANUARY,
|
||||
1,
|
||||
null);
|
||||
} else {
|
||||
nextJan1 = gregorianCutoverDate;
|
||||
calForJan1 = gcal;
|
||||
}
|
||||
|
||||
long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
|
||||
getFirstDayOfWeek());
|
||||
int ndays = (int)(nextJan1st - nextJan1);
|
||||
@ -2409,10 +2657,24 @@ public class GregorianCalendar extends Calendar {
|
||||
}
|
||||
gfd = jfd;
|
||||
} else {
|
||||
gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
|
||||
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
|
||||
gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
|
||||
}
|
||||
|
||||
// Now we have to determine which calendar date it is.
|
||||
|
||||
// If the date is relative from the beginning of the year
|
||||
// in the Julian calendar, then use jfd;
|
||||
if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
|
||||
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
|
||||
fixedDate = jfd;
|
||||
break calculateFixedDate;
|
||||
} else if (year == gregorianCutoverYear) {
|
||||
fixedDate = gfd;
|
||||
break calculateFixedDate;
|
||||
}
|
||||
}
|
||||
|
||||
if (gfd >= gregorianCutoverDate) {
|
||||
if (jfd >= gregorianCutoverDate) {
|
||||
fixedDate = gfd;
|
||||
@ -2494,9 +2756,10 @@ public class GregorianCalendar extends Calendar {
|
||||
continue;
|
||||
}
|
||||
if (originalFields[field] != internalGet(field)) {
|
||||
String s = originalFields[field] + " -> " + internalGet(field);
|
||||
// Restore the original field values
|
||||
System.arraycopy(originalFields, 0, fields, 0, fields.length);
|
||||
throw new IllegalArgumentException(getFieldName(field));
|
||||
throw new IllegalArgumentException(getFieldName(field) + ": " + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2669,9 +2932,7 @@ public class GregorianCalendar extends Calendar {
|
||||
* method returns Gregorian. Otherwise, Julian.
|
||||
*/
|
||||
private BaseCalendar getCutoverCalendarSystem() {
|
||||
CalendarDate date = getGregorianCutoverDate();
|
||||
if (date.getMonth() == BaseCalendar.JANUARY
|
||||
&& date.getDayOfMonth() == 1) {
|
||||
if (gregorianCutoverYearJulian < gregorianCutoverYear) {
|
||||
return gcal;
|
||||
}
|
||||
return getJulianCalendarSystem();
|
||||
|
||||
166
jdk/test/java/text/Format/DateFormat/WeekDateTest.java
Normal file
166
jdk/test/java/text/Format/DateFormat/WeekDateTest.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4267450
|
||||
* @summary Unit test for week date support
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import static java.util.GregorianCalendar.*;
|
||||
|
||||
public class WeekDateTest {
|
||||
static SimpleDateFormat ymdFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
static SimpleDateFormat ywdFormat = new SimpleDateFormat("YYYY-'W'ww-u");
|
||||
static {
|
||||
ymdFormat.setCalendar(newCalendar());
|
||||
ywdFormat.setCalendar(newCalendar());
|
||||
}
|
||||
|
||||
// Round-trip Data
|
||||
static final String[][] roundTripData = {
|
||||
{ "2005-01-01", "2004-W53-6" },
|
||||
{ "2005-01-02", "2004-W53-7" },
|
||||
{ "2005-12-31", "2005-W52-6" },
|
||||
{ "2007-01-01", "2007-W01-1" },
|
||||
{ "2007-12-30", "2007-W52-7" },
|
||||
{ "2007-12-31", "2008-W01-1" },
|
||||
{ "2008-01-01", "2008-W01-2" },
|
||||
{ "2008-12-29", "2009-W01-1" },
|
||||
{ "2008-12-31", "2009-W01-3" },
|
||||
{ "2009-01-01", "2009-W01-4" },
|
||||
{ "2009-12-31", "2009-W53-4" },
|
||||
{ "2010-01-03", "2009-W53-7" },
|
||||
{ "2009-12-31", "2009-W53-4" },
|
||||
{ "2010-01-01", "2009-W53-5" },
|
||||
{ "2010-01-02", "2009-W53-6" },
|
||||
{ "2010-01-03", "2009-W53-7" },
|
||||
{ "2008-12-28", "2008-W52-7" },
|
||||
{ "2008-12-29", "2009-W01-1" },
|
||||
{ "2008-12-30", "2009-W01-2" },
|
||||
{ "2008-12-31", "2009-W01-3" },
|
||||
{ "2009-01-01", "2009-W01-4" },
|
||||
{ "2009-01-01", "2009-W01-4" },
|
||||
};
|
||||
|
||||
// Data for leniency test
|
||||
static final String[][] leniencyData = {
|
||||
{ "2008-12-28", "2009-W01-0" },
|
||||
{ "2010-01-04", "2009-W53-8" },
|
||||
{ "2008-12-29", "2008-W53-1" },
|
||||
};
|
||||
|
||||
static final String[] invalidData = {
|
||||
"2010-W00-1",
|
||||
"2010-W55-1",
|
||||
"2010-W03-0",
|
||||
"2010-W04-8",
|
||||
"2010-W04-19"
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
formatTest(roundTripData);
|
||||
parseTest(roundTripData);
|
||||
parseTest(leniencyData);
|
||||
nonLenientTest(invalidData);
|
||||
noWeekDateSupport();
|
||||
}
|
||||
|
||||
private static void formatTest(String[][] data) throws Exception {
|
||||
for (String[] dates : data) {
|
||||
String regularDate = dates[0];
|
||||
String weekDate = dates[1];
|
||||
Date date = null;
|
||||
date = ymdFormat.parse(regularDate);
|
||||
String s = ywdFormat.format(date);
|
||||
if (!s.equals(weekDate)) {
|
||||
throw new RuntimeException("format: got="+s+", expecetd="+weekDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseTest(String[][] data) throws Exception {
|
||||
for (String[] dates : data) {
|
||||
String regularDate = dates[0];
|
||||
String weekDate = dates[1];
|
||||
Date date1 = null, date2 = null;
|
||||
date1 = ymdFormat.parse(regularDate);
|
||||
date2 = ywdFormat.parse(weekDate);
|
||||
if (!date1.equals(date2)) {
|
||||
System.err.println(regularDate + ": date1 = " + date1);
|
||||
System.err.println(weekDate + ": date2 = " + date2);
|
||||
throw new RuntimeException("parse: date1 != date2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Non-lenient mode test
|
||||
private static void nonLenientTest(String[] data) {
|
||||
ywdFormat.setLenient(false);
|
||||
for (String date : data) {
|
||||
try {
|
||||
Date d = ywdFormat.parse(date);
|
||||
throw new RuntimeException("No ParseException thrown with " + date);
|
||||
} catch (ParseException e) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
ywdFormat.setLenient(true);
|
||||
}
|
||||
|
||||
|
||||
private static void noWeekDateSupport() throws Exception {
|
||||
// Tests with Japanese Imperial Calendar that doesn't support week dates.
|
||||
Calendar jcal = Calendar.getInstance(TimeZone.getTimeZone("GMT"),
|
||||
new Locale("ja", "JP", "JP"));
|
||||
|
||||
jcal.setFirstDayOfWeek(MONDAY);
|
||||
jcal.setMinimalDaysInFirstWeek(4);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("Y-'W'ww-u");
|
||||
sdf.setCalendar(jcal);
|
||||
Date d = sdf.parse("21-W01-3"); // 2008-12-31 == H20-12-31
|
||||
GregorianCalendar gcal = newCalendar();
|
||||
gcal.setTime(d);
|
||||
if (gcal.get(YEAR) != 2008
|
||||
|| gcal.get(MONTH) != DECEMBER
|
||||
|| gcal.get(DAY_OF_MONTH) != 31) {
|
||||
String s = String.format("noWeekDateSupport: got %04d-%02d-%02d, expected 2008-12-31%n",
|
||||
gcal.get(YEAR),
|
||||
gcal.get(MONTH)+1,
|
||||
gcal.get(DAY_OF_MONTH));
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static GregorianCalendar newCalendar() {
|
||||
// Use GMT to avoid any surprises related DST transitions.
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
|
||||
// Setup the ISO 8601 compatible parameters
|
||||
cal.setFirstDayOfWeek(MONDAY);
|
||||
cal.setMinimalDaysInFirstWeek(4);
|
||||
return cal;
|
||||
}
|
||||
}
|
||||
133
jdk/test/java/util/Calendar/WeekDateTest.java
Normal file
133
jdk/test/java/util/Calendar/WeekDateTest.java
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4267450
|
||||
* @summary Unit test for week date support
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import static java.util.GregorianCalendar.*;
|
||||
|
||||
public class WeekDateTest {
|
||||
|
||||
// Week dates are in the ISO numbering for day-of-week.
|
||||
static int[][][] data = {
|
||||
// Calendar year-date, Week year-date
|
||||
{{ 2005, 01, 01}, {2004, 53, 6}},
|
||||
{{ 2005, 01, 02}, {2004, 53, 7}},
|
||||
{{ 2005, 12, 31}, {2005, 52, 6}},
|
||||
{{ 2007, 01, 01}, {2007, 01, 1}},
|
||||
{{ 2007, 12, 30}, {2007, 52, 7}},
|
||||
{{ 2007, 12, 31}, {2008, 01, 1}},
|
||||
{{ 2008, 01, 01}, {2008, 01, 2}},
|
||||
{{ 2008, 12, 29}, {2009, 01, 1}},
|
||||
{{ 2008, 12, 31}, {2009, 01, 3}},
|
||||
{{ 2009, 01, 01}, {2009, 01, 4}},
|
||||
{{ 2009, 12, 31}, {2009, 53, 4}},
|
||||
{{ 2010, 01, 03}, {2009, 53, 7}},
|
||||
{{ 2009, 12, 31}, {2009, 53, 4}},
|
||||
{{ 2010, 01, 01}, {2009, 53, 5}},
|
||||
{{ 2010, 01, 02}, {2009, 53, 6}},
|
||||
{{ 2010, 01, 03}, {2009, 53, 7}},
|
||||
{{ 2008, 12, 28}, {2008, 52, 7}},
|
||||
{{ 2008, 12, 29}, {2009, 01, 1}},
|
||||
{{ 2008, 12, 30}, {2009, 01, 2}},
|
||||
{{ 2008, 12, 31}, {2009, 01, 3}},
|
||||
{{ 2009, 01, 01}, {2009, 01, 4}}
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
GregorianCalendar cal = newCalendar();
|
||||
for (int[][] dates : data) {
|
||||
int[] expected = dates[0];
|
||||
int[] weekDate = dates[1];
|
||||
// Convert ISO 8601 day-of-week to Calendar.DAY_OF_WEEK.
|
||||
int dayOfWeek = weekDate[2] == 7 ? SUNDAY : weekDate[2] + 1;
|
||||
|
||||
cal.clear();
|
||||
cal.setWeekDate(weekDate[0], weekDate[1], dayOfWeek);
|
||||
if (cal.get(YEAR) != expected[0]
|
||||
|| cal.get(MONTH)+1 != expected[1]
|
||||
|| cal.get(DAY_OF_MONTH) != expected[2]) {
|
||||
String s = String.format("got=%4d-%02d-%02d, expected=%4d-%02d-%02d",
|
||||
cal.get(YEAR), cal.get(MONTH)+1, cal.get(DAY_OF_MONTH),
|
||||
expected[0], expected[1], expected[2]);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
if (cal.getWeekYear() != weekDate[0]
|
||||
|| cal.get(WEEK_OF_YEAR) != weekDate[1]
|
||||
|| cal.get(DAY_OF_WEEK) != dayOfWeek) {
|
||||
String s = String.format(
|
||||
"got=%4d-W%02d-%d, expected=%4d-W%02d-%d (not ISO day-of-week)",
|
||||
cal.getWeekYear(), cal.get(WEEK_OF_YEAR), cal.get(DAY_OF_WEEK),
|
||||
weekDate[0], weekDate[1], dayOfWeek);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Test getWeeksInWeekYear().
|
||||
// If we avoid the first week of January and the last week of
|
||||
// December, getWeeksInWeekYear() and
|
||||
// getActualMaximum(WEEK_OF_YEAR) values should be the same.
|
||||
for (int year = 2000; year <= 2100; year++) {
|
||||
cal.clear();
|
||||
cal.set(year, JUNE, 1);
|
||||
int n = cal.getWeeksInWeekYear();
|
||||
if (n != cal.getActualMaximum(WEEK_OF_YEAR)) {
|
||||
String s = String.format("getWeeksInWeekYear() = %d, "
|
||||
+ "getActualMaximum(WEEK_OF_YEAR) = %d%n",
|
||||
n, cal.getActualMaximum(WEEK_OF_YEAR));
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
cal.setWeekDate(cal.getWeekYear(), 1, MONDAY);
|
||||
System.out.println(cal.getTime());
|
||||
if (cal.getWeeksInWeekYear() != n) {
|
||||
String s = String.format("first day: got %d, expected %d%n",
|
||||
cal.getWeeksInWeekYear(), n);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
cal.setWeekDate(cal.getWeekYear(), n, SUNDAY);
|
||||
System.out.println(cal.getTime());
|
||||
if (cal.getWeeksInWeekYear() != n) {
|
||||
String s = String.format("last day: got %d, expected %d%n",
|
||||
cal.getWeeksInWeekYear(), n);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GregorianCalendar newCalendar() {
|
||||
// Use GMT to avoid any surprises related DST transitions.
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
|
||||
if (!cal.isWeekDateSupported()) {
|
||||
throw new RuntimeException("Week dates not supported");
|
||||
}
|
||||
// Setup the ISO 8601 compatible parameters
|
||||
cal.setFirstDayOfWeek(MONDAY);
|
||||
cal.setMinimalDaysInFirstWeek(4);
|
||||
return cal;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user