实际上,JSF 日期时间转换器是 Java™ SimpleDateFormat 类的 JavaScript 实现。
日期时间转换器可将字符串(通常是输入字段的值)转换为 JavaScript 日期对象,或将相应的日期对象转换为字符串。该转换由描述日期的格式(例如,日期组件的顺序、每个组件的格式以及分隔符等)的 Java 日期格式模式进行控制。
日期转换器使用的格式是“随语言环境而定的”。该格式准确地定义日期组件的顺序,例如,组件是按月-日-年顺序还是按年-月-日顺序来显示。它还准确地定义用作组件之间的分隔符的字符,例如,使用 / 字符来分隔所有组件,或使用一个空格来分隔前两个组件,以及使用逗号-空格来分隔其后的两个组件。日期/时间中使用的所有“单词”都是从本地化字符串文件中获取的,该文件已包含在(或发送至)页面中。页面中的所有转换都将使用相同的单词集,例如,所有转换都将使用法语。当前,不能让一些转换使用一种语言,而让另一些转换使用不同的语言。
为了最大程度地与实际情况相吻合,日期转换器使用 Java DateFormat 类所使用的算法来转换日期/字符串,以使客户端和服务器端转换相同。
此转换器可供其他客户端组件使用,例如,JSFBehaviorValidate、日期时间辅助(日期/时间的键盘辅助)以及客户端数据高速缓存。如果程序员需要将包含已格式化数据的字符串“强制转换”为 JavaScript 日期对象,则也可以直接使用此转换器。
hX_5.addConverter("id", new hX_5.DateTimeConverter(attributes)); 其中
id |
组件所连接至的 HTML 标记的 ID。 |
属性名称 |
描述 |
||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
format |
转换此值时要使用的 Java 日期时间模式。请参阅下面的内容以了解详细信息。 |
||||||||||
ICU4J |
如果存在且不为 false,则星号和加号将作为模式字符来解析,而辅助分组符号将在该模式中进行解析。 |
||||||||||
base-2digit-span |
对位数为 2 的年份进行解析时,当前日期之前的许多年份将被视为“上个世纪”。例如,如果今年是 2003,范围是 30,则“73”与“99”之间的年份将被视为“1973 到 1999”。注意,按照 Microsoft® 标准,此值是 30,而按照 Java 标准,此值是 80。 |
||||||||||
first-day-of-week |
如果存在,则指定在计算“星期”时要使用星期几。0 表示星期日,1 表示星期一,以此类推。
注: 即使未设置 ICU4J,也应该始终提供此属性,以便可以正确计算“w”和“Y”。
|
||||||||||
digits |
如果提供,则表示 Unicode 字符集中有效零数字(而不是西文字符“0”)的单字符。如果对值进行格式化,则 Unicode 字符集中的此字符和后续 9 个字符将作为“数字”来输出。如果此值是从字符串转换的,则这些字符将解析为数字。这对于非西文数字同样适用,例如,正确的阿拉伯数字和/或印度-阿拉伯数字。值是此字符(以十进制表示)的 Unicode 代码点。例如,阿拉伯数字 0 是十六进制 660,因此在这种情况下,1632 应该是此属性的值。 |
||||||||||
epoch |
要使用的日历/纪元系统。即使未设置 ICU4J,也可以指定此属性。支持下列系统:
|
||||||||||
strict |
如果为 0(字面值),则对值进行解析时将忽略所有“字面值”,将重新排列所有错误排列的组件,使用当前日期时间提供任何缺少的组件,允许拼写错漏(只要不对其计算产生影响),以及忽略“E”和其他重复组件。 如果为 1(精确),则对值进行解析时将忽略所有“字面值”,使用当前日期时间提供任何缺少的组件,允许拼写错漏(只要不对其计算产生影响),以及忽略“E”和其他重复组件。例如,如果模式为 MMMM dd, yyyy,则用户可以输入“Feb/02/04”,它将被解析为 February 02, 2004。 如果为 2(非常精确),则要求准确匹配,不过长月份名称会“缩短”为最小的唯一字符数目,并忽略“E”和其他重复组件。字面值必须准确匹配。 |
有关 Java 十进制格式数字模式的更多信息,如果 ICU4J 未启用,则请参阅 http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html;如果 ICU4J 已启用,则请参阅 http://icu.sourceforge.net/apiref/icu4j/。对语法进行了概括,模式包含一系列格式化字符,其中每个字符描述在日期/时间中的相应位置所允许使用的内容。基本格式化字符包括:
GGGG |
纪元符号,表示为完整字符串,例如,“Heisei”(平成纪元)或“Anno Domini”(公元)。注意,GGGG 的 Java Util 1.4x 实现不能正常工作 - 它显示 AD,而不是 Anno Domini。 |
GGG, GG, G |
纪元符号,表示为短字符串,例如,“A.D”或“Hei”。 |
yyyy |
年份,表示为一个最多带 3 个前导零的四位数字符串,例如,1993。 |
yyy |
如果不是日语,则与 yy 相同。如果是日语,则年份表示为一个最多带 2 个前导零的三位数字符串。 |
yy |
如果不是日语,则年份表示为一个两位数的字符串,例如,93,而不是 1993。输入时将遵循世纪计算规则,请参阅上面的 base-2digit-span。如果是日语,则年份表示为一个最多带一个前导零的字符串,例如,“Heisei 02”。 |
y |
如果不是日语,则与 yy 相同。如果是日语,则年份不带前导零。 |
IYYYY, YYY, YY, Y |
与“y”相同,但与“w”模式字符配合使用。将对年份进行调整以使它对于年份的第一周/最后一周是正确的,例如,Jan 1, 2005 在使用“w YYYY”显示时将变成“53 2004”。 |
MMMM |
月份,表示为完整的字符串,例如,“January”。 |
MMM |
月份,表示为缩写的字符串,例如,“Jan”。注意,在 Java 中,月份几乎始终为三个字符的缩写词。 |
MM |
月份,表示为一个数字,根据需要包括一个前导零,例如,“09”。 |
M |
月份,表示为一个不包括前导零的数字,例如,“9”。 |
EEEE |
星期几,表示为完整的字符串,例如,“Wednesday”。 |
EEE, EE, E |
星期几,表示为缩写的字符串,例如,“Wed”。注意,在 Java 中,星期几通常是三个字符的缩写词。 |
Ie |
星期几,表示为数字。值从 1 开始,且已本地化。例如,如果一周中的第一天是星期二,则星期三将变成“2”。 |
dd |
几号,表示为数字,根据需要包括一个前导零,例如,“04”。 |
d |
几号,表示为一个不包括前导零的数字,例如,“4”。 |
DDD |
一年中的某一天,表示为数字,根据需要包括最多两个前导零,例如,002。 |
DD |
一年中的某一天,表示为数字,根据需要包括最多一个前导零,例如,020。 |
D |
一年中的某一天,表示为数字,不包括前导零,例如,189。 |
F |
一个月中的第几个星期几,表示为数字,例如,2 表示这个月中的第二个星期三。注意:在解析字符串时将忽略 F。 |
Ig, gg ... gggggggg |
... gggggggg 儒略日期,从 January 1, 4713 BC(作为 0 值)算起的某一天。 |
ww |
一年中的某一周,表示为数字,根据需要包括前导零,例如,05。 |
w |
一年中的某一周,表示为数字,不包括前导零,例如,51。 |
W |
一个月中的第几周,表示为数字,例如,2。注意:将字符串转换为日期时将忽略 w 和 W。此外,从日期转换为字符串时,将使用 Java 的规则。在 Java 中,一年中的第一周结束于这一年的第一个星期六,因此第一周可能没有 7 天,而第二周是从第一周之后的星期日开始计算的,后续各周以此类推。 |
hh |
12 小时制中的第几个小时,根据需要包括前导零,例如,06。 |
h |
12 小时制中的第几个小时,不包括前导零,例如,6。 |
HH |
24 小时制中的第几个小时,例如,17,并根据需要包括前导零,例如,07。 |
H |
24 小时制中的第几个小时,不包括前导零,例如,7 和 17。 |
kk |
与 HH 相似,但从 1 算起,即,01-24。 |
k |
与 H 相似,但从 1 算起,即,1-24。 |
KK |
与 hh 相似,但从 1 算起,即,01-12。 |
K |
与 h 相似,但从 1 算起,即,1-12。 |
mm |
分钟,根据需要包括前导零,例如,08。 |
m |
分钟,不包括前导零,例如,8。 |
ss |
秒,根据需要包括前导零,例如,09。 |
s |
秒,不包括前导零,例如,9。 |
SSS |
毫秒,显示全部三个数字。 |
SS |
毫秒,显示前两个数字。 |
S |
毫秒,显示第一个数字。 |
a |
AM/PM 标记,扩展为语言环境所需的大小。 |
IA, AA ... AAAAAAAA |
一天中的第几毫秒。 |
z |
时区,扩展为语言环境所需的大小。时区的常规格式是 GMT+nn:nn,其中 nn:nn 是与 GMT 的偏移量。对于特定的语言,例如,英语,可能会改用“常见形式的”时区,例如,EST 或 PST。 |
Iv |
不带“夏令时”指示符的时区。该时区不受支持,原因是客户机将始终使用客户机上通常为夏令时的时区来显示时间。 |
IZ |
以 RFC 822 格式来表示的时区。该格式是 +/-nnnn,其中 nn:nn 是与 GMT 的偏移量。 |
zzzz |
“长格式”的时区。该时区不受支持,原因是无法对其进行解析。 |
o |
一个月中的第几天。它不受支持,原因是无法对其进行本地化。 |
Iu |
ICU4J 加长年份。它不受支持,原因是它对 hxclient 所支持的年份似乎毫无意义。 |
' |
使用单引号将与符号相冲突的文字文本括起。 |
'' |
使用两个单引号来指定一个内容为单引号的文字字符。 |
通过将上面的字符组装在一个字符串中来构造格式,上面的每个字符在该模式中最多只能出现一次。在格式字符串中遇到的、不属于上面的格式化字符的任何字符都将作为“定界符”(文字文本)来处理。例如,在格式字符串“MM/dd/yyyy”中,斜杠将被作为字面值来处理。必须注意,不要在无意中将格式化字符包含在文字文本中。某些格式化字符比较费解,许多用户可能不知道它们是否为格式化字符。对于可能与格式字符串字符相冲突的任何文本,请使用单引号将其括起。例如,“hh o'' clock”将不会返回“12 o'clock”,相反,由于“o”是格式字符,它将返回“12 12th' cl12thck”。如果字母字符包含在格式中,而该字符不是格式字符并且未使用引号括起,则 Java 可能会抛出异常,但它不会对所有非格式字符的字母字符都抛出异常。
在构造模式以用于将字符串转换为日期对象时,必须注意确保提供了足够的组件,以使字符串可以被明确解释。例如,如果您包含一个“z”(时区),则应该在格式中包含一个“日期”,这是因为如果不知道日期,则将无法解释时区。如果格式中没有日期,则将缺省使用今天的日期。
必须注意,打开 ICU4J 将更改现有模式的解释方式。例如,如果 ICU4J 是关闭的,则对值“Jan 1, 2005”应用模式“Y: yyyy”后,此值将显示为“Y: 2005”。如果 ICU4J 是打开的,则值将显示为“04: 2005”。在 ICU4J 关闭时,“Y”不是模式字符,因此它被视为一个字面值。在 ICU4J 打开时,它是模式字符。
API 调用 |
描述 |
---|---|
number = stringToValue(string) |
将字符串转换为 JavaScript 数字对象。失败时返回 NULL。 |
string = valueToString(date) |
将 JavaScript 日期对象转换为字符串。失败时返回 NULL。 |
string = lastError() |
如果转换失败,则将失败原因作为本地化字符串返回。 |
object = setAttribute(attribute) |
设置属性,或如果以前已设置属性,则更改其值。 |
string = getAttribute(attribute-name) |
检索属性的当前值。 |
在 Java 中,对日期时间对象进行处理以及转换为这些对象或从这些对象转换时,存在许多问题/局限性。JavaScript 转换器也存在同样的问题/局限性。本文档中未对所有问题进行详尽描述。以下列表描述了其中一些较为重要的局限性和问题。
1582 年 10 月 15 日是儒略日历首次更改为格里高利日历的时间。在儒略日历中,每 4 年(能够被 4 整除的每个年份)是一个闰年。在格里高利日历中,闰年必须能够被 4 整除,如果是百年,则必须能够被 400 整除,因此 1900 不是闰年,而 2000 是闰年。从儒略日历更改为格里高利日历后,必须从日历中删除“多出的闰日”,即,在儒略日历中添加的闰日不应该出现在格里高利日历的规则中。因此,如果一个国家/地区在 1582 年从儒略日历更改为格里高利日历,则应该从日历中除去 10 月 5 日、10 月 14 日以及两者之间的日期,即,10 月 4 日应紧随 10 月 15 日。意大利、葡萄牙、西班牙和波兰是首批从儒略日历更改为格里高利日历的国家。世界上的其他国家或地区要稍晚一些。例如,英国及其殖民地(例如波士顿)在 1752 年从儒略日历更改为格里高利日历。世界上有些国家或地区直到 20 世纪才作出更改,例如,希腊是在 1924 年,土耳其是在 1927 年,而中国大陆是在 1949 年。
注意,日期时间转换器不支持 ICU4J 格里高利日历选项修改格里高利日历转换日期,即,它不支持 setGregorianChange(),因此,转换始终发生于 1582 年。
为了处理从儒略日历到格里高利日历的转换,Java 对 1582 年之前的日期使用儒略日历规则,除去 10 月 5 日、10 月 14 日以及两者之间的日期,而对 1582 年 10 月 15 日之后的日期使用格里高利日历规则。因此,1582 年 10 月 10 日不是有效的日期,1300 年 2 月 29 日是有效的日期,1900 年 2 月 29 日不是有效的日期。此外,转换为儒略日期或从儒略日期转换遵循相同的模式,其中儒略日期是指从公元前 4713 年 1 月 1 日开始计算的绝对天数,例如,公元 1000 年 1 月 1 日是儒略日期 2086308。注意,即使儒略日历在公元前 64 年才开始使用,但仍对公元前 64 年之前的日期使用儒略日历规则。在恺撒大帝之前没有儒略日历,如同在教皇格里高利十三世之前没有格里高利日历一样。
JavaScript并不按照相同的方式来处理日期。JavaScript 将格里高利日历规则应用于所有日期。因此 1582 年 10 月 10 日是有效的日期。1300 年 2 月 29 日不是有效的日期,1900 年 2 月 29 日也不是有效的日期。同样,如果 JavaScript 支持儒略日期,则公元 1000 年 1 月 1 日就是儒略日期 2086303,与上面的相差 5 天。换句话说,JavaScript 与 Java 对公元 1582 年 10 月 15 日之前的日期的处理方式不同。
日期时间转换器尽可能使用 Java 所使用的规则。因此它计算儒略日期的方法与 Java 计算儒略日期的方法一样。但是,日期时间转换器不允许输入 2 月 29 日作为 1582 年之前的任何年份的日期,原因是格里高利日历不允许使用这些日期,JavaScript 只是将这些日期转换为 3 月 1 日,而且对此似乎没有任何变通方法。因此,不管是哪个日历(格里高利日历或非格里高利日历),对 1582 年以前的日期进行解析时,日期组件将转换为 JavaScript 日期,但不能表示某些闰年中的 2 月 29 日。
例如,在 Windows® 中,用户可以为“短日期”和“长日期”指定首选格式。浏览器(或服务器)不能读取此信息,因此从不使用此信息来对日期进行格式化。用于显示日期的唯一信息是传递至日期时间转换器的格式和语言环境信息。
设计日期/时间格式时,设计者可选择精确指定此格式,即提供一种格式,或者他们也可使用一种随语言环境而定的格式,如“短”、“中等”或“长”。如果他们选择一种随语言环境而定的格式,则使用的格式应该是一种为那个语言环境的所有用户定义的格式,单个用户首选项将被忽略。因此,过度哀叹、抱怨此局限性将于事无补。
将输入字段的值转换为 JavaScript 日期,然后给该日期加一并再次存储到结果。
// Construct the converter with a format of MMMM dd, yyyy hX.addConverter("AZ1", new hX.DateTimeConverter("format:MMMM dd, yyyy", "strict:2", "base-2digit-span:30")); // Convert the value of an input field from a string formatted using this pattern to a JS date var x = document.getElementById("form1:text1"); var cvt = hX.getConverterById("AZ1"); var d = cvt.stringToValue(x.value); // Check for errors if (d==null) alert ("ERROR: " + cvt.lastError()); // Increment the value and put it back else { d.setDate(d.getDate()+1); x.value = cvt.valueToString(d); }