Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
0473c96f
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
0473c96f
编写于
9月 02, 2010
作者:
L
lana
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
0bada536
ccbf2c93
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
1105 addition
and
215 deletion
+1105
-215
make/java/text/base/FILES_java.gmk
make/java/text/base/FILES_java.gmk
+2
-1
src/share/classes/java/text/CalendarBuilder.java
src/share/classes/java/text/CalendarBuilder.java
+170
-0
src/share/classes/java/text/DateFormatSymbols.java
src/share/classes/java/text/DateFormatSymbols.java
+28
-5
src/share/classes/java/text/SimpleDateFormat.java
src/share/classes/java/text/SimpleDateFormat.java
+176
-135
src/share/classes/java/util/Calendar.java
src/share/classes/java/util/Calendar.java
+97
-2
src/share/classes/java/util/GregorianCalendar.java
src/share/classes/java/util/GregorianCalendar.java
+333
-72
test/java/text/Format/DateFormat/WeekDateTest.java
test/java/text/Format/DateFormat/WeekDateTest.java
+166
-0
test/java/util/Calendar/WeekDateTest.java
test/java/util/Calendar/WeekDateTest.java
+133
-0
未找到文件。
make/java/text/base/FILES_java.gmk
浏览文件 @
0473c96f
#
# Copyright (c) 1996, 20
07
, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1996, 20
10
, 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 \
...
...
src/share/classes/java/text/CalendarBuilder.java
0 → 100644
浏览文件 @
0473c96f
/*
* 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
;
}
}
src/share/classes/java/text/DateFormatSymbols.java
浏览文件 @
0473c96f
/*
* Copyright (c) 1996, 20
06
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, 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
;
}
/**
...
...
src/share/classes/java/text/SimpleDateFormat.java
浏览文件 @
0473c96f
/*
* Copyright (c) 1996, 20
08
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, 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
)
{
cal
endar
.
set
(
field
,
bestMatch
);
cal
b
.
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
)
{
cal
endar
.
set
(
field
,
data
.
get
(
bestMatch
));
cal
b
.
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
)))
{
cal
endar
.
set
(
Calendar
.
ZONE_OFFSET
,
tz
.
getRawOffset
());
calendar
.
set
(
Calendar
.
DST_OFFSET
,
dstAmount
);
cal
b
.
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
;
}
}
cal
endar
.
set
(
field
,
value
);
cal
b
.
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
);
}
cal
endar
.
set
(
Calendar
.
YEAR
,
value
);
cal
b
.
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.]
cal
endar
.
set
(
Calendar
.
MONTH
,
value
-
1
);
cal
b
.
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
;
cal
endar
.
set
(
Calendar
.
HOUR_OF_DAY
,
value
);
cal
b
.
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
;
cal
endar
.
set
(
Calendar
.
HOUR
,
value
);
cal
b
.
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
;
cal
endar
.
set
(
Calendar
.
DST_OFFSET
,
0
);
cal
b
.
set
(
Calendar
.
DST_OFFSET
,
0
);
pos
.
index
=
start
+
GMT
.
length
();
try
{
// try-catch for "GMT" only time zone string
...
...
@@ -1811,7 +1845,7 @@ public class SimpleDateFormat extends DateFormat {
catch
(
StringIndexOutOfBoundsException
e
)
{}
if
(
sign
==
0
)
{
/* "GMT" without offset */
cal
endar
.
set
(
Calendar
.
ZONE_OFFSET
,
0
);
cal
b
.
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
--;
}
cal
endar
.
set
(
field
,
value
);
cal
b
.
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
);
...
...
src/share/classes/java/util/Calendar.java
浏览文件 @
0473c96f
/*
* Copyright (c) 1996, 20
07
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, 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
...
...
src/share/classes/java/util/GregorianCalendar.java
浏览文件 @
0473c96f
/*
* Copyright (c) 1996, 20
06
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, 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,9 +1777,14 @@ 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
;
case
WEEK_OF_MONTH:
...
...
@@ -1934,34 +1974,55 @@ public class GregorianCalendar extends Calendar {
}
}
//////////////////////
// Proposed public API
//////////////////////
/**
* 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.
*
* <p>This method calls {@link Calendar#complete} before
* calculating the week-based year.
* Returns {@code true} indicating this {@code GregorianCalendar}
* supports week dates.
*
* @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 {@code true} (always)
* @see #getWeekYear()
* @see #setWeekDate(int,int,int)
* @see #getWeeksInWeekYear()
* @since 1.7
*/
/*
public int getWeekBasedYear() {
complete();
// TODO: Below doesn't work for gregorian cutover...
@Override
public
final
boolean
isWeekDateSupported
()
{
return
true
;
}
/**
* 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 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
*/
@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
);
int year = internalGet(YEAR);
if (internalGet(MONTH) == Calendar.JANUARY) {
if
(
internalGet
(
MONTH
)
==
JANUARY
)
{
if
(
weekOfYear
>=
52
)
{
--
year
;
}
...
...
@@ -1972,8 +2033,180 @@ public class GregorianCalendar extends Calendar {
}
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
{
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
(
g
etCutoverCalendarSystem
()
==
jcal
)
{
if
(
g
regorianCutoverYearJulian
<=
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,24 +2441,33 @@ 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
();
}
if
(
calForJan1
==
jcal
)
{
prevJan1
=
calForJan1
.
getFixedDate
(
prevYear
,
BaseCalendar
.
JANUARY
,
1
,
null
);
while
(
prevJan1
>
fixedDec31
)
{
prevJan1
=
getJulianCalendarSystem
().
getFixedDate
(--
prevYear
,
}
else
{
prevJan1
=
gregorianCutoverDate
;
calForJan1
=
gcal
;
}
}
else
if
(
prevYear
<=
gregorianCutoverYearJulian
)
{
calForJan1
=
getJulianCalendarSystem
();
prevJan1
=
calForJan1
.
getFixedDate
(
prevYear
,
BaseCalendar
.
JANUARY
,
1
,
null
);
...
...
@@ -2260,14 +2502,20 @@ public class GregorianCalendar extends Calendar {
if
(
nextYear
==
gregorianCutoverYear
)
{
calForJan1
=
getCutoverCalendarSystem
();
}
long
nextJan1
=
calForJan1
.
getFixedDate
(
nextYear
,
long
nextJan1
;
if
(
nextYear
>
gregorianCutoverYear
||
gregorianCutoverYearJulian
==
gregorianCutoverYear
||
nextYear
==
gregorianCutoverYearJulian
)
{
nextJan1
=
calForJan1
.
getFixedDate
(
nextYear
,
BaseCalendar
.
JANUARY
,
1
,
null
);
if
(
nextJan1
<
fixedDate
)
{
}
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
();
...
...
test/java/text/Format/DateFormat/WeekDateTest.java
0 → 100644
浏览文件 @
0473c96f
/*
* 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
;
}
}
test/java/util/Calendar/WeekDateTest.java
0 → 100644
浏览文件 @
0473c96f
/*
* 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
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录