Merge
This commit is contained in:
commit
f06239abab
@ -21,4 +21,4 @@
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
tzdata2012i
|
||||
tzdata2013c
|
||||
|
@ -27,9 +27,9 @@
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# From Paul Eggert (2013-02-21):
|
||||
#
|
||||
# A good source for time zone historical data outside the U.S. is
|
||||
# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
|
||||
@ -48,6 +48,10 @@
|
||||
# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
|
||||
# I found in the UCLA library.
|
||||
#
|
||||
# For data circa 1899, a common source is:
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>.
|
||||
#
|
||||
# A reliable and entertaining source about time zones is
|
||||
# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
|
||||
#
|
||||
@ -139,8 +143,12 @@ Zone Africa/Porto-Novo 0:10:28 - LMT 1912
|
||||
1:00 - WAT
|
||||
|
||||
# Botswana
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# Milne says they were regulated by the Cape Town Signal in 1899;
|
||||
# assume they switched to 2:00 when Cape Town did.
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Africa/Gaborone 1:43:40 - LMT 1885
|
||||
1:30 - SAST 1903 Mar
|
||||
2:00 - CAT 1943 Sep 19 2:00
|
||||
2:00 1:00 CAST 1944 Mar 19 2:00
|
||||
2:00 - CAT
|
||||
@ -212,6 +220,11 @@ Zone Africa/Djibouti 2:52:36 - LMT 1911 Jul
|
||||
|
||||
# Egypt
|
||||
|
||||
# Milne says Cairo used 2:05:08.9, the local mean time of the Abbasizeh
|
||||
# observatory; round to nearest. Milne also says that the official time for
|
||||
# Egypt was mean noon at the Great Pyramid, 2:04:30.5, but apparently this
|
||||
# did not apply to Cairo, Alexandria, or Port Said.
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Egypt 1940 only - Jul 15 0:00 1:00 S
|
||||
Rule Egypt 1940 only - Oct 1 0:00 0 -
|
||||
@ -352,7 +365,7 @@ Rule Egypt 2010 only - Sep 10 0:00 1:00 S
|
||||
Rule Egypt 2010 only - Sep lastThu 23:00s 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Africa/Cairo 2:05:00 - LMT 1900 Oct
|
||||
Zone Africa/Cairo 2:05:09 - LMT 1900 Oct
|
||||
2:00 Egypt EE%sT
|
||||
|
||||
# Equatorial Guinea
|
||||
@ -447,6 +460,20 @@ Zone Africa/Monrovia -0:43:08 - LMT 1882
|
||||
|
||||
# Libya
|
||||
|
||||
# From Even Scharning (2012-11-10):
|
||||
# Libya set their time one hour back at 02:00 on Saturday November 10.
|
||||
# http://www.libyaherald.com/2012/11/04/clocks-to-go-back-an-hour-on-saturday/
|
||||
# Here is an official source [in Arabic]: http://ls.ly/fb6Yc
|
||||
#
|
||||
# Steffen Thorsen forwarded a translation (2012-11-10) in
|
||||
# http://mm.icann.org/pipermail/tz/2012-November/018451.html
|
||||
#
|
||||
# From Tim Parenti (2012-11-11):
|
||||
# Treat the 2012-11-10 change as a zone change from UTC+2 to UTC+1.
|
||||
# The DST rules planned for 2013 and onward roughly mirror those of Europe
|
||||
# (either two days before them or five days after them, so as to fall on
|
||||
# lastFri instead of lastSun).
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Libya 1951 only - Oct 14 2:00 1:00 S
|
||||
Rule Libya 1952 only - Jan 1 0:00 0 -
|
||||
@ -461,17 +488,21 @@ Rule Libya 1986 only - Apr 4 0:00 1:00 S
|
||||
Rule Libya 1986 only - Oct 3 0:00 0 -
|
||||
Rule Libya 1987 1989 - Apr 1 0:00 1:00 S
|
||||
Rule Libya 1987 1989 - Oct 1 0:00 0 -
|
||||
Rule Libya 1997 only - Apr 4 0:00 1:00 S
|
||||
Rule Libya 1997 only - Oct 4 0:00 0 -
|
||||
Rule Libya 2013 max - Mar lastFri 1:00 1:00 S
|
||||
Rule Libya 2013 max - Oct lastFri 2:00 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Africa/Tripoli 0:52:44 - LMT 1920
|
||||
1:00 Libya CE%sT 1959
|
||||
2:00 - EET 1982
|
||||
1:00 Libya CE%sT 1990 May 4
|
||||
# The following entries are from Shanks & Pottenger;
|
||||
# The 1996 and 1997 entries are from Shanks & Pottenger;
|
||||
# the IATA SSIM data contain some obvious errors.
|
||||
2:00 - EET 1996 Sep 30
|
||||
1:00 - CET 1997 Apr 4
|
||||
1:00 1:00 CEST 1997 Oct 4
|
||||
2:00 - EET
|
||||
1:00 Libya CE%sT 1997 Oct 4
|
||||
2:00 - EET 2012 Nov 10 2:00
|
||||
1:00 Libya CE%sT
|
||||
|
||||
# Madagascar
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
@ -838,6 +869,41 @@ Zone Indian/Mayotte 3:00:56 - LMT 1911 Jul # Mamoutzou
|
||||
# 3:00 am Friday, July 20, 2012 and will again be advanced by 60 minutes
|
||||
# August 20, 2012 from 2:00 am.
|
||||
|
||||
# From Paul Eggert (2013-03-06):
|
||||
# Morocco's daylight-saving transitions due to Ramadan seem to be
|
||||
# announced a bit in advance. On 2012-07-11 the Moroccan government
|
||||
# announced that year's Ramadan daylight-saving transitions would be
|
||||
# 2012-07-20 and 2012-08-20; see
|
||||
# <http://www.mmsp.gov.ma/fr/actualites.aspx?id=288>.
|
||||
#
|
||||
# To estimate what the Moroccan government will do in future years,
|
||||
# transition dates for 2013 through 2021 were determined by running
|
||||
# the following program under GNU Emacs 24.3:
|
||||
#
|
||||
# (let ((islamic-year 1434))
|
||||
# (while (< islamic-year 1444)
|
||||
# (let ((a
|
||||
# (calendar-gregorian-from-absolute
|
||||
# (calendar-islamic-to-absolute (list 9 1 islamic-year))))
|
||||
# (b
|
||||
# (calendar-gregorian-from-absolute
|
||||
# (calendar-islamic-to-absolute (list 10 1 islamic-year)))))
|
||||
# (insert
|
||||
# (format
|
||||
# (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 3:00\t0\t-\n"
|
||||
# "Rule\tMorocco\t%d\tonly\t-\t%s\t %2d\t 2:00\t1:00\tS\n")
|
||||
# (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
|
||||
# (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
|
||||
# (setq islamic-year (+ 1 islamic-year))))
|
||||
#
|
||||
# with the results hand-edited for 2020-2022, when the normal spring-forward
|
||||
# date falls during the estimated Ramadan.
|
||||
#
|
||||
# From 2023 through 2038 Ramadan is not predicted to overlap with
|
||||
# daylight saving time. Starting in 2039 there will be overlap again,
|
||||
# but 32-bit time_t values roll around in 2038 so for now do not worry
|
||||
# about dates after 2038.
|
||||
|
||||
# RULE NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
|
||||
Rule Morocco 1939 only - Sep 12 0:00 1:00 S
|
||||
@ -863,10 +929,28 @@ Rule Morocco 2010 only - May 2 0:00 1:00 S
|
||||
Rule Morocco 2010 only - Aug 8 0:00 0 -
|
||||
Rule Morocco 2011 only - Apr 3 0:00 1:00 S
|
||||
Rule Morocco 2011 only - Jul 31 0 0 -
|
||||
Rule Morocco 2012 max - Apr lastSun 2:00 1:00 S
|
||||
Rule Morocco 2012 2019 - Apr lastSun 2:00 1:00 S
|
||||
Rule Morocco 2012 max - Sep lastSun 3:00 0 -
|
||||
Rule Morocco 2012 only - Jul 20 3:00 0 -
|
||||
Rule Morocco 2012 only - Aug 20 2:00 1:00 S
|
||||
Rule Morocco 2013 only - Jul 9 3:00 0 -
|
||||
Rule Morocco 2013 only - Aug 8 2:00 1:00 S
|
||||
Rule Morocco 2014 only - Jun 29 3:00 0 -
|
||||
Rule Morocco 2014 only - Jul 29 2:00 1:00 S
|
||||
Rule Morocco 2015 only - Jun 18 3:00 0 -
|
||||
Rule Morocco 2015 only - Jul 18 2:00 1:00 S
|
||||
Rule Morocco 2016 only - Jun 7 3:00 0 -
|
||||
Rule Morocco 2016 only - Jul 7 2:00 1:00 S
|
||||
Rule Morocco 2017 only - May 27 3:00 0 -
|
||||
Rule Morocco 2017 only - Jun 26 2:00 1:00 S
|
||||
Rule Morocco 2018 only - May 16 3:00 0 -
|
||||
Rule Morocco 2018 only - Jun 15 2:00 1:00 S
|
||||
Rule Morocco 2019 only - May 6 3:00 0 -
|
||||
Rule Morocco 2019 only - Jun 5 2:00 1:00 S
|
||||
Rule Morocco 2020 only - May 24 2:00 1:00 S
|
||||
Rule Morocco 2021 only - May 13 2:00 1:00 S
|
||||
Rule Morocco 2022 only - May 3 2:00 1:00 S
|
||||
Rule Morocco 2023 max - Apr lastSun 2:00 1:00 S
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26
|
||||
|
@ -73,38 +73,8 @@ Rule ChileAQ 2009 only - Mar Sun>=9 3:00u 0 -
|
||||
Rule ChileAQ 2010 only - Apr Sun>=1 3:00u 0 -
|
||||
Rule ChileAQ 2011 only - May Sun>=2 3:00u 0 -
|
||||
Rule ChileAQ 2011 only - Aug Sun>=16 4:00u 1:00 S
|
||||
Rule ChileAQ 2012 only - Apr Sun>=23 3:00u 0 -
|
||||
Rule ChileAQ 2012 only - Sep Sun>=2 4:00u 1:00 S
|
||||
Rule ChileAQ 2013 max - Mar Sun>=9 3:00u 0 -
|
||||
Rule ChileAQ 2013 max - Oct Sun>=9 4:00u 1:00 S
|
||||
|
||||
# These rules are stolen from the `australasia' file.
|
||||
Rule AusAQ 1917 only - Jan 1 0:01 1:00 -
|
||||
Rule AusAQ 1917 only - Mar 25 2:00 0 -
|
||||
Rule AusAQ 1942 only - Jan 1 2:00 1:00 -
|
||||
Rule AusAQ 1942 only - Mar 29 2:00 0 -
|
||||
Rule AusAQ 1942 only - Sep 27 2:00 1:00 -
|
||||
Rule AusAQ 1943 1944 - Mar lastSun 2:00 0 -
|
||||
Rule AusAQ 1943 only - Oct 3 2:00 1:00 -
|
||||
Rule ATAQ 1967 only - Oct Sun>=1 2:00s 1:00 -
|
||||
Rule ATAQ 1968 only - Mar lastSun 2:00s 0 -
|
||||
Rule ATAQ 1968 1985 - Oct lastSun 2:00s 1:00 -
|
||||
Rule ATAQ 1969 1971 - Mar Sun>=8 2:00s 0 -
|
||||
Rule ATAQ 1972 only - Feb lastSun 2:00s 0 -
|
||||
Rule ATAQ 1973 1981 - Mar Sun>=1 2:00s 0 -
|
||||
Rule ATAQ 1982 1983 - Mar lastSun 2:00s 0 -
|
||||
Rule ATAQ 1984 1986 - Mar Sun>=1 2:00s 0 -
|
||||
Rule ATAQ 1986 only - Oct Sun>=15 2:00s 1:00 -
|
||||
Rule ATAQ 1987 1990 - Mar Sun>=15 2:00s 0 -
|
||||
Rule ATAQ 1987 only - Oct Sun>=22 2:00s 1:00 -
|
||||
Rule ATAQ 1988 1990 - Oct lastSun 2:00s 1:00 -
|
||||
Rule ATAQ 1991 1999 - Oct Sun>=1 2:00s 1:00 -
|
||||
Rule ATAQ 1991 2005 - Mar lastSun 2:00s 0 -
|
||||
Rule ATAQ 2000 only - Aug lastSun 2:00s 1:00 -
|
||||
Rule ATAQ 2001 max - Oct Sun>=1 2:00s 1:00 -
|
||||
Rule ATAQ 2006 only - Apr Sun>=1 2:00s 0 -
|
||||
Rule ATAQ 2007 only - Mar lastSun 2:00s 0 -
|
||||
Rule ATAQ 2008 max - Apr Sun>=1 2:00s 0 -
|
||||
Rule ChileAQ 2012 max - Apr Sun>=23 3:00u 0 -
|
||||
Rule ChileAQ 2012 max - Sep Sun>=2 4:00u 1:00 S
|
||||
|
||||
# Argentina - year-round bases
|
||||
# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
|
||||
@ -147,10 +117,7 @@ Rule ATAQ 2008 max - Apr Sun>=1 2:00s 0 -
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2010-03-10):
|
||||
# We got these changes from the Australian Antarctic Division:
|
||||
# - Macquarie Island will stay on UTC+11 for winter and therefore not
|
||||
# switch back from daylight savings time when other parts of Australia do
|
||||
# on 4 April.
|
||||
# We got these changes from the Australian Antarctic Division: ...
|
||||
#
|
||||
# - Casey station reverted to its normal time of UTC+8 on 5 March 2010.
|
||||
# The change to UTC+11 is being considered as a regular summer thing but
|
||||
@ -161,9 +128,6 @@ Rule ATAQ 2008 max - Apr Sun>=1 2:00s 0 -
|
||||
#
|
||||
# - Mawson station stays on UTC+5.
|
||||
#
|
||||
# In addition to the Rule changes for Casey/Davis, it means that Macquarie
|
||||
# will no longer be like Hobart and will have to have its own Zone created.
|
||||
#
|
||||
# Background:
|
||||
# <a href="http://www.timeanddate.com/news/time/antartica-time-changes-2010.html">
|
||||
# http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
|
||||
@ -190,12 +154,6 @@ Zone Antarctica/Mawson 0 - zzz 1954 Feb 13
|
||||
6:00 - MAWT 2009 Oct 18 2:00
|
||||
# Mawson Time
|
||||
5:00 - MAWT
|
||||
Zone Antarctica/Macquarie 0 - zzz 1911
|
||||
10:00 - EST 1916 Oct 1 2:00
|
||||
10:00 1:00 EST 1917 Feb
|
||||
10:00 AusAQ EST 1967
|
||||
10:00 ATAQ EST 2010 Apr 4 3:00
|
||||
11:00 - MIST # Macquarie Island Time
|
||||
# References:
|
||||
# <a href="http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html">
|
||||
# Casey Weather (1998-02-26)
|
||||
|
@ -27,9 +27,9 @@
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# From Paul Eggert (2013-02-21):
|
||||
#
|
||||
# A good source for time zone historical data outside the U.S. is
|
||||
# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
|
||||
@ -48,6 +48,10 @@
|
||||
# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
|
||||
# I found in the UCLA library.
|
||||
#
|
||||
# For data circa 1899, a common source is:
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>.
|
||||
#
|
||||
# A reliable and entertaining source about time zones is
|
||||
# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
|
||||
#
|
||||
@ -302,9 +306,12 @@ Zone Asia/Brunei 7:39:40 - LMT 1926 Mar # Bandar Seri Begawan
|
||||
8:00 - BNT
|
||||
|
||||
# Burma / Myanmar
|
||||
|
||||
# Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon.
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Rangoon 6:24:40 - LMT 1880 # or Yangon
|
||||
6:24:36 - RMT 1920 # Rangoon Mean Time?
|
||||
6:24:40 - RMT 1920 # Rangoon Mean Time?
|
||||
6:30 - BURT 1942 May # Burma Time
|
||||
9:00 - JST 1945 May 3
|
||||
6:30 - MMT # Myanmar Time
|
||||
@ -407,7 +414,8 @@ Zone Asia/Harbin 8:26:44 - LMT 1928 # or Haerbin
|
||||
8:00 PRC C%sT
|
||||
# Zhongyuan Time ("Central plain Time")
|
||||
# most of China
|
||||
Zone Asia/Shanghai 8:05:52 - LMT 1928
|
||||
# Milne gives 8:05:56.7; round to nearest.
|
||||
Zone Asia/Shanghai 8:05:57 - LMT 1928
|
||||
8:00 Shang C%sT 1949
|
||||
8:00 PRC C%sT
|
||||
# Long-shu Time (probably due to Long and Shu being two names of that area)
|
||||
@ -504,6 +512,10 @@ Zone Asia/Kashgar 5:03:56 - LMT 1928 # or Kashi or Kaxgar
|
||||
8:00 PRC C%sT
|
||||
|
||||
|
||||
# Hong Kong (Xianggang)
|
||||
|
||||
# Milne gives 7:36:41.7; round this.
|
||||
|
||||
# From Lee Yiu Chung (2009-10-24):
|
||||
# I found there are some mistakes for the...DST rule for Hong
|
||||
# Kong. [According] to the DST record from Hong Kong Observatory (actually,
|
||||
@ -570,7 +582,6 @@ Zone Asia/Kashgar 5:03:56 - LMT 1928 # or Kashi or Kaxgar
|
||||
# The Japanese surrender of Hong Kong was signed 1945-09-15.
|
||||
# For lack of anything better, use start of those days as the transition times.
|
||||
|
||||
# Hong Kong (Xianggang)
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule HK 1941 only - Apr 1 3:30 1:00 S
|
||||
Rule HK 1941 only - Sep 30 3:30 0 -
|
||||
@ -592,7 +603,7 @@ Rule HK 1973 only - Dec 30 3:30 1:00 S
|
||||
Rule HK 1979 only - May Sun>=8 3:30 1:00 S
|
||||
Rule HK 1979 only - Oct Sun>=16 3:30 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Hong_Kong 7:36:36 - LMT 1904 Oct 30
|
||||
Zone Asia/Hong_Kong 7:36:42 - LMT 1904 Oct 30
|
||||
8:00 HK HK%sT 1941 Dec 25
|
||||
9:00 - JST 1945 Sep 15
|
||||
8:00 HK HK%sT
|
||||
@ -669,6 +680,9 @@ Zone Asia/Macau 7:34:20 - LMT 1912
|
||||
###############################################################################
|
||||
|
||||
# Cyprus
|
||||
#
|
||||
# Milne says the Eastern Telegraph Company used 2:14:00. Stick with LMT.
|
||||
#
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Cyprus 1975 only - Apr 13 0:00 1:00 S
|
||||
Rule Cyprus 1975 only - Oct 12 0:00 0 -
|
||||
@ -1222,7 +1236,6 @@ Rule Zion 2012 only - Mar Fri>=26 2:00 1:00 D
|
||||
Rule Zion 2012 only - Sep 23 2:00 0 S
|
||||
|
||||
# From Ephraim Silverberg (2012-10-18):
|
||||
|
||||
# Yesterday, the Interior Ministry Committee, after more than a year
|
||||
# past, approved sending the proposed June 2011 changes to the Time
|
||||
# Decree Law back to the Knesset for second and third (final) votes
|
||||
@ -1235,6 +1248,10 @@ Rule Zion 2012 only - Sep 23 2:00 0 S
|
||||
# later (i.e. at 02:00 the first Monday after October 2).
|
||||
# [Rosh Hashana holidays are factored in until 2100.]
|
||||
|
||||
# From Ephraim Silverberg (2012-11-05):
|
||||
# The Knesset passed today (in second and final readings) the amendment to the
|
||||
# Time Decree Law making the changes ... law.
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Zion 2013 max - Mar Fri>=23 2:00 1:00 D
|
||||
Rule Zion 2013 2026 - Oct Sun>=2 2:00 0 S
|
||||
@ -1824,8 +1841,11 @@ Zone Asia/Kathmandu 5:41:16 - LMT 1920
|
||||
5:45 - NPT # Nepal Time
|
||||
|
||||
# Oman
|
||||
|
||||
# Milne says 3:54:24 was the meridian of the Muscat Tidal Observatory.
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Muscat 3:54:20 - LMT 1920
|
||||
Zone Asia/Muscat 3:54:24 - LMT 1920
|
||||
4:00 - GST
|
||||
|
||||
# Pakistan
|
||||
@ -2072,8 +2092,7 @@ Zone Asia/Karachi 4:28:12 - LMT 1907
|
||||
# occurred before our cutoff date of 1970.
|
||||
# However, as we get more information, we may need to add entries
|
||||
# for parts of the West Bank as they transitioned from Israel's rules
|
||||
# to Palestine's rules. If you have more info about this, please
|
||||
# send it to tz@elsie.nci.nih.gov for incorporation into future editions.
|
||||
# to Palestine's rules.
|
||||
|
||||
# From IINS News Service - Israel - 1998-03-23 10:38:07 Israel time,
|
||||
# forwarded by Ephraim Silverberg:
|
||||
@ -2295,11 +2314,20 @@ Zone Asia/Karachi 4:28:12 - LMT 1907
|
||||
# http://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html
|
||||
# </a>
|
||||
|
||||
# From Arthur David Olson (2012-03-27):
|
||||
# The timeanddate article for 2012 says that "the end date has not yet been
|
||||
# announced" and that "Last year, both...paused daylight saving time during...
|
||||
# Ramadan. It is not yet known [for] 2012."
|
||||
# For now, assume both switch back on the last Friday in September. XXX
|
||||
# From Steffen Thorsen (2013-03-26):
|
||||
# The following news sources tells that Palestine will "start daylight saving
|
||||
# time from midnight on Friday, March 29, 2013" (translated).
|
||||
# [These are in Arabic and are for Gaza and for Ramallah, respectively.]
|
||||
# http://www.samanews.com/index.php?act=Show&id=154120
|
||||
# http://safa.ps/details/news/99844/%D8%B1%D8%A7%D9%85-%D8%A7%D9%84%D9%84%D9%87-%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-29-%D8%A7%D9%84%D8%AC%D8%A7%D8%B1%D9%8A.html
|
||||
|
||||
# From Paul Eggert (2013-04-15):
|
||||
# For future dates, guess the last Thursday in March at 24:00 through
|
||||
# the first Friday on or after September 21 at 01:00. This is consistent with
|
||||
# the predictions in today's editions of the following URLs,
|
||||
# which are for Gaza and Hebron respectively:
|
||||
# http://www.timeanddate.com/worldclock/timezone.html?n=702
|
||||
# http://www.timeanddate.com/worldclock/timezone.html?n=2364
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule EgyptAsia 1957 only - May 10 0:00 1:00 S
|
||||
@ -2313,19 +2341,20 @@ Rule Palestine 1999 2005 - Apr Fri>=15 0:00 1:00 S
|
||||
Rule Palestine 1999 2003 - Oct Fri>=15 0:00 0 -
|
||||
Rule Palestine 2004 only - Oct 1 1:00 0 -
|
||||
Rule Palestine 2005 only - Oct 4 2:00 0 -
|
||||
Rule Palestine 2006 2008 - Apr 1 0:00 1:00 S
|
||||
Rule Palestine 2006 2007 - Apr 1 0:00 1:00 S
|
||||
Rule Palestine 2006 only - Sep 22 0:00 0 -
|
||||
Rule Palestine 2007 only - Sep Thu>=8 2:00 0 -
|
||||
Rule Palestine 2008 only - Aug lastFri 0:00 0 -
|
||||
Rule Palestine 2009 only - Mar lastFri 0:00 1:00 S
|
||||
Rule Palestine 2009 only - Sep Fri>=1 2:00 0 -
|
||||
Rule Palestine 2010 only - Mar lastSat 0:01 1:00 S
|
||||
Rule Palestine 2008 2009 - Mar lastFri 0:00 1:00 S
|
||||
Rule Palestine 2008 only - Sep 1 0:00 0 -
|
||||
Rule Palestine 2009 only - Sep Fri>=1 1:00 0 -
|
||||
Rule Palestine 2010 only - Mar 26 0:00 1:00 S
|
||||
Rule Palestine 2010 only - Aug 11 0:00 0 -
|
||||
|
||||
# From Arthur David Olson (2011-09-20):
|
||||
# 2011 transitions per http://www.timeanddate.com as of 2011-09-20.
|
||||
# From Paul Eggert (2012-10-12):
|
||||
# 2012 transitions per http://www.timeanddate.com as of 2012-10-12.
|
||||
Rule Palestine 2011 only - Apr 1 0:01 1:00 S
|
||||
Rule Palestine 2011 only - Aug 1 0:00 0 -
|
||||
Rule Palestine 2011 only - Aug 30 0:00 1:00 S
|
||||
Rule Palestine 2011 only - Sep 30 0:00 0 -
|
||||
Rule Palestine 2012 max - Mar lastThu 24:00 1:00 S
|
||||
Rule Palestine 2012 max - Sep Fri>=21 1:00 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
|
||||
@ -2333,26 +2362,20 @@ Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
|
||||
2:00 EgyptAsia EE%sT 1967 Jun 5
|
||||
2:00 Zion I%sT 1996
|
||||
2:00 Jordan EE%sT 1999
|
||||
2:00 Palestine EE%sT 2011 Apr 2 12:01
|
||||
2:00 1:00 EEST 2011 Aug 1
|
||||
2:00 - EET 2012 Mar 30
|
||||
2:00 1:00 EEST 2012 Sep 21 1:00
|
||||
2:00 - EET
|
||||
2:00 Palestine EE%sT 2008 Aug 29 0:00
|
||||
2:00 - EET 2008 Sep
|
||||
2:00 Palestine EE%sT 2010
|
||||
2:00 - EET 2010 Mar 27 0:01
|
||||
2:00 Palestine EE%sT 2011 Aug 1
|
||||
2:00 - EET 2012
|
||||
2:00 Palestine EE%sT
|
||||
|
||||
Zone Asia/Hebron 2:20:23 - LMT 1900 Oct
|
||||
2:00 Zion EET 1948 May 15
|
||||
2:00 EgyptAsia EE%sT 1967 Jun 5
|
||||
2:00 Zion I%sT 1996
|
||||
2:00 Jordan EE%sT 1999
|
||||
2:00 Palestine EE%sT 2008 Aug
|
||||
2:00 1:00 EEST 2008 Sep
|
||||
2:00 Palestine EE%sT 2011 Apr 1 12:01
|
||||
2:00 1:00 EEST 2011 Aug 1
|
||||
2:00 - EET 2011 Aug 30
|
||||
2:00 1:00 EEST 2011 Sep 30 3:00
|
||||
2:00 - EET 2012 Mar 30
|
||||
2:00 1:00 EEST 2012 Sep 21 1:00
|
||||
2:00 - EET
|
||||
2:00 Palestine EE%sT
|
||||
|
||||
# Paracel Is
|
||||
# no information
|
||||
@ -2421,6 +2444,13 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1
|
||||
# no information
|
||||
|
||||
# Sri Lanka
|
||||
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# Milne says "Madras mean time use from May 1, 1898. Prior to this Colombo
|
||||
# mean time, 5h. 4m. 21.9s. F., was used." But 5:04:21.9 differs considerably
|
||||
# from Colombo's meridian 5:19:24, so for now ignore Milne and stick with
|
||||
# Shanks and Pottenger.
|
||||
|
||||
# From Paul Eggert (1996-09-03):
|
||||
# "Sri Lanka advances clock by an hour to avoid blackout"
|
||||
# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
|
||||
@ -2720,6 +2750,12 @@ Zone Asia/Tashkent 4:37:12 - LMT 1924 May 2
|
||||
|
||||
# Vietnam
|
||||
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# Milne gives 7:16:56 for the meridian of Saigon in 1899, as being
|
||||
# used in Lower Laos, Cambodia, and Annam. But this is quite a ways
|
||||
# from Saigon's location. For now, ignore this and stick with Shanks
|
||||
# and Pottenger.
|
||||
|
||||
# From Arthur David Olson (2008-03-18):
|
||||
# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
|
||||
# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
|
||||
@ -2733,6 +2769,10 @@ Zone Asia/Ho_Chi_Minh 7:06:40 - LMT 1906 Jun 9
|
||||
7:00 - ICT
|
||||
|
||||
# Yemen
|
||||
|
||||
# Milne says 2:59:54 was the meridian of the saluting battery at Aden,
|
||||
# and that Yemen was at 1:55:56, the meridian of the Hagia Sophia.
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Aden 3:00:48 - LMT 1950
|
||||
Zone Asia/Aden 2:59:54 - LMT 1950
|
||||
3:00 - AST
|
||||
|
@ -241,9 +241,26 @@ Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb
|
||||
# no times are set
|
||||
#
|
||||
# Macquarie
|
||||
# permanent occupation (scientific station) since 1948;
|
||||
# sealing and penguin oil station operated 1888/1917
|
||||
# like Australia/Hobart
|
||||
# Permanent occupation (scientific station) 1911-1915 and since 25 March 1948;
|
||||
# sealing and penguin oil station operated Nov 1899 to Apr 1919. See the
|
||||
# Tasmania Parks & Wildlife Service history of sealing at Macquarie Island
|
||||
# <http://www.parks.tas.gov.au/index.aspx?base=1828>
|
||||
# <http://www.parks.tas.gov.au/index.aspx?base=1831>.
|
||||
# Guess that it was like Australia/Hobart while inhabited before 2010.
|
||||
#
|
||||
# From Steffen Thorsen (2010-03-10):
|
||||
# We got these changes from the Australian Antarctic Division:
|
||||
# - Macquarie Island will stay on UTC+11 for winter and therefore not
|
||||
# switch back from daylight savings time when other parts of Australia do
|
||||
# on 4 April.
|
||||
Zone Antarctica/Macquarie 0 - zzz 1899 Nov
|
||||
10:00 - EST 1916 Oct 1 2:00
|
||||
10:00 1:00 EST 1917 Feb
|
||||
10:00 Aus EST 1919 Apr
|
||||
0 - zzz 1948 Mar 25
|
||||
10:00 Aus EST 1967
|
||||
10:00 AT EST 2010 Apr 4 3:00
|
||||
11:00 - MIST # Macquarie I Standard Time
|
||||
|
||||
# Christmas
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
@ -269,6 +286,9 @@ Zone Indian/Cocos 6:27:40 - LMT 1900
|
||||
6:30 - CCT # Cocos Islands Time
|
||||
|
||||
# Fiji
|
||||
|
||||
# Milne gives 11:55:44 for Suva.
|
||||
|
||||
# From Alexander Krivenyshev (2009-11-10):
|
||||
# According to Fiji Broadcasting Corporation, Fiji plans to re-introduce DST
|
||||
# from November 29th 2009 to April 25th 2010.
|
||||
@ -362,7 +382,7 @@ Rule Fiji 2010 max - Oct Sun>=18 2:00 1:00 S
|
||||
Rule Fiji 2011 only - Mar Sun>=1 3:00 0 -
|
||||
Rule Fiji 2012 max - Jan Sun>=18 3:00 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Pacific/Fiji 11:53:40 - LMT 1915 Oct 26 # Suva
|
||||
Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva
|
||||
12:00 Fiji FJ%sT # Fiji Time
|
||||
|
||||
# French Polynesia
|
||||
@ -803,9 +823,9 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# A good source for time zone historical data outside the U.S. is
|
||||
# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
|
||||
# San Diego: ACS Publications, Inc. (2003).
|
||||
@ -823,6 +843,10 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901
|
||||
# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
|
||||
# I found in the UCLA library.
|
||||
#
|
||||
# For data circa 1899, a common source is:
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>.
|
||||
#
|
||||
# A reliable and entertaining source about time zones is
|
||||
# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
|
||||
#
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# A good source for time zone historical data outside the U.S. is
|
||||
@ -53,6 +53,12 @@
|
||||
# William Willett, The Waste of Daylight, 19th edition
|
||||
# </a> (1914-03)
|
||||
#
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>. He writes:
|
||||
# "It is requested that corrections and additions to these tables
|
||||
# may be sent to Mr. John Milne, Royal Geographical Society,
|
||||
# Savile Row, London." Nowadays please email them to tz@iana.org.
|
||||
#
|
||||
# Brazil's Departamento Servico da Hora (DSH),
|
||||
# <a href="http://pcdsh01.on.br/HISTHV.htm">
|
||||
# History of Summer Time
|
||||
@ -689,6 +695,8 @@ Zone Europe/Andorra 0:06:04 - LMT 1901
|
||||
|
||||
# Austria
|
||||
|
||||
# Milne says Vienna time was 1:05:21.
|
||||
|
||||
# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
|
||||
# 1945-11-18, but the Austrian Federal Office of Metrology and
|
||||
# Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
|
||||
@ -706,7 +714,7 @@ Rule Austria 1948 only - Apr 18 2:00s 1:00 S
|
||||
Rule Austria 1980 only - Apr 6 0:00 1:00 S
|
||||
Rule Austria 1980 only - Sep 28 0:00 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Europe/Vienna 1:05:20 - LMT 1893 Apr
|
||||
Zone Europe/Vienna 1:05:21 - LMT 1893 Apr
|
||||
1:00 C-Eur CE%sT 1920
|
||||
1:00 Austria CE%sT 1940 Apr 1 2:00s
|
||||
1:00 C-Eur CE%sT 1945 Apr 2 2:00s
|
||||
@ -1262,6 +1270,21 @@ Zone Europe/Berlin 0:53:28 - LMT 1893 Apr
|
||||
1:00 Germany CE%sT 1980
|
||||
1:00 EU CE%sT
|
||||
|
||||
# From Tobias Conradi (2011-09-12):
|
||||
# Busingen <http://www.buesingen.de>, surrounded by the Swiss canton
|
||||
# Schaffhausen, did not start observing DST in 1980 as the rest of DE
|
||||
# (West Germany at that time) and DD (East Germany at that time) did.
|
||||
# DD merged into DE, the area is currently covered by code DE in ISO 3166-1,
|
||||
# which in turn is covered by the zone Europe/Berlin.
|
||||
#
|
||||
# Source for the time in Busingen 1980:
|
||||
# http://www.srf.ch/player/video?id=c012c029-03b7-4c2b-9164-aa5902cd58d3
|
||||
|
||||
# From Arthur David Olson (2012-03-03):
|
||||
# Busingen and Zurich have shared clocks since 1970.
|
||||
|
||||
Link Europe/Zurich Europe/Busingen
|
||||
|
||||
# Georgia
|
||||
# Please see the "asia" file for Asia/Tbilisi.
|
||||
# Herodotus (Histories, IV.45) says Georgia north of the Phasis (now Rioni)
|
||||
@ -2066,6 +2089,70 @@ Zone Europe/Bucharest 1:44:24 - LMT 1891 Oct
|
||||
|
||||
# Russia
|
||||
|
||||
# From Alexander Krivenyshev (2011-09-15):
|
||||
# Based on last Russian Government Decree # 725 on August 31, 2011
|
||||
# (Government document
|
||||
# <a href="http://www.government.ru/gov/results/16355/print/">
|
||||
# http://www.government.ru/gov/results/16355/print/
|
||||
# </a>
|
||||
# in Russian)
|
||||
# there are few corrections have to be made for some Russian time zones...
|
||||
# All updated Russian Time Zones were placed in table and translated to English
|
||||
# by WorldTimeZone.com at the link below:
|
||||
# <a href="http://www.worldtimezone.com/dst_news/dst_news_russia36.htm">
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_russia36.htm
|
||||
# </a>
|
||||
|
||||
# From Sanjeev Gupta (2011-09-27):
|
||||
# Scans of [Decree #23 of January 8, 1992] are available at:
|
||||
# <a href="http://government.consultant.ru/page.aspx?1223966">
|
||||
# http://government.consultant.ru/page.aspx?1223966
|
||||
# They are in Cyrillic letters (presumably Russian).
|
||||
|
||||
# From Arthur David Olson (2012-05-09):
|
||||
# Regarding the instant when clocks in time-zone-shifting parts of Russia
|
||||
# changed in September 2011:
|
||||
#
|
||||
# One source is
|
||||
# < a href="http://government.ru/gov/results/16355/>
|
||||
# http://government.ru/gov/results/16355/
|
||||
# </a>
|
||||
# which, according to translate.google.com, begins "Decree of August 31,
|
||||
# 2011 No 725" and contains no other dates or "effective date" information.
|
||||
#
|
||||
# Another source is
|
||||
# <a href="http://www.rg.ru/2011/09/06/chas-zona-dok.html">
|
||||
# http://www.rg.ru/2011/09/06/chas-zona-dok.html
|
||||
# </a>
|
||||
# which, according to translate.google.com, begins "Resolution of the
|
||||
# Government of the Russian Federation on August 31, 2011 N 725" and also
|
||||
# contains "Date first official publication: September 6, 2011 Posted on:
|
||||
# in the 'RG' - Federal Issue number 5573 September 6, 2011" but which
|
||||
# does not contain any "effective date" information.
|
||||
#
|
||||
# Another source is
|
||||
# <a href="http://en.wikipedia.org/wiki/Oymyakonsky_District#cite_note-RuTime-7">
|
||||
# http://en.wikipedia.org/wiki/Oymyakonsky_District#cite_note-RuTime-7
|
||||
# </a>
|
||||
# which, in note 8, contains "Resolution #725 of August 31, 2011...
|
||||
# Effective as of after 7 days following the day of the official publication"
|
||||
# but which does not contain any reference to September 6, 2011.
|
||||
#
|
||||
# The Wikipedia article refers to
|
||||
# <a href="http://base.consultant.ru/cons/cgi/online.cgi?req=doc;base=LAW;n=118896">
|
||||
# http://base.consultant.ru/cons/cgi/online.cgi?req=doc;base=LAW;n=118896
|
||||
# </a>
|
||||
# which seems to copy the text of the government.ru page.
|
||||
#
|
||||
# Tobias Conradi combines Wikipedia's
|
||||
# "as of after 7 days following the day of the official publication"
|
||||
# with www.rg.ru's "Date of first official publication: September 6, 2011" to get
|
||||
# September 13, 2011 as the cutover date (unusually, a Tuesday, as Tobias Conradi notes).
|
||||
#
|
||||
# None of the sources indicates a time of day for changing clocks.
|
||||
#
|
||||
# Go with 2011-09-13 0:00s.
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
|
||||
# Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
|
||||
@ -2293,14 +2380,32 @@ Zone Asia/Yakutsk 8:38:40 - LMT 1919 Dec 15
|
||||
# [parts of] Respublika Sakha (Yakutiya).
|
||||
|
||||
# From Oscar van Vlijmen (2009-11-29):
|
||||
# The Sakha districts are: Bulunskij, Verkhoyanskij, Tomponskij, Ust'-Majskij,
|
||||
# Ust'-Yanskij.
|
||||
# The Sakha districts are: Bulunskij, Verkhoyanskij, ... Ust'-Yanskij.
|
||||
Zone Asia/Vladivostok 8:47:44 - LMT 1922 Nov 15
|
||||
9:00 - VLAT 1930 Jun 21 # Vladivostok Time
|
||||
10:00 Russia VLA%sT 1991 Mar 31 2:00s
|
||||
9:00 Russia VLA%sST 1992 Jan 19 2:00s
|
||||
10:00 Russia VLA%sT 2011 Mar 27 2:00s
|
||||
11:00 - VLAT
|
||||
|
||||
# From Arthur David Olson (2012-05-09):
|
||||
# Tomponskij and Ust'-Majskij switched from Vladivostok time to Yakutsk time
|
||||
# in 2011.
|
||||
#
|
||||
# From Paul Eggert (2012-11-25):
|
||||
# Shanks and Pottenger (2003) has Khandyga on Yakutsk time.
|
||||
# Make a wild guess that it switched to Vladivostok time in 2004.
|
||||
# This transition is no doubt wrong, but we have no better info.
|
||||
#
|
||||
Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15
|
||||
8:00 - YAKT 1930 Jun 21 # Yakutsk Time
|
||||
9:00 Russia YAK%sT 1991 Mar 31 2:00s
|
||||
8:00 Russia YAK%sT 1992 Jan 19 2:00s
|
||||
9:00 Russia YAK%sT 2004
|
||||
10:00 Russia VLA%sT 2011 Mar 27 2:00s
|
||||
11:00 - VLAT 2011 Sep 13 0:00s # Decree 725?
|
||||
10:00 - YAKT
|
||||
|
||||
#
|
||||
# Sakhalinskaya oblast'.
|
||||
# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
|
||||
@ -2319,14 +2424,26 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23
|
||||
|
||||
# From Oscar van Vlijmen (2009-11-29):
|
||||
# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
|
||||
# Nizhnekolymskij, Ojmyakonskij, Srednekolymskij.
|
||||
# Nizhnekolymskij, ... Srednekolymskij.
|
||||
Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
|
||||
10:00 - MAGT 1930 Jun 21 # Magadan Time
|
||||
11:00 Russia MAG%sT 1991 Mar 31 2:00s
|
||||
10:00 Russia MAG%sT 1992 Jan 19 2:00s
|
||||
11:00 Russia MAG%sT 2011 Mar 27 2:00s
|
||||
12:00 - MAGT
|
||||
#
|
||||
|
||||
# From Arthur David Olson (2012-05-09):
|
||||
# Ojmyakonskij and the Kuril Islands switched from
|
||||
# Magadan time to Vladivostok time in 2011.
|
||||
Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15
|
||||
8:00 - YAKT 1930 Jun 21 # Yakutsk Time
|
||||
9:00 Russia YAKT 1981 Apr 1
|
||||
11:00 Russia MAG%sT 1991 Mar 31 2:00s
|
||||
10:00 Russia MAG%sT 1992 Jan 19 2:00s
|
||||
11:00 Russia MAG%sT 2011 Mar 27 2:00s
|
||||
12:00 - MAGT 2011 Sep 13 0:00s # Decree 725?
|
||||
11:00 - VLAT
|
||||
|
||||
# From Oscar van Vlijmen (2001-08-25): [This region consists of]
|
||||
# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
|
||||
#
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (1999-03-22):
|
||||
# A reliable and entertaining source about time zones is
|
||||
@ -1042,6 +1042,9 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00
|
||||
# William Willett, The Waste of Daylight, 19th edition
|
||||
# </a> (1914-03)
|
||||
#
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>.
|
||||
#
|
||||
# See the `europe' file for Greenland.
|
||||
|
||||
# Canada
|
||||
@ -2577,6 +2580,8 @@ Zone America/Antigua -4:07:12 - LMT 1912 Mar 2
|
||||
|
||||
# Bahamas
|
||||
#
|
||||
# For 1899 Milne gives -5:09:29.5; round that.
|
||||
#
|
||||
# From Sue Williams (2006-12-07):
|
||||
# The Bahamas announced about a month ago that they plan to change their DST
|
||||
# rules to sync with the U.S. starting in 2007....
|
||||
@ -2586,11 +2591,14 @@ Zone America/Antigua -4:07:12 - LMT 1912 Mar 2
|
||||
Rule Bahamas 1964 1975 - Oct lastSun 2:00 0 S
|
||||
Rule Bahamas 1964 1975 - Apr lastSun 2:00 1:00 D
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Nassau -5:09:24 - LMT 1912 Mar 2
|
||||
Zone America/Nassau -5:09:30 - LMT 1912 Mar 2
|
||||
-5:00 Bahamas E%sT 1976
|
||||
-5:00 US E%sT
|
||||
|
||||
# Barbados
|
||||
|
||||
# For 1899 Milne gives -3:58:29.2; round that.
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Barb 1977 only - Jun 12 2:00 1:00 D
|
||||
Rule Barb 1977 1978 - Oct Sun>=1 2:00 0 S
|
||||
@ -2598,8 +2606,8 @@ Rule Barb 1978 1980 - Apr Sun>=15 2:00 1:00 D
|
||||
Rule Barb 1979 only - Sep 30 2:00 0 S
|
||||
Rule Barb 1980 only - Sep 25 2:00 0 S
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Barbados -3:58:28 - LMT 1924 # Bridgetown
|
||||
-3:58:28 - BMT 1932 # Bridgetown Mean Time
|
||||
Zone America/Barbados -3:58:29 - LMT 1924 # Bridgetown
|
||||
-3:58:29 - BMT 1932 # Bridgetown Mean Time
|
||||
-4:00 Barb A%sT
|
||||
|
||||
# Belize
|
||||
@ -2617,6 +2625,9 @@ Zone America/Belize -5:52:48 - LMT 1912 Apr
|
||||
|
||||
# Bermuda
|
||||
|
||||
# For 1899 Milne gives -4:19:18.3 as the meridian of the clock tower,
|
||||
# Bermuda dockyard, Ireland I; round that.
|
||||
|
||||
# From Dan Jones, reporting in The Royal Gazette (2006-06-26):
|
||||
|
||||
# Next year, however, clocks in the US will go forward on the second Sunday
|
||||
@ -2626,7 +2637,7 @@ Zone America/Belize -5:52:48 - LMT 1912 Apr
|
||||
# http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Atlantic/Bermuda -4:19:04 - LMT 1930 Jan 1 2:00 # Hamilton
|
||||
Zone Atlantic/Bermuda -4:19:18 - LMT 1930 Jan 1 2:00 # Hamilton
|
||||
-4:00 - AST 1974 Apr 28 2:00
|
||||
-4:00 Bahamas A%sT 1976
|
||||
-4:00 US A%sT
|
||||
@ -2638,6 +2649,9 @@ Zone America/Cayman -5:25:32 - LMT 1890 # Georgetown
|
||||
-5:00 - EST
|
||||
|
||||
# Costa Rica
|
||||
|
||||
# Milne gives -5:36:13.3 as San Jose mean time; round to nearest.
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule CR 1979 1980 - Feb lastSun 0:00 1:00 D
|
||||
Rule CR 1979 1980 - Jun Sun>=1 0:00 0 S
|
||||
@ -2648,14 +2662,19 @@ Rule CR 1991 only - Jul 1 0:00 0 S
|
||||
Rule CR 1992 only - Mar 15 0:00 0 S
|
||||
# There are too many San Joses elsewhere, so we'll use `Costa Rica'.
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Costa_Rica -5:36:20 - LMT 1890 # San Jose
|
||||
-5:36:20 - SJMT 1921 Jan 15 # San Jose Mean Time
|
||||
Zone America/Costa_Rica -5:36:13 - LMT 1890 # San Jose
|
||||
-5:36:13 - SJMT 1921 Jan 15 # San Jose Mean Time
|
||||
-6:00 CR C%sT
|
||||
# Coco
|
||||
# no information; probably like America/Costa_Rica
|
||||
|
||||
# Cuba
|
||||
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# Milne gives -5:28:50.45 for the observatory at Havana, -5:29:23.57
|
||||
# for the port, and -5:30 for meteorological observations.
|
||||
# For now, stick with Shanks & Pottenger.
|
||||
|
||||
# From Arthur David Olson (1999-03-29):
|
||||
# The 1999-03-28 exhibition baseball game held in Havana, Cuba, between
|
||||
# the Cuban National Team and the Baltimore Orioles was carried live on
|
||||
@ -3004,24 +3023,21 @@ Zone America/Guatemala -6:02:04 - LMT 1918 Oct 5
|
||||
# apparently using the same start and end date as USA/Canada.
|
||||
# So this means they have already changed their time.
|
||||
#
|
||||
# (Sources in French):
|
||||
# <a href="http://www.alterpresse.org/spip.php?article12510">
|
||||
# http://www.alterpresse.org/spip.php?article12510
|
||||
# </a>
|
||||
# <a href="http://radiovision2000haiti.net/home/?p=13253">
|
||||
# http://radiovision2000haiti.net/home/?p=13253
|
||||
# </a>
|
||||
#
|
||||
# Our coverage:
|
||||
# <a href="http://www.timeanddate.com/news/time/haiti-dst-2012.html">
|
||||
# http://www.timeanddate.com/news/time/haiti-dst-2012.html
|
||||
# </a>
|
||||
|
||||
# From Arthur David Olson (2012-03-11):
|
||||
# The alterpresse.org source seems to show a US-style leap from 2:00 a.m. to
|
||||
# 3:00 a.m. rather than the traditional Haitian jump at midnight.
|
||||
# Assume a US-style fall back as well XXX.
|
||||
# Do not yet assume that the change carries forward past 2012 XXX.
|
||||
# Assume a US-style fall back as well.
|
||||
|
||||
# From Steffen Thorsen (2013-03-10):
|
||||
# It appears that Haiti is observing DST this year as well, same rules
|
||||
# as US/Canada. They did it last year as well, and it looks like they
|
||||
# are going to observe DST every year now...
|
||||
#
|
||||
# http://radiovision2000haiti.net/public/haiti-avis-changement-dheure-dimanche/
|
||||
# http://www.canalplushaiti.net/?p=6714
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Haiti 1983 only - May 8 0:00 1:00 D
|
||||
@ -3033,8 +3049,8 @@ Rule Haiti 1988 1997 - Apr Sun>=1 1:00s 1:00 D
|
||||
Rule Haiti 1988 1997 - Oct lastSun 1:00s 0 S
|
||||
Rule Haiti 2005 2006 - Apr Sun>=1 0:00 1:00 D
|
||||
Rule Haiti 2005 2006 - Oct lastSun 0:00 0 S
|
||||
Rule Haiti 2012 only - Mar Sun>=8 2:00 1:00 D
|
||||
Rule Haiti 2012 only - Nov Sun>=1 2:00 0 S
|
||||
Rule Haiti 2012 max - Mar Sun>=8 2:00 1:00 D
|
||||
Rule Haiti 2012 max - Nov Sun>=1 2:00 0 S
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Port-au-Prince -4:49:20 - LMT 1890
|
||||
-4:49 - PPMT 1917 Jan 24 12:00 # P-a-P MT
|
||||
|
@ -27,13 +27,17 @@
|
||||
|
||||
# This data is by no means authoritative; if you think you know better,
|
||||
# go ahead and edit the file (and please send any changes to
|
||||
# tz@elsie.nci.nih.gov for general use in the future).
|
||||
# tz@iana.org for general use in the future).
|
||||
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# A good source for time zone historical data outside the U.S. is
|
||||
# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
|
||||
# San Diego: ACS Publications, Inc. (2003).
|
||||
#
|
||||
# For data circa 1899, a common source is:
|
||||
# Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94
|
||||
# <http://www.jstor.org/stable/1774359>.
|
||||
#
|
||||
# Gwillim Law writes that a good source
|
||||
# for recent time zone data is the International Air Transport
|
||||
# Association's Standard Schedules Information Manual (IATA SSIM),
|
||||
@ -404,21 +408,11 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 S
|
||||
# <a/>
|
||||
# is the official page for the Province Government).
|
||||
#
|
||||
# There's also a note in only one of the major national papers (La Nación) at
|
||||
# <a href="http://www.lanacion.com.ar/nota.asp?nota_id=1107912">
|
||||
# There's also a note in only one of the major national papers ...
|
||||
# http://www.lanacion.com.ar/nota.asp?nota_id=1107912
|
||||
# </a>
|
||||
#
|
||||
# The press release says:
|
||||
# (...) anunció que el próximo domingo a las 00:00 los puntanos deberán
|
||||
# atrasar una hora sus relojes.
|
||||
#
|
||||
# A partir de entonces, San Luis establecerá el huso horario propio de
|
||||
# la Provincia. De esta manera, durante el periodo del calendario anual
|
||||
# 2009, el cambio horario quedará comprendido entre las 00:00 del tercer
|
||||
# domingo de marzo y las 24:00 del segundo sábado de octubre.
|
||||
# Quick&dirty translation
|
||||
# (...) announced that next Sunday, at 00:00, Puntanos (the San Luis
|
||||
# The press release says [quick and dirty translation]:
|
||||
# ... announced that next Sunday, at 00:00, Puntanos (the San Luis
|
||||
# inhabitants) will have to turn back one hour their clocks
|
||||
#
|
||||
# Since then, San Luis will establish its own Province timezone. Thus,
|
||||
@ -480,6 +474,9 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 S
|
||||
# rules...San Luis is still using "Western ARgentina Time" and it got
|
||||
# stuck on Summer daylight savings time even though the summer is over.
|
||||
|
||||
# From Paul Eggert (2013-02-21):
|
||||
# Milne says Cordoba time was -4:16:48.2. Round to the nearest second.
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
#
|
||||
# Buenos Aires (BA), Capital Federal (CF),
|
||||
@ -835,9 +832,9 @@ Zone America/La_Paz -4:32:36 - LMT 1890
|
||||
|
||||
# From Guilherme Bernardes Rodrigues (2011-10-07):
|
||||
# There is news in the media, however there is still no decree about it.
|
||||
# I just send a e-mail to Zulmira Brandão at
|
||||
# I just send a e-mail to Zulmira Brandao at
|
||||
# <a href="http://pcdsh01.on.br/">http://pcdsh01.on.br/</a> the
|
||||
# oficial agency about time in Brazil, and she confirmed that the old rule is
|
||||
# official agency about time in Brazil, and she confirmed that the old rule is
|
||||
# still in force.
|
||||
|
||||
# From Guilherme Bernardes Rodrigues (2011-10-14)
|
||||
@ -1266,9 +1263,13 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914
|
||||
# b. Saturday, September 1, 2012, clocks should go forward 60 minutes; that is,
|
||||
# at 23:59:59, instead of passing to 0:00, the time should be adjusted to be
|
||||
# 01:00 on September 2.
|
||||
#
|
||||
# Note that...this is yet another "temporary" change that will be reevaluated
|
||||
# AGAIN in 2013.
|
||||
|
||||
# From Steffen Thorsen (2013-02-15):
|
||||
# According to several news sources, Chile has extended DST this year,
|
||||
# they will end DST later and start DST earlier than planned. They
|
||||
# hope to save energy. The new end date is 2013-04-28 00:00 and new
|
||||
# start date is 2013-09-08 00:00....
|
||||
# http://www.gob.cl/informa/2013/02/15/gobierno-anuncia-fechas-de-cambio-de-hora-para-el-ano-2013.htm
|
||||
|
||||
# NOTE: ChileAQ rules for Antarctic bases are stored separately in the
|
||||
# 'antarctica' file.
|
||||
@ -1311,10 +1312,8 @@ Rule Chile 2009 only - Mar Sun>=9 3:00u 0 -
|
||||
Rule Chile 2010 only - Apr Sun>=1 3:00u 0 -
|
||||
Rule Chile 2011 only - May Sun>=2 3:00u 0 -
|
||||
Rule Chile 2011 only - Aug Sun>=16 4:00u 1:00 S
|
||||
Rule Chile 2012 only - Apr Sun>=23 3:00u 0 -
|
||||
Rule Chile 2012 only - Sep Sun>=2 4:00u 1:00 S
|
||||
Rule Chile 2013 max - Mar Sun>=9 3:00u 0 -
|
||||
Rule Chile 2013 max - Oct Sun>=9 4:00u 1:00 S
|
||||
Rule Chile 2012 max - Apr Sun>=23 3:00u 0 -
|
||||
Rule Chile 2012 max - Sep Sun>=2 4:00u 1:00 S
|
||||
# IATA SSIM anomalies: (1992-02) says 1992-03-14;
|
||||
# (1996-09) says 1998-03-08. Ignore these.
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
@ -1336,17 +1335,23 @@ Zone Pacific/Easter -7:17:44 - LMT 1890
|
||||
# San Felix, and Antarctic bases, are like America/Santiago.
|
||||
|
||||
# Colombia
|
||||
|
||||
# Milne gives 4:56:16.4 for Bogota time in 1899; round to nearest. He writes,
|
||||
# "A variation of fifteen minutes in the public clocks of Bogota is not rare."
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule CO 1992 only - May 3 0:00 1:00 S
|
||||
Rule CO 1993 only - Apr 4 0:00 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Bogota -4:56:20 - LMT 1884 Mar 13
|
||||
-4:56:20 - BMT 1914 Nov 23 # Bogota Mean Time
|
||||
Zone America/Bogota -4:56:16 - LMT 1884 Mar 13
|
||||
-4:56:16 - BMT 1914 Nov 23 # Bogota Mean Time
|
||||
-5:00 CO CO%sT # Colombia Time
|
||||
# Malpelo, Providencia, San Andres
|
||||
# no information; probably like America/Bogota
|
||||
|
||||
# Curacao
|
||||
|
||||
# Milne gives 4:35:46.9 for Curacao mean time; round to nearest.
|
||||
#
|
||||
# From Paul Eggert (2006-03-22):
|
||||
# Shanks & Pottenger say that The Bottom and Philipsburg have been at
|
||||
@ -1363,7 +1368,7 @@ Zone America/Bogota -4:56:20 - LMT 1884 Mar 13
|
||||
# though, as far as we know.
|
||||
#
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Curacao -4:35:44 - LMT 1912 Feb 12 # Willemstad
|
||||
Zone America/Curacao -4:35:47 - LMT 1912 Feb 12 # Willemstad
|
||||
-4:30 - ANT 1965 # Netherlands Antilles Time
|
||||
-4:00 - AST
|
||||
|
||||
@ -1377,6 +1382,8 @@ Link America/Curacao America/Kralendijk # Bonaire, Sint Estatius and Saba
|
||||
|
||||
# Ecuador
|
||||
#
|
||||
# Milne says the Sentral and South American Telegraph Company used -5:24:15.
|
||||
#
|
||||
# From Paul Eggert (2007-03-04):
|
||||
# Apparently Ecuador had a failed experiment with DST in 1992.
|
||||
# <http://midena.gov.ec/content/view/1261/208/> (2007-02-27) and
|
||||
@ -1582,7 +1589,16 @@ Rule Para 2005 2009 - Mar Sun>=8 0:00 0 -
|
||||
# forward 60 minutes, in all the territory of the Paraguayan Republic.
|
||||
# ...
|
||||
Rule Para 2010 max - Oct Sun>=1 0:00 1:00 S
|
||||
Rule Para 2010 max - Apr Sun>=8 0:00 0 -
|
||||
Rule Para 2010 2012 - Apr Sun>=8 0:00 0 -
|
||||
#
|
||||
# From Steffen Thorsen (2013-03-07):
|
||||
# Paraguay will end DST on 2013-03-24 00:00....
|
||||
# http://www.ande.gov.py/interna.php?id=1075
|
||||
#
|
||||
# From Carlos Raul Perasso (2013-03-15):
|
||||
# The change in Paraguay is now final. Decree number 10780
|
||||
# http://www.presidencia.gov.py/uploads/pdf/presidencia-3b86ff4b691c79d4f5927ca964922ec74772ce857c02ca054a52a37b49afc7fb.pdf
|
||||
Rule Para 2013 max - Mar Sun>=22 0:00 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone America/Asuncion -3:50:40 - LMT 1890
|
||||
|
@ -65,7 +65,6 @@ AQ -6617+11031 Antarctica/Casey Casey Station, Bailey Peninsula
|
||||
AQ -7824+10654 Antarctica/Vostok Vostok Station, Lake Vostok
|
||||
AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie
|
||||
AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I
|
||||
AQ -5430+15857 Antarctica/Macquarie Macquarie Island Station, Macquarie Island
|
||||
AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF)
|
||||
AR -3124-06411 America/Argentina/Cordoba most locations (CB, CC, CN, ER, FM, MN, SE, SF)
|
||||
AR -2447-06525 America/Argentina/Salta (SA, LP, NQ, RN)
|
||||
@ -81,6 +80,7 @@ AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF)
|
||||
AS -1416-17042 Pacific/Pago_Pago
|
||||
AT +4813+01620 Europe/Vienna
|
||||
AU -3133+15905 Australia/Lord_Howe Lord Howe Island
|
||||
AU -5430+15857 Antarctica/Macquarie Macquarie Island
|
||||
AU -4253+14719 Australia/Hobart Tasmania - most locations
|
||||
AU -3956+14352 Australia/Currie Tasmania - King Island
|
||||
AU -3749+14458 Australia/Melbourne Victoria
|
||||
@ -182,7 +182,8 @@ CW +1211-06900 America/Curacao
|
||||
CX -1025+10543 Indian/Christmas
|
||||
CY +3510+03322 Asia/Nicosia
|
||||
CZ +5005+01426 Europe/Prague
|
||||
DE +5230+01322 Europe/Berlin
|
||||
DE +5230+01322 Europe/Berlin most locations
|
||||
DE +4742+00841 Europe/Busingen Busingen
|
||||
DJ +1136+04309 Africa/Djibouti
|
||||
DK +5540+01235 Europe/Copenhagen
|
||||
DM +1518-06124 America/Dominica
|
||||
@ -364,8 +365,10 @@ RU +5345+08707 Asia/Novokuznetsk Moscow+03 - Novokuznetsk
|
||||
RU +5601+09250 Asia/Krasnoyarsk Moscow+04 - Yenisei River
|
||||
RU +5216+10420 Asia/Irkutsk Moscow+05 - Lake Baikal
|
||||
RU +6200+12940 Asia/Yakutsk Moscow+06 - Lena River
|
||||
RU +623923+1353314 Asia/Khandyga Moscow+06 - Tomponsky, Ust-Maysky
|
||||
RU +4310+13156 Asia/Vladivostok Moscow+07 - Amur River
|
||||
RU +4658+14242 Asia/Sakhalin Moscow+07 - Sakhalin Island
|
||||
RU +643337+1431336 Asia/Ust-Nera Moscow+07 - Oymyakonsky
|
||||
RU +5934+15048 Asia/Magadan Moscow+08 - Magadan
|
||||
RU +5301+15839 Asia/Kamchatka Moscow+08 - Kamchatka
|
||||
RU +6445+17729 Asia/Anadyr Moscow+08 - Bering Sea
|
||||
|
@ -87,9 +87,6 @@ build: $(FILES_genout_extcs) $(CHARSETS_JAR)
|
||||
#
|
||||
# Extra rules to build character converters.
|
||||
|
||||
SERVICE_DESCRIPTION = java.nio.charset.spi.CharsetProvider
|
||||
SERVICE_DESCRIPTION_PATH = META-INF/services/$(SERVICE_DESCRIPTION)
|
||||
|
||||
GENCSDATASRC = $(BUILDDIR)/tools/CharsetMapping
|
||||
GENCSSRCDIR = $(BUILDDIR)/tools/src/build/tools/charsetmapping
|
||||
GENCSEXT = $(GENSRCDIR)/sun/nio/cs/ext
|
||||
@ -118,10 +115,6 @@ $(FILES_genout_extcs): \
|
||||
$(GENCSSRCDIR)/HKSCS.java
|
||||
$(BOOT_JAVA_CMD) -jar $(CHARSETMAPPING_JARFILE) $(GENCSDATASRC) $(GENCSEXT) dbcs
|
||||
|
||||
$(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH): \
|
||||
$(SHARE_SRC)/classes/sun/nio/cs/ext/$(SERVICE_DESCRIPTION_PATH)
|
||||
$(install-file)
|
||||
|
||||
# no compression unless requested
|
||||
ifndef COMPRESS_JARS
|
||||
CREATE_JAR_OPTS_NOMANIFEST = cf0
|
||||
@ -129,10 +122,9 @@ else
|
||||
CREATE_JAR_OPTS_NOMANIFEST = cf
|
||||
endif
|
||||
|
||||
$(CHARSETS_JAR): $(FILES_class) $(CLASSDESTDIR)/$(SERVICE_DESCRIPTION_PATH) $(FILES_DAT)
|
||||
$(CHARSETS_JAR): $(FILES_class) $(FILES_DAT)
|
||||
$(BOOT_JAR_CMD) $(CREATE_JAR_OPTS_NOMANIFEST) $(CHARSETS_JAR) \
|
||||
-C $(CLASSDESTDIR) sun \
|
||||
-C $(CLASSDESTDIR) $(SERVICE_DESCRIPTION_PATH) \
|
||||
$(BOOT_JAR_JFLAGS)
|
||||
@$(java-vm-cleanup)
|
||||
|
||||
|
@ -34,6 +34,8 @@ import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
|
||||
|
||||
/**
|
||||
@ -234,6 +236,17 @@ public class CLDRConverter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the parser to allow access to DTDs on the file system.
|
||||
*/
|
||||
private static void enableFileAccess(SAXParser parser) throws SAXNotSupportedException {
|
||||
try {
|
||||
parser.setProperty("http://javax.xml.XMLConstants/property/accessExternalDTD", "file");
|
||||
} catch (SAXNotRecognizedException ignore) {
|
||||
// property requires >= JAXP 1.5
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Bundle> readBundleList() throws Exception {
|
||||
ResourceBundle.Control defCon = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
|
||||
List<Bundle> retList = new ArrayList<>();
|
||||
@ -279,6 +292,7 @@ public class CLDRConverter {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setValidating(true);
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
enableFileAccess(parser);
|
||||
LDMLParseHandler handler = new LDMLParseHandler(id);
|
||||
File file = new File(SOURCE_FILE_DIR + File.separator + id + ".xml");
|
||||
if (!file.exists()) {
|
||||
@ -314,6 +328,7 @@ public class CLDRConverter {
|
||||
SAXParserFactory factorySuppl = SAXParserFactory.newInstance();
|
||||
factorySuppl.setValidating(true);
|
||||
SAXParser parserSuppl = factorySuppl.newSAXParser();
|
||||
enableFileAccess(parserSuppl);
|
||||
handlerSuppl = new SupplementDataParseHandler();
|
||||
File fileSupply = new File(SPPL_SOURCE_FILE);
|
||||
parserSuppl.parse(fileSupply, handlerSuppl);
|
||||
@ -322,6 +337,7 @@ public class CLDRConverter {
|
||||
SAXParserFactory numberingParser = SAXParserFactory.newInstance();
|
||||
numberingParser.setValidating(true);
|
||||
SAXParser parserNumbering = numberingParser.newSAXParser();
|
||||
enableFileAccess(parserNumbering);
|
||||
handlerNumbering = new NumberingSystemsParseHandler();
|
||||
File fileNumbering = new File(NUMBERING_SOURCE_FILE);
|
||||
parserNumbering.parse(fileNumbering, handlerNumbering);
|
||||
@ -330,6 +346,7 @@ public class CLDRConverter {
|
||||
SAXParserFactory metazonesParser = SAXParserFactory.newInstance();
|
||||
metazonesParser.setValidating(true);
|
||||
SAXParser parserMetaZones = metazonesParser.newSAXParser();
|
||||
enableFileAccess(parserMetaZones);
|
||||
handlerMetaZones = new MetaZonesParseHandler();
|
||||
File fileMetaZones = new File(METAZONES_SOURCE_FILE);
|
||||
parserNumbering.parse(fileMetaZones, handlerMetaZones);
|
||||
|
@ -201,7 +201,6 @@ RT_JAR_EXCLUDES += \
|
||||
META-INF/services/com.sun.jdi.connect.spi.TransportService \
|
||||
META-INF/services/com.sun.tools.attach.spi.AttachProvider \
|
||||
META-INF/services/com.sun.tools.xjc.Plugin \
|
||||
META-INF/services/java.nio.charset.spi.CharsetProvider \
|
||||
META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor \
|
||||
org/relaxng/datatype \
|
||||
sun/awt/HKSCS.class \
|
||||
@ -428,8 +427,7 @@ $(eval $(call SetupArchive,BUILD_CHARSETS_JAR,,\
|
||||
SUFFIXES:=.class .dat,\
|
||||
INCLUDES:=sun/nio/cs/ext,\
|
||||
EXTRA_FILES := sun/awt/HKSCS.class \
|
||||
$(CHARSETS_EXTRA_FILES) \
|
||||
META-INF/services/java.nio.charset.spi.CharsetProvider, \
|
||||
$(CHARSETS_EXTRA_FILES), \
|
||||
JAR:=$(IMAGES_OUTPUTDIR)/lib/charsets.jar, \
|
||||
SKIP_METAINF := true, \
|
||||
CHECK_COMPRESS_JAR:=true))
|
||||
|
@ -29,7 +29,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
@ -1024,10 +1023,10 @@ public final class ProcessBuilder
|
||||
dir,
|
||||
redirects,
|
||||
redirectErrorStream);
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
String exceptionInfo = ": " + e.getMessage();
|
||||
Throwable cause = e;
|
||||
if (security != null) {
|
||||
if ((e instanceof IOException) && security != null) {
|
||||
// Can not disclose the fail reason for read-protected files.
|
||||
try {
|
||||
security.checkRead(prog);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2013, 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
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A thread-safe, mutable sequence of characters.
|
||||
@ -98,6 +99,12 @@ package java.lang;
|
||||
implements java.io.Serializable, CharSequence
|
||||
{
|
||||
|
||||
/**
|
||||
* A cache of the last value returned by toString. Cleared
|
||||
* whenever the StringBuffer is modified.
|
||||
*/
|
||||
private transient char[] toStringCache;
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
static final long serialVersionUID = 3388685877147921107L;
|
||||
|
||||
@ -183,6 +190,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized void setLength(int newLength) {
|
||||
toStringCache = null;
|
||||
super.setLength(newLength);
|
||||
}
|
||||
|
||||
@ -247,17 +255,20 @@ package java.lang;
|
||||
public synchronized void setCharAt(int index, char ch) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
toStringCache = null;
|
||||
value[index] = ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(Object obj) {
|
||||
toStringCache = null;
|
||||
super.append(String.valueOf(obj));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(String str) {
|
||||
toStringCache = null;
|
||||
super.append(str);
|
||||
return this;
|
||||
}
|
||||
@ -287,6 +298,7 @@ package java.lang;
|
||||
* @since 1.4
|
||||
*/
|
||||
public synchronized StringBuffer append(StringBuffer sb) {
|
||||
toStringCache = null;
|
||||
super.append(sb);
|
||||
return this;
|
||||
}
|
||||
@ -296,6 +308,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
synchronized StringBuffer append(AbstractStringBuilder asb) {
|
||||
toStringCache = null;
|
||||
super.append(asb);
|
||||
return this;
|
||||
}
|
||||
@ -325,6 +338,7 @@ package java.lang;
|
||||
public StringBuffer append(CharSequence s) {
|
||||
// Note, synchronization achieved via invocations of other StringBuffer methods after
|
||||
// narrowing of s to specific type
|
||||
// Ditto for toStringCache clearing
|
||||
super.append(s);
|
||||
return this;
|
||||
}
|
||||
@ -336,12 +350,14 @@ package java.lang;
|
||||
@Override
|
||||
public synchronized StringBuffer append(CharSequence s, int start, int end)
|
||||
{
|
||||
toStringCache = null;
|
||||
super.append(s, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(char[] str) {
|
||||
toStringCache = null;
|
||||
super.append(str);
|
||||
return this;
|
||||
}
|
||||
@ -351,24 +367,28 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer append(char[] str, int offset, int len) {
|
||||
toStringCache = null;
|
||||
super.append(str, offset, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(boolean b) {
|
||||
toStringCache = null;
|
||||
super.append(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(char c) {
|
||||
toStringCache = null;
|
||||
super.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(int i) {
|
||||
toStringCache = null;
|
||||
super.append(i);
|
||||
return this;
|
||||
}
|
||||
@ -378,24 +398,28 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer appendCodePoint(int codePoint) {
|
||||
toStringCache = null;
|
||||
super.appendCodePoint(codePoint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(long lng) {
|
||||
toStringCache = null;
|
||||
super.append(lng);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(float f) {
|
||||
toStringCache = null;
|
||||
super.append(f);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized StringBuffer append(double d) {
|
||||
toStringCache = null;
|
||||
super.append(d);
|
||||
return this;
|
||||
}
|
||||
@ -406,6 +430,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer delete(int start, int end) {
|
||||
toStringCache = null;
|
||||
super.delete(start, end);
|
||||
return this;
|
||||
}
|
||||
@ -416,6 +441,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer deleteCharAt(int index) {
|
||||
toStringCache = null;
|
||||
super.deleteCharAt(index);
|
||||
return this;
|
||||
}
|
||||
@ -426,6 +452,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer replace(int start, int end, String str) {
|
||||
toStringCache = null;
|
||||
super.replace(start, end, str);
|
||||
return this;
|
||||
}
|
||||
@ -465,6 +492,7 @@ package java.lang;
|
||||
public synchronized StringBuffer insert(int index, char[] str, int offset,
|
||||
int len)
|
||||
{
|
||||
toStringCache = null;
|
||||
super.insert(index, str, offset, len);
|
||||
return this;
|
||||
}
|
||||
@ -474,6 +502,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer insert(int offset, Object obj) {
|
||||
toStringCache = null;
|
||||
super.insert(offset, String.valueOf(obj));
|
||||
return this;
|
||||
}
|
||||
@ -483,6 +512,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer insert(int offset, String str) {
|
||||
toStringCache = null;
|
||||
super.insert(offset, str);
|
||||
return this;
|
||||
}
|
||||
@ -492,6 +522,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer insert(int offset, char[] str) {
|
||||
toStringCache = null;
|
||||
super.insert(offset, str);
|
||||
return this;
|
||||
}
|
||||
@ -504,6 +535,7 @@ package java.lang;
|
||||
public StringBuffer insert(int dstOffset, CharSequence s) {
|
||||
// Note, synchronization achieved via invocations of other StringBuffer methods
|
||||
// after narrowing of s to specific type
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(dstOffset, s);
|
||||
return this;
|
||||
}
|
||||
@ -516,6 +548,7 @@ package java.lang;
|
||||
public synchronized StringBuffer insert(int dstOffset, CharSequence s,
|
||||
int start, int end)
|
||||
{
|
||||
toStringCache = null;
|
||||
super.insert(dstOffset, s, start, end);
|
||||
return this;
|
||||
}
|
||||
@ -527,6 +560,7 @@ package java.lang;
|
||||
public StringBuffer insert(int offset, boolean b) {
|
||||
// Note, synchronization achieved via invocation of StringBuffer insert(int, String)
|
||||
// after conversion of b to String by super class method
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(offset, b);
|
||||
return this;
|
||||
}
|
||||
@ -536,6 +570,7 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer insert(int offset, char c) {
|
||||
toStringCache = null;
|
||||
super.insert(offset, c);
|
||||
return this;
|
||||
}
|
||||
@ -547,6 +582,7 @@ package java.lang;
|
||||
public StringBuffer insert(int offset, int i) {
|
||||
// Note, synchronization achieved via invocation of StringBuffer insert(int, String)
|
||||
// after conversion of i to String by super class method
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(offset, i);
|
||||
return this;
|
||||
}
|
||||
@ -558,6 +594,7 @@ package java.lang;
|
||||
public StringBuffer insert(int offset, long l) {
|
||||
// Note, synchronization achieved via invocation of StringBuffer insert(int, String)
|
||||
// after conversion of l to String by super class method
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(offset, l);
|
||||
return this;
|
||||
}
|
||||
@ -569,6 +606,7 @@ package java.lang;
|
||||
public StringBuffer insert(int offset, float f) {
|
||||
// Note, synchronization achieved via invocation of StringBuffer insert(int, String)
|
||||
// after conversion of f to String by super class method
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(offset, f);
|
||||
return this;
|
||||
}
|
||||
@ -580,6 +618,7 @@ package java.lang;
|
||||
public StringBuffer insert(int offset, double d) {
|
||||
// Note, synchronization achieved via invocation of StringBuffer insert(int, String)
|
||||
// after conversion of d to String by super class method
|
||||
// Ditto for toStringCache clearing
|
||||
super.insert(offset, d);
|
||||
return this;
|
||||
}
|
||||
@ -623,13 +662,17 @@ package java.lang;
|
||||
*/
|
||||
@Override
|
||||
public synchronized StringBuffer reverse() {
|
||||
toStringCache = null;
|
||||
super.reverse();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return new String(value, 0, count);
|
||||
if (toStringCache == null) {
|
||||
toStringCache = Arrays.copyOfRange(value, 0, count);
|
||||
}
|
||||
return new String(toStringCache, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,6 +50,18 @@ import java.util.Date;
|
||||
* <a href="doc-files/net-properties.html#Proxies">Proxy settings</a> as well as
|
||||
* <a href="doc-files/net-properties.html#MiscHTTP"> various other settings</a>.
|
||||
* </P>
|
||||
* <p>
|
||||
* <b>Security permissions</b>
|
||||
* <p>
|
||||
* If a security manager is installed, and if a method is called which results in an
|
||||
* attempt to open a connection, the caller must possess either:-
|
||||
* <ul><li>a "connect" {@link SocketPermission} to the host/port combination of the
|
||||
* destination URL or</li>
|
||||
* <li>a {@link HttpURLPermission} that permits this request.</li>
|
||||
* </ul><p>
|
||||
* If automatic redirection is enabled, and this request is redirected to another
|
||||
* destination, then the caller must also have permission to connect to the
|
||||
* redirected host/URL.
|
||||
*
|
||||
* @see java.net.HttpURLConnection#disconnect()
|
||||
* @since JDK1.1
|
||||
|
406
jdk/src/share/classes/java/net/HttpURLPermission.java
Normal file
406
jdk/src/share/classes/java/net/HttpURLPermission.java
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.net;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.security.Permission;
|
||||
|
||||
/**
|
||||
* Represents permission to access a resource or set of resources defined by a
|
||||
* given http or https url, and for a given set of user-settable request methods
|
||||
* and request headers. The <i>name</i> of the permission is the url string.
|
||||
* The <i>actions</i> string is a concatenation of the request methods and headers.
|
||||
* The range of method and header names is not restricted by this class.
|
||||
* <p><b>The url</b><p>
|
||||
* The url string is also used to instantiate a {@link URI} object which is
|
||||
* used for comparison with other HttpURLPermission instances. Therefore, any
|
||||
* references in this specification to url, mean this URI object.
|
||||
* The path component of the url comprises a sequence of path segments, separated
|
||||
* by '/' characters. The path is specified in a similar way to the path
|
||||
* in {@link java.io.FilePermission}. There are three different ways
|
||||
* as the following examples show:
|
||||
* <table border>
|
||||
* <tr><th>Example url</th><th>Description</th></tr>
|
||||
* <tr><td style="white-space:nowrap;">http://www.oracle.com/a/b/c.html</td>
|
||||
* <td>A url which identifies a specific (single) resource</td>
|
||||
* </tr>
|
||||
* <tr><td>http://www.oracle.com/a/b/*</td>
|
||||
* <td>The '*' character refers to all resources in the same "directory" - in
|
||||
* other words all resources with the same number of path components, and
|
||||
* which only differ in the final path component, represented by the '*'.
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr><td>http://www.oracle.com/a/b/-</li>
|
||||
* <td>The '-' character refers to all resources recursively below the
|
||||
* preceding path (eg. http://www.oracle.com/a/b/c/d/e.html matches this
|
||||
* example).
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* The '*' and '-' may only be specified in the final segment of a path and must be
|
||||
* the only character in that segment. Any query or fragment components of the
|
||||
* url are ignored when constructing HttpURLPermissions.
|
||||
* <p>
|
||||
* As a special case, urls of the form, "http:*" or "https:*" are accepted to
|
||||
* mean any url of the given scheme.
|
||||
* <p><b>The actions string</b><p>
|
||||
* The actions string of a HttpURLPermission is a concatenation of the <i>method list</i>
|
||||
* and the <i>request headers list</i>. These are lists of the permitted HTTP request
|
||||
* methods and permitted request headers of the permission (respectively). The two lists
|
||||
* are separated by a colon ':' character and elements of each list are comma separated.
|
||||
* Some examples are:
|
||||
* <pre>
|
||||
* "POST,GET,DELETE"
|
||||
* "GET:X-Foo-Request,X-Bar-Request"
|
||||
* "POST,GET:Header1,Header2"
|
||||
* </pre>
|
||||
* The first example specifies the methods: POST, GET and DELETE, but no request headers.
|
||||
* The second example specifies one request method and two headers. The third
|
||||
* example specifies two request methods, and two headers.
|
||||
* <p>
|
||||
* The colon separator need not be present if the request headers list is empty.
|
||||
* No white-space is permitted in the actions string. The action strings supplied to
|
||||
* the HttpURLPermission constructors are case-insensitive and are normalized by converting
|
||||
* method names to upper-case and header names to the form defines in RFC2616 (lower case
|
||||
* with initial letter of each word capitalized). Either list can contain a wild-card '*'
|
||||
* character which signifies all request methods or headers respectively.
|
||||
* <p>
|
||||
* Note. Depending on the context of use, some request methods and headers may be permitted
|
||||
* at all times, and others may not be permitted at any time. For example, the
|
||||
* HTTP protocol handler might disallow certain headers such as Content-Length
|
||||
* from being set by application code, regardless of whether the security policy
|
||||
* in force, permits it.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class HttpURLPermission extends Permission {
|
||||
|
||||
private static final long serialVersionUID = -2702463814894478682L;
|
||||
|
||||
private transient URI uri;
|
||||
private transient List<String> methods;
|
||||
private transient List<String> requestHeaders;
|
||||
|
||||
// serialized field
|
||||
private String actions;
|
||||
|
||||
/**
|
||||
* Creates a new HttpURLPermission from a url string and which permits the given
|
||||
* request methods and user-settable request headers.
|
||||
* The name of the permission is its url string. Only the scheme, authority
|
||||
* and path components of the url are used. Any fragment or query
|
||||
* components are ignored. The permissions action string is as specified above.
|
||||
*
|
||||
* @param url the url string
|
||||
*
|
||||
* @param actions the actions string
|
||||
*
|
||||
* @throws IllegalArgumentException if url does not result in a valid {@link URI},
|
||||
* its scheme is not http or https, or if actions contains white-space.
|
||||
*/
|
||||
public HttpURLPermission(String url, String actions) {
|
||||
super(url);
|
||||
init(actions);
|
||||
}
|
||||
|
||||
private void init(String actions) {
|
||||
URI uri = parseURI(getName());
|
||||
int colon = actions.indexOf(':');
|
||||
if (actions.lastIndexOf(':') != colon) {
|
||||
throw new IllegalArgumentException("invalid actions string");
|
||||
}
|
||||
|
||||
String methods, headers;
|
||||
if (colon == -1) {
|
||||
methods = actions;
|
||||
headers = "";
|
||||
} else {
|
||||
methods = actions.substring(0, colon);
|
||||
headers = actions.substring(colon+1);
|
||||
}
|
||||
|
||||
List<String> l = normalizeMethods(methods);
|
||||
Collections.sort(l);
|
||||
this.methods = Collections.unmodifiableList(l);
|
||||
|
||||
l = normalizeHeaders(headers);
|
||||
Collections.sort(l);
|
||||
this.requestHeaders = Collections.unmodifiableList(l);
|
||||
|
||||
this.actions = actions();
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HttpURLPermission with the given url string and unrestricted
|
||||
* methods and request headers by invoking the two argument
|
||||
* constructor as follows: HttpURLPermission(url, "*:*")
|
||||
*
|
||||
* @throws IllegalArgumentException if url does not result in a valid {@link URI}
|
||||
*/
|
||||
public HttpURLPermission(String url) {
|
||||
this(url, "*:*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized method list and request
|
||||
* header list, in the form:
|
||||
* <pre>
|
||||
* "method-names : header-names"
|
||||
* </pre>
|
||||
* <p>
|
||||
* where method-names is the list of methods separated by commas
|
||||
* and header-names is the list of permitted headers separated by commas.
|
||||
* There is no white space in the returned String. If header-names is empty
|
||||
* then the colon separator will not be present.
|
||||
*/
|
||||
public String getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this HttpURLPermission implies the given permission.
|
||||
* Specifically, the following checks are done as if in the
|
||||
* following sequence:
|
||||
* <p><ul>
|
||||
* <li>if 'p' is not an instance of HttpURLPermission return false</li>
|
||||
* <li>if any of p's methods are not in this's method list, and if
|
||||
* this's method list is not equal to "*", then return false.</li>
|
||||
* <li>if any of p's headers are not in this's request header list, and if
|
||||
* this's request header list is not equal to "*", then return false.</li>
|
||||
* <li>if this's url is equal to p's url , then return true</li>
|
||||
* <li>if this's url scheme is not equal to p's url scheme return false</li>
|
||||
* <li>if the scheme specific part of this's url is '*' return true</li>
|
||||
* <li>if this's url authority is not equal to p's url authority
|
||||
* return false</li>
|
||||
* <li>if the path or paths specified by p's url are contained in the
|
||||
* set of paths specified by this's url, then return true
|
||||
* <li>otherwise, return false</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* Some examples of how paths are matched are shown below:
|
||||
* <p>
|
||||
* <table border>
|
||||
* <tr><th>this's path</th><th>p's path</th><th>match</th></tr>
|
||||
* <tr><td>/a/b</td><td>/a/b</td><td>yes</td></tr>
|
||||
* <tr><td>/a/b/*</td><td>/a/b/c</td><td>yes</td></tr>
|
||||
* <tr><td>/a/b/*</td><td>/a/b/c/d</td><td>no</td></tr>
|
||||
* <tr><td>/a/b/-</td><td>/a/b/c/d</td><td>yes</td></tr>
|
||||
* <tr><td>/a/b/-</td><td>/a/b/c/d/e</td><td>yes</td></tr>
|
||||
* <tr><td>/a/b/-</td><td>/a/b/c/*</td><td>yes</td></tr>
|
||||
* <tr><td>/a/b/*</td><td>/a/b/c/-</td><td>no</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public boolean implies(Permission p) {
|
||||
if (! (p instanceof HttpURLPermission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpURLPermission that = (HttpURLPermission)p;
|
||||
|
||||
if (!this.methods.get(0).equals("*") &&
|
||||
Collections.indexOfSubList(this.methods, that.methods) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.requestHeaders.isEmpty() && !that.requestHeaders.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.requestHeaders.isEmpty() &&
|
||||
!this.requestHeaders.get(0).equals("*") &&
|
||||
Collections.indexOfSubList(this.requestHeaders,
|
||||
that.requestHeaders) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.uri.equals(that.uri)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.uri.getScheme().equals(that.uri.getScheme())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.uri.getSchemeSpecificPart().equals("*")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String thisAuthority = this.uri.getAuthority();
|
||||
|
||||
if (thisAuthority != null &&
|
||||
!thisAuthority.equals(that.uri.getAuthority())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String thispath = this.uri.getPath();
|
||||
String thatpath = that.uri.getPath();
|
||||
|
||||
if (thispath.endsWith("/-")) {
|
||||
String thisprefix = thispath.substring(0, thispath.length() - 1);
|
||||
return thatpath.startsWith(thisprefix);
|
||||
}
|
||||
|
||||
if (thispath.endsWith("/*")) {
|
||||
String thisprefix = thispath.substring(0, thispath.length() - 1);
|
||||
if (!thatpath.startsWith(thisprefix)) {
|
||||
return false;
|
||||
}
|
||||
String thatsuffix = thatpath.substring(thisprefix.length());
|
||||
// suffix must not contain '/' chars
|
||||
if (thatsuffix.indexOf('/') != -1) {
|
||||
return false;
|
||||
}
|
||||
if (thatsuffix.equals("-")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if, this.getActions().equals(p.getActions())
|
||||
* and p's url equals this's url. Returns false otherwise.
|
||||
*/
|
||||
public boolean equals(Object p) {
|
||||
if (!(p instanceof HttpURLPermission)) {
|
||||
return false;
|
||||
}
|
||||
HttpURLPermission that = (HttpURLPermission)p;
|
||||
return this.getActions().equals(that.getActions()) &&
|
||||
this.uri.equals(that.uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode calculated from the hashcode of the
|
||||
* actions String and the url
|
||||
*/
|
||||
public int hashCode() {
|
||||
return getActions().hashCode() + uri.hashCode();
|
||||
}
|
||||
|
||||
|
||||
private List<String> normalizeMethods(String methods) {
|
||||
List<String> l = new ArrayList<>();
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (int i=0; i<methods.length(); i++) {
|
||||
char c = methods.charAt(i);
|
||||
if (c == ',') {
|
||||
String s = b.toString();
|
||||
if (s.length() > 0)
|
||||
l.add(s);
|
||||
b = new StringBuilder();
|
||||
} else if (c == ' ' || c == '\t') {
|
||||
throw new IllegalArgumentException("white space not allowed");
|
||||
} else {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c += 'A' - 'a';
|
||||
}
|
||||
b.append(c);
|
||||
}
|
||||
}
|
||||
String s = b.toString();
|
||||
if (s.length() > 0)
|
||||
l.add(s);
|
||||
return l;
|
||||
}
|
||||
|
||||
private List<String> normalizeHeaders(String headers) {
|
||||
List<String> l = new ArrayList<>();
|
||||
StringBuilder b = new StringBuilder();
|
||||
boolean capitalizeNext = true;
|
||||
for (int i=0; i<headers.length(); i++) {
|
||||
char c = headers.charAt(i);
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
if (capitalizeNext) {
|
||||
c += 'A' - 'a';
|
||||
capitalizeNext = false;
|
||||
}
|
||||
b.append(c);
|
||||
} else if (c == ' ' || c == '\t') {
|
||||
throw new IllegalArgumentException("white space not allowed");
|
||||
} else if (c == '-') {
|
||||
capitalizeNext = true;
|
||||
b.append(c);
|
||||
} else if (c == ',') {
|
||||
String s = b.toString();
|
||||
if (s.length() > 0)
|
||||
l.add(s);
|
||||
b = new StringBuilder();
|
||||
capitalizeNext = true;
|
||||
} else {
|
||||
capitalizeNext = false;
|
||||
b.append(c);
|
||||
}
|
||||
}
|
||||
String s = b.toString();
|
||||
if (s.length() > 0)
|
||||
l.add(s);
|
||||
return l;
|
||||
}
|
||||
|
||||
private URI parseURI(String url) {
|
||||
URI u = URI.create(url);
|
||||
String scheme = u.getScheme();
|
||||
if (!(scheme.equalsIgnoreCase("http") ||
|
||||
scheme.equalsIgnoreCase("https"))) {
|
||||
throw new IllegalArgumentException ("unexpected URL scheme");
|
||||
}
|
||||
if (!u.getSchemeSpecificPart().equals("*")) {
|
||||
u = URI.create(scheme + "://" + u.getAuthority() + u.getPath());
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
private String actions() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (String s : methods) {
|
||||
b.append(s);
|
||||
}
|
||||
b.append(":");
|
||||
for (String s : requestHeaders) {
|
||||
b.append(s);
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
/**
|
||||
* restore the state of this object from stream
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream.GetField fields = s.readFields();
|
||||
String actions = (String)fields.get("actions", null);
|
||||
|
||||
init(actions);
|
||||
}
|
||||
}
|
@ -607,9 +607,9 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable SO_TIMEOUT with the specified timeout, in
|
||||
* milliseconds. With this option set to a non-zero timeout,
|
||||
* a call to accept() for this ServerSocket
|
||||
* Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} with the
|
||||
* specified timeout, in milliseconds. With this option set to a non-zero
|
||||
* timeout, a call to accept() for this ServerSocket
|
||||
* will block for only this amount of time. If the timeout expires,
|
||||
* a <B>java.net.SocketTimeoutException</B> is raised, though the
|
||||
* ServerSocket is still valid. The option <B>must</B> be enabled
|
||||
@ -629,9 +629,9 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve setting for SO_TIMEOUT. 0 returns implies that the
|
||||
* option is disabled (i.e., timeout of infinity).
|
||||
* @return the SO_TIMEOUT value
|
||||
* Retrieve setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
|
||||
* 0 returns implies that the option is disabled (i.e., timeout of infinity).
|
||||
* @return the {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} value
|
||||
* @exception IOException if an I/O error occurs
|
||||
* @since JDK1.1
|
||||
* @see #setSoTimeout(int)
|
||||
@ -649,7 +649,8 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the SO_REUSEADDR socket option.
|
||||
* Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
|
||||
* socket option.
|
||||
* <p>
|
||||
* When a TCP connection is closed the connection may remain
|
||||
* in a timeout state for a period of time after the connection
|
||||
@ -660,24 +661,23 @@ class ServerSocket implements java.io.Closeable {
|
||||
* <tt>SocketAddress</tt> if there is a connection in the
|
||||
* timeout state involving the socket address or port.
|
||||
* <p>
|
||||
* Enabling <tt>SO_REUSEADDR</tt> prior to binding the socket
|
||||
* using {@link #bind(SocketAddress)} allows the socket to be
|
||||
* bound even though a previous connection is in a timeout
|
||||
* state.
|
||||
* Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} prior to
|
||||
* binding the socket using {@link #bind(SocketAddress)} allows the socket
|
||||
* to be bound even though a previous connection is in a timeout state.
|
||||
* <p>
|
||||
* When a <tt>ServerSocket</tt> is created the initial setting
|
||||
* of <tt>SO_REUSEADDR</tt> is not defined. Applications can
|
||||
* use {@link #getReuseAddress()} to determine the initial
|
||||
* setting of <tt>SO_REUSEADDR</tt>.
|
||||
* of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is not defined.
|
||||
* Applications can use {@link #getReuseAddress()} to determine the initial
|
||||
* setting of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}.
|
||||
* <p>
|
||||
* The behaviour when <tt>SO_REUSEADDR</tt> is enabled or
|
||||
* disabled after a socket is bound (See {@link #isBound()})
|
||||
* The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
|
||||
* enabled or disabled after a socket is bound (See {@link #isBound()})
|
||||
* is not defined.
|
||||
*
|
||||
* @param on whether to enable or disable the socket option
|
||||
* @exception SocketException if an error occurs enabling or
|
||||
* disabling the <tt>SO_RESUEADDR</tt> socket option,
|
||||
* or the socket is closed.
|
||||
* disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
|
||||
* socket option, or the socket is closed.
|
||||
* @since 1.4
|
||||
* @see #getReuseAddress()
|
||||
* @see #bind(SocketAddress)
|
||||
@ -691,9 +691,10 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if SO_REUSEADDR is enabled.
|
||||
* Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled.
|
||||
* @return a <code>boolean</code> indicating whether or not
|
||||
* {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since 1.4
|
||||
@ -768,15 +769,16 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default proposed value for the SO_RCVBUF option for sockets
|
||||
* Sets a default proposed value for the
|
||||
* {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option for sockets
|
||||
* accepted from this <tt>ServerSocket</tt>. The value actually set
|
||||
* in the accepted socket must be determined by calling
|
||||
* {@link Socket#getReceiveBufferSize()} after the socket
|
||||
* is returned by {@link #accept()}.
|
||||
* <p>
|
||||
* The value of SO_RCVBUF is used both to set the size of the internal
|
||||
* socket receive buffer, and to set the size of the TCP receive window
|
||||
* that is advertized to the remote peer.
|
||||
* The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to
|
||||
* set the size of the internal socket receive buffer, and to set the size
|
||||
* of the TCP receive window that is advertized to the remote peer.
|
||||
* <p>
|
||||
* It is possible to change the value subsequently, by calling
|
||||
* {@link Socket#setReceiveBufferSize(int)}. However, if the application
|
||||
@ -812,15 +814,16 @@ class ServerSocket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the SO_RCVBUF option for this <tt>ServerSocket</tt>,
|
||||
* that is the proposed buffer size that will be used for Sockets accepted
|
||||
* from this <tt>ServerSocket</tt>.
|
||||
* Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
|
||||
* for this <tt>ServerSocket</tt>, that is the proposed buffer size that
|
||||
* will be used for Sockets accepted from this <tt>ServerSocket</tt>.
|
||||
*
|
||||
* <p>Note, the value actually set in the accepted socket is determined by
|
||||
* calling {@link Socket#getReceiveBufferSize()}.
|
||||
* @return the value of the SO_RCVBUF option for this <tt>Socket</tt>.
|
||||
* @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
|
||||
* option for this <tt>Socket</tt>.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @see #setReceiveBufferSize(int)
|
||||
* @since 1.4
|
||||
*/
|
||||
|
@ -924,7 +924,8 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
|
||||
* Enable/disable {@link SocketOptions#TCP_NODELAY TCP_NODELAY}
|
||||
* (disable/enable Nagle's algorithm).
|
||||
*
|
||||
* @param on <code>true</code> to enable TCP_NODELAY,
|
||||
* <code>false</code> to disable.
|
||||
@ -943,9 +944,10 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if TCP_NODELAY is enabled.
|
||||
* Tests if {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not TCP_NODELAY is enabled.
|
||||
* @return a <code>boolean</code> indicating whether or not
|
||||
* {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since JDK1.1
|
||||
@ -958,8 +960,9 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable SO_LINGER with the specified linger time in seconds.
|
||||
* The maximum timeout value is platform specific.
|
||||
* Enable/disable {@link SocketOptions#SO_LINGER SO_LINGER} with the
|
||||
* specified linger time in seconds. The maximum timeout value is platform
|
||||
* specific.
|
||||
*
|
||||
* The setting only affects socket close.
|
||||
*
|
||||
@ -987,12 +990,13 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns setting for SO_LINGER. -1 returns implies that the
|
||||
* Returns setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
|
||||
* -1 returns implies that the
|
||||
* option is disabled.
|
||||
*
|
||||
* The setting only affects socket close.
|
||||
*
|
||||
* @return the setting for SO_LINGER.
|
||||
* @return the setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since JDK1.1
|
||||
@ -1027,7 +1031,8 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable OOBINLINE (receipt of TCP urgent data)
|
||||
* Enable/disable {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}
|
||||
* (receipt of TCP urgent data)
|
||||
*
|
||||
* By default, this option is disabled and TCP urgent data received on a
|
||||
* socket is silently discarded. If the user wishes to receive urgent data, then
|
||||
@ -1039,8 +1044,9 @@ class Socket implements java.io.Closeable {
|
||||
* and there is no capability to distinguish between normal data and urgent
|
||||
* data unless provided by a higher level protocol.
|
||||
*
|
||||
* @param on <code>true</code> to enable OOBINLINE,
|
||||
* <code>false</code> to disable.
|
||||
* @param on <code>true</code> to enable
|
||||
* {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE},
|
||||
* <code>false</code> to disable.
|
||||
*
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
@ -1056,9 +1062,11 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if OOBINLINE is enabled.
|
||||
* Tests if {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not
|
||||
* {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not OOBINLINE is enabled.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since 1.4
|
||||
@ -1071,15 +1079,16 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable SO_TIMEOUT with the specified timeout, in
|
||||
* milliseconds. With this option set to a non-zero timeout,
|
||||
* a read() call on the InputStream associated with this Socket
|
||||
* will block for only this amount of time. If the timeout expires,
|
||||
* a <B>java.net.SocketTimeoutException</B> is raised, though the
|
||||
* Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
|
||||
* with the specified timeout, in milliseconds. With this option set
|
||||
* to a non-zero timeout, a read() call on the InputStream associated with
|
||||
* this Socket will block for only this amount of time. If the timeout
|
||||
* expires, a <B>java.net.SocketTimeoutException</B> is raised, though the
|
||||
* Socket is still valid. The option <B>must</B> be enabled
|
||||
* prior to entering the blocking operation to have effect. The
|
||||
* timeout must be > 0.
|
||||
* A timeout of zero is interpreted as an infinite timeout.
|
||||
*
|
||||
* @param timeout the specified timeout, in milliseconds.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
@ -1096,11 +1105,13 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns setting for SO_TIMEOUT. 0 returns implies that the
|
||||
* option is disabled (i.e., timeout of infinity).
|
||||
* @return the setting for SO_TIMEOUT
|
||||
* Returns setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
|
||||
* 0 returns implies that the option is disabled (i.e., timeout of infinity).
|
||||
*
|
||||
* @return the setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
*
|
||||
* @since JDK1.1
|
||||
* @see #setSoTimeout(int)
|
||||
*/
|
||||
@ -1117,14 +1128,15 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SO_SNDBUF option to the specified value for this
|
||||
* <tt>Socket</tt>. The SO_SNDBUF option is used by the platform's
|
||||
* networking code as a hint for the size to set
|
||||
* the underlying network I/O buffers.
|
||||
* Sets the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option to the
|
||||
* specified value for this <tt>Socket</tt>.
|
||||
* The {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option is used by the
|
||||
* platform's networking code as a hint for the size to set the underlying
|
||||
* network I/O buffers.
|
||||
*
|
||||
* <p>Because SO_SNDBUF is a hint, applications that want to
|
||||
* verify what size the buffers were set to should call
|
||||
* {@link #getSendBufferSize()}.
|
||||
* <p>Because {@link SocketOptions#SO_SNDBUF SO_SNDBUF} is a hint,
|
||||
* applications that want to verify what size the buffers were set to
|
||||
* should call {@link #getSendBufferSize()}.
|
||||
*
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
@ -1149,10 +1161,11 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of the SO_SNDBUF option for this <tt>Socket</tt>,
|
||||
* that is the buffer size used by the platform
|
||||
* Get value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option
|
||||
* for this <tt>Socket</tt>, that is the buffer size used by the platform
|
||||
* for output on this <tt>Socket</tt>.
|
||||
* @return the value of the SO_SNDBUF option for this <tt>Socket</tt>.
|
||||
* @return the value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF}
|
||||
* option for this <tt>Socket</tt>.
|
||||
*
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
@ -1172,25 +1185,26 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SO_RCVBUF option to the specified value for this
|
||||
* <tt>Socket</tt>. The SO_RCVBUF option is used by the platform's
|
||||
* networking code as a hint for the size to set
|
||||
* Sets the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option to the
|
||||
* specified value for this <tt>Socket</tt>. The
|
||||
* {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option is
|
||||
* used by the platform's networking code as a hint for the size to set
|
||||
* the underlying network I/O buffers.
|
||||
*
|
||||
* <p>Increasing the receive buffer size can increase the performance of
|
||||
* network I/O for high-volume connection, while decreasing it can
|
||||
* help reduce the backlog of incoming data.
|
||||
*
|
||||
* <p>Because SO_RCVBUF is a hint, applications that want to
|
||||
* verify what size the buffers were set to should call
|
||||
* {@link #getReceiveBufferSize()}.
|
||||
* <p>Because {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is a hint,
|
||||
* applications that want to verify what size the buffers were set to
|
||||
* should call {@link #getReceiveBufferSize()}.
|
||||
*
|
||||
* <p>The value of SO_RCVBUF is also used to set the TCP receive window
|
||||
* that is advertized to the remote peer. Generally, the window size
|
||||
* can be modified at any time when a socket is connected. However, if
|
||||
* a receive window larger than 64K is required then this must be requested
|
||||
* <B>before</B> the socket is connected to the remote peer. There are two
|
||||
* cases to be aware of:<p>
|
||||
* <p>The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used
|
||||
* to set the TCP receive window that is advertized to the remote peer.
|
||||
* Generally, the window size can be modified at any time when a socket is
|
||||
* connected. However, if a receive window larger than 64K is required then
|
||||
* this must be requested <B>before</B> the socket is connected to the
|
||||
* remote peer. There are two cases to be aware of:<p>
|
||||
* <ol>
|
||||
* <li>For sockets accepted from a ServerSocket, this must be done by calling
|
||||
* {@link ServerSocket#setReceiveBufferSize(int)} before the ServerSocket
|
||||
@ -1221,11 +1235,12 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the SO_RCVBUF option for this <tt>Socket</tt>,
|
||||
* that is the buffer size used by the platform for
|
||||
* input on this <tt>Socket</tt>.
|
||||
* Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
|
||||
* for this <tt>Socket</tt>, that is the buffer size used by the platform
|
||||
* for input on this <tt>Socket</tt>.
|
||||
*
|
||||
* @return the value of the SO_RCVBUF option for this <tt>Socket</tt>.
|
||||
* @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
|
||||
* option for this <tt>Socket</tt>.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @see #setReceiveBufferSize(int)
|
||||
@ -1244,9 +1259,9 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable SO_KEEPALIVE.
|
||||
* Enable/disable {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE}.
|
||||
*
|
||||
* @param on whether or not to have socket keep alive turned on.
|
||||
* @param on whether or not to have socket keep alive turned on.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since 1.3
|
||||
@ -1259,9 +1274,10 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if SO_KEEPALIVE is enabled.
|
||||
* Tests if {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not SO_KEEPALIVE is enabled.
|
||||
* @return a <code>boolean</code> indicating whether or not
|
||||
* {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since 1.3
|
||||
@ -1317,6 +1333,7 @@ class Socket implements java.io.Closeable {
|
||||
* traffic class or type-of-service
|
||||
* @since 1.4
|
||||
* @see #getTrafficClass
|
||||
* @see SocketOptions#IP_TOS
|
||||
*/
|
||||
public void setTrafficClass(int tc) throws SocketException {
|
||||
if (tc < 0 || tc > 255)
|
||||
@ -1341,13 +1358,15 @@ class Socket implements java.io.Closeable {
|
||||
* traffic class or type-of-service value.
|
||||
* @since 1.4
|
||||
* @see #setTrafficClass(int)
|
||||
* @see SocketOptions#IP_TOS
|
||||
*/
|
||||
public int getTrafficClass() throws SocketException {
|
||||
return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the SO_REUSEADDR socket option.
|
||||
* Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
|
||||
* socket option.
|
||||
* <p>
|
||||
* When a TCP connection is closed the connection may remain
|
||||
* in a timeout state for a period of time after the connection
|
||||
@ -1358,22 +1377,22 @@ class Socket implements java.io.Closeable {
|
||||
* <tt>SocketAddress</tt> if there is a connection in the
|
||||
* timeout state involving the socket address or port.
|
||||
* <p>
|
||||
* Enabling <tt>SO_REUSEADDR</tt> prior to binding the socket
|
||||
* using {@link #bind(SocketAddress)} allows the socket to be
|
||||
* bound even though a previous connection is in a timeout
|
||||
* Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
|
||||
* prior to binding the socket using {@link #bind(SocketAddress)} allows
|
||||
* the socket to be bound even though a previous connection is in a timeout
|
||||
* state.
|
||||
* <p>
|
||||
* When a <tt>Socket</tt> is created the initial setting
|
||||
* of <tt>SO_REUSEADDR</tt> is disabled.
|
||||
* of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is disabled.
|
||||
* <p>
|
||||
* The behaviour when <tt>SO_REUSEADDR</tt> is enabled or
|
||||
* disabled after a socket is bound (See {@link #isBound()})
|
||||
* The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
|
||||
* enabled or disabled after a socket is bound (See {@link #isBound()})
|
||||
* is not defined.
|
||||
*
|
||||
* @param on whether to enable or disable the socket option
|
||||
* @exception SocketException if an error occurs enabling or
|
||||
* disabling the <tt>SO_RESUEADDR</tt> socket option,
|
||||
* or the socket is closed.
|
||||
* disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
|
||||
* socket option, or the socket is closed.
|
||||
* @since 1.4
|
||||
* @see #getReuseAddress()
|
||||
* @see #bind(SocketAddress)
|
||||
@ -1387,9 +1406,10 @@ class Socket implements java.io.Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if SO_REUSEADDR is enabled.
|
||||
* Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled.
|
||||
* @return a <code>boolean</code> indicating whether or not
|
||||
* {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
|
||||
* @exception SocketException if there is an error
|
||||
* in the underlying protocol, such as a TCP error.
|
||||
* @since 1.4
|
||||
|
@ -427,46 +427,38 @@ public abstract class Charset
|
||||
}
|
||||
|
||||
/* The extended set of charsets */
|
||||
private static Object extendedProviderLock = new Object();
|
||||
private static boolean extendedProviderProbed = false;
|
||||
private static CharsetProvider extendedProvider = null;
|
||||
|
||||
private static void probeExtendedProvider() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
try {
|
||||
Class<?> epc
|
||||
= Class.forName("sun.nio.cs.ext.ExtendedCharsets");
|
||||
extendedProvider = (CharsetProvider)epc.newInstance();
|
||||
} catch (ClassNotFoundException x) {
|
||||
// Extended charsets not available
|
||||
// (charsets.jar not present)
|
||||
} catch (InstantiationException x) {
|
||||
throw new Error(x);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
private static class ExtendedProviderHolder {
|
||||
static final CharsetProvider extendedProvider = extendedProvider();
|
||||
// returns ExtendedProvider, if installed
|
||||
private static CharsetProvider extendedProvider() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<CharsetProvider>() {
|
||||
public CharsetProvider run() {
|
||||
try {
|
||||
Class<?> epc
|
||||
= Class.forName("sun.nio.cs.ext.ExtendedCharsets");
|
||||
return (CharsetProvider)epc.newInstance();
|
||||
} catch (ClassNotFoundException x) {
|
||||
// Extended charsets not available
|
||||
// (charsets.jar not present)
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Charset lookupExtendedCharset(String charsetName) {
|
||||
CharsetProvider ecp = null;
|
||||
synchronized (extendedProviderLock) {
|
||||
if (!extendedProviderProbed) {
|
||||
probeExtendedProvider();
|
||||
extendedProviderProbed = true;
|
||||
}
|
||||
ecp = extendedProvider;
|
||||
}
|
||||
CharsetProvider ecp = ExtendedProviderHolder.extendedProvider;
|
||||
return (ecp != null) ? ecp.charsetForName(charsetName) : null;
|
||||
}
|
||||
|
||||
private static Charset lookup(String charsetName) {
|
||||
if (charsetName == null)
|
||||
throw new IllegalArgumentException("Null charset name");
|
||||
|
||||
Object[] a;
|
||||
if ((a = cache1) != null && charsetName.equals(a[0]))
|
||||
return (Charset)a[1];
|
||||
@ -483,7 +475,6 @@ public abstract class Charset
|
||||
cache1 = a;
|
||||
return (Charset)a[1];
|
||||
}
|
||||
|
||||
Charset cs;
|
||||
if ((cs = standardProvider.charsetForName(charsetName)) != null ||
|
||||
(cs = lookupExtendedCharset(charsetName)) != null ||
|
||||
@ -589,6 +580,9 @@ public abstract class Charset
|
||||
new TreeMap<String,Charset>(
|
||||
ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
|
||||
put(standardProvider.charsets(), m);
|
||||
CharsetProvider ecp = ExtendedProviderHolder.extendedProvider;
|
||||
if (ecp != null)
|
||||
put(ecp.charsets(), m);
|
||||
for (Iterator<CharsetProvider> i = providers(); i.hasNext();) {
|
||||
CharsetProvider cp = i.next();
|
||||
put(cp.charsets(), m);
|
||||
|
@ -103,7 +103,7 @@ import java.util.TimeZone;
|
||||
* system clock This may use {@link System#currentTimeMillis()}, or a higher
|
||||
* resolution clock if one is available.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This abstract class must be implemented with care to ensure other operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* <p>
|
||||
@ -112,13 +112,23 @@ import java.util.TimeZone;
|
||||
* obtain the time from a central time server across the network. Obviously, in this case the
|
||||
* lookup could fail, and so the method is permitted to throw an exception.
|
||||
* <p>
|
||||
* The returned instants from {@code Clock} work on a time-scale that ignores leap seconds.
|
||||
* If the implementation wraps a source that provides leap second information, then a mechanism
|
||||
* should be used to "smooth" the leap second, such as UTC-SLS.
|
||||
* The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,
|
||||
* as described in {@link Instant}. If the implementation wraps a source that provides leap
|
||||
* second information, then a mechanism should be used to "smooth" the leap second.
|
||||
* The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose
|
||||
* how accurate they are with the time-scale so long as they document how they work.
|
||||
* Implementations are therefore not required to actually perform the UTC-SLS slew or to
|
||||
* otherwise be aware of leap seconds.
|
||||
* <p>
|
||||
* Implementations should implement {@code Serializable} wherever possible and must
|
||||
* document whether or not they do support serialization.
|
||||
*
|
||||
* @implNote
|
||||
* The clock implementation provided here is based on {@link System#currentTimeMillis()}.
|
||||
* That method provides little to no guarantee about the accuracy of the clock.
|
||||
* Applications requiring a more accurate clock must implement this abstract class
|
||||
* themselves using a different external clock, such as an NTP server.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public abstract class Clock {
|
||||
@ -370,7 +380,7 @@ public abstract class Clock {
|
||||
/**
|
||||
* Gets the current millisecond instant of the clock.
|
||||
* <p>
|
||||
* This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC.
|
||||
* This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).
|
||||
* This is equivalent to the definition of {@link System#currentTimeMillis()}.
|
||||
* <p>
|
||||
* Most applications should avoid this method and use {@link Instant} to represent
|
||||
@ -381,7 +391,7 @@ public abstract class Clock {
|
||||
* The default implementation currently calls {@link #instant}.
|
||||
*
|
||||
* @return the current millisecond instant from this clock, measured from
|
||||
* the Java epoch of 1970-01-01T00:00 UTC, not null
|
||||
* the Java epoch of 1970-01-01T00:00Z (UTC), not null
|
||||
* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
|
||||
*/
|
||||
public long millis() {
|
||||
|
@ -67,7 +67,7 @@ package java.time;
|
||||
* This exception is used to indicate problems with creating, querying
|
||||
* and manipulating date-time objects.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is intended for use in a single thread.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -100,7 +100,7 @@ import java.util.Locale;
|
||||
* As such, this enum may be used by any calendar system that has the day-of-week
|
||||
* concept defined exactly equivalent to the ISO calendar system.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -118,7 +118,7 @@ import java.util.regex.Pattern;
|
||||
* most applications.
|
||||
* See {@link Instant} for a discussion as to the meaning of the second and time-scales.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -142,47 +142,60 @@ import java.util.Objects;
|
||||
* introduce other changes.
|
||||
* <p>
|
||||
* Given the complexity of accurate timekeeping described above, this Java API defines
|
||||
* its own time-scale with a simplification. The Java time-scale is defined as follows:
|
||||
* its own time-scale, the <i>Java Time-Scale</i>.
|
||||
* <p>
|
||||
* The Java Time-Scale divides each calendar day into exactly 86400
|
||||
* subdivisions, known as seconds. These seconds may differ from the
|
||||
* SI second. It closely matches the de facto international civil time
|
||||
* scale, the definition of which changes from time to time.
|
||||
* <p>
|
||||
* The Java Time-Scale has slightly different definitions for different
|
||||
* segments of the time-line, each based on the consensus international
|
||||
* time scale that is used as the basis for civil time. Whenever the
|
||||
* internationally-agreed time scale is modified or replaced, a new
|
||||
* segment of the Java Time-Scale must be defined for it. Each segment
|
||||
* must meet these requirements:
|
||||
* <p><ul>
|
||||
* <li>midday will always be exactly as defined by the agreed international civil time</li>
|
||||
* <li>other times during the day will be broadly in line with the agreed international civil time</li>
|
||||
* <li>the day will be divided into exactly 86400 subdivisions, referred to as "seconds"</li>
|
||||
* <li>the Java "second" may differ from an SI second</li>
|
||||
* <li>a well-defined algorithm must be specified to map each second in the accurate agreed
|
||||
* international civil time to each "second" in this time-scale</li>
|
||||
* <li>the Java Time-Scale shall closely match the underlying international
|
||||
* civil time scale;</li>
|
||||
* <li>the Java Time-Scale shall exactly match the international civil
|
||||
* time scale at noon each day;</li>
|
||||
* <li>the Java Time-Scale shall have a precisely-defined relationship to
|
||||
* the international civil time scale.</li>
|
||||
* </ul><p>
|
||||
* Agreed international civil time is the base time-scale agreed by international convention,
|
||||
* which in 2012 is UTC (with leap-seconds).
|
||||
* There are currently, as of 2013, two segments in the Java time-scale.
|
||||
* <p>
|
||||
* In 2012, the definition of the Java time-scale is the same as UTC for all days except
|
||||
* those where a leap-second occurs. On days where a leap-second does occur, the time-scale
|
||||
* effectively eliminates the leap-second, maintaining the fiction of 86400 seconds in the day.
|
||||
* The approved well-defined algorithm to eliminate leap-seconds is specified as
|
||||
* For the segment from 1972-11-03 (exact boundary discussed below) until
|
||||
* further notice, the consensus international time scale is UTC (with
|
||||
* leap seconds). In this segment, the Java Time-Scale is identical to
|
||||
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>.
|
||||
* This is identical to UTC on days that do not have a leap second.
|
||||
* On days that do have a leap second, the leap second is spread equally
|
||||
* over the last 1000 seconds of the day, maintaining the appearance of
|
||||
* exactly 86400 seconds per day.
|
||||
* <p>
|
||||
* UTC-SLS is a simple algorithm that smoothes the leap-second over the last 1000 seconds of
|
||||
* the day, making each of the last 1000 seconds 1/1000th longer or shorter than an SI second.
|
||||
* Implementations built on an accurate leap-second aware time source should use UTC-SLS.
|
||||
* Use of a different algorithm risks confusion and misinterpretation of instants around a
|
||||
* leap-second and is discouraged.
|
||||
* For the segment prior to 1972-11-03, extending back arbitrarily far,
|
||||
* the consensus international time scale is defined to be UT1, applied
|
||||
* proleptically, which is equivalent to the (mean) solar time on the
|
||||
* prime meridian (Greenwich). In this segment, the Java Time-Scale is
|
||||
* identical to the consensus international time scale. The exact
|
||||
* boundary between the two segments is the instant where UT1 = UTC
|
||||
* between 1972-11-03T00:00 and 1972-11-04T12:00.
|
||||
* <p>
|
||||
* The main benefit of always dividing the day into 86400 subdivisions is that it matches the
|
||||
* expectations of most users of the API. The alternative is to force every user to understand
|
||||
* what a leap second is and to force them to have special logic to handle them.
|
||||
* Most applications do not have access to a clock that is accurate enough to record leap-seconds.
|
||||
* Most applications also do not have a problem with a second being a very small amount longer or
|
||||
* shorter than a real SI second during a leap-second.
|
||||
* <p>
|
||||
* One final problem is the definition of the agreed international civil time before the
|
||||
* introduction of modern UTC in 1972. This includes the Java epoch of {@code 1970-01-01}.
|
||||
* It is intended that instants before 1972 be interpreted based on the solar day divided
|
||||
* into 86400 subdivisions, as per the principles of UT1.
|
||||
* Implementations of the Java time-scale using the JSR-310 API are not
|
||||
* required to provide any clock that is sub-second accurate, or that
|
||||
* progresses monotonically or smoothly. Implementations are therefore
|
||||
* not required to actually perform the UTC-SLS slew or to otherwise be
|
||||
* aware of leap seconds. JSR-310 does, however, require that
|
||||
* implementations must document the approach they use when defining a
|
||||
* clock representing the current instant.
|
||||
* See {@link Clock} for details on the available clocks.
|
||||
* <p>
|
||||
* The Java time-scale is used for all date-time classes.
|
||||
* This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
|
||||
* {@code ZonedDateTime} and {@code Duration}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -1030,16 +1043,16 @@ public final class Instant
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this instant and another instant in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another instant in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two instants in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code Instant}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified instant.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two instants.
|
||||
* The {@code Temporal} passed to this method must be an {@code Instant}.
|
||||
* For example, the period in days between two dates can be calculated
|
||||
* For example, the amount in days between two dates can be calculated
|
||||
* using {@code startInstant.periodUntil(endInstant, SECONDS)}.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -1064,10 +1077,10 @@ public final class Instant
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endInstant the end date, which must be a {@code LocalDate}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date and the end date
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param endInstant the end date, which must be an {@code Instant}, not null
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this instant and the end instant
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1075,7 +1088,7 @@ public final class Instant
|
||||
public long periodUntil(Temporal endInstant, TemporalUnit unit) {
|
||||
if (endInstant instanceof Instant == false) {
|
||||
Objects.requireNonNull(endInstant, "endInstant");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
Instant end = (Instant) endInstant;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -121,7 +121,7 @@ import java.util.Objects;
|
||||
* However, any application that makes use of historical dates, and requires them
|
||||
* to be accurate will find the ISO-8601 approach unsuitable.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -1489,19 +1489,19 @@ public final class LocalDate
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this date and another date in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another date in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two dates in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code LocalDate}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a {@code LocalDate}.
|
||||
* For example, the period in days between two dates can be calculated
|
||||
* For example, the amount in days between two dates can be calculated
|
||||
* using {@code startDate.periodUntil(endDate, DAYS)}.
|
||||
* <p>
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two dates.
|
||||
* For example, the period in months between 2012-06-15 and 2012-08-14
|
||||
* For example, the amount in months between 2012-06-15 and 2012-08-14
|
||||
* will only be one month as it is one day short of two months.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -1527,9 +1527,9 @@ public final class LocalDate
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endDate the end date, which must be a {@code LocalDate}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date and the end date
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date and the end date
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1538,7 +1538,7 @@ public final class LocalDate
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
if (endDate instanceof LocalDate == false) {
|
||||
Objects.requireNonNull(endDate, "endDate");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
LocalDate end = (LocalDate) endDate;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -119,7 +119,7 @@ import java.util.Objects;
|
||||
* However, any application that makes use of historical dates, and requires them
|
||||
* to be accurate will find the ISO-8601 approach unsuitable.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -1562,19 +1562,19 @@ public final class LocalDateTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this date-time and another date-time in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another date-time in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two date-times in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code LocalDateTime}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date-time.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
|
||||
* For example, the period in days between two date-times can be calculated
|
||||
* For example, the amount in days between two date-times can be calculated
|
||||
* using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
|
||||
* <p>
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two date-times.
|
||||
* For example, the period in months between 2012-06-15T00:00 and 2012-08-14T23:59
|
||||
* For example, the amount in months between 2012-06-15T00:00 and 2012-08-14T23:59
|
||||
* will only be one month as it is one minute short of two months.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -1602,9 +1602,9 @@ public final class LocalDateTime
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date-time and the end date-time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date-time and the end date-time
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1612,7 +1612,7 @@ public final class LocalDateTime
|
||||
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
|
||||
if (endDateTime instanceof LocalDateTime == false) {
|
||||
Objects.requireNonNull(endDateTime, "endDateTime");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
LocalDateTime end = (LocalDateTime) endDateTime;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -109,7 +109,7 @@ import java.util.Objects;
|
||||
* in most of the world. This API assumes that all calendar systems use the same
|
||||
* representation, this class, for time-of-day.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -974,9 +974,6 @@ public final class LocalTime
|
||||
* Returns a {@code LocalTime} with the specified number of half-days added.
|
||||
* This is equivalent to {@link #plusHours(long)} with the amount
|
||||
* multiplied by 12.
|
||||
* <li>{@code DAYS} -
|
||||
* Returns a {@code LocalTime} with the specified number of days added.
|
||||
* This returns {@code this} time.
|
||||
* </ul>
|
||||
* <p>
|
||||
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
@ -1007,7 +1004,6 @@ public final class LocalTime
|
||||
case MINUTES: return plusMinutes(amountToAdd);
|
||||
case HOURS: return plusHours(amountToAdd);
|
||||
case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
|
||||
case DAYS: return this;
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
@ -1291,19 +1287,19 @@ public final class LocalTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this time and another time in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another time in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two times in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code LocalTime}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified time.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a {@code LocalTime}.
|
||||
* For example, the period in hours between two times can be calculated
|
||||
* For example, the amount in hours between two times can be calculated
|
||||
* using {@code startTime.periodUntil(endTime, HOURS)}.
|
||||
* <p>
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two times.
|
||||
* For example, the period in hours between 11:30 and 13:29 will only
|
||||
* For example, the amount in hours between 11:30 and 13:29 will only
|
||||
* be one hour as it is one minute short of two hours.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -1329,9 +1325,9 @@ public final class LocalTime
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endTime the end time, which must be a {@code LocalTime}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this time and the end time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this time and the end time
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1339,7 +1335,7 @@ public final class LocalTime
|
||||
public long periodUntil(Temporal endTime, TemporalUnit unit) {
|
||||
if (endTime instanceof LocalTime == false) {
|
||||
Objects.requireNonNull(endTime, "endTime");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
LocalTime end = (LocalTime) endTime;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -97,7 +97,7 @@ import java.util.Locale;
|
||||
* As such, this enum may be used by any calendar system that has the month-of-year
|
||||
* concept defined exactly equivalent to the ISO-8601 calendar system.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -111,7 +111,7 @@ import java.util.Objects;
|
||||
* However, any application that makes use of historical dates, and requires them
|
||||
* to be accurate will find the ISO-8601 approach unsuitable.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -111,7 +111,7 @@ import java.util.Objects;
|
||||
* in simpler applications. This class may be used when modeling date-time concepts in
|
||||
* more detail, or when communicating to a database or in a network protocol.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -1521,10 +1521,10 @@ public final class OffsetDateTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this date-time and another date-time in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another date-time in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two date-times in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code OffsetDateTime}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date-time.
|
||||
* The result will be negative if the end is before the start.
|
||||
* For example, the period in days between two date-times can be calculated
|
||||
@ -1564,9 +1564,9 @@ public final class OffsetDateTime
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date-time and the end date-time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date-time and the end date-time
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1574,7 +1574,7 @@ public final class OffsetDateTime
|
||||
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
|
||||
if (endDateTime instanceof OffsetDateTime == false) {
|
||||
Objects.requireNonNull(endDateTime, "endDateTime");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
OffsetDateTime end = (OffsetDateTime) endDateTime;
|
||||
|
@ -102,7 +102,7 @@ import java.util.Objects;
|
||||
* For example, the value "13:45.30.123456789+02:00" can be stored
|
||||
* in an {@code OffsetTime}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -1077,10 +1077,10 @@ public final class OffsetTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this time and another time in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another time in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two times in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code OffsetTime}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified time.
|
||||
* The result will be negative if the end is before the start.
|
||||
* For example, the period in hours between two times can be calculated
|
||||
@ -1118,9 +1118,9 @@ public final class OffsetTime
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endTime the end time, which must be an {@code OffsetTime}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this time and the end time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this time and the end time
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -1128,7 +1128,7 @@ public final class OffsetTime
|
||||
public long periodUntil(Temporal endTime, TemporalUnit unit) {
|
||||
if (endTime instanceof OffsetTime == false) {
|
||||
Objects.requireNonNull(endTime, "endTime");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
OffsetTime end = (OffsetTime) endTime;
|
||||
|
@ -119,7 +119,7 @@ import java.util.regex.Pattern;
|
||||
* The months and years fields may be {@linkplain #normalized() normalized}.
|
||||
* The normalization assumes a 12 month year, so is not appropriate for all calendar systems.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -66,7 +66,7 @@ import java.io.StreamCorruptedException;
|
||||
/**
|
||||
* The shared serialization delegate for this package.
|
||||
*
|
||||
* <h3>Implementation notes</h3>
|
||||
* @implNote
|
||||
* This class wraps the object being serialized, and takes a byte representing the type of the class to
|
||||
* be serialized. This byte can also be used for versioning the serialization format. In this case another
|
||||
* byte flag would be used in order to specify an alternative version of the type format.
|
||||
|
@ -115,7 +115,7 @@ import java.util.Objects;
|
||||
* However, any application that makes use of historical dates, and requires them
|
||||
* to be accurate will find the ISO-8601 approach unsuitable.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -813,10 +813,10 @@ public final class Year
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this year and another year in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another year in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two years in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code Year}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified year.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a {@code Year}.
|
||||
@ -851,9 +851,9 @@ public final class Year
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endYear the end year, which must be a {@code Year}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this year and the end year
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this year and the end year
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -861,7 +861,7 @@ public final class Year
|
||||
public long periodUntil(Temporal endYear, TemporalUnit unit) {
|
||||
if (endYear instanceof Year == false) {
|
||||
Objects.requireNonNull(endYear, "endYear");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
Year end = (Year) endYear;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -110,7 +110,7 @@ import java.util.Objects;
|
||||
* However, any application that makes use of historical dates, and requires them
|
||||
* to be accurate will find the ISO-8601 approach unsuitable.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -944,10 +944,10 @@ public final class YearMonth
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this year-month and another year-month in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another year-month in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two year-months in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code YearMonth}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified year-month.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a {@code YearMonth}.
|
||||
@ -982,9 +982,9 @@ public final class YearMonth
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this year-month and the end year-month
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this year-month and the end year-month
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -992,7 +992,7 @@ public final class YearMonth
|
||||
public long periodUntil(Temporal endYearMonth, TemporalUnit unit) {
|
||||
if (endYearMonth instanceof YearMonth == false) {
|
||||
Objects.requireNonNull(endYearMonth, "endYearMonth");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
YearMonth end = (YearMonth) endYearMonth;
|
||||
if (unit instanceof ChronoUnit) {
|
||||
|
@ -157,7 +157,7 @@ import java.util.TimeZone;
|
||||
* This approach is designed to allow a {@link ZonedDateTime} to be loaded and
|
||||
* queried, but not modified, on a Java Runtime with incomplete time-zone information.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This abstract class has two implementations, both of which are immutable and thread-safe.
|
||||
* One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
|
||||
* offset-based IDs. This difference is visible in serialization.
|
||||
|
@ -114,7 +114,7 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* Implementations may choose to cache certain common offsets, however
|
||||
* applications must not rely on such caching.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -83,7 +83,7 @@ import java.util.regex.Pattern;
|
||||
* By contrast, the region identifier is well-defined and long-lived.
|
||||
* This separation also allows rules to be shared between regions if appropriate.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -142,7 +142,7 @@ import java.util.Objects;
|
||||
* a vital, but secondary, piece of information, used to ensure that the class
|
||||
* represents an instant, especially during a daylight savings overlap.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* A {@code ZonedDateTime} holds state equivalent to three separate objects,
|
||||
* a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
|
||||
* The offset and local date-time are used to define an instant when necessary.
|
||||
@ -1983,10 +1983,10 @@ public final class ZonedDateTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this date-time and another date-time in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another date-time in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two date-times in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code ZonedDateTime}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date-time.
|
||||
* The result will be negative if the end is before the start.
|
||||
* For example, the period in days between two date-times can be calculated
|
||||
@ -2040,9 +2040,9 @@ public final class ZonedDateTime
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date-time and the end date-time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date-time and the end date-time
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@ -2050,7 +2050,7 @@ public final class ZonedDateTime
|
||||
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
|
||||
if (endDateTime instanceof ZonedDateTime == false) {
|
||||
Objects.requireNonNull(endDateTime, "endDateTime");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
ZonedDateTime end = (ZonedDateTime) endDateTime;
|
||||
|
@ -130,7 +130,7 @@ import java.util.Objects;
|
||||
* The subclass must function according to the {@code Chronology} class description and must provide its
|
||||
* {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This abstract class must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
@ -325,11 +325,11 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
|
||||
Objects.requireNonNull(endDateTime, "endDateTime");
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
if (endDateTime instanceof ChronoLocalDate == false) {
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
|
||||
if (getChronology().equals(end.getChronology()) == false) {
|
||||
throw new DateTimeException("Unable to calculate period between two different chronologies");
|
||||
throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
switch ((ChronoUnit) unit) {
|
||||
|
@ -234,7 +234,7 @@ import java.util.Objects;
|
||||
* Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal}
|
||||
* if read-write access is required.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
@ -257,6 +257,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the position of the date on the local time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-day.
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
*
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
@ -510,17 +511,17 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the period between this date and another date in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another date in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two dates in terms of a single unit.
|
||||
* This calculates the amount of time between two {@code ChronoLocalDate}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method must be a
|
||||
* {@code ChronoLocalDate} in the same chronology.
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two dates.
|
||||
* For example, the period in days between two dates can be calculated
|
||||
* For example, the amount in days between two dates can be calculated
|
||||
* using {@code startDate.periodUntil(endDate, DAYS)}.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -548,9 +549,9 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
|
||||
*
|
||||
* @param endDate the end date, which must be a {@code ChronoLocalDate}
|
||||
* in the same chronology, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date and the end date
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date and the end date
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
|
@ -106,7 +106,7 @@ import java.util.Objects;
|
||||
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
|
||||
* before using this interface.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
@ -127,6 +127,8 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
|
||||
* on the position of the date-time on the local time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-day and nano-of-day.
|
||||
*
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
*
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
* @see #isEqual
|
||||
|
@ -92,7 +92,7 @@ import java.util.Objects;
|
||||
* It does not store or represent a time-zone. For example, the value
|
||||
* "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
@ -353,12 +353,12 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
|
||||
@Override
|
||||
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
|
||||
if (endDateTime instanceof ChronoLocalDateTime == false) {
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) endDateTime;
|
||||
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
|
||||
throw new DateTimeException("Unable to calculate period between two different chronologies");
|
||||
throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
ChronoUnit f = (ChronoUnit) unit;
|
||||
|
@ -107,7 +107,7 @@ import java.util.Objects;
|
||||
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
|
||||
* before using this interface.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
@ -128,6 +128,8 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
|
||||
* on the position of the date-time on the instant time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-second and nano-of-second.
|
||||
*
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
*
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
* @see #isEqual
|
||||
|
@ -95,7 +95,7 @@ import java.util.Objects;
|
||||
* the local time-line overlaps, typically as a result of the end of daylight time.
|
||||
* Information about the local-time can be obtained using methods on the time-zone.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
@ -287,12 +287,12 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
|
||||
@Override
|
||||
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
|
||||
if (endDateTime instanceof ChronoZonedDateTime == false) {
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) endDateTime;
|
||||
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
|
||||
throw new DateTimeException("Unable to calculate period between two different chronologies");
|
||||
throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
|
||||
}
|
||||
if (unit instanceof ChronoUnit) {
|
||||
end = end.withZoneSameInstant(offset);
|
||||
|
@ -176,7 +176,7 @@ import sun.util.logging.PlatformLogger;
|
||||
* CLDR specification then the calendar type is the concatenation of the
|
||||
* CLDR type and, if applicable, the CLDR variant,
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
@ -338,16 +338,13 @@ public abstract class Chronology implements Comparable<Chronology> {
|
||||
* <p>
|
||||
* The {@code Locale} class also supports an extension mechanism that
|
||||
* can be used to identify a calendar system. The mechanism is a form
|
||||
* of key-value pairs, where the calendar system has the key "ca"
|
||||
* and an optional variant key "cv".
|
||||
* of key-value pairs, where the calendar system has the key "ca".
|
||||
* For example, the locale "en-JP-u-ca-japanese" represents the English
|
||||
* language as used in Japan with the Japanese calendar system.
|
||||
* <p>
|
||||
* This method finds the desired calendar system by in a manner equivalent
|
||||
* to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
|
||||
* If the "ca" key is not present, then {@code IsoChronology} is returned.
|
||||
* The variant, if present, is appended to the "ca" value separated by "-"
|
||||
* and the concatenated value is used to find the calendar system by type.
|
||||
* <p>
|
||||
* Note that the behavior of this method differs from the older
|
||||
* {@link java.util.Calendar#getInstance(Locale)} method.
|
||||
@ -374,10 +371,6 @@ public abstract class Chronology implements Comparable<Chronology> {
|
||||
if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
|
||||
return IsoChronology.INSTANCE;
|
||||
}
|
||||
String variant = locale.getUnicodeLocaleType("cv");
|
||||
if (variant != null && !variant.isEmpty()) {
|
||||
type = type + '-' + variant;
|
||||
}
|
||||
// Not pre-defined; lookup by the type
|
||||
do {
|
||||
Chronology chrono = CHRONOS_BY_TYPE.get(type);
|
||||
@ -563,7 +556,7 @@ public abstract class Chronology implements Comparable<Chronology> {
|
||||
* and the variant, if applicable, is appended separated by "-".
|
||||
* The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
|
||||
*
|
||||
* @return the calendar system type, null if the calendar is not defined
|
||||
* @return the calendar system type, null if the calendar is not defined by CLDR/LDML
|
||||
* @see #getId()
|
||||
*/
|
||||
public abstract String getCalendarType();
|
||||
|
@ -93,7 +93,7 @@ import java.util.Locale;
|
||||
* <p>
|
||||
* Instances of {@code Era} may be compared using the {@code ==} operator.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations must be singletons - final, immutable and thread-safe.
|
||||
* It is recommended to use an enum whenever possible.
|
||||
|
@ -133,9 +133,10 @@ import sun.util.logging.PlatformLogger;
|
||||
* Chronology chrono = Chronology.ofLocale(locale);
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
* <h3>Implementation Note for Hijrah Calendar Variant Configuration</h3>
|
||||
*
|
||||
* @implNote
|
||||
* Each Hijrah variant is configured individually. Each variant is defined by a
|
||||
* property resource that defines the {@code ID}, the {@code calendar type},
|
||||
* the start of the calendar, the alignment with the
|
||||
@ -229,6 +230,11 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
* {@link Chronology#getAvailableChronologies}.
|
||||
*/
|
||||
public static final HijrahChronology INSTANCE;
|
||||
/**
|
||||
* Flag to indicate the initialization of configuration data is complete.
|
||||
* @see #checkCalendarInit()
|
||||
*/
|
||||
private volatile boolean initComplete;
|
||||
/**
|
||||
* Array of epoch days indexed by Hijrah Epoch month.
|
||||
* Computed by {@link #loadCalendarData}.
|
||||
@ -285,7 +291,8 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
private static final String PROP_TYPE_SUFFIX = ".type";
|
||||
|
||||
/**
|
||||
* Name data.
|
||||
* Static initialization of the predefined calendars found in the
|
||||
* lib/calendars.properties file.
|
||||
*/
|
||||
static {
|
||||
try {
|
||||
@ -299,8 +306,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
// Register it by its aliases
|
||||
Chronology.registerChrono(INSTANCE, "Hijrah");
|
||||
Chronology.registerChrono(INSTANCE, "islamic");
|
||||
|
||||
} catch (Exception ex) {
|
||||
} catch (DateTimeException ex) {
|
||||
// Absence of Hijrah calendar is fatal to initializing this class.
|
||||
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
|
||||
logger.severe("Unable to initialize Hijrah calendar: Hijrah-umalqura", ex);
|
||||
@ -327,7 +333,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
// Create and register the variant
|
||||
HijrahChronology chrono = new HijrahChronology(id);
|
||||
Chronology.registerChrono(chrono);
|
||||
} catch (Exception ex) {
|
||||
} catch (DateTimeException ex) {
|
||||
// Log error and continue
|
||||
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
|
||||
logger.severe("Unable to initialize Hijrah calendar: " + id, ex);
|
||||
@ -343,22 +349,39 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
* The property names are {@code "calendar.hijrah." + id}
|
||||
* and {@code "calendar.hijrah." + id + ".type"}
|
||||
* @param id the id of the calendar
|
||||
* @throws Exception if the resource can not be accessed or
|
||||
* the format is invalid
|
||||
* @throws DateTimeException if the calendar type is missing from the properties file.
|
||||
* @throws IllegalArgumentException if the id is empty
|
||||
*/
|
||||
private HijrahChronology(String id) throws Exception {
|
||||
private HijrahChronology(String id) throws DateTimeException {
|
||||
if (id.isEmpty()) {
|
||||
throw new IllegalArgumentException("calendar id is empty");
|
||||
}
|
||||
String propName = PROP_PREFIX + id + PROP_TYPE_SUFFIX;
|
||||
String calType = calendarProperties.getProperty(propName);
|
||||
if (calType == null || calType.isEmpty()) {
|
||||
throw new DateTimeException("calendarType is missing or empty for: " + propName);
|
||||
}
|
||||
this.typeId = id;
|
||||
this.calendarType = calendarProperties.getProperty(PROP_PREFIX + id + PROP_TYPE_SUFFIX);
|
||||
this.calendarType = calType;
|
||||
}
|
||||
|
||||
try {
|
||||
String resource = calendarProperties.getProperty(PROP_PREFIX + id);
|
||||
Objects.requireNonNull(resource, "Resource missing for calendar");
|
||||
loadCalendarData(resource);
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Unable to initialize HijrahCalendar: " + id, ex);
|
||||
/**
|
||||
* Check and ensure that the calendar data has been initialized.
|
||||
* The initialization check is performed at the boundary between
|
||||
* public and package methods. If a public calls another public method
|
||||
* a check is not necessary in the caller.
|
||||
* The constructors of HijrahDate call {@link #getEpochDay} or
|
||||
* {@link #getHijrahDateInfo} so every call from HijrahDate to a
|
||||
* HijrahChronology via package private methods has been checked.
|
||||
*
|
||||
* @throws DateTimeException if the calendar data configuration is
|
||||
* malformed or IOExceptions occur loading the data
|
||||
*/
|
||||
private void checkCalendarInit() {
|
||||
// Keep this short so it can be inlined for performance
|
||||
if (initComplete == false) {
|
||||
loadCalendarData();
|
||||
initComplete = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,6 +532,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean isLeapYear(long prolepticYear) {
|
||||
checkCalendarInit();
|
||||
int epochMonth = yearToEpochMonth((int) prolepticYear);
|
||||
if (epochMonth < 0 || epochMonth > maxEpochDay) {
|
||||
throw new DateTimeException("Hijrah date out of range");
|
||||
@ -543,6 +567,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
checkCalendarInit();
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = field;
|
||||
switch (f) {
|
||||
@ -595,6 +620,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
* @return int[0] = YEAR, int[1] = MONTH, int[2] = DATE
|
||||
*/
|
||||
int[] getHijrahDateInfo(int epochDay) {
|
||||
checkCalendarInit(); // ensure that the chronology is initialized
|
||||
if (epochDay < minEpochDay || epochDay >= maxEpochDay) {
|
||||
throw new DateTimeException("Hijrah date out of range");
|
||||
}
|
||||
@ -621,6 +647,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
* @return the epoch day
|
||||
*/
|
||||
long getEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) {
|
||||
checkCalendarInit(); // ensure that the chronology is initialized
|
||||
checkValidMonth(monthOfYear);
|
||||
int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1);
|
||||
if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) {
|
||||
@ -846,84 +873,90 @@ public final class HijrahChronology extends Chronology implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and processes the Hijrah calendar properties file.
|
||||
* Loads and processes the Hijrah calendar properties file for this calendarType.
|
||||
* The starting Hijrah date and the corresponding ISO date are
|
||||
* extracted and used to calculate the epochDate offset.
|
||||
* The version number is identified and ignored.
|
||||
* Everything else is the data for a year with containing the length of each
|
||||
* of 12 months.
|
||||
*
|
||||
* @param resourceName containing the properties defining the calendar, not null
|
||||
* @throws IllegalArgumentException if any of the values are malformed
|
||||
* @throws NumberFormatException if numbers, including properties that should
|
||||
* be years are invalid
|
||||
* @throws IOException if access to the property resource fails.
|
||||
* @throws DateTimeException if initialization of the calendar data from the
|
||||
* resource fails
|
||||
*/
|
||||
private void loadCalendarData(String resourceName) throws Exception {
|
||||
Properties props = readConfigProperties(resourceName);
|
||||
private void loadCalendarData() {
|
||||
try {
|
||||
String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
|
||||
Objects.requireNonNull(resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
|
||||
Properties props = readConfigProperties(resourceName);
|
||||
|
||||
Map<Integer, int[]> years = new HashMap<>();
|
||||
int minYear = Integer.MAX_VALUE;
|
||||
int maxYear = Integer.MIN_VALUE;
|
||||
String id = null;
|
||||
String type = null;
|
||||
String version = null;
|
||||
int isoStart = 0;
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
switch (key) {
|
||||
case KEY_ID:
|
||||
id = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_TYPE:
|
||||
type = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_VERSION:
|
||||
version = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_ISO_START: {
|
||||
int[] ymd = parseYMD((String) entry.getValue());
|
||||
isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
try {
|
||||
// Everything else is either a year or invalid
|
||||
int year = Integer.valueOf(key);
|
||||
int[] months = parseMonths((String) entry.getValue());
|
||||
years.put(year, months);
|
||||
maxYear = Math.max(maxYear, year);
|
||||
minYear = Math.min(minYear, year);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IllegalArgumentException("bad key: " + key);
|
||||
Map<Integer, int[]> years = new HashMap<>();
|
||||
int minYear = Integer.MAX_VALUE;
|
||||
int maxYear = Integer.MIN_VALUE;
|
||||
String id = null;
|
||||
String type = null;
|
||||
String version = null;
|
||||
int isoStart = 0;
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
switch (key) {
|
||||
case KEY_ID:
|
||||
id = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_TYPE:
|
||||
type = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_VERSION:
|
||||
version = (String)entry.getValue();
|
||||
break;
|
||||
case KEY_ISO_START: {
|
||||
int[] ymd = parseYMD((String) entry.getValue());
|
||||
isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
try {
|
||||
// Everything else is either a year or invalid
|
||||
int year = Integer.valueOf(key);
|
||||
int[] months = parseMonths((String) entry.getValue());
|
||||
years.put(year, months);
|
||||
maxYear = Math.max(maxYear, year);
|
||||
minYear = Math.min(minYear, year);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IllegalArgumentException("bad key: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!getId().equals(id)) {
|
||||
throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
|
||||
}
|
||||
if (!getCalendarType().equals(type)) {
|
||||
throw new IllegalArgumentException("Configuration is for a different calendar type: " + type);
|
||||
}
|
||||
if (version == null || version.isEmpty()) {
|
||||
throw new IllegalArgumentException("Configuration does not contain a version");
|
||||
}
|
||||
if (isoStart == 0) {
|
||||
throw new IllegalArgumentException("Configuration does not contain a ISO start date");
|
||||
}
|
||||
if (!getId().equals(id)) {
|
||||
throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
|
||||
}
|
||||
if (!getCalendarType().equals(type)) {
|
||||
throw new IllegalArgumentException("Configuration is for a different calendar type: " + type);
|
||||
}
|
||||
if (version == null || version.isEmpty()) {
|
||||
throw new IllegalArgumentException("Configuration does not contain a version");
|
||||
}
|
||||
if (isoStart == 0) {
|
||||
throw new IllegalArgumentException("Configuration does not contain a ISO start date");
|
||||
}
|
||||
|
||||
// Now create and validate the array of epochDays indexed by epochMonth
|
||||
hijrahStartEpochMonth = minYear * 12;
|
||||
minEpochDay = isoStart;
|
||||
hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
|
||||
maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];
|
||||
// Now create and validate the array of epochDays indexed by epochMonth
|
||||
hijrahStartEpochMonth = minYear * 12;
|
||||
minEpochDay = isoStart;
|
||||
hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
|
||||
maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];
|
||||
|
||||
// Compute the min and max year length in days.
|
||||
for (int year = minYear; year < maxYear; year++) {
|
||||
int length = getYearLength(year);
|
||||
minYearLength = Math.min(minYearLength, length);
|
||||
maxYearLength = Math.max(maxYearLength, length);
|
||||
// Compute the min and max year length in days.
|
||||
for (int year = minYear; year < maxYear; year++) {
|
||||
int length = getYearLength(year);
|
||||
minYearLength = Math.min(minYearLength, length);
|
||||
maxYearLength = Math.max(maxYearLength, length);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Log error and throw a DateTimeException
|
||||
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
|
||||
logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex);
|
||||
throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ import java.time.temporal.ValueRange;
|
||||
* to create new HijrahDate instances.
|
||||
* Alternatively, the {@link #withVariant} method can be used to convert
|
||||
* to a new HijrahChronology.
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -81,7 +81,7 @@ import java.time.temporal.ValueRange;
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -121,7 +121,7 @@ import java.util.Objects;
|
||||
* <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
|
||||
* </ul><p>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -588,7 +588,12 @@ public final class IsoChronology extends Chronology implements Serializable {
|
||||
int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
|
||||
int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
|
||||
if (resolverStyle == ResolverStyle.SMART) { // previous valid
|
||||
dom = Math.min(dom, Month.of(moy).length(Year.isLeap(y)));
|
||||
if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
|
||||
dom = Math.min(dom, 30);
|
||||
} else if (moy == 2) {
|
||||
dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
|
||||
|
||||
}
|
||||
}
|
||||
return LocalDate.of(y, moy, dom);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ import java.time.DateTimeException;
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -85,7 +85,7 @@ import sun.util.calendar.LocalGregorianCalendar;
|
||||
* Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported.
|
||||
* Older eras are handled as an unknown era where the year-of-era is the ISO year.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -197,7 +197,7 @@ public final class JapaneseChronology extends Chronology implements Serializable
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
|
||||
return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,16 +251,19 @@ public final class JapaneseChronology extends Chronology implements Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
|
||||
}
|
||||
@ -286,19 +289,27 @@ public final class JapaneseChronology extends Chronology implements Serializable
|
||||
if (era instanceof JapaneseEra == false) {
|
||||
throw new ClassCastException("Era must be JapaneseEra");
|
||||
}
|
||||
|
||||
if (era == JapaneseEra.SEIREKI) {
|
||||
JapaneseEra nextEra = JapaneseEra.values()[1];
|
||||
int nextEraYear = nextEra.getPrivateEra().getSinceDate().getYear();
|
||||
if (yearOfEra >= nextEraYear || yearOfEra < Year.MIN_VALUE) {
|
||||
throw new DateTimeException("Invalid yearOfEra value");
|
||||
}
|
||||
return yearOfEra;
|
||||
}
|
||||
|
||||
JapaneseEra jera = (JapaneseEra) era;
|
||||
int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
|
||||
if (yearOfEra == 1) {
|
||||
return gregorianYear;
|
||||
}
|
||||
LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
|
||||
jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
|
||||
if (!JapaneseChronology.JCAL.validate(jdate)) {
|
||||
throw new DateTimeException("Invalid yearOfEra value");
|
||||
}
|
||||
JCAL.normalize(jdate);
|
||||
if (jdate.getNormalizedYear() == gregorianYear) {
|
||||
return gregorianYear;
|
||||
if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
|
||||
LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
|
||||
jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
|
||||
if (JapaneseChronology.JCAL.validate(jdate)) {
|
||||
return gregorianYear;
|
||||
}
|
||||
}
|
||||
throw new DateTimeException("Invalid yearOfEra value");
|
||||
}
|
||||
@ -322,13 +333,20 @@ public final class JapaneseChronology extends Chronology implements Serializable
|
||||
|
||||
@Override
|
||||
public List<Era> eras() {
|
||||
return Arrays.asList(JapaneseEra.values());
|
||||
return Arrays.<Era>asList(JapaneseEra.values());
|
||||
}
|
||||
|
||||
JapaneseEra getCurrentEra() {
|
||||
// Assume that the last JapaneseEra is the current one.
|
||||
JapaneseEra[] eras = JapaneseEra.values();
|
||||
return eras[eras.length - 1];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
switch (field) {
|
||||
case YEAR:
|
||||
case DAY_OF_MONTH:
|
||||
case DAY_OF_WEEK:
|
||||
case MICRO_OF_DAY:
|
||||
@ -345,27 +363,23 @@ public final class JapaneseChronology extends Chronology implements Serializable
|
||||
case NANO_OF_SECOND:
|
||||
case CLOCK_HOUR_OF_DAY:
|
||||
case CLOCK_HOUR_OF_AMPM:
|
||||
case EPOCH_DAY: // TODO: if year is restricted, then so is epoch-day
|
||||
case EPOCH_DAY:
|
||||
case PROLEPTIC_MONTH:
|
||||
case MONTH_OF_YEAR:
|
||||
return field.range();
|
||||
case ERA:
|
||||
return ValueRange.of(JapaneseEra.SEIREKI.getValue(),
|
||||
getCurrentEra().getValue());
|
||||
}
|
||||
Calendar jcal = Calendar.getInstance(LOCALE);
|
||||
int fieldIndex;
|
||||
switch (field) {
|
||||
case ERA:
|
||||
return ValueRange.of(JapaneseEra.SEIREKI.getValue(),
|
||||
jcal.getMaximum(Calendar.ERA) - JapaneseEra.ERA_OFFSET);
|
||||
case YEAR:
|
||||
case YEAR_OF_ERA:
|
||||
// TODO: this is not right
|
||||
case YEAR_OF_ERA: {
|
||||
int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
|
||||
return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR),
|
||||
jcal.getLeastMaximum(Calendar.YEAR), Year.MAX_VALUE);
|
||||
case PROLEPTIC_MONTH:
|
||||
// TODO: should be the range of months bound by the valid range of years
|
||||
return ValueRange.of((jcal.getGreatestMinimum(Calendar.YEAR) - 1) * 12,
|
||||
(jcal.getLeastMaximum(Calendar.YEAR)) * 12);
|
||||
case MONTH_OF_YEAR:
|
||||
return ValueRange.of(jcal.getMinimum(Calendar.MONTH) + 1, jcal.getGreatestMinimum(Calendar.MONTH) + 1,
|
||||
jcal.getLeastMaximum(Calendar.MONTH) + 1, jcal.getMaximum(Calendar.MONTH) + 1);
|
||||
jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
|
||||
Year.MAX_VALUE - startYear);
|
||||
}
|
||||
case DAY_OF_YEAR:
|
||||
fieldIndex = Calendar.DAY_OF_YEAR;
|
||||
break;
|
||||
|
@ -83,6 +83,7 @@ import java.time.temporal.ValueRange;
|
||||
import java.util.Calendar;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.util.calendar.CalendarDate;
|
||||
import sun.util.calendar.LocalGregorianCalendar;
|
||||
|
||||
/**
|
||||
@ -101,7 +102,7 @@ import sun.util.calendar.LocalGregorianCalendar;
|
||||
* Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
|
||||
* {@code JapaneseChronology.ERA_HEISEI}.<br>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -234,6 +235,24 @@ public final class JapaneseDate
|
||||
return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
|
||||
}
|
||||
|
||||
static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
|
||||
CalendarDate firstDay = era.getPrivateEra().getSinceDate();
|
||||
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
|
||||
jdate.setEra(era.getPrivateEra());
|
||||
if (yearOfEra == 1) {
|
||||
jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
|
||||
} else {
|
||||
jdate.setDate(yearOfEra, 1, dayOfYear);
|
||||
}
|
||||
JapaneseChronology.JCAL.normalize(jdate);
|
||||
if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
|
||||
throw new DateTimeException("Invalid parameters");
|
||||
}
|
||||
LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
|
||||
jdate.getMonth(), jdate.getDayOfMonth());
|
||||
return new JapaneseDate(era, yearOfEra, localdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
|
||||
* system from the era, year-of-era, month-of-year and day-of-month fields.
|
||||
|
@ -91,7 +91,7 @@ import sun.util.calendar.CalendarDate;
|
||||
* and the year of era of Seireki is proleptic Gregorian year.
|
||||
* (The Julian to Gregorian transition is not supported.)
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -95,7 +95,7 @@ import java.util.Locale;
|
||||
* are never out of step.
|
||||
* </ul><p>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -89,7 +89,7 @@ import java.util.Objects;
|
||||
* This calendar system is primarily used in the Republic of China, often known as Taiwan.
|
||||
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -102,7 +102,7 @@ import java.time.DateTimeException;
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -68,7 +68,7 @@ import java.time.LocalDateTime;
|
||||
/**
|
||||
* The shared serialization delegate for this package.
|
||||
*
|
||||
* <h3>Implementation notes</h3>
|
||||
* @implNote
|
||||
* This class wraps the object being serialized, and takes a byte representing the type of the class to
|
||||
* be serialized. This byte can also be used for versioning the serialization format. In this case another
|
||||
* byte flag would be used in order to specify an alternative version of the type format.
|
||||
|
@ -96,7 +96,7 @@ import java.util.Locale;
|
||||
* are never out of step.
|
||||
* </ul><p>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -89,7 +89,7 @@ import java.util.Objects;
|
||||
* This calendar system is primarily used in Thailand.
|
||||
* Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -102,7 +102,7 @@ import java.time.DateTimeException;
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ThaiBuddhistEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -77,6 +77,7 @@ import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.chrono.Chronology;
|
||||
@ -121,7 +122,7 @@ import java.util.Set;
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* In addition to the format, formatters can be created with desired Locale,
|
||||
* Chronology, ZoneId, and formatting symbols.
|
||||
* Chronology, ZoneId, and DecimalStyle.
|
||||
* <p>
|
||||
* The {@link #withLocale withLocale} method returns a new formatter that
|
||||
* overrides the locale. The locale affects some aspects of formatting and
|
||||
@ -138,8 +139,8 @@ import java.util.Set;
|
||||
* with the requested ZoneId before formatting. During parsing the ZoneId is
|
||||
* applied before the value is returned.
|
||||
* <p>
|
||||
* The {@link #withSymbols withSymbols} method returns a new formatter that
|
||||
* overrides the {@link DateTimeFormatSymbols}. The symbols are used for
|
||||
* The {@link #withDecimalStyle withDecimalStyle} method returns a new formatter that
|
||||
* overrides the {@link DecimalStyle}. The DecimalStyle symbols are used for
|
||||
* formatting and parsing.
|
||||
* <p>
|
||||
* Some applications may need to use the older {@link Format java.text.Format}
|
||||
@ -417,7 +418,65 @@ import java.util.Set;
|
||||
* that you want to output directly to ensure that future changes do not break
|
||||
* your application.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* <h3 id="resolving">Resolving</h3>
|
||||
* Parsing is implemented as a two-phase operation.
|
||||
* First, the text is parsed using the layout defined by the formatter, producing
|
||||
* a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
|
||||
* Second, the parsed data is <em>resolved</em>, by validating, combining and
|
||||
* simplifying the various fields into more useful ones.
|
||||
* <p>
|
||||
* Five parsing methods are supplied by this class.
|
||||
* Four of these perform both the parse and resolve phases.
|
||||
* The fifth method, {@link #parseUnresolved(CharSequence, ParsePosition)},
|
||||
* only performs the first phase, leaving the result unresolved.
|
||||
* As such, it is essentially a low-level operation.
|
||||
* <p>
|
||||
* The resolve phase is controlled by two parameters, set on this class.
|
||||
* <p>
|
||||
* The {@link ResolverStyle} is an enum that offers three different approaches,
|
||||
* strict, smart and lenient. The smart option is the default.
|
||||
* It can be set using {@link #withResolverStyle(ResolverStyle)}.
|
||||
* <p>
|
||||
* The {@link #withResolverFields(TemporalField...)} parameter allows the
|
||||
* set of fields that will be resolved to be filtered before resolving starts.
|
||||
* For example, if the formatter has parsed a year, month, day-of-month
|
||||
* and day-of-year, then there are two approaches to resolve a date:
|
||||
* (year + month + day-of-month) and (year + day-of-year).
|
||||
* The resolver fields allows one of the two approaches to be selected.
|
||||
* If no resolver fields are set then both approaches must result in the same date.
|
||||
* <p>
|
||||
* Resolving separate fields to form a complete date and time is a complex
|
||||
* process with behaviour distributed across a number of classes.
|
||||
* It follows these steps:
|
||||
* <ol>
|
||||
* <li>The chronology is determined.
|
||||
* The chronology of the result is either the chronology that was parsed,
|
||||
* or if no chronology was parsed, it is the chronology set on this class,
|
||||
* or if that is null, it is {@code IsoChronology}.
|
||||
* <li>The {@code ChronoField} date fields are resolved.
|
||||
* This is achieved using {@link Chronology#resolveDate(Map, ResolverStyle)}.
|
||||
* Documentation about field resolution is located in the implementation
|
||||
* of {@code Chronology}.
|
||||
* <li>The {@code ChronoField} time fields are resolved.
|
||||
* This is documented on {@link ChronoField} and is the same for all chronologies.
|
||||
* <li>Any fields that are not {@code ChronoField} are processed.
|
||||
* This is achieved using {@link TemporalField#resolve(TemporalAccessor, long, ResolverStyle)}.
|
||||
* Documentation about field resolution is located in the implementation
|
||||
* of {@code TemporalField}.
|
||||
* <li>The {@code ChronoField} date and time fields are re-resolved.
|
||||
* This allows fields in step four to produce {@code ChronoField} values
|
||||
* and have them be processed into dates and times.
|
||||
* <li>A {@code LocalTime} is formed if there is at least an hour-of-day available.
|
||||
* This involves providing default values for minute, second and fraction of second.
|
||||
* <li>Any remaining unresolved fields are cross-checked against any
|
||||
* date and/or time that was resolved. Thus, an earlier stage would resolve
|
||||
* (year + month + day-of-month) to a date, and this stage would check that
|
||||
* day-of-week was valid for the date.
|
||||
* <li>If an {@linkplain #parsedExcessDays() excess number of days}
|
||||
* was parsed then it is added to the date if a date is available.
|
||||
* </ol>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -435,7 +494,7 @@ public final class DateTimeFormatter {
|
||||
/**
|
||||
* The symbols to use for formatting, not null.
|
||||
*/
|
||||
private final DateTimeFormatSymbols symbols;
|
||||
private final DecimalStyle decimalStyle;
|
||||
/**
|
||||
* The resolver style to use, not null.
|
||||
*/
|
||||
@ -1040,6 +1099,11 @@ public final class DateTimeFormatter {
|
||||
* <p>
|
||||
* This returns an immutable formatter capable of formatting and parsing
|
||||
* the ISO-8601 instant format.
|
||||
* When formatting, the second-of-minute is always output.
|
||||
* The nano-of-second outputs zero, three, six or nine digits digits as necessary.
|
||||
* When parsing, time to at least the seconds field is required.
|
||||
* Fractional seconds from zero to nine are parsed.
|
||||
* The localized decimal style is not used.
|
||||
* <p>
|
||||
* This is a special case formatter intended to allow a human readable form
|
||||
* of an {@link java.time.Instant}. The {@code Instant} class is designed to
|
||||
@ -1201,25 +1265,117 @@ public final class DateTimeFormatter {
|
||||
.toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A query that provides access to the excess days that were parsed.
|
||||
* <p>
|
||||
* This returns a singleton {@linkplain TemporalQuery query} that provides
|
||||
* access to additional information from the parse. The query always returns
|
||||
* a non-null period, with a zero period returned instead of null.
|
||||
* <p>
|
||||
* There are two situations where this query may return a non-zero period.
|
||||
* <p><ul>
|
||||
* <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed
|
||||
* without a date, then the complete result of the parse consists of a
|
||||
* {@code LocalTime} and an excess {@code Period} in days.
|
||||
* <p>
|
||||
* <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed
|
||||
* without a date where the time is 24:00:00, then the complete result of
|
||||
* the parse consists of a {@code LocalTime} of 00:00:00 and an excess
|
||||
* {@code Period} of one day.
|
||||
* </ul>
|
||||
* <p>
|
||||
* In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant}
|
||||
* is parsed, then the excess days are added to the date part.
|
||||
* As a result, this query will return a zero period.
|
||||
* <p>
|
||||
* The {@code SMART} behaviour handles the common "end of day" 24:00 value.
|
||||
* Processing in {@code LENIENT} mode also produces the same result:
|
||||
* <pre>
|
||||
* Text to parse Parsed object Excess days
|
||||
* "2012-12-03T00:00" LocalDateTime.of(2012, 12, 3, 0, 0) ZERO
|
||||
* "2012-12-03T24:00" LocalDateTime.of(2012, 12, 4, 0, 0) ZERO
|
||||
* "00:00" LocalTime.of(0, 0) ZERO
|
||||
* "24:00" LocalTime.of(0, 0) Period.ofDays(1)
|
||||
* </pre>
|
||||
* The query can be used as follows:
|
||||
* <pre>
|
||||
* TemporalAccessor parsed = formatter.parse(str);
|
||||
* LocalTime time = parsed.query(LocalTime::from);
|
||||
* Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays());
|
||||
* </pre>
|
||||
*/
|
||||
public static final TemporalQuery<Period> parsedExcessDays() {
|
||||
return PARSED_EXCESS_DAYS;
|
||||
}
|
||||
private static final TemporalQuery<Period> PARSED_EXCESS_DAYS = t -> {
|
||||
if (t instanceof Parsed) {
|
||||
return ((Parsed) t).excessDays;
|
||||
} else {
|
||||
return Period.ZERO;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A query that provides access to whether a leap-second was parsed.
|
||||
* <p>
|
||||
* This returns a singleton {@linkplain TemporalQuery query} that provides
|
||||
* access to additional information from the parse. The query always returns
|
||||
* a non-null boolean, true if parsing saw a leap-second, false if not.
|
||||
* <p>
|
||||
* Instant parsing handles the special "leap second" time of '23:59:60'.
|
||||
* Leap seconds occur at '23:59:60' in the UTC time-zone, but at other
|
||||
* local times in different time-zones. To avoid this potential ambiguity,
|
||||
* the handling of leap-seconds is limited to
|
||||
* {@link DateTimeFormatterBuilder#appendInstant()}, as that method
|
||||
* always parses the instant with the UTC zone offset.
|
||||
* <p>
|
||||
* If the time '23:59:60' is received, then a simple conversion is applied,
|
||||
* replacing the second-of-minute of 60 with 59. This query can be used
|
||||
* on the parse result to determine if the leap-second adjustment was made.
|
||||
* The query will return one second of excess if it did adjust to remove
|
||||
* the leap-second, and zero if not. Note that applying a leap-second
|
||||
* smoothing mechanism, such as UTC-SLS, is the responsibility of the
|
||||
* application, as follows:
|
||||
* <pre>
|
||||
* TemporalAccessor parsed = formatter.parse(str);
|
||||
* Instant instant = parsed.query(Instant::from);
|
||||
* if (parsed.query(DateTimeFormatter.parsedLeapSecond())) {
|
||||
* // validate leap-second is correct and apply correct smoothing
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static final TemporalQuery<Boolean> parsedLeapSecond() {
|
||||
return PARSED_LEAP_SECOND;
|
||||
}
|
||||
private static final TemporalQuery<Boolean> PARSED_LEAP_SECOND = t -> {
|
||||
if (t instanceof Parsed) {
|
||||
return ((Parsed) t).leapSecond;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param printerParser the printer/parser to use, not null
|
||||
* @param locale the locale to use, not null
|
||||
* @param symbols the symbols to use, not null
|
||||
* @param decimalStyle the DecimalStyle to use, not null
|
||||
* @param resolverStyle the resolver style to use, not null
|
||||
* @param resolverFields the fields to use during resolving, null for all fields
|
||||
* @param chrono the chronology to use, null for no override
|
||||
* @param zone the zone to use, null for no override
|
||||
*/
|
||||
DateTimeFormatter(CompositePrinterParser printerParser,
|
||||
Locale locale, DateTimeFormatSymbols symbols,
|
||||
Locale locale, DecimalStyle decimalStyle,
|
||||
ResolverStyle resolverStyle, Set<TemporalField> resolverFields,
|
||||
Chronology chrono, ZoneId zone) {
|
||||
this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
|
||||
this.resolverFields = resolverFields;
|
||||
this.locale = Objects.requireNonNull(locale, "locale");
|
||||
this.symbols = Objects.requireNonNull(symbols, "symbols");
|
||||
this.decimalStyle = Objects.requireNonNull(decimalStyle, "decimalStyle");
|
||||
this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle");
|
||||
this.chrono = chrono;
|
||||
this.zone = zone;
|
||||
@ -1253,32 +1409,32 @@ public final class DateTimeFormatter {
|
||||
if (this.locale.equals(locale)) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the set of symbols to be used during formatting.
|
||||
* Gets the DecimalStyle to be used during formatting.
|
||||
*
|
||||
* @return the locale of this formatter, not null
|
||||
*/
|
||||
public DateTimeFormatSymbols getSymbols() {
|
||||
return symbols;
|
||||
public DecimalStyle getDecimalStyle() {
|
||||
return decimalStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this formatter with a new set of symbols.
|
||||
* Returns a copy of this formatter with a new DecimalStyle.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param symbols the new symbols, not null
|
||||
* @return a formatter based on this formatter with the requested symbols, not null
|
||||
* @param decimalStyle the new DecimalStyle, not null
|
||||
* @return a formatter based on this formatter with the requested DecimalStyle, not null
|
||||
*/
|
||||
public DateTimeFormatter withSymbols(DateTimeFormatSymbols symbols) {
|
||||
if (this.symbols.equals(symbols)) {
|
||||
public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) {
|
||||
if (this.decimalStyle.equals(decimalStyle)) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1332,7 +1488,7 @@ public final class DateTimeFormatter {
|
||||
if (Objects.equals(this.chrono, chrono)) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1389,7 +1545,7 @@ public final class DateTimeFormatter {
|
||||
if (Objects.equals(this.zone, zone)) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1431,7 +1587,7 @@ public final class DateTimeFormatter {
|
||||
if (Objects.equals(this.resolverStyle, resolverStyle)) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1495,7 +1651,7 @@ public final class DateTimeFormatter {
|
||||
return this;
|
||||
}
|
||||
fields = Collections.unmodifiableSet(fields);
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, fields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1543,7 +1699,7 @@ public final class DateTimeFormatter {
|
||||
return this;
|
||||
}
|
||||
resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields));
|
||||
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
|
||||
return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -77,6 +77,7 @@ import java.math.BigInteger;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.ParsePosition;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
@ -142,7 +143,7 @@ import sun.util.locale.provider.TimeZoneNameUtility;
|
||||
* can be used, see {@link #appendPattern(String)}.
|
||||
* In practice, this simply parses the pattern and calls other methods on the builder.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is a mutable builder intended for use from a single thread.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -186,6 +187,44 @@ public final class DateTimeFormatterBuilder {
|
||||
*/
|
||||
private int valueParserIndex = -1;
|
||||
|
||||
/**
|
||||
* Gets the formatting pattern for date and time styles for a locale and chronology.
|
||||
* The locale and chronology are used to lookup the locale specific format
|
||||
* for the requested dateStyle and/or timeStyle.
|
||||
*
|
||||
* @param dateStyle the FormatStyle for the date
|
||||
* @param timeStyle the FormatStyle for the time
|
||||
* @param chrono the Chronology, non-null
|
||||
* @param locale the locale, non-null
|
||||
* @return the locale and Chronology specific formatting pattern
|
||||
* @throws IllegalArgumentException if both dateStyle and timeStyle are null
|
||||
*/
|
||||
public static String getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle,
|
||||
Chronology chrono, Locale locale) {
|
||||
Objects.requireNonNull(locale, "locale");
|
||||
Objects.requireNonNull(chrono, "chrono");
|
||||
if (dateStyle == null && timeStyle == null) {
|
||||
throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
|
||||
}
|
||||
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
|
||||
String pattern = lr.getJavaTimeDateTimePattern(
|
||||
convertStyle(timeStyle), convertStyle(dateStyle), chrono.getCalendarType());
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given FormatStyle to the java.text.DateFormat style.
|
||||
*
|
||||
* @param style the FormatStyle style
|
||||
* @return the int style, or -1 if style is null, indicating un-required
|
||||
*/
|
||||
private static int convertStyle(FormatStyle style) {
|
||||
if (style == null) {
|
||||
return -1;
|
||||
}
|
||||
return style.ordinal(); // indices happen to align
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the builder.
|
||||
*/
|
||||
@ -344,7 +383,7 @@ public final class DateTimeFormatterBuilder {
|
||||
*/
|
||||
public DateTimeFormatterBuilder appendValue(TemporalField field) {
|
||||
Objects.requireNonNull(field, "field");
|
||||
active.valueParserIndex = appendInternal(new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL));
|
||||
appendValue(new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -360,15 +399,15 @@ public final class DateTimeFormatterBuilder {
|
||||
* If the value of the field is negative then an exception is thrown during formatting.
|
||||
* <p>
|
||||
* This method supports a special technique of parsing known as 'adjacent value parsing'.
|
||||
* This technique solves the problem where a variable length value is followed by one or more
|
||||
* This technique solves the problem where a value, variable or fixed width, is followed by one or more
|
||||
* fixed length values. The standard parser is greedy, and thus it would normally
|
||||
* steal the digits that are needed by the fixed width value parsers that follow the
|
||||
* variable width one.
|
||||
* <p>
|
||||
* No action is required to initiate 'adjacent value parsing'.
|
||||
* When a call to {@code appendValue} with a variable width is made, the builder
|
||||
* When a call to {@code appendValue} is made, the builder
|
||||
* enters adjacent value parsing setup mode. If the immediately subsequent method
|
||||
* call or calls on the same builder are to this method, then the parser will reserve
|
||||
* call or calls on the same builder are for a fixed width value, then the parser will reserve
|
||||
* space so that the fixed width values can be parsed.
|
||||
* <p>
|
||||
* For example, consider {@code builder.appendValue(YEAR).appendValue(MONTH_OF_YEAR, 2);}
|
||||
@ -381,7 +420,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* nothing for the month.
|
||||
* <p>
|
||||
* Adjacent value parsing applies to each set of fixed width not-negative values in the parser
|
||||
* that immediately follow any kind of variable width value.
|
||||
* that immediately follow any kind of value, variable or fixed width.
|
||||
* Calling any other append method will end the setup of adjacent value parsing.
|
||||
* Thus, in the unlikely event that you need to avoid adjacent value parsing behavior,
|
||||
* simply add the {@code appendValue} to another {@code DateTimeFormatterBuilder}
|
||||
@ -402,7 +441,8 @@ public final class DateTimeFormatterBuilder {
|
||||
throw new IllegalArgumentException("The width must be from 1 to 19 inclusive but was " + width);
|
||||
}
|
||||
NumberPrinterParser pp = new NumberPrinterParser(field, width, width, SignStyle.NOT_NEGATIVE);
|
||||
return appendFixedWidth(width, pp);
|
||||
appendValue(pp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,8 +460,10 @@ public final class DateTimeFormatterBuilder {
|
||||
* This behavior can be affected by 'adjacent value parsing'.
|
||||
* See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
|
||||
* <p>
|
||||
* In strict parsing mode, the minimum number of parsed digits is {@code minWidth}.
|
||||
* In lenient parsing mode, the minimum number of parsed digits is one.
|
||||
* In strict parsing mode, the minimum number of parsed digits is {@code minWidth}
|
||||
* and the maximum is {@code maxWidth}.
|
||||
* In lenient parsing mode, the minimum number of parsed digits is one
|
||||
* and the maximum is 19 (except as limited by adjacent value parsing).
|
||||
* <p>
|
||||
* If this method is invoked with equal minimum and maximum widths and a sign style of
|
||||
* {@code NOT_NEGATIVE} then it delegates to {@code appendValue(TemporalField,int)}.
|
||||
@ -452,17 +494,13 @@ public final class DateTimeFormatterBuilder {
|
||||
maxWidth + " < " + minWidth);
|
||||
}
|
||||
NumberPrinterParser pp = new NumberPrinterParser(field, minWidth, maxWidth, signStyle);
|
||||
if (minWidth == maxWidth) {
|
||||
appendInternal(pp);
|
||||
} else {
|
||||
active.valueParserIndex = appendInternal(pp);
|
||||
}
|
||||
appendValue(pp);
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Appends the reduced value of a date-time field to the formatter.
|
||||
* Appends the reduced value of a date-time field with fixed width to the formatter.
|
||||
* <p>
|
||||
* This is typically used for formatting and parsing a two digit year.
|
||||
* The {@code width} is the printed and parsed width.
|
||||
@ -471,51 +509,116 @@ public final class DateTimeFormatterBuilder {
|
||||
* For formatting, the width is used to determine the number of characters to format.
|
||||
* The rightmost characters are output to match the width, left padding with zero.
|
||||
* <p>
|
||||
* For parsing, exactly the number of characters specified by the width are parsed.
|
||||
* This is incomplete information however, so the base value is used to complete the parse.
|
||||
* The base value is the first valid value in a range of ten to the power of width.
|
||||
* For strict parsing, the number of characters allowed by the width are parsed.
|
||||
* For lenient parsing, the number of characters must be at least 1 and less than 10.
|
||||
* If the number of digits parsed is equal to {@code width} and the value is positive,
|
||||
* the value of the field is computed to be the first number greater than
|
||||
* or equal to the {@code baseValue} with the same least significant characters,
|
||||
* otherwise the value parsed is the field value.
|
||||
* This allows a reduced value to be entered for values in range of the baseValue
|
||||
* and width and absolute values can be entered for values outside the range.
|
||||
* <p>
|
||||
* For example, a base value of {@code 1980} and a width of {@code 2} will have
|
||||
* valid values from {@code 1980} to {@code 2079}.
|
||||
* During parsing, the text {@code "12"} will result in the value {@code 2012} as that
|
||||
* is the value within the range where the last two digits are "12".
|
||||
* <p>
|
||||
* This is a fixed width parser operating using 'adjacent value parsing'.
|
||||
* See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
|
||||
* is the value within the range where the last two characters are "12".
|
||||
* Compare with lenient parsing the text {@code "1915"} that will result in the
|
||||
* value {@code 1915}.
|
||||
*
|
||||
* @param field the field to append, not null
|
||||
* @param width the width of the printed and parsed field, from 1 to 18
|
||||
* @param width the field width of the printed and parsed field, from 1 to 10
|
||||
* @param baseValue the base value of the range of valid values
|
||||
* @return this, for chaining, not null
|
||||
* @throws IllegalArgumentException if the width or base value is invalid
|
||||
* @see #appendValueReduced(java.time.temporal.TemporalField, int, int, int)
|
||||
*/
|
||||
public DateTimeFormatterBuilder appendValueReduced(TemporalField field,
|
||||
int width, int baseValue) {
|
||||
return appendValueReduced(field, width, width, baseValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the reduced value of a date-time field with a flexible width to the formatter.
|
||||
* <p>
|
||||
* This is typically used for formatting and parsing a two digit year
|
||||
* but allowing for the year value to be up to maxWidth.
|
||||
* <p>
|
||||
* For formatting, the {@code width} and {@code maxWidth} are used to
|
||||
* determine the number of characters to format.
|
||||
* If the value of the field is within the range of the {@code baseValue} using
|
||||
* {@code width} characters then the reduced value is formatted otherwise the value is
|
||||
* truncated to fit {@code maxWidth}.
|
||||
* The rightmost characters are output to match the width, left padding with zero.
|
||||
* <p>
|
||||
* For strict parsing, the number of characters allowed by {@code width} to {@code maxWidth} are parsed.
|
||||
* For lenient parsing, the number of characters must be at least 1 and less than 10.
|
||||
* If the number of digits parsed is equal to {@code width} and the value is positive,
|
||||
* the value of the field is computed to be the first number greater than
|
||||
* or equal to the {@code baseValue} with the same least significant characters,
|
||||
* otherwise the value parsed is the field value.
|
||||
* This allows a reduced value to be entered for values in range of the baseValue
|
||||
* and width and absolute values can be entered for values outside the range.
|
||||
* <p>
|
||||
* For example, a base value of {@code 1980} and a width of {@code 2} will have
|
||||
* valid values from {@code 1980} to {@code 2079}.
|
||||
* During parsing, the text {@code "12"} will result in the value {@code 2012} as that
|
||||
* is the value within the range where the last two characters are "12".
|
||||
* Compare with parsing the text {@code "1915"} that will result in the
|
||||
* value {@code 1915}.
|
||||
*
|
||||
* @param field the field to append, not null
|
||||
* @param width the field width of the printed and parsed field, from 1 to 10
|
||||
* @param maxWidth the maximum field width of the printed field, from 1 to 10
|
||||
* @param baseValue the base value of the range of valid values
|
||||
* @return this, for chaining, not null
|
||||
* @throws IllegalArgumentException if the width or base value is invalid
|
||||
*/
|
||||
public DateTimeFormatterBuilder appendValueReduced(
|
||||
TemporalField field, int width, int baseValue) {
|
||||
public DateTimeFormatterBuilder appendValueReduced(TemporalField field,
|
||||
int width, int maxWidth, int baseValue) {
|
||||
Objects.requireNonNull(field, "field");
|
||||
ReducedPrinterParser pp = new ReducedPrinterParser(field, width, baseValue);
|
||||
appendFixedWidth(width, pp);
|
||||
ReducedPrinterParser pp = new ReducedPrinterParser(field, width, maxWidth, baseValue);
|
||||
appendValue(pp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a fixed width printer-parser.
|
||||
* Appends a fixed or variable width printer-parser handling adjacent value mode.
|
||||
* If a PrinterParser is not active then the new PrinterParser becomes
|
||||
* the active PrinterParser.
|
||||
* Otherwise, the active PrinterParser is modified depending on the new PrinterParser.
|
||||
* If the new PrinterParser is fixed width and has sign style {@code NOT_NEGATIVE}
|
||||
* then its width is added to the active PP and
|
||||
* the new PrinterParser is forced to be fixed width.
|
||||
* If the new PrinterParser is variable width, the active PrinterParser is changed
|
||||
* to be fixed width and the new PrinterParser becomes the active PP.
|
||||
*
|
||||
* @param width the width
|
||||
* @param pp the printer-parser, not null
|
||||
* @return this, for chaining, not null
|
||||
*/
|
||||
private DateTimeFormatterBuilder appendFixedWidth(int width, NumberPrinterParser pp) {
|
||||
private DateTimeFormatterBuilder appendValue(NumberPrinterParser pp) {
|
||||
if (active.valueParserIndex >= 0) {
|
||||
final int activeValueParser = active.valueParserIndex;
|
||||
|
||||
// adjacent parsing mode, update setting in previous parsers
|
||||
NumberPrinterParser basePP = (NumberPrinterParser) active.printerParsers.get(active.valueParserIndex);
|
||||
basePP = basePP.withSubsequentWidth(width);
|
||||
int activeValueParser = active.valueParserIndex;
|
||||
active.printerParsers.set(active.valueParserIndex, basePP);
|
||||
appendInternal(pp.withFixedWidth());
|
||||
active.valueParserIndex = activeValueParser;
|
||||
NumberPrinterParser basePP = (NumberPrinterParser) active.printerParsers.get(activeValueParser);
|
||||
if (pp.minWidth == pp.maxWidth && pp.signStyle == SignStyle.NOT_NEGATIVE) {
|
||||
// Append the width to the subsequentWidth of the active parser
|
||||
basePP = basePP.withSubsequentWidth(pp.maxWidth);
|
||||
// Append the new parser as a fixed width
|
||||
appendInternal(pp.withFixedWidth());
|
||||
// Retain the previous active parser
|
||||
active.valueParserIndex = activeValueParser;
|
||||
} else {
|
||||
// Modify the active parser to be fixed width
|
||||
basePP = basePP.withFixedWidth();
|
||||
// The new parser becomes the mew active parser
|
||||
active.valueParserIndex = appendInternal(pp);
|
||||
}
|
||||
// Replace the modified parser with the updated one
|
||||
active.printerParsers.set(activeValueParser, basePP);
|
||||
} else {
|
||||
// not adjacent parsing
|
||||
appendInternal(pp);
|
||||
// The new Parser becomes the active parser
|
||||
active.valueParserIndex = appendInternal(pp);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -657,11 +760,24 @@ public final class DateTimeFormatterBuilder {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Appends an instant using ISO-8601 to the formatter.
|
||||
* Appends an instant using ISO-8601 to the formatter, formatting fractional
|
||||
* digits in groups of three.
|
||||
* <p>
|
||||
* Instants have a fixed output format.
|
||||
* They are converted to a date-time with a zone-offset of UTC and printed
|
||||
* They are converted to a date-time with a zone-offset of UTC and formatted
|
||||
* using the standard ISO-8601 format.
|
||||
* With this method, formatting nano-of-second outputs zero, three, six
|
||||
* or nine digits digits as necessary.
|
||||
* The localized decimal style is not used.
|
||||
* <p>
|
||||
* The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
|
||||
* and optionally (@code NANO_OF_SECOND). The value of {@code INSTANT_SECONDS}
|
||||
* may be outside the maximum range of {@code LocalDateTime}.
|
||||
* <p>
|
||||
* The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
|
||||
* The end-of-day time of '24:00' is handled as midnight at the start of the following day.
|
||||
* The leap-second time of '23:59:59' is handled to some degree, see
|
||||
* {@link DateTimeFormatter#parsedLeapSecond()} for full details.
|
||||
* <p>
|
||||
* An alternative to this method is to format/parse the instant as a single
|
||||
* epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
|
||||
@ -669,10 +785,54 @@ public final class DateTimeFormatterBuilder {
|
||||
* @return this, for chaining, not null
|
||||
*/
|
||||
public DateTimeFormatterBuilder appendInstant() {
|
||||
appendInternal(new InstantPrinterParser());
|
||||
appendInternal(new InstantPrinterParser(-2));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an instant using ISO-8601 to the formatter with control over
|
||||
* the number of fractional digits.
|
||||
* <p>
|
||||
* Instants have a fixed output format, although this method provides some
|
||||
* control over the fractional digits. They are converted to a date-time
|
||||
* with a zone-offset of UTC and printed using the standard ISO-8601 format.
|
||||
* The localized decimal style is not used.
|
||||
* <p>
|
||||
* The {@code fractionalDigits} parameter allows the output of the fractional
|
||||
* second to be controlled. Specifying zero will cause no fractional digits
|
||||
* to be output. From 1 to 9 will output an increasing number of digits, using
|
||||
* zero right-padding if necessary. The special value -1 is used to output as
|
||||
* many digits as necessary to avoid any trailing zeroes.
|
||||
* <p>
|
||||
* When parsing in strict mode, the number of parsed digits must match the
|
||||
* fractional digits. When parsing in lenient mode, any number of fractional
|
||||
* digits from zero to nine are accepted.
|
||||
* <p>
|
||||
* The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
|
||||
* and optionally (@code NANO_OF_SECOND). The value of {@code INSTANT_SECONDS}
|
||||
* may be outside the maximum range of {@code LocalDateTime}.
|
||||
* <p>
|
||||
* The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
|
||||
* The end-of-day time of '24:00' is handled as midnight at the start of the following day.
|
||||
* The leap-second time of '23:59:59' is handled to some degree, see
|
||||
* {@link DateTimeFormatter#parsedLeapSecond()} for full details.
|
||||
* <p>
|
||||
* An alternative to this method is to format/parse the instant as a single
|
||||
* epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
|
||||
*
|
||||
* @param fractionalDigits the number of fractional second digits to format with,
|
||||
* from 0 to 9, or -1 to use as many digits as necessary
|
||||
* @return this, for chaining, not null
|
||||
*/
|
||||
public DateTimeFormatterBuilder appendInstant(int fractionalDigits) {
|
||||
if (fractionalDigits < -1 || fractionalDigits > 9) {
|
||||
throw new IllegalArgumentException("The fractional digits must be from -1 to 9 inclusive but was " + fractionalDigits);
|
||||
}
|
||||
appendInternal(new InstantPrinterParser(fractionalDigits));
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Appends the zone offset, such as '+01:00', to the formatter.
|
||||
* <p>
|
||||
@ -1049,7 +1209,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* <p>
|
||||
* The calendar system name will be output during a format.
|
||||
* If the chronology cannot be obtained then an exception will be thrown.
|
||||
* The calendar system name is obtained from the formatting symbols.
|
||||
* The calendar system name is obtained from the Chronology.
|
||||
*
|
||||
* @param textStyle the text style to use, not null
|
||||
* @return this, for chaining, not null
|
||||
@ -1838,7 +1998,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* using the default locale.
|
||||
* <p>
|
||||
* This will create a formatter with the {@linkplain Locale#getDefault(Locale.Category) default FORMAT locale}.
|
||||
* Numbers will be printed and parsed using the standard non-localized set of symbols.
|
||||
* Numbers will be printed and parsed using the standard DecimalStyle.
|
||||
* The resolver style will be {@link ResolverStyle#SMART SMART}.
|
||||
* <p>
|
||||
* Calling this method will end any open optional sections by repeatedly
|
||||
@ -1858,7 +2018,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* using the specified locale.
|
||||
* <p>
|
||||
* This will create a formatter with the specified locale.
|
||||
* Numbers will be printed and parsed using the standard non-localized set of symbols.
|
||||
* Numbers will be printed and parsed using the standard DecimalStyle.
|
||||
* The resolver style will be {@link ResolverStyle#SMART SMART}.
|
||||
* <p>
|
||||
* Calling this method will end any open optional sections by repeatedly
|
||||
@ -1898,7 +2058,7 @@ public final class DateTimeFormatterBuilder {
|
||||
optionalEnd();
|
||||
}
|
||||
CompositePrinterParser pp = new CompositePrinterParser(printerParsers, false);
|
||||
return new DateTimeFormatter(pp, locale, DateTimeFormatSymbols.STANDARD,
|
||||
return new DateTimeFormatter(pp, locale, DecimalStyle.STANDARD,
|
||||
resolverStyle, null, chrono, null);
|
||||
}
|
||||
|
||||
@ -1921,7 +2081,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* for the next parser. If an error occurs, the returned index will be negative
|
||||
* and will have the error position encoded using the complement operator.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* <p>
|
||||
@ -2282,24 +2442,25 @@ public final class DateTimeFormatterBuilder {
|
||||
/**
|
||||
* Array of 10 to the power of n.
|
||||
*/
|
||||
static final int[] EXCEED_POINTS = new int[] {
|
||||
0,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
static final long[] EXCEED_POINTS = new long[] {
|
||||
0L,
|
||||
10L,
|
||||
100L,
|
||||
1000L,
|
||||
10000L,
|
||||
100000L,
|
||||
1000000L,
|
||||
10000000L,
|
||||
100000000L,
|
||||
1000000000L,
|
||||
10000000000L,
|
||||
};
|
||||
|
||||
final TemporalField field;
|
||||
final int minWidth;
|
||||
private final int maxWidth;
|
||||
final int maxWidth;
|
||||
private final SignStyle signStyle;
|
||||
private final int subsequentWidth;
|
||||
final int subsequentWidth;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -2328,7 +2489,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater,
|
||||
* -1 if fixed width due to active adjacent parsing
|
||||
*/
|
||||
private NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth) {
|
||||
protected NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth) {
|
||||
// validated by caller
|
||||
this.field = field;
|
||||
this.minWidth = minWidth;
|
||||
@ -2343,6 +2504,9 @@ public final class DateTimeFormatterBuilder {
|
||||
* @return a new updated printer-parser, not null
|
||||
*/
|
||||
NumberPrinterParser withFixedWidth() {
|
||||
if (subsequentWidth == -1) {
|
||||
return this;
|
||||
}
|
||||
return new NumberPrinterParser(field, minWidth, maxWidth, signStyle, -1);
|
||||
}
|
||||
|
||||
@ -2363,24 +2527,24 @@ public final class DateTimeFormatterBuilder {
|
||||
return false;
|
||||
}
|
||||
long value = getValue(valueLong);
|
||||
DateTimeFormatSymbols symbols = context.getSymbols();
|
||||
DecimalStyle decimalStyle = context.getDecimalStyle();
|
||||
String str = (value == Long.MIN_VALUE ? "9223372036854775808" : Long.toString(Math.abs(value)));
|
||||
if (str.length() > maxWidth) {
|
||||
throw new DateTimeException("Field " + field.getName() +
|
||||
" cannot be printed as the value " + value +
|
||||
" exceeds the maximum print width of " + maxWidth);
|
||||
}
|
||||
str = symbols.convertNumberToI18N(str);
|
||||
str = decimalStyle.convertNumberToI18N(str);
|
||||
|
||||
if (value >= 0) {
|
||||
switch (signStyle) {
|
||||
case EXCEEDS_PAD:
|
||||
if (minWidth < 19 && value >= EXCEED_POINTS[minWidth]) {
|
||||
buf.append(symbols.getPositiveSign());
|
||||
buf.append(decimalStyle.getPositiveSign());
|
||||
}
|
||||
break;
|
||||
case ALWAYS:
|
||||
buf.append(symbols.getPositiveSign());
|
||||
buf.append(decimalStyle.getPositiveSign());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -2388,7 +2552,7 @@ public final class DateTimeFormatterBuilder {
|
||||
case NORMAL:
|
||||
case EXCEEDS_PAD:
|
||||
case ALWAYS:
|
||||
buf.append(symbols.getNegativeSign());
|
||||
buf.append(decimalStyle.getNegativeSign());
|
||||
break;
|
||||
case NOT_NEGATIVE:
|
||||
throw new DateTimeException("Field " + field.getName() +
|
||||
@ -2397,7 +2561,7 @@ public final class DateTimeFormatterBuilder {
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < minWidth - str.length(); i++) {
|
||||
buf.append(symbols.getZeroDigit());
|
||||
buf.append(decimalStyle.getZeroDigit());
|
||||
}
|
||||
buf.append(str);
|
||||
return true;
|
||||
@ -2426,13 +2590,13 @@ public final class DateTimeFormatterBuilder {
|
||||
char sign = text.charAt(position); // IOOBE if invalid position
|
||||
boolean negative = false;
|
||||
boolean positive = false;
|
||||
if (sign == context.getSymbols().getPositiveSign()) {
|
||||
if (sign == context.getDecimalStyle().getPositiveSign()) {
|
||||
if (signStyle.parse(true, context.isStrict(), minWidth == maxWidth) == false) {
|
||||
return ~position;
|
||||
}
|
||||
positive = true;
|
||||
position++;
|
||||
} else if (sign == context.getSymbols().getNegativeSign()) {
|
||||
} else if (sign == context.getDecimalStyle().getNegativeSign()) {
|
||||
if (signStyle.parse(false, context.isStrict(), minWidth == maxWidth) == false) {
|
||||
return ~position;
|
||||
}
|
||||
@ -2448,7 +2612,7 @@ public final class DateTimeFormatterBuilder {
|
||||
if (minEndPos > length) {
|
||||
return ~position;
|
||||
}
|
||||
int effMaxWidth = maxWidth + Math.max(subsequentWidth, 0);
|
||||
int effMaxWidth = (context.isStrict() || isFixedWidth() ? maxWidth : 9) + Math.max(subsequentWidth, 0);
|
||||
long total = 0;
|
||||
BigInteger totalBig = null;
|
||||
int pos = position;
|
||||
@ -2456,7 +2620,7 @@ public final class DateTimeFormatterBuilder {
|
||||
int maxEndPos = Math.min(pos + effMaxWidth, length);
|
||||
while (pos < maxEndPos) {
|
||||
char ch = text.charAt(pos++);
|
||||
int digit = context.getSymbols().convertToDigit(ch);
|
||||
int digit = context.getDecimalStyle().convertToDigit(ch);
|
||||
if (digit < 0) {
|
||||
pos--;
|
||||
if (pos < minEndPos) {
|
||||
@ -2550,62 +2714,110 @@ public final class DateTimeFormatterBuilder {
|
||||
*/
|
||||
static final class ReducedPrinterParser extends NumberPrinterParser {
|
||||
private final int baseValue;
|
||||
private final int range;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param field the field to format, validated not null
|
||||
* @param width the field width, from 1 to 18
|
||||
* @param minWidth the minimum field width, from 1 to 10
|
||||
* @param maxWidth the maximum field width, from 1 to 10
|
||||
* @param baseValue the base value
|
||||
*/
|
||||
ReducedPrinterParser(TemporalField field, int width, int baseValue) {
|
||||
super(field, width, width, SignStyle.NOT_NEGATIVE);
|
||||
if (width < 1 || width > 18) {
|
||||
throw new IllegalArgumentException("The width must be from 1 to 18 inclusive but was " + width);
|
||||
ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth,
|
||||
int baseValue) {
|
||||
this(field, minWidth, maxWidth, baseValue, 0);
|
||||
if (minWidth < 1 || minWidth > 10) {
|
||||
throw new IllegalArgumentException("The minWidth must be from 1 to 10 inclusive but was " + minWidth);
|
||||
}
|
||||
if (maxWidth < 1 || maxWidth > 10) {
|
||||
throw new IllegalArgumentException("The maxWidth must be from 1 to 10 inclusive but was " + minWidth);
|
||||
}
|
||||
if (maxWidth < minWidth) {
|
||||
throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " +
|
||||
maxWidth + " < " + minWidth);
|
||||
}
|
||||
if (field.range().isValidValue(baseValue) == false) {
|
||||
throw new IllegalArgumentException("The base value must be within the range of the field");
|
||||
}
|
||||
this.baseValue = baseValue;
|
||||
this.range = EXCEED_POINTS[width];
|
||||
if ((((long) baseValue) + range) > Integer.MAX_VALUE) {
|
||||
if ((((long) baseValue) + EXCEED_POINTS[maxWidth]) > Integer.MAX_VALUE) {
|
||||
throw new DateTimeException("Unable to add printer-parser as the range exceeds the capacity of an int");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* The arguments have already been checked.
|
||||
*
|
||||
* @param field the field to format, validated not null
|
||||
* @param minWidth the minimum field width, from 1 to 10
|
||||
* @param maxWidth the maximum field width, from 1 to 10
|
||||
* @param baseValue the base value
|
||||
* @param subsequentWidth the subsequentWidth for this instance
|
||||
*/
|
||||
private ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth,
|
||||
int baseValue, int subsequentWidth) {
|
||||
super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth);
|
||||
this.baseValue = baseValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
long getValue(long value) {
|
||||
return Math.abs(value % range);
|
||||
long absValue = Math.abs(value);
|
||||
if (value >= baseValue && value < baseValue + EXCEED_POINTS[minWidth]) {
|
||||
// Use the reduced value if it fits in minWidth
|
||||
return absValue % EXCEED_POINTS[minWidth];
|
||||
}
|
||||
// Otherwise truncate to fit in maxWidth
|
||||
return absValue % EXCEED_POINTS[maxWidth];
|
||||
}
|
||||
|
||||
@Override
|
||||
int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) {
|
||||
int lastPart = baseValue % range;
|
||||
if (baseValue > 0) {
|
||||
value = baseValue - lastPart + value;
|
||||
} else {
|
||||
value = baseValue - lastPart - value;
|
||||
}
|
||||
if (value < baseValue) {
|
||||
value += range;
|
||||
int parseLen = successPos - errorPos;
|
||||
if (parseLen == minWidth && value >= 0) {
|
||||
long range = EXCEED_POINTS[minWidth];
|
||||
long lastPart = baseValue % range;
|
||||
long basePart = baseValue - lastPart;
|
||||
if (baseValue > 0) {
|
||||
value = basePart + value;
|
||||
} else {
|
||||
value = basePart - value;
|
||||
}
|
||||
if (basePart != 0 && value < baseValue) {
|
||||
value += range;
|
||||
}
|
||||
}
|
||||
return context.setParsedField(field, value, errorPos, successPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with fixed width flag set.
|
||||
*
|
||||
* @return a new updated printer-parser, not null
|
||||
*/
|
||||
@Override
|
||||
NumberPrinterParser withFixedWidth() {
|
||||
return this;
|
||||
ReducedPrinterParser withFixedWidth() {
|
||||
if (subsequentWidth == -1) {
|
||||
return this;
|
||||
}
|
||||
return new ReducedPrinterParser(field, minWidth, maxWidth, baseValue, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with an updated subsequent width.
|
||||
*
|
||||
* @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater
|
||||
* @return a new updated printer-parser, not null
|
||||
*/
|
||||
@Override
|
||||
boolean isFixedWidth() {
|
||||
return true;
|
||||
ReducedPrinterParser withSubsequentWidth(int subsequentWidth) {
|
||||
return new ReducedPrinterParser(field, minWidth, maxWidth, baseValue,
|
||||
this.subsequentWidth + subsequentWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReducedValue(" + field.getName() + "," + minWidth + "," + baseValue + ")";
|
||||
return "ReducedValue(" + field.getName() + "," + minWidth + "," + maxWidth + "," + baseValue + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@ -2654,24 +2866,24 @@ public final class DateTimeFormatterBuilder {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
DateTimeFormatSymbols symbols = context.getSymbols();
|
||||
DecimalStyle decimalStyle = context.getDecimalStyle();
|
||||
BigDecimal fraction = convertToFraction(value);
|
||||
if (fraction.scale() == 0) { // scale is zero if value is zero
|
||||
if (minWidth > 0) {
|
||||
if (decimalPoint) {
|
||||
buf.append(symbols.getDecimalSeparator());
|
||||
buf.append(decimalStyle.getDecimalSeparator());
|
||||
}
|
||||
for (int i = 0; i < minWidth; i++) {
|
||||
buf.append(symbols.getZeroDigit());
|
||||
buf.append(decimalStyle.getZeroDigit());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int outputScale = Math.min(Math.max(fraction.scale(), minWidth), maxWidth);
|
||||
fraction = fraction.setScale(outputScale, RoundingMode.FLOOR);
|
||||
String str = fraction.toPlainString().substring(2);
|
||||
str = symbols.convertNumberToI18N(str);
|
||||
str = decimalStyle.convertNumberToI18N(str);
|
||||
if (decimalPoint) {
|
||||
buf.append(symbols.getDecimalSeparator());
|
||||
buf.append(decimalStyle.getDecimalSeparator());
|
||||
}
|
||||
buf.append(str);
|
||||
}
|
||||
@ -2688,7 +2900,7 @@ public final class DateTimeFormatterBuilder {
|
||||
return (effectiveMin > 0 ? ~position : position);
|
||||
}
|
||||
if (decimalPoint) {
|
||||
if (text.charAt(position) != context.getSymbols().getDecimalSeparator()) {
|
||||
if (text.charAt(position) != context.getDecimalStyle().getDecimalSeparator()) {
|
||||
// valid if whole field is optional, invalid if minimum width
|
||||
return (effectiveMin > 0 ? ~position : position);
|
||||
}
|
||||
@ -2703,7 +2915,7 @@ public final class DateTimeFormatterBuilder {
|
||||
int pos = position;
|
||||
while (pos < maxEndPos) {
|
||||
char ch = text.charAt(pos++);
|
||||
int digit = context.getSymbols().convertToDigit(ch);
|
||||
int digit = context.getDecimalStyle().convertToDigit(ch);
|
||||
if (digit < 0) {
|
||||
if (pos < minEndPos) {
|
||||
return ~position; // need at least min width digits
|
||||
@ -2883,43 +3095,50 @@ public final class DateTimeFormatterBuilder {
|
||||
// seconds per day = 86400
|
||||
private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
|
||||
private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
|
||||
private static final CompositePrinterParser PARSER = new DateTimeFormatterBuilder()
|
||||
.parseCaseInsensitive()
|
||||
.append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T')
|
||||
.append(DateTimeFormatter.ISO_LOCAL_TIME).appendLiteral('Z')
|
||||
.toFormatter().toPrinterParser(false);
|
||||
private final int fractionalDigits;
|
||||
|
||||
InstantPrinterParser() {
|
||||
InstantPrinterParser(int fractionalDigits) {
|
||||
this.fractionalDigits = fractionalDigits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean format(DateTimePrintContext context, StringBuilder buf) {
|
||||
// use INSTANT_SECONDS, thus this code is not bound by Instant.MAX
|
||||
Long inSecs = context.getValue(INSTANT_SECONDS);
|
||||
Long inNanos = context.getValue(NANO_OF_SECOND);
|
||||
if (inSecs == null || inNanos == null) {
|
||||
Long inNanos = null;
|
||||
if (context.getTemporal().isSupported(NANO_OF_SECOND)) {
|
||||
inNanos = context.getTemporal().getLong(NANO_OF_SECOND);
|
||||
}
|
||||
if (inSecs == null) {
|
||||
return false;
|
||||
}
|
||||
long inSec = inSecs;
|
||||
int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos);
|
||||
int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos != null ? inNanos : 0);
|
||||
// format mostly using LocalDateTime.toString
|
||||
if (inSec >= -SECONDS_0000_TO_1970) {
|
||||
// current era
|
||||
long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
|
||||
long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
|
||||
long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
|
||||
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
|
||||
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
|
||||
if (hi > 0) {
|
||||
buf.append('+').append(hi);
|
||||
}
|
||||
buf.append(ldt).append('Z');
|
||||
buf.append(ldt);
|
||||
if (ldt.getSecond() == 0) {
|
||||
buf.append(":00");
|
||||
}
|
||||
} else {
|
||||
// before current era
|
||||
long zeroSecs = inSec + SECONDS_0000_TO_1970;
|
||||
long hi = zeroSecs / SECONDS_PER_10000_YEARS;
|
||||
long lo = zeroSecs % SECONDS_PER_10000_YEARS;
|
||||
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
|
||||
LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
|
||||
int pos = buf.length();
|
||||
buf.append(ldt).append('Z');
|
||||
buf.append(ldt);
|
||||
if (ldt.getSecond() == 0) {
|
||||
buf.append(":00");
|
||||
}
|
||||
if (hi < 0) {
|
||||
if (ldt.getYear() == -10_000) {
|
||||
buf.replace(pos, pos + 2, Long.toString(hi - 1));
|
||||
@ -2930,14 +3149,38 @@ public final class DateTimeFormatterBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
// add fraction
|
||||
if ((fractionalDigits < 0 && inNano > 0) || fractionalDigits > 0) {
|
||||
buf.append('.');
|
||||
int div = 100_000_000;
|
||||
for (int i = 0; ((fractionalDigits == -1 && inNano > 0) ||
|
||||
(fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) ||
|
||||
i < fractionalDigits); i++) {
|
||||
int digit = inNano / div;
|
||||
buf.append((char) (digit + '0'));
|
||||
inNano = inNano - (digit * div);
|
||||
div = div / 10;
|
||||
}
|
||||
}
|
||||
buf.append('Z');
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int parse(DateTimeParseContext context, CharSequence text, int position) {
|
||||
// new context to avoid overwriting fields like year/month/day
|
||||
int minDigits = (fractionalDigits < 0 ? 0 : fractionalDigits);
|
||||
int maxDigits = (fractionalDigits < 0 ? 9 : fractionalDigits);
|
||||
CompositePrinterParser parser = new DateTimeFormatterBuilder()
|
||||
.append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T')
|
||||
.appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
|
||||
.appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
|
||||
.appendValue(SECOND_OF_MINUTE, 2)
|
||||
.appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
|
||||
.appendLiteral('Z')
|
||||
.toFormatter().toPrinterParser(false);
|
||||
DateTimeParseContext newContext = context.copy();
|
||||
int pos = PARSER.parse(newContext, text, position);
|
||||
int pos = parser.parse(newContext, text, position);
|
||||
if (pos < 0) {
|
||||
return pos;
|
||||
}
|
||||
@ -2952,10 +3195,18 @@ public final class DateTimeFormatterBuilder {
|
||||
Long nanoVal = newContext.getParsed(NANO_OF_SECOND);
|
||||
int sec = (secVal != null ? secVal.intValue() : 0);
|
||||
int nano = (nanoVal != null ? nanoVal.intValue() : 0);
|
||||
int days = 0;
|
||||
if (hour == 24 && min == 0 && sec == 0 && nano == 0) {
|
||||
hour = 0;
|
||||
days = 1;
|
||||
} else if (hour == 23 && min == 59 && sec == 60) {
|
||||
context.setParsedLeapSecond();
|
||||
sec = 59;
|
||||
}
|
||||
int year = (int) yearParsed % 10_000;
|
||||
long instantSecs;
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0);
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0).plusDays(days);
|
||||
instantSecs = ldt.toEpochSecond(ZoneOffset.UTC);
|
||||
instantSecs += Math.multiplyExact(yearParsed / 10_000L, SECONDS_PER_10000_YEARS);
|
||||
} catch (RuntimeException ex) {
|
||||
@ -4017,9 +4268,7 @@ public final class DateTimeFormatterBuilder {
|
||||
String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle;
|
||||
DateTimeFormatter formatter = FORMATTER_CACHE.get(key);
|
||||
if (formatter == null) {
|
||||
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
|
||||
String pattern = lr.getJavaTimeDateTimePattern(
|
||||
convertStyle(timeStyle), convertStyle(dateStyle), chrono.getCalendarType());
|
||||
String pattern = getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale);
|
||||
formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
|
||||
DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter);
|
||||
if (old != null) {
|
||||
@ -4029,19 +4278,6 @@ public final class DateTimeFormatterBuilder {
|
||||
return formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given FormatStyle to the java.text.DateFormat style.
|
||||
*
|
||||
* @param style the FormatStyle style
|
||||
* @return the int style, or -1 if style is null, indicating unrequired
|
||||
*/
|
||||
private int convertStyle(FormatStyle style) {
|
||||
if (style == null) {
|
||||
return -1;
|
||||
}
|
||||
return style.ordinal(); // indices happen to align
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Localized(" + (dateStyle != null ? dateStyle : "") + "," +
|
||||
@ -4096,7 +4332,7 @@ public final class DateTimeFormatterBuilder {
|
||||
case 'Y':
|
||||
field = weekDef.weekBasedYear();
|
||||
if (count == 2) {
|
||||
return new ReducedPrinterParser(field, 2, 2000);
|
||||
return new ReducedPrinterParser(field, 2, 2, 2000, 0);
|
||||
} else {
|
||||
return new NumberPrinterParser(field, count, 19,
|
||||
(count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
|
||||
|
@ -61,6 +61,7 @@
|
||||
*/
|
||||
package java.time.format;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.ZoneId;
|
||||
import java.time.chrono.Chronology;
|
||||
import java.time.chrono.IsoChronology;
|
||||
@ -79,7 +80,7 @@ import java.util.Objects;
|
||||
* Once parsing is complete, the {@link #toParsed()} is used to obtain the data.
|
||||
* It contains a method to resolve the separate parsed fields into meaningful values.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is a mutable context intended for use from a single thread.
|
||||
* Usage of the class is thread-safe within standard parsing as a new instance of this class
|
||||
* is automatically created for each parse and parsing is single-threaded
|
||||
@ -118,9 +119,13 @@ final class DateTimeParseContext {
|
||||
|
||||
/**
|
||||
* Creates a copy of this context.
|
||||
* This retains the case sensitive and strict flags.
|
||||
*/
|
||||
DateTimeParseContext copy() {
|
||||
return new DateTimeParseContext(formatter);
|
||||
DateTimeParseContext newContext = new DateTimeParseContext(formatter);
|
||||
newContext.caseSensitive = caseSensitive;
|
||||
newContext.strict = strict;
|
||||
return newContext;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -128,7 +133,7 @@ final class DateTimeParseContext {
|
||||
* Gets the locale.
|
||||
* <p>
|
||||
* This locale is used to control localization in the parse except
|
||||
* where localization is controlled by the symbols.
|
||||
* where localization is controlled by the DecimalStyle.
|
||||
*
|
||||
* @return the locale, not null
|
||||
*/
|
||||
@ -137,14 +142,14 @@ final class DateTimeParseContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatting symbols.
|
||||
* Gets the DecimalStyle.
|
||||
* <p>
|
||||
* The symbols control the localization of numeric parsing.
|
||||
* The DecimalStyle controls the numeric parsing.
|
||||
*
|
||||
* @return the formatting symbols, not null
|
||||
* @return the DecimalStyle, not null
|
||||
*/
|
||||
DateTimeFormatSymbols getSymbols() {
|
||||
return formatter.getSymbols();
|
||||
DecimalStyle getDecimalStyle() {
|
||||
return formatter.getDecimalStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,6 +375,13 @@ final class DateTimeParseContext {
|
||||
currentParsed().zone = zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the parsed leap second.
|
||||
*/
|
||||
void setParsedLeapSecond() {
|
||||
currentParsed().leapSecond = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a string version of the context for debugging.
|
||||
|
@ -68,7 +68,7 @@ import java.time.DateTimeException;
|
||||
* <p>
|
||||
* This exception includes the text being parsed and the error index.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is intended for use in a single thread.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -85,7 +85,7 @@ import java.util.Objects;
|
||||
* <p>
|
||||
* This class provides a single wrapper to items used in the format.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is a mutable context intended for use from a single thread.
|
||||
* Usage of the class is thread-safe within standard printing as the framework creates
|
||||
* a new instance of the class for each format and printing is single-threaded.
|
||||
@ -234,7 +234,7 @@ final class DateTimePrintContext {
|
||||
* Gets the locale.
|
||||
* <p>
|
||||
* This locale is used to control localization in the format output except
|
||||
* where localization is controlled by the symbols.
|
||||
* where localization is controlled by the DecimalStyle.
|
||||
*
|
||||
* @return the locale, not null
|
||||
*/
|
||||
@ -243,14 +243,14 @@ final class DateTimePrintContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatting symbols.
|
||||
* Gets the DecimalStyle.
|
||||
* <p>
|
||||
* The symbols control the localization of numeric output.
|
||||
* The DecimalStyle controls the localization of numeric output.
|
||||
*
|
||||
* @return the formatting symbols, not null
|
||||
* @return the DecimalStyle, not null
|
||||
*/
|
||||
DateTimeFormatSymbols getSymbols() {
|
||||
return formatter.getSymbols();
|
||||
DecimalStyle getDecimalStyle() {
|
||||
return formatter.getDecimalStyle();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -94,7 +94,7 @@ import sun.util.locale.provider.LocaleResources;
|
||||
/**
|
||||
* A provider to obtain the textual form of a date-time field.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must be thread-safe.
|
||||
* Implementations should cache the textual information.
|
||||
*
|
||||
|
@ -62,34 +62,38 @@
|
||||
package java.time.format;
|
||||
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Localized symbols used in date and time formatting.
|
||||
* Localized decimal style used in date and time formatting.
|
||||
* <p>
|
||||
* A significant part of dealing with dates and times is the localization.
|
||||
* This class acts as a central point for accessing the information.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class DateTimeFormatSymbols {
|
||||
public final class DecimalStyle {
|
||||
|
||||
/**
|
||||
* The standard set of non-localized symbols.
|
||||
* The standard set of non-localized decimal style symbols.
|
||||
* <p>
|
||||
* This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point.
|
||||
*/
|
||||
public static final DateTimeFormatSymbols STANDARD = new DateTimeFormatSymbols('0', '+', '-', '.');
|
||||
public static final DecimalStyle STANDARD = new DecimalStyle('0', '+', '-', '.');
|
||||
/**
|
||||
* The cache of symbols instances.
|
||||
* The cache of DecimalStyle instances.
|
||||
*/
|
||||
private static final ConcurrentMap<Locale, DateTimeFormatSymbols> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
private static final ConcurrentMap<Locale, DecimalStyle> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
|
||||
/**
|
||||
* The zero digit.
|
||||
@ -114,17 +118,20 @@ public final class DateTimeFormatSymbols {
|
||||
* <p>
|
||||
* The locale 'en_US' will always be present.
|
||||
*
|
||||
* @return an array of locales for which localization is supported
|
||||
* @return a Set of Locales for which localization is supported
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
return DecimalFormatSymbols.getAvailableLocales();
|
||||
public static Set<Locale> getAvailableLocales() {
|
||||
Locale[] l = DecimalFormatSymbols.getAvailableLocales();
|
||||
Set<Locale> locales = new HashSet<>(l.length);
|
||||
Collections.addAll(locales, l);
|
||||
return locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains symbols for the default
|
||||
* Obtains the DecimalStyle for the default
|
||||
* {@link java.util.Locale.Category#FORMAT FORMAT} locale.
|
||||
* <p>
|
||||
* This method provides access to locale sensitive symbols.
|
||||
* This method provides access to locale sensitive decimal style symbols.
|
||||
* <p>
|
||||
* This is equivalent to calling
|
||||
* {@link #of(Locale)
|
||||
@ -133,21 +140,21 @@ public final class DateTimeFormatSymbols {
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @return the info, not null
|
||||
*/
|
||||
public static DateTimeFormatSymbols ofDefaultLocale() {
|
||||
public static DecimalStyle ofDefaultLocale() {
|
||||
return of(Locale.getDefault(Locale.Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains symbols for the specified locale.
|
||||
* Obtains the DecimalStyle for the specified locale.
|
||||
* <p>
|
||||
* This method provides access to locale sensitive symbols.
|
||||
* This method provides access to locale sensitive decimal style symbols.
|
||||
*
|
||||
* @param locale the locale, not null
|
||||
* @return the info, not null
|
||||
*/
|
||||
public static DateTimeFormatSymbols of(Locale locale) {
|
||||
public static DecimalStyle of(Locale locale) {
|
||||
Objects.requireNonNull(locale, "locale");
|
||||
DateTimeFormatSymbols info = CACHE.get(locale);
|
||||
DecimalStyle info = CACHE.get(locale);
|
||||
if (info == null) {
|
||||
info = create(locale);
|
||||
CACHE.putIfAbsent(locale, info);
|
||||
@ -156,7 +163,7 @@ public final class DateTimeFormatSymbols {
|
||||
return info;
|
||||
}
|
||||
|
||||
private static DateTimeFormatSymbols create(Locale locale) {
|
||||
private static DecimalStyle create(Locale locale) {
|
||||
DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale);
|
||||
char zeroDigit = oldSymbols.getZeroDigit();
|
||||
char positiveSign = '+';
|
||||
@ -165,7 +172,7 @@ public final class DateTimeFormatSymbols {
|
||||
if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') {
|
||||
return STANDARD;
|
||||
}
|
||||
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -177,7 +184,7 @@ public final class DateTimeFormatSymbols {
|
||||
* @param negativeSignChar the character to use for the negative sign
|
||||
* @param decimalPointChar the character to use for the decimal point
|
||||
*/
|
||||
private DateTimeFormatSymbols(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
|
||||
private DecimalStyle(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
|
||||
this.zeroDigit = zeroChar;
|
||||
this.positiveSign = positiveSignChar;
|
||||
this.negativeSign = negativeSignChar;
|
||||
@ -207,11 +214,11 @@ public final class DateTimeFormatSymbols {
|
||||
* @return a copy with a new character that represents zero, not null
|
||||
|
||||
*/
|
||||
public DateTimeFormatSymbols withZeroDigit(char zeroDigit) {
|
||||
public DecimalStyle withZeroDigit(char zeroDigit) {
|
||||
if (zeroDigit == this.zeroDigit) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -236,11 +243,11 @@ public final class DateTimeFormatSymbols {
|
||||
* @param positiveSign the character for the positive sign
|
||||
* @return a copy with a new character that represents the positive sign, not null
|
||||
*/
|
||||
public DateTimeFormatSymbols withPositiveSign(char positiveSign) {
|
||||
public DecimalStyle withPositiveSign(char positiveSign) {
|
||||
if (positiveSign == this.positiveSign) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -265,11 +272,11 @@ public final class DateTimeFormatSymbols {
|
||||
* @param negativeSign the character for the negative sign
|
||||
* @return a copy with a new character that represents the negative sign, not null
|
||||
*/
|
||||
public DateTimeFormatSymbols withNegativeSign(char negativeSign) {
|
||||
public DecimalStyle withNegativeSign(char negativeSign) {
|
||||
if (negativeSign == this.negativeSign) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -294,11 +301,11 @@ public final class DateTimeFormatSymbols {
|
||||
* @param decimalSeparator the character for the decimal point
|
||||
* @return a copy with a new character that represents the decimal point, not null
|
||||
*/
|
||||
public DateTimeFormatSymbols withDecimalSeparator(char decimalSeparator) {
|
||||
public DecimalStyle withDecimalSeparator(char decimalSeparator) {
|
||||
if (decimalSeparator == this.decimalSeparator) {
|
||||
return this;
|
||||
}
|
||||
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -333,7 +340,7 @@ public final class DateTimeFormatSymbols {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if these symbols equal another set of symbols.
|
||||
* Checks if this DecimalStyle is equal another DecimalStyle.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
@ -343,8 +350,8 @@ public final class DateTimeFormatSymbols {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof DateTimeFormatSymbols) {
|
||||
DateTimeFormatSymbols other = (DateTimeFormatSymbols) obj;
|
||||
if (obj instanceof DecimalStyle) {
|
||||
DecimalStyle other = (DecimalStyle) obj;
|
||||
return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
|
||||
negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
|
||||
}
|
||||
@ -352,7 +359,7 @@ public final class DateTimeFormatSymbols {
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for these symbols.
|
||||
* A hash code for this DecimalStyle.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@ -363,13 +370,13 @@ public final class DateTimeFormatSymbols {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a string describing these symbols.
|
||||
* Returns a string describing this DecimalStyle.
|
||||
*
|
||||
* @return a string description, not null
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Symbols[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
|
||||
return "DecimalStyle[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
|
||||
}
|
||||
|
||||
}
|
@ -67,7 +67,7 @@ package java.time.format;
|
||||
* These styles are used when obtaining a date-time style from configuration.
|
||||
* See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -80,6 +80,7 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.chrono.ChronoLocalDate;
|
||||
import java.time.chrono.Chronology;
|
||||
@ -105,7 +106,7 @@ import java.util.Set;
|
||||
* Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}.
|
||||
* In most cases, it is only exposed once the fields have been resolved.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is a mutable context intended for use from a single thread.
|
||||
* Usage of the class is thread-safe within standard parsing as a new instance of this class
|
||||
* is automatically created for each parse and parsing is single-threaded
|
||||
@ -127,6 +128,10 @@ final class Parsed implements TemporalAccessor {
|
||||
* The parsed chronology.
|
||||
*/
|
||||
Chronology chrono;
|
||||
/**
|
||||
* Whether a leap-second is parsed.
|
||||
*/
|
||||
boolean leapSecond;
|
||||
/**
|
||||
* The effective chronology.
|
||||
*/
|
||||
@ -143,6 +148,10 @@ final class Parsed implements TemporalAccessor {
|
||||
* The resolved time.
|
||||
*/
|
||||
private LocalTime time;
|
||||
/**
|
||||
* The excess period from time-only parsing.
|
||||
*/
|
||||
Period excessDays = Period.ZERO;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
@ -159,6 +168,7 @@ final class Parsed implements TemporalAccessor {
|
||||
cloned.fieldValues.putAll(this.fieldValues);
|
||||
cloned.zone = this.zone;
|
||||
cloned.chrono = this.chrono;
|
||||
cloned.leapSecond = this.leapSecond;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
@ -232,6 +242,7 @@ final class Parsed implements TemporalAccessor {
|
||||
resolveFields();
|
||||
resolveTimeLenient();
|
||||
crossCheck();
|
||||
resolvePeriod();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -308,36 +319,72 @@ final class Parsed implements TemporalAccessor {
|
||||
private void resolveTimeFields() {
|
||||
// simplify fields
|
||||
if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) {
|
||||
// lenient allows anything, smart allows 0-24, strict allows 1-24
|
||||
long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY);
|
||||
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
|
||||
CLOCK_HOUR_OF_DAY.checkValidValue(ch);
|
||||
}
|
||||
updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch);
|
||||
}
|
||||
if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) {
|
||||
// lenient allows anything, smart allows 0-12, strict allows 1-12
|
||||
long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM);
|
||||
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
|
||||
CLOCK_HOUR_OF_AMPM.checkValidValue(ch);
|
||||
}
|
||||
updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch);
|
||||
}
|
||||
if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) {
|
||||
long ap = fieldValues.remove(AMPM_OF_DAY);
|
||||
long hap = fieldValues.remove(HOUR_OF_AMPM);
|
||||
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, Math.addExact(Math.multiplyExact(ap, 12), hap));
|
||||
} else { // STRICT or SMART
|
||||
AMPM_OF_DAY.checkValidValue(ap);
|
||||
HOUR_OF_AMPM.checkValidValue(ap);
|
||||
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);
|
||||
}
|
||||
}
|
||||
if (fieldValues.containsKey(NANO_OF_DAY)) {
|
||||
long nod = fieldValues.remove(NANO_OF_DAY);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
NANO_OF_DAY.checkValidValue(nod);
|
||||
}
|
||||
updateCheckConflict(NANO_OF_DAY, HOUR_OF_DAY, nod / 3600_000_000_000L);
|
||||
updateCheckConflict(NANO_OF_DAY, MINUTE_OF_HOUR, (nod / 60_000_000_000L) % 60);
|
||||
updateCheckConflict(NANO_OF_DAY, SECOND_OF_MINUTE, (nod / 1_000_000_000L) % 60);
|
||||
updateCheckConflict(NANO_OF_DAY, NANO_OF_SECOND, nod % 1_000_000_000L);
|
||||
}
|
||||
if (fieldValues.containsKey(MICRO_OF_DAY)) {
|
||||
long cod = fieldValues.remove(MICRO_OF_DAY);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
MICRO_OF_DAY.checkValidValue(cod);
|
||||
}
|
||||
updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L);
|
||||
updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L);
|
||||
}
|
||||
if (fieldValues.containsKey(MILLI_OF_DAY)) {
|
||||
long lod = fieldValues.remove(MILLI_OF_DAY);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
MILLI_OF_DAY.checkValidValue(lod);
|
||||
}
|
||||
updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000);
|
||||
updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000);
|
||||
}
|
||||
if (fieldValues.containsKey(SECOND_OF_DAY)) {
|
||||
long sod = fieldValues.remove(SECOND_OF_DAY);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
SECOND_OF_DAY.checkValidValue(sod);
|
||||
}
|
||||
updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600);
|
||||
updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60);
|
||||
updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60);
|
||||
}
|
||||
if (fieldValues.containsKey(MINUTE_OF_DAY)) {
|
||||
long mod = fieldValues.remove(MINUTE_OF_DAY);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
MINUTE_OF_DAY.checkValidValue(mod);
|
||||
}
|
||||
updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60);
|
||||
updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60);
|
||||
}
|
||||
@ -345,29 +392,34 @@ final class Parsed implements TemporalAccessor {
|
||||
// combine partial second fields strictly, leaving lenient expansion to later
|
||||
if (fieldValues.containsKey(NANO_OF_SECOND)) {
|
||||
long nos = fieldValues.get(NANO_OF_SECOND);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
NANO_OF_SECOND.checkValidValue(nos);
|
||||
}
|
||||
if (fieldValues.containsKey(MICRO_OF_SECOND)) {
|
||||
long cos = fieldValues.remove(MICRO_OF_SECOND);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
MICRO_OF_SECOND.checkValidValue(cos);
|
||||
}
|
||||
nos = cos * 1000 + (nos % 1000);
|
||||
updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos);
|
||||
}
|
||||
if (fieldValues.containsKey(MILLI_OF_SECOND)) {
|
||||
long los = fieldValues.remove(MILLI_OF_SECOND);
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
MILLI_OF_SECOND.checkValidValue(los);
|
||||
}
|
||||
updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L));
|
||||
}
|
||||
}
|
||||
|
||||
// convert to time if possible
|
||||
if (fieldValues.containsKey(NANO_OF_DAY)) {
|
||||
long nod = fieldValues.remove(NANO_OF_DAY);
|
||||
updateCheckConflict(LocalTime.ofNanoOfDay(nod));
|
||||
}
|
||||
// convert to time if all four fields available (optimization)
|
||||
if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) &&
|
||||
fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) {
|
||||
int hodVal = HOUR_OF_DAY.checkValidIntValue(fieldValues.remove(HOUR_OF_DAY));
|
||||
int mohVal = MINUTE_OF_HOUR.checkValidIntValue(fieldValues.remove(MINUTE_OF_HOUR));
|
||||
int somVal = SECOND_OF_MINUTE.checkValidIntValue(fieldValues.remove(SECOND_OF_MINUTE));
|
||||
int nosVal = NANO_OF_SECOND.checkValidIntValue(fieldValues.remove(NANO_OF_SECOND));
|
||||
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal));
|
||||
long hod = fieldValues.remove(HOUR_OF_DAY);
|
||||
long moh = fieldValues.remove(MINUTE_OF_HOUR);
|
||||
long som = fieldValues.remove(SECOND_OF_MINUTE);
|
||||
long nos = fieldValues.remove(NANO_OF_SECOND);
|
||||
resolveTime(hod, moh, som, nos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,7 +429,7 @@ final class Parsed implements TemporalAccessor {
|
||||
// which would break updateCheckConflict(field)
|
||||
|
||||
if (time == null) {
|
||||
// can only get here if NANO_OF_SECOND not present
|
||||
// NANO_OF_SECOND merged with MILLI/MICRO above
|
||||
if (fieldValues.containsKey(MILLI_OF_SECOND)) {
|
||||
long los = fieldValues.remove(MILLI_OF_SECOND);
|
||||
if (fieldValues.containsKey(MICRO_OF_SECOND)) {
|
||||
@ -395,43 +447,87 @@ final class Parsed implements TemporalAccessor {
|
||||
long cos = fieldValues.remove(MICRO_OF_SECOND);
|
||||
fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
|
||||
}
|
||||
}
|
||||
|
||||
// merge hour/minute/second/nano leniently
|
||||
Long hod = fieldValues.get(HOUR_OF_DAY);
|
||||
if (hod != null) {
|
||||
int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);
|
||||
Long moh = fieldValues.get(MINUTE_OF_HOUR);
|
||||
Long som = fieldValues.get(SECOND_OF_MINUTE);
|
||||
Long nos = fieldValues.get(NANO_OF_SECOND);
|
||||
// merge hour/minute/second/nano leniently
|
||||
Long hod = fieldValues.get(HOUR_OF_DAY);
|
||||
if (hod != null) {
|
||||
Long moh = fieldValues.get(MINUTE_OF_HOUR);
|
||||
Long som = fieldValues.get(SECOND_OF_MINUTE);
|
||||
Long nos = fieldValues.get(NANO_OF_SECOND);
|
||||
|
||||
// check for invalid combinations that cannot be defaulted
|
||||
if (time == null) {
|
||||
// check for invalid combinations that cannot be defaulted
|
||||
if ((moh == null && (som != null || nos != null)) ||
|
||||
(moh != null && som == null && nos != null)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// default as necessary and build time
|
||||
int mohVal = (moh != null ? MINUTE_OF_HOUR.checkValidIntValue(moh) : (time != null ? time.getMinute() : 0));
|
||||
int somVal = (som != null ? SECOND_OF_MINUTE.checkValidIntValue(som) : (time != null ? time.getSecond() : 0));
|
||||
int nosVal = (nos != null ? NANO_OF_SECOND.checkValidIntValue(nos) : (time != null ? time.getNano() : 0));
|
||||
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal));
|
||||
fieldValues.remove(HOUR_OF_DAY);
|
||||
fieldValues.remove(MINUTE_OF_HOUR);
|
||||
fieldValues.remove(SECOND_OF_MINUTE);
|
||||
fieldValues.remove(NANO_OF_SECOND);
|
||||
// default as necessary and build time
|
||||
long mohVal = (moh != null ? moh : 0);
|
||||
long somVal = (som != null ? som : 0);
|
||||
long nosVal = (nos != null ? nos : 0);
|
||||
resolveTime(hod, mohVal, somVal, nosVal);
|
||||
fieldValues.remove(HOUR_OF_DAY);
|
||||
fieldValues.remove(MINUTE_OF_HOUR);
|
||||
fieldValues.remove(SECOND_OF_MINUTE);
|
||||
fieldValues.remove(NANO_OF_SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
// validate remaining
|
||||
if (resolverStyle != ResolverStyle.LENIENT && fieldValues.size() > 0) {
|
||||
for (Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
|
||||
TemporalField field = entry.getKey();
|
||||
if (field instanceof ChronoField && field.isTimeBased()) {
|
||||
((ChronoField) field).checkValidValue(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCheckConflict(LocalTime lt) {
|
||||
private void resolveTime(long hod, long moh, long som, long nos) {
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long totalNanos = Math.multiplyExact(hod, 3600_000_000_000L);
|
||||
totalNanos = Math.addExact(totalNanos, Math.multiplyExact(moh, 60_000_000_000L));
|
||||
totalNanos = Math.addExact(totalNanos, Math.multiplyExact(som, 1_000_000_000L));
|
||||
totalNanos = Math.addExact(totalNanos, nos);
|
||||
int excessDays = (int) Math.floorDiv(totalNanos, 86400_000_000_000L); // safe int cast
|
||||
long nod = Math.floorMod(totalNanos, 86400_000_000_000L);
|
||||
updateCheckConflict(LocalTime.ofNanoOfDay(nod), Period.ofDays(excessDays));
|
||||
} else { // STRICT or SMART
|
||||
int mohVal = MINUTE_OF_HOUR.checkValidIntValue(moh);
|
||||
int nosVal = NANO_OF_SECOND.checkValidIntValue(nos);
|
||||
// handle 24:00 end of day
|
||||
if (resolverStyle == ResolverStyle.SMART && hod == 24 && mohVal == 0 && som == 0 && nosVal == 0) {
|
||||
updateCheckConflict(LocalTime.MIDNIGHT, Period.ofDays(1));
|
||||
} else {
|
||||
int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);
|
||||
int somVal = SECOND_OF_MINUTE.checkValidIntValue(som);
|
||||
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal), Period.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolvePeriod() {
|
||||
// add whole days if we have both date and time
|
||||
if (date != null && time != null && excessDays.isZero() == false) {
|
||||
date = date.plus(excessDays);
|
||||
excessDays = Period.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCheckConflict(LocalTime timeToSet, Period periodToSet) {
|
||||
if (time != null) {
|
||||
if (lt != null && time.equals(lt) == false) {
|
||||
throw new DateTimeException("Conflict found: Fields resolved to two different times: " + time + " " + lt);
|
||||
if (time.equals(timeToSet) == false) {
|
||||
throw new DateTimeException("Conflict found: Fields resolved to different times: " + time + " " + timeToSet);
|
||||
}
|
||||
if (excessDays.isZero() == false && periodToSet.isZero() == false && excessDays.equals(periodToSet) == false) {
|
||||
throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " + excessDays + " " + periodToSet);
|
||||
} else {
|
||||
excessDays = periodToSet;
|
||||
}
|
||||
} else {
|
||||
time = lt;
|
||||
time = timeToSet;
|
||||
excessDays = periodToSet;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ package java.time.format;
|
||||
* Phase 2 resolves the parsed field-value pairs into date and/or time objects.
|
||||
* This style is used to control how phase 2, resolving, happens.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -96,10 +96,9 @@ public enum ResolverStyle {
|
||||
* behavior. Individual fields will interpret this differently.
|
||||
* <p>
|
||||
* For example, resolving year-month and day-of-month in the ISO calendar
|
||||
* system using smart mode will ensure that the day-of-month is valid
|
||||
* for the year-month, rejecting invalid values, with the exception that
|
||||
* February 29th in a year other than a leap year will be converted to
|
||||
* February 28th.
|
||||
* system using smart mode will ensure that the day-of-month is from
|
||||
* 1 to 31, converting any value beyond the last valid day-of-month to be
|
||||
* the last valid day-of-month.
|
||||
*/
|
||||
SMART,
|
||||
/**
|
||||
@ -110,6 +109,7 @@ public enum ResolverStyle {
|
||||
* <p>
|
||||
* For example, lenient mode allows the month in the ISO calendar system
|
||||
* to be outside the range 1 to 12.
|
||||
* For example, month 15 is treated as being 3 months after month 12.
|
||||
*/
|
||||
LENIENT;
|
||||
|
||||
|
@ -68,7 +68,7 @@ package java.time.format;
|
||||
* to be controlled using this enum.
|
||||
* See {@link DateTimeFormatterBuilder} for usage.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -80,7 +80,7 @@ import java.util.Calendar;
|
||||
* For example, the word used for a month when used alone in a date picker is different
|
||||
* to the word used for month in association with a day and year in a date.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is immutable and thread-safe enum.
|
||||
*/
|
||||
public enum TextStyle {
|
||||
|
@ -76,7 +76,7 @@
|
||||
* Localization occurs by calling
|
||||
* {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)}
|
||||
* on the formatter. Further customization is possible using
|
||||
* {@link java.time.format.DateTimeFormatSymbols DateTimeFormatSymbols}.
|
||||
* {@link java.time.format.DecimalStyle DecimalStyle}.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Package specification</h3>
|
||||
|
@ -93,7 +93,7 @@ import sun.util.locale.provider.LocaleResources;
|
||||
* just with slightly different rules.
|
||||
* The documentation of each field explains how it operates.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is a final, immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -115,6 +115,10 @@ public enum ChronoField implements TemporalField {
|
||||
* object stores, using integer division to remove excess precision.
|
||||
* For example, if the {@code TemporalAccessor} stores time to millisecond precision,
|
||||
* then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The field is resolved in combination with {@code MILLI_OF_SECOND} and {@code MICRO_OF_SECOND}.
|
||||
*/
|
||||
NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)),
|
||||
/**
|
||||
@ -126,6 +130,11 @@ public enum ChronoField implements TemporalField {
|
||||
* This field is used to represent the nano-of-day handling any fraction of the second.
|
||||
* Implementations of {@code TemporalAccessor} should provide a value for this field if
|
||||
* they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The value is split to form {@code NANO_OF_SECOND}, {@code SECOND_OF_MINUTE},
|
||||
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
|
||||
*/
|
||||
NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)),
|
||||
/**
|
||||
@ -141,6 +150,11 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* When this field is used for setting a value, it should behave in the same way as
|
||||
* setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The field is resolved in combination with {@code MILLI_OF_SECOND} to produce
|
||||
* {@code NANO_OF_SECOND}.
|
||||
*/
|
||||
MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)),
|
||||
/**
|
||||
@ -155,6 +169,11 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* When this field is used for setting a value, it should behave in the same way as
|
||||
* setting {@link #NANO_OF_DAY} with the value multiplied by 1,000.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The value is split to form {@code MICRO_OF_SECOND}, {@code SECOND_OF_MINUTE},
|
||||
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
|
||||
*/
|
||||
MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)),
|
||||
/**
|
||||
@ -170,6 +189,11 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* When this field is used for setting a value, it should behave in the same way as
|
||||
* setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The field is resolved in combination with {@code MICRO_OF_SECOND} to produce
|
||||
* {@code NANO_OF_SECOND}.
|
||||
*/
|
||||
MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)),
|
||||
/**
|
||||
@ -184,6 +208,11 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* When this field is used for setting a value, it should behave in the same way as
|
||||
* setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The value is split to form {@code MILLI_OF_SECOND}, {@code SECOND_OF_MINUTE},
|
||||
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
|
||||
*/
|
||||
MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)),
|
||||
/**
|
||||
@ -191,6 +220,9 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* This counts the second within the minute, from 0 to 59.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
*/
|
||||
SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59), "second"),
|
||||
/**
|
||||
@ -198,6 +230,11 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The value is split to form {@code SECOND_OF_MINUTE}, {@code MINUTE_OF_HOUR}
|
||||
* and {@code HOUR_OF_DAY} fields.
|
||||
*/
|
||||
SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)),
|
||||
/**
|
||||
@ -205,6 +242,9 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* This counts the minute within the hour, from 0 to 59.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
*/
|
||||
MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59), "minute"),
|
||||
/**
|
||||
@ -212,6 +252,10 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* This counts the minute within the day, from 0 to (24 * 60) - 1.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The value is split to form {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
|
||||
*/
|
||||
MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)),
|
||||
/**
|
||||
@ -220,6 +264,12 @@ public enum ChronoField implements TemporalField {
|
||||
* This counts the hour within the AM/PM, from 0 to 11.
|
||||
* This is the hour that would be observed on a standard 12-hour digital clock.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated from 0 to 11 in strict and smart mode.
|
||||
* In lenient mode the value is not validated. It is combined with
|
||||
* {@code AMPM_OF_DAY} to form {@code HOUR_OF_DAY} by multiplying
|
||||
* the {AMPM_OF_DAY} value by 12.
|
||||
*/
|
||||
HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)),
|
||||
/**
|
||||
@ -228,6 +278,12 @@ public enum ChronoField implements TemporalField {
|
||||
* This counts the hour within the AM/PM, from 1 to 12.
|
||||
* This is the hour that would be observed on a standard 12-hour analog wall clock.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated from 1 to 12 in strict mode and from
|
||||
* 0 to 12 in smart mode. In lenient mode the value is not validated.
|
||||
* The field is converted to an {@code HOUR_OF_AMPM} with the same value,
|
||||
* unless the value is 12, in which case it is converted to 0.
|
||||
*/
|
||||
CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)),
|
||||
/**
|
||||
@ -236,6 +292,13 @@ public enum ChronoField implements TemporalField {
|
||||
* This counts the hour within the day, from 0 to 23.
|
||||
* This is the hour that would be observed on a standard 24-hour digital clock.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated in strict and smart mode but not in lenient mode.
|
||||
* The field is combined with {@code MINUTE_OF_HOUR}, {@code SECOND_OF_MINUTE} and
|
||||
* {@code NANO_OF_SECOND} to produce a {@code LocalTime}.
|
||||
* In lenient mode, any excess days are added to the parsed date, or
|
||||
* made available via {@link java.time.format.DateTimeFormatter#parsedExcessDays()}.
|
||||
*/
|
||||
HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23), "hour"),
|
||||
/**
|
||||
@ -244,6 +307,12 @@ public enum ChronoField implements TemporalField {
|
||||
* This counts the hour within the AM/PM, from 1 to 24.
|
||||
* This is the hour that would be observed on a 24-hour analog wall clock.
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated from 1 to 24 in strict mode and from
|
||||
* 0 to 24 in smart mode. In lenient mode the value is not validated.
|
||||
* The field is converted to an {@code HOUR_OF_DAY} with the same value,
|
||||
* unless the value is 24, in which case it is converted to 0.
|
||||
*/
|
||||
CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)),
|
||||
/**
|
||||
@ -251,6 +320,12 @@ public enum ChronoField implements TemporalField {
|
||||
* <p>
|
||||
* This counts the AM/PM within the day, from 0 (AM) to 1 (PM).
|
||||
* This field has the same meaning for all calendar systems.
|
||||
* <p>
|
||||
* When parsing this field it behaves equivalent to the following:
|
||||
* The value is validated from 0 to 1 in strict and smart mode.
|
||||
* In lenient mode the value is not validated. It is combined with
|
||||
* {@code HOUR_OF_AMPM} to form {@code HOUR_OF_DAY} by multiplying
|
||||
* the {AMPM_OF_DAY} value by 12.
|
||||
*/
|
||||
AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1), "dayperiod"),
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ import java.time.chrono.ChronoZonedDateTime;
|
||||
* just with slightly different rules.
|
||||
* The documentation of each unit explains how it operates.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is a final, immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -146,7 +146,7 @@ import sun.util.locale.provider.LocaleResources;
|
||||
* <tr><th>2009-01-05</th><td>Monday</td><td>Week 2 of week-based-year 2009</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* <p>
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
|
@ -81,7 +81,7 @@ import java.util.Map;
|
||||
* The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available.
|
||||
* The fields work with all chronologies.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe class.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -119,7 +119,7 @@ import java.time.ZoneId;
|
||||
* days to months.
|
||||
* </ul><p>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface places no restrictions on the mutability of implementations,
|
||||
* however immutability is strongly recommended.
|
||||
* All implementations must be {@link Comparable}.
|
||||
@ -146,7 +146,7 @@ public interface Temporal extends TemporalAccessor {
|
||||
* date = date.with(next(WEDNESDAY)); // static import from Adjusters and DayOfWeek
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must not alter either this object.
|
||||
* Instead, an adjusted copy of the original must be returned.
|
||||
* This provides equivalent, safe behavior for immutable and mutable implementations.
|
||||
@ -177,7 +177,7 @@ public interface Temporal extends TemporalAccessor {
|
||||
* In cases like this, the field is responsible for resolving the result. Typically it will choose
|
||||
* the previous valid date, which would be the last valid day of February in this example.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all fields defined in {@link ChronoField}.
|
||||
* If the field is supported, then the adjustment must be performed.
|
||||
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
|
||||
@ -217,7 +217,7 @@ public interface Temporal extends TemporalAccessor {
|
||||
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to
|
||||
* return the same date-time.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must not alter either this object.
|
||||
* Instead, an adjusted copy of the original must be returned.
|
||||
* This provides equivalent, safe behavior for immutable and mutable implementations.
|
||||
@ -247,12 +247,8 @@ public interface Temporal extends TemporalAccessor {
|
||||
* a date representing the 31st January, then adding one month would be unclear.
|
||||
* In cases like this, the field is responsible for resolving the result. Typically it will choose
|
||||
* the previous valid date, which would be the last valid day of February in this example.
|
||||
* <p>
|
||||
* If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
|
||||
* then the permitted units must include the boundary unit, but no multiples of the boundary unit.
|
||||
* For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all units defined in {@link ChronoUnit}.
|
||||
* If the unit is supported, then the addition must be performed.
|
||||
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
|
||||
@ -292,7 +288,7 @@ public interface Temporal extends TemporalAccessor {
|
||||
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to
|
||||
* return the same date-time.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must not alter either this object.
|
||||
* Instead, an adjusted copy of the original must be returned.
|
||||
* This provides equivalent, safe behavior for immutable and mutable implementations.
|
||||
@ -322,12 +318,8 @@ public interface Temporal extends TemporalAccessor {
|
||||
* a date representing the 31st March, then subtracting one month would be unclear.
|
||||
* In cases like this, the field is responsible for resolving the result. Typically it will choose
|
||||
* the previous valid date, which would be the last valid day of February in this example.
|
||||
* <p>
|
||||
* If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
|
||||
* then the permitted units must include the boundary unit, but no multiples of the boundary unit.
|
||||
* For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must behave in a manor equivalent to the default method behavior.
|
||||
* <p>
|
||||
* Implementations must not alter either this object or the specified temporal object.
|
||||
@ -353,10 +345,10 @@ public interface Temporal extends TemporalAccessor {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Calculates the period between this temporal and another temporal in
|
||||
* terms of the specified unit.
|
||||
* Calculates the amount of time until another temporal in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the period between two temporals in terms of a single unit.
|
||||
* This calculates the amount of time between two temporal objects
|
||||
* of the same type in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified temporal.
|
||||
* The result will be negative if the end is before the start.
|
||||
* For example, the period in hours between two temporal objects can be
|
||||
@ -385,7 +377,7 @@ public interface Temporal extends TemporalAccessor {
|
||||
* long daysBetween = DAYS.between(start, end);
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must begin by checking to ensure that the input temporal
|
||||
* object is of the same observable type as the implementation.
|
||||
* They must then perform the calculation for all instances of {@link ChronoUnit}.
|
||||
@ -410,11 +402,11 @@ public interface Temporal extends TemporalAccessor {
|
||||
* Neither this object, nor the specified temporal, may be altered.
|
||||
*
|
||||
* @param endTemporal the end temporal, of the same type as this object, not null
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the period between this temporal object and the specified one in terms of
|
||||
* the unit; positive if the specified object is later than this one, negative if
|
||||
* it is earlier than this one
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this temporal object and the specified one
|
||||
* in terms of the unit; positive if the specified object is later than this one,
|
||||
* negative if it is earlier than this one
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
|
@ -94,7 +94,7 @@ import java.util.Objects;
|
||||
* of this interface may be in calendar systems other than ISO.
|
||||
* See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface places no restrictions on the mutability of implementations,
|
||||
* however immutability is strongly recommended.
|
||||
*
|
||||
@ -109,7 +109,7 @@ public interface TemporalAccessor {
|
||||
* If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get}
|
||||
* methods will throw an exception.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all fields defined in {@link ChronoField}.
|
||||
* If the field is supported, then true is returned, otherwise false
|
||||
* <p>
|
||||
@ -137,7 +137,7 @@ public interface TemporalAccessor {
|
||||
* and it is important not to read too much into them. For example, there
|
||||
* could be values within the range that are invalid for the field.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all fields defined in {@link ChronoField}.
|
||||
* If the field is supported, then the range of the field must be returned.
|
||||
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
|
||||
@ -183,7 +183,7 @@ public interface TemporalAccessor {
|
||||
* If the date-time cannot return the value, because the field is unsupported or for
|
||||
* some other reason, an exception will be thrown.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all fields defined in {@link ChronoField}.
|
||||
* If the field is supported and has an {@code int} range, then the value of
|
||||
* the field must be returned.
|
||||
@ -231,7 +231,7 @@ public interface TemporalAccessor {
|
||||
* If the date-time cannot return the value, because the field is unsupported or for
|
||||
* some other reason, an exception will be thrown.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations must check and handle all fields defined in {@link ChronoField}.
|
||||
* If the field is supported, then the value of the field must be returned.
|
||||
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
|
||||
@ -265,7 +265,7 @@ public interface TemporalAccessor {
|
||||
* {@code LocalDate::from} and {@code ZoneId::from}.
|
||||
* Additional implementations are provided as static methods on {@link TemporalQuery}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The default implementation must behave equivalent to this code:
|
||||
* <pre>
|
||||
* if (query == TemporalQuery.zoneId() ||
|
||||
|
@ -97,7 +97,7 @@ import java.util.function.UnaryOperator;
|
||||
* <li>finding the next or previous day-of-week, such as "next Thursday"
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface places no restrictions on the mutability of implementations,
|
||||
* however immutability is strongly recommended.
|
||||
* <p>
|
||||
@ -127,7 +127,7 @@ public interface TemporalAdjuster {
|
||||
* It is recommended to use the second approach, {@code with(TemporalAdjuster)},
|
||||
* as it is a lot clearer to read in code.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The implementation must take the input object and adjust it.
|
||||
* The implementation defines the logic of the adjustment and is responsible for
|
||||
* documenting that logic. It may use any method on {@code Temporal} to
|
||||
@ -162,10 +162,10 @@ public interface TemporalAdjuster {
|
||||
* This is provided for convenience to make user-written adjusters simpler.
|
||||
* <p>
|
||||
* In general, user-written adjusters should be static constants:
|
||||
* <pre>
|
||||
* <pre>{@code
|
||||
* static TemporalAdjuster TWO_DAYS_LATER = TemporalAdjuster.ofDateAdjuster(
|
||||
* date -> date.plusDays(2));
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param dateBasedAdjuster the date-based adjuster, not null
|
||||
* @return the temporal adjuster wrapping on the date adjuster, not null
|
||||
|
@ -90,7 +90,7 @@ import java.util.List;
|
||||
* used in application code. Instead, applications should create and pass
|
||||
* around instances of concrete types, such as {@code Period} and {@code Duration}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface places no restrictions on the mutability of implementations,
|
||||
* however immutability is strongly recommended.
|
||||
*
|
||||
@ -104,7 +104,7 @@ public interface TemporalAmount {
|
||||
* value of the {@code TemporalAmount}. A value must be returned
|
||||
* for each unit listed in {@code getUnits}.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* Implementations may declare support for units not listed by {@link #getUnits()}.
|
||||
* Typically, the implementation would define additional units
|
||||
* as conversions for the convenience of developers.
|
||||
@ -124,7 +124,7 @@ public interface TemporalAmount {
|
||||
* The units are ordered from longest duration to the shortest duration
|
||||
* of the unit.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The list of units completely and uniquely represents the
|
||||
* state of the object without omissions, overlaps or duplication.
|
||||
* The units are in order from longest duration to shortest.
|
||||
@ -150,7 +150,7 @@ public interface TemporalAmount {
|
||||
* It is recommended to use the second approach, {@code plus(TemporalAmount)},
|
||||
* as it is a lot clearer to read in code.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The implementation must take the input object and add to it.
|
||||
* The implementation defines the logic of the addition and is responsible for
|
||||
* documenting that logic. It may use any method on {@code Temporal} to
|
||||
@ -192,7 +192,7 @@ public interface TemporalAmount {
|
||||
* It is recommended to use the second approach, {@code minus(TemporalAmount)},
|
||||
* as it is a lot clearer to read in code.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The implementation must take the input object and subtract from it.
|
||||
* The implementation defines the logic of the subtraction and is responsible for
|
||||
* documenting that logic. It may use any method on {@code Temporal} to
|
||||
|
@ -82,7 +82,7 @@ import java.util.Objects;
|
||||
* If it is, then the date-time must handle it.
|
||||
* Otherwise, the method call is re-dispatched to the matching method in this interface.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Implementations should be {@code Serializable} where possible.
|
||||
|
@ -96,7 +96,7 @@ import java.time.chrono.Chronology;
|
||||
* {@code LocalDate::from} and {@code ZoneId::from}.
|
||||
* Additional common implementations are provided on this interface as static methods.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface places no restrictions on the mutability of implementations,
|
||||
* however immutability is strongly recommended.
|
||||
*
|
||||
@ -124,7 +124,7 @@ public interface TemporalQuery<R> {
|
||||
* It is recommended to use the second approach, {@code query(TemporalQuery)},
|
||||
* as it is a lot clearer to read in code.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* The implementation must take the input object and query it.
|
||||
* The implementation defines the logic of the query and is responsible for
|
||||
* documenting that logic.
|
||||
|
@ -83,7 +83,7 @@ import java.time.Period;
|
||||
* If it is, then the date-time must handle it.
|
||||
* Otherwise, the method call is re-dispatched to the matching method in this interface.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* It is recommended to use an enum where possible.
|
||||
@ -197,19 +197,17 @@ public interface TemporalUnit {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Calculates the period in terms of this unit between two temporal objects
|
||||
* of the same type.
|
||||
* Calculates the amount of time between two temporal objects.
|
||||
* <p>
|
||||
* This calculates the period between two temporals in terms of this unit.
|
||||
* The start and end points are supplied as temporal objects and must be
|
||||
* of the same type.
|
||||
* This calculates the amount in terms of this unit. The start and end
|
||||
* points are supplied as temporal objects and must be of the same type.
|
||||
* The result will be negative if the end is before the start.
|
||||
* For example, the period in hours between two temporal objects can be
|
||||
* For example, the amount in hours between two temporal objects can be
|
||||
* calculated using {@code HOURS.between(startTime, endTime)}.
|
||||
* <p>
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two temporals.
|
||||
* For example, the period in hours between the times 11:30 and 13:29
|
||||
* For example, the amount in hours between the times 11:30 and 13:29
|
||||
* will only be one hour as it is one minute short of two hours.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
@ -237,9 +235,9 @@ public interface TemporalUnit {
|
||||
*
|
||||
* @param temporal1 the base temporal object, not null
|
||||
* @param temporal2 the other temporal object, not null
|
||||
* @return the period between temporal1 and temporal2 in terms of this unit;
|
||||
* @return the amount of time between temporal1 and temporal2 in terms of this unit;
|
||||
* positive if temporal2 is later than temporal1, negative if earlier
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws DateTimeException if the amount cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
|
@ -67,7 +67,7 @@ import java.time.DateTimeException;
|
||||
* UnsupportedTemporalTypeException indicates that a ChronoField or ChronoUnit is
|
||||
* not supported for a Temporal class.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is intended for use in a single thread.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -79,7 +79,7 @@ import java.time.DateTimeException;
|
||||
* <p>
|
||||
* Instances of this class are not tied to a specific field.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -170,7 +170,8 @@ import sun.util.locale.provider.LocaleResources;
|
||||
* <tr><th>2009-01-05</th><td>Monday</td>
|
||||
* <td>Week 2 of 2009</td><td>Week 1 of 2009</td></tr>
|
||||
* </table>
|
||||
* <h3>Specification for implementors</h3>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
@ -200,8 +201,6 @@ public final class WeekFields implements Serializable {
|
||||
* Note that the first week may start in the previous calendar year.
|
||||
* Note also that the first few days of a calendar year may be in the
|
||||
* week-based-year corresponding to the previous calendar year.
|
||||
* <p>
|
||||
* This field is an immutable and thread-safe singleton.
|
||||
*/
|
||||
public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
|
||||
|
||||
@ -211,8 +210,6 @@ public final class WeekFields implements Serializable {
|
||||
* <p>
|
||||
* Defined as starting on Sunday and with a minimum of 1 day in the month.
|
||||
* This week definition is in use in the US and other European countries.
|
||||
* <p>
|
||||
* This field is an immutable and thread-safe singleton.
|
||||
*/
|
||||
public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1);
|
||||
|
||||
@ -230,7 +227,7 @@ public final class WeekFields implements Serializable {
|
||||
* In that case, the week is set to the last week of the year
|
||||
* with the same day-of-week.
|
||||
* <p>
|
||||
* This field is an immutable and thread-safe singleton.
|
||||
* This unit is an immutable and thread-safe singleton.
|
||||
*/
|
||||
public static final TemporalUnit WEEK_BASED_YEARS = IsoFields.WEEK_BASED_YEARS;
|
||||
|
||||
@ -247,22 +244,18 @@ public final class WeekFields implements Serializable {
|
||||
* The minimal number of days in the first week.
|
||||
*/
|
||||
private final int minimalDays;
|
||||
|
||||
/**
|
||||
* The field used to access the computed DayOfWeek.
|
||||
*/
|
||||
private transient final TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this);
|
||||
|
||||
/**
|
||||
* The field used to access the computed WeekOfMonth.
|
||||
*/
|
||||
private transient final TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this);
|
||||
|
||||
/**
|
||||
* The field used to access the computed WeekOfYear.
|
||||
*/
|
||||
private transient final TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this);
|
||||
|
||||
/**
|
||||
* The field that represents the week-of-week-based-year.
|
||||
* <p>
|
||||
@ -271,7 +264,6 @@ public final class WeekFields implements Serializable {
|
||||
* This unit is an immutable and thread-safe singleton.
|
||||
*/
|
||||
private transient final TemporalField weekOfWeekBasedYear = ComputedDayOfField.ofWeekOfWeekBasedYearField(this);
|
||||
|
||||
/**
|
||||
* The field that represents the week-based-year.
|
||||
* <p>
|
||||
@ -281,6 +273,7 @@ public final class WeekFields implements Serializable {
|
||||
*/
|
||||
private transient final TemporalField weekBasedYear = ComputedDayOfField.ofWeekBasedYearField(this);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code WeekFields} appropriate for a locale.
|
||||
* <p>
|
||||
@ -359,8 +352,7 @@ public final class WeekFields implements Serializable {
|
||||
try {
|
||||
return WeekFields.of(firstDayOfWeek, minimalDays);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InvalidObjectException("Invalid serialized WeekFields: "
|
||||
+ iae.getMessage());
|
||||
throw new InvalidObjectException("Invalid serialized WeekFields: " + iae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,21 +386,24 @@ public final class WeekFields implements Serializable {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a field to access the day of week,
|
||||
* computed based on this WeekFields.
|
||||
* Returns a field to access the day of week based on this {@code WeekFields}.
|
||||
* <p>
|
||||
* The days of week are numbered from 1 to 7.
|
||||
* Day number 1 is the {@link #getFirstDayOfWeek() first day-of-week}.
|
||||
* This is similar to {@link ChronoField#DAY_OF_WEEK} but uses values for
|
||||
* the day-of-week based on this {@code WeekFields}.
|
||||
* The days are numbered from 1 to 7 where the
|
||||
* {@link #getFirstDayOfWeek() first day-of-week} is assigned the value 1.
|
||||
* <p>
|
||||
* For example, if the first day-of-week is Sunday, then that will have the
|
||||
* value 1, with other days ranging from Monday as 2 to Saturday as 7.
|
||||
*
|
||||
* @return the field for day-of-week using this week definition, not null
|
||||
* @return a field providing access to the day-of-week with localized numbering, not null
|
||||
*/
|
||||
public TemporalField dayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field to access the week of month,
|
||||
* computed based on this WeekFields.
|
||||
* Returns a field to access the week of month based on this {@code WeekFields}.
|
||||
* <p>
|
||||
* This represents the concept of the count of weeks within the month where weeks
|
||||
* start on a fixed day-of-week, such as Monday.
|
||||
@ -426,15 +421,15 @@ public final class WeekFields implements Serializable {
|
||||
* - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
|
||||
* <p>
|
||||
* This field can be used with any calendar system.
|
||||
* @return a TemporalField to access the WeekOfMonth, not null
|
||||
*
|
||||
* @return a field providing access to the week-of-month, not null
|
||||
*/
|
||||
public TemporalField weekOfMonth() {
|
||||
return weekOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field to access the week of year,
|
||||
* computed based on this WeekFields.
|
||||
* Returns a field to access the week of year based on this {@code WeekFields}.
|
||||
* <p>
|
||||
* This represents the concept of the count of weeks within the year where weeks
|
||||
* start on a fixed day-of-week, such as Monday.
|
||||
@ -452,15 +447,15 @@ public final class WeekFields implements Serializable {
|
||||
* - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
|
||||
* <p>
|
||||
* This field can be used with any calendar system.
|
||||
* @return a TemporalField to access the WeekOfYear, not null
|
||||
*
|
||||
* @return a field providing access to the week-of-year, not null
|
||||
*/
|
||||
public TemporalField weekOfYear() {
|
||||
return weekOfYear;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field to access the week of a week-based-year,
|
||||
* computed based on this WeekFields.
|
||||
* Returns a field to access the week of a week-based-year based on this {@code WeekFields}.
|
||||
* <p>
|
||||
* This represents the concept of the count of weeks within the year where weeks
|
||||
* start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.
|
||||
@ -482,15 +477,15 @@ public final class WeekFields implements Serializable {
|
||||
* the 1st to 4th is in week one<br>
|
||||
* <p>
|
||||
* This field can be used with any calendar system.
|
||||
* @return a TemporalField to access the week of week-based-year, not null
|
||||
*
|
||||
* @return a field providing access to the week-of-week-based-year, not null
|
||||
*/
|
||||
public TemporalField weekOfWeekBasedYear() {
|
||||
return weekOfWeekBasedYear;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field to access the year of a week-based-year,
|
||||
* computed based on this WeekFields.
|
||||
* Returns a field to access the year of a week-based-year based on this {@code WeekFields}.
|
||||
* <p>
|
||||
* This represents the concept of the year where weeks start on a fixed day-of-week,
|
||||
* such as Monday and each week belongs to exactly one year.
|
||||
@ -504,14 +499,16 @@ public final class WeekFields implements Serializable {
|
||||
* is in the last week of the previous year.
|
||||
* <p>
|
||||
* This field can be used with any calendar system.
|
||||
* @return a TemporalField to access the year of week-based-year, not null
|
||||
*
|
||||
* @return a field providing access to the week-based-year, not null
|
||||
*/
|
||||
public TemporalField weekBasedYear() {
|
||||
return weekBasedYear;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if this WeekFields is equal to the specified object.
|
||||
* Checks if this {@code WeekFields} is equal to the specified object.
|
||||
* <p>
|
||||
* The comparison is based on the entire state of the rules, which is
|
||||
* the first day-of-week and minimal days.
|
||||
@ -531,7 +528,7 @@ public final class WeekFields implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for these rules.
|
||||
* A hash code for this {@code WeekFields}.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@ -542,7 +539,7 @@ public final class WeekFields implements Serializable {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* A string representation of this definition.
|
||||
* A string representation of this {@code WeekFields} instance.
|
||||
*
|
||||
* @return the string representation, not null
|
||||
*/
|
||||
@ -957,7 +954,6 @@ public final class WeekFields implements Serializable {
|
||||
/**
|
||||
* Map the field range to a week range of a week year.
|
||||
* @param temporal the temporal
|
||||
* @param field the field to get the range of
|
||||
* @return the ValueRange with the range adjusted to weeks.
|
||||
*/
|
||||
private ValueRange rangeWeekOfWeekBasedYear(TemporalAccessor temporal) {
|
||||
|
@ -74,7 +74,7 @@ import java.time.ZoneOffset;
|
||||
/**
|
||||
* The shared serialization delegate for this package.
|
||||
*
|
||||
* <h3>Implementation notes</h3>
|
||||
* @implNote
|
||||
* This class is mutable and should be created once per serialization.
|
||||
*
|
||||
* @serial include
|
||||
|
@ -89,7 +89,7 @@ import java.util.Objects;
|
||||
* An example would be when the offset changes from {@code +04:00} to {@code +03:00}.
|
||||
* This might be described as 'the clocks will move back one hour tonight at 2am'.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -90,7 +90,7 @@ import java.util.Objects;
|
||||
* </ul><p>
|
||||
* These different rule types can be expressed and queried.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -100,7 +100,7 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* Applications should treat the data provided as representing the best information
|
||||
* available to the implementation of this rule.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -64,7 +64,7 @@ import java.time.DateTimeException;
|
||||
* This exception is used to indicate a problems with the configured
|
||||
* time-zone rules.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This class is intended for use in a single thread.
|
||||
*
|
||||
* @since 1.8
|
||||
|
@ -111,7 +111,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
* Each provider will provide the latest rules for each zone ID, but they
|
||||
* may also provide the history of how the rules changed.
|
||||
*
|
||||
* <h3>Specification for implementors</h3>
|
||||
* @implSpec
|
||||
* This interface is a service provider that can be called by multiple threads.
|
||||
* Implementations must be immutable and thread-safe.
|
||||
* <p>
|
||||
|
@ -625,7 +625,8 @@ public class Base64 {
|
||||
* character(s) padded), they are decoded as if followed by padding
|
||||
* character(s). If there is padding character present in the
|
||||
* final unit, the correct number of padding character(s) must be
|
||||
* present, otherwise {@code IllegalArgumentException} is thrown
|
||||
* present, otherwise {@code IllegalArgumentException} (
|
||||
* {@code IOException} when reading from a Base64 stream) is thrown
|
||||
* during decoding.
|
||||
*
|
||||
* <p> Instances of {@link Decoder} class are safe for use by
|
||||
@ -1306,7 +1307,12 @@ public class Base64 {
|
||||
return off - oldOff;
|
||||
}
|
||||
if (v == '=') { // padding byte(s)
|
||||
if (nextin != 6 && nextin != 0) {
|
||||
// = shiftto==18 unnecessary padding
|
||||
// x= shiftto==12 invalid unit
|
||||
// xx= shiftto==6 && missing last '='
|
||||
// xx=y or last is not '='
|
||||
if (nextin == 18 || nextin == 12 ||
|
||||
nextin == 6 && is.read() != '=') {
|
||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||
}
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
|
@ -249,11 +249,14 @@ class JapaneseImperialCalendar extends Calendar {
|
||||
CalendarDate transitionDate = eras[i].getSinceDate();
|
||||
date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
|
||||
long fdd = gcal.getFixedDate(date);
|
||||
dayOfYear = Math.min((int)(fdd - fd), dayOfYear);
|
||||
if (fd != fdd) {
|
||||
dayOfYear = Math.min((int)(fd - fdd) + 1, dayOfYear);
|
||||
}
|
||||
date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
|
||||
fdd = gcal.getFixedDate(date) + 1;
|
||||
dayOfYear = Math.min((int)(fd - fdd), dayOfYear);
|
||||
|
||||
fdd = gcal.getFixedDate(date);
|
||||
if (fd != fdd) {
|
||||
dayOfYear = Math.min((int)(fdd - fd) + 1, dayOfYear);
|
||||
}
|
||||
LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
|
||||
int y = lgd.getYear();
|
||||
// Unless the first year starts from January 1, the actual
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2013, 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
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* This class consists of {@code static} utility methods for operating
|
||||
* on objects. These utilities include {@code null}-safe or {@code
|
||||
@ -262,4 +264,30 @@ public final class Objects {
|
||||
public static boolean nonNull(Object obj) {
|
||||
return obj != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified object reference is not {@code null} and
|
||||
* throws a customized {@link NullPointerException} if it is.
|
||||
*
|
||||
* <p>Unlike the method {@link #requireNonNull(Object, String)},
|
||||
* this method allows creation of the message to be deferred until
|
||||
* after the null check is made. While this may confer a
|
||||
* performance advantage in the non-null case, when deciding to
|
||||
* call this method care should be taken that the costs of
|
||||
* creating the message supplier are less than the cost of just
|
||||
* creating the string message directly.
|
||||
*
|
||||
* @param obj the object reference to check for nullity
|
||||
* @param messageSupplier supplier of the detail message to be
|
||||
* used in the event that a {@code NullPointerException} is thrown
|
||||
* @param <T> the type of the reference
|
||||
* @return {@code obj} if not {@code null}
|
||||
* @throws NullPointerException if {@code obj} is {@code null}
|
||||
* @since 1.8
|
||||
*/
|
||||
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException(messageSupplier.get());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,7 @@ package sun.net.www;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.*;
|
||||
|
||||
/** An RFC 844 or MIME message header. Includes methods
|
||||
for parsing headers from incoming streams, fetching
|
||||
@ -59,6 +54,17 @@ class MessageHeader {
|
||||
parseHeader(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of header names in a comma separated list
|
||||
*/
|
||||
public synchronized String getHeaderNamesInList() {
|
||||
StringJoiner joiner = new StringJoiner(",");
|
||||
for (int i=0; i<nkeys; i++) {
|
||||
joiner.add(keys[i]);
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a message header (all key/values removed)
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@ import java.net.HttpCookie;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.SocketPermission;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
@ -45,8 +46,13 @@ import java.net.ResponseCache;
|
||||
import java.net.CacheResponse;
|
||||
import java.net.SecureCacheResponse;
|
||||
import java.net.CacheRequest;
|
||||
import java.net.HttpURLPermission;
|
||||
import java.net.Authenticator.RequestorType;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@ -303,6 +309,19 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
*/
|
||||
private MessageHeader requests;
|
||||
|
||||
/* The headers actually set by the user are recorded here also
|
||||
*/
|
||||
private MessageHeader userHeaders;
|
||||
|
||||
/* Headers and request method cannot be changed
|
||||
* once this flag is set in :-
|
||||
* - getOutputStream()
|
||||
* - getInputStream())
|
||||
* - connect()
|
||||
* Access synchronized on this.
|
||||
*/
|
||||
private boolean connecting = false;
|
||||
|
||||
/* The following two fields are only used with Digest Authentication */
|
||||
String domain; /* The list of authentication domains */
|
||||
DigestAuthentication.Parameters digestparams;
|
||||
@ -370,6 +389,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
private int connectTimeout = NetworkClient.DEFAULT_CONNECT_TIMEOUT;
|
||||
private int readTimeout = NetworkClient.DEFAULT_READ_TIMEOUT;
|
||||
|
||||
/* A permission converted from a HttpURLPermission */
|
||||
private SocketPermission socketPermission;
|
||||
|
||||
/* Logging support */
|
||||
private static final PlatformLogger logger =
|
||||
PlatformLogger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
|
||||
@ -487,6 +509,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setRequestMethod(String method)
|
||||
throws ProtocolException {
|
||||
if (connecting) {
|
||||
throw new IllegalStateException("connect in progress");
|
||||
}
|
||||
super.setRequestMethod(method);
|
||||
}
|
||||
|
||||
/* adds the standard key/val pairs to reqests if necessary & write to
|
||||
* given PrintStream
|
||||
*/
|
||||
@ -729,6 +759,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
super(u);
|
||||
requests = new MessageHeader();
|
||||
responses = new MessageHeader();
|
||||
userHeaders = new MessageHeader();
|
||||
this.handler = handler;
|
||||
instProxy = p;
|
||||
if (instProxy instanceof sun.net.ApplicationProxy) {
|
||||
@ -849,6 +880,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
// overridden in HTTPS subclass
|
||||
|
||||
public void connect() throws IOException {
|
||||
synchronized (this) {
|
||||
connecting = true;
|
||||
}
|
||||
plainConnect();
|
||||
}
|
||||
|
||||
@ -867,10 +901,86 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void plainConnect() throws IOException {
|
||||
if (connected) {
|
||||
return;
|
||||
private String getHostAndPort(URL url) {
|
||||
String host = url.getHost();
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
String scheme = url.getProtocol();
|
||||
if ("http".equals(scheme)) {
|
||||
return host + ":80";
|
||||
} else { // scheme must be https
|
||||
return host + ":443";
|
||||
}
|
||||
}
|
||||
return host + ":" + Integer.toString(port);
|
||||
}
|
||||
|
||||
protected void plainConnect() throws IOException {
|
||||
synchronized (this) {
|
||||
if (connected) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SocketPermission p = URLtoSocketPermission(this.url);
|
||||
if (p != null) {
|
||||
try {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws IOException {
|
||||
plainConnect0();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// }, null, p -- replace line above, when limited doPriv ready
|
||||
);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
}
|
||||
} else {
|
||||
// run without additional permission
|
||||
plainConnect0();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the caller has a HttpURLPermission for connecting to the
|
||||
* given URL, then return a SocketPermission which permits
|
||||
* access to that destination. Return null otherwise. The permission
|
||||
* is cached in a field (which can only be changed by redirects)
|
||||
*/
|
||||
SocketPermission URLtoSocketPermission(URL url) throws IOException {
|
||||
|
||||
if (socketPermission != null) {
|
||||
return socketPermission;
|
||||
}
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// the permission, which we might grant
|
||||
|
||||
SocketPermission newPerm = new SocketPermission(
|
||||
getHostAndPort(url), "connect"
|
||||
);
|
||||
|
||||
String actions = getRequestMethod()+":" +
|
||||
getUserSetHeaders().getHeaderNamesInList();
|
||||
|
||||
HttpURLPermission p = new HttpURLPermission(url.toString(), actions);
|
||||
try {
|
||||
sm.checkPermission(p);
|
||||
socketPermission = newPerm;
|
||||
return socketPermission;
|
||||
} catch (SecurityException e) {
|
||||
// fall thru
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void plainConnect0() throws IOException {
|
||||
// try to see if request can be served from local cache
|
||||
if (cacheHandler != null && getUseCaches()) {
|
||||
try {
|
||||
@ -1068,7 +1178,28 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
|
||||
@Override
|
||||
public synchronized OutputStream getOutputStream() throws IOException {
|
||||
connecting = true;
|
||||
SocketPermission p = URLtoSocketPermission(this.url);
|
||||
|
||||
if (p != null) {
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<OutputStream>() {
|
||||
public OutputStream run() throws IOException {
|
||||
return getOutputStream0();
|
||||
}
|
||||
}
|
||||
// }, null, p -- replace line above, when limited doPriv ready
|
||||
);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
}
|
||||
} else {
|
||||
return getOutputStream0();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized OutputStream getOutputStream0() throws IOException {
|
||||
try {
|
||||
if (!doOutput) {
|
||||
throw new ProtocolException("cannot write to a URLConnection"
|
||||
@ -1231,8 +1362,30 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("empty-statement")
|
||||
public synchronized InputStream getInputStream() throws IOException {
|
||||
connecting = true;
|
||||
SocketPermission p = URLtoSocketPermission(this.url);
|
||||
|
||||
if (p != null) {
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<InputStream>() {
|
||||
public InputStream run() throws IOException {
|
||||
return getInputStream0();
|
||||
}
|
||||
}
|
||||
// }, null, p -- replace line above, when limited doPriv ready
|
||||
);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
}
|
||||
} else {
|
||||
return getInputStream0();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("empty-statement")
|
||||
private synchronized InputStream getInputStream0() throws IOException {
|
||||
|
||||
if (!doInput) {
|
||||
throw new ProtocolException("Cannot read from URLConnection"
|
||||
@ -2319,18 +2472,19 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
return false;
|
||||
}
|
||||
|
||||
int stat = getResponseCode();
|
||||
final int stat = getResponseCode();
|
||||
if (stat < 300 || stat > 307 || stat == 306
|
||||
|| stat == HTTP_NOT_MODIFIED) {
|
||||
return false;
|
||||
}
|
||||
String loc = getHeaderField("Location");
|
||||
final String loc = getHeaderField("Location");
|
||||
if (loc == null) {
|
||||
/* this should be present - if not, we have no choice
|
||||
* but to go forward w/ the response we got
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
URL locUrl;
|
||||
try {
|
||||
locUrl = new URL(loc);
|
||||
@ -2342,6 +2496,38 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
// treat loc as a relative URI to conform to popular browsers
|
||||
locUrl = new URL(url, loc);
|
||||
}
|
||||
|
||||
final URL locUrl0 = locUrl;
|
||||
socketPermission = null; // force recalculation
|
||||
SocketPermission p = URLtoSocketPermission(locUrl);
|
||||
|
||||
if (p != null) {
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Boolean>() {
|
||||
public Boolean run() throws IOException {
|
||||
return followRedirect0(loc, stat, locUrl0);
|
||||
}
|
||||
}
|
||||
// }, null, p -- replace line above, when limited doPriv ready
|
||||
);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
}
|
||||
} else {
|
||||
// run without additional permission
|
||||
return followRedirect0(loc, stat, locUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tells us whether to follow a redirect. If so, it
|
||||
* closes the connection (break any keep-alive) and
|
||||
* resets the url, re-connects, and resets the request
|
||||
* property.
|
||||
*/
|
||||
private boolean followRedirect0(String loc, int stat, URL locUrl)
|
||||
throws IOException
|
||||
{
|
||||
disconnectInternal();
|
||||
if (streaming()) {
|
||||
throw new HttpRetryException (RETRY_MSG3, stat, loc);
|
||||
@ -2753,17 +2939,24 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
* @param value the value to be set
|
||||
*/
|
||||
@Override
|
||||
public void setRequestProperty(String key, String value) {
|
||||
if (connected)
|
||||
public synchronized void setRequestProperty(String key, String value) {
|
||||
if (connected || connecting)
|
||||
throw new IllegalStateException("Already connected");
|
||||
if (key == null)
|
||||
throw new NullPointerException ("key is null");
|
||||
|
||||
if (isExternalMessageHeaderAllowed(key, value)) {
|
||||
requests.set(key, value);
|
||||
if (!key.equalsIgnoreCase("Content-Type")) {
|
||||
userHeaders.set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageHeader getUserSetHeaders() {
|
||||
return userHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a general request property specified by a
|
||||
* key-value pair. This method will not overwrite
|
||||
@ -2776,14 +2969,17 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public void addRequestProperty(String key, String value) {
|
||||
if (connected)
|
||||
public synchronized void addRequestProperty(String key, String value) {
|
||||
if (connected || connecting)
|
||||
throw new IllegalStateException("Already connected");
|
||||
if (key == null)
|
||||
throw new NullPointerException ("key is null");
|
||||
|
||||
if (isExternalMessageHeaderAllowed(key, value)) {
|
||||
requests.add(key, value);
|
||||
if (!key.equalsIgnoreCase("Content-Type")) {
|
||||
userHeaders.add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user