1 /*
2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
68 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
69 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
70 import static java.time.temporal.ChronoField.OFFSET_SECONDS;
71 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
72 import static java.time.temporal.ChronoField.YEAR;
73 import static java.time.temporal.ChronoField.ERA;
74
75 import java.lang.ref.SoftReference;
76 import java.math.BigDecimal;
77 import java.math.BigInteger;
78 import java.math.RoundingMode;
79 import java.text.ParsePosition;
80 import java.time.DateTimeException;
81 import java.time.Instant;
82 import java.time.LocalDate;
83 import java.time.LocalDateTime;
84 import java.time.LocalTime;
85 import java.time.ZoneId;
86 import java.time.ZoneOffset;
87 import java.time.chrono.ChronoLocalDate;
88 import java.time.chrono.ChronoLocalDateTime;
89 import java.time.chrono.Chronology;
90 import java.time.chrono.Era;
91 import java.time.chrono.IsoChronology;
92 import java.time.format.DateTimeTextProvider.LocaleStore;
93 import java.time.temporal.ChronoField;
94 import java.time.temporal.IsoFields;
95 import java.time.temporal.JulianFields;
96 import java.time.temporal.TemporalAccessor;
97 import java.time.temporal.TemporalField;
98 import java.time.temporal.TemporalQueries;
99 import java.time.temporal.TemporalQuery;
100 import java.time.temporal.ValueRange;
101 import java.time.temporal.WeekFields;
102 import java.time.zone.ZoneRulesProvider;
103 import java.util.AbstractMap.SimpleImmutableEntry;
104 import java.util.ArrayList;
105 import java.util.Arrays;
106 import java.util.Collections;
107 import java.util.Comparator;
108 import java.util.HashMap;
109 import java.util.HashSet;
110 import java.util.Iterator;
111 import java.util.LinkedHashMap;
112 import java.util.List;
113 import java.util.Locale;
114 import java.util.Map;
115 import java.util.Map.Entry;
116 import java.util.Objects;
117 import java.util.Set;
118 import java.util.TimeZone;
119 import java.util.concurrent.ConcurrentHashMap;
120 import java.util.concurrent.ConcurrentMap;
121
122 import sun.text.spi.JavaTimeDateTimePatternProvider;
123 import sun.util.locale.provider.CalendarDataUtility;
124 import sun.util.locale.provider.LocaleProviderAdapter;
125 import sun.util.locale.provider.LocaleResources;
126 import sun.util.locale.provider.TimeZoneNameUtility;
127
128 /**
129 * Builder to create date-time formatters.
130 * <p>
131 * This allows a {@code DateTimeFormatter} to be created.
132 * All date-time formatters are created ultimately using this builder.
133 * <p>
134 * The basic elements of date-time can all be added:
135 * <ul>
136 * <li>Value - a numeric value</li>
137 * <li>Fraction - a fractional value including the decimal place. Always use this when
138 * outputting fractions to ensure that the fraction is parsed correctly</li>
139 * <li>Text - the textual equivalent for the value</li>
140 * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
141 * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
142 * <li>ZoneText - the name of the time-zone</li>
143 * <li>ChronologyId - the {@linkplain Chronology chronology} id</li>
144 * <li>ChronologyText - the name of the chronology</li>
145 * <li>Literal - a text literal</li>
3854 /**
3855 * Constructor.
3856 *
3857 * @param style the style, not null
3858 */
3859 LocalizedOffsetIdPrinterParser(TextStyle style) {
3860 this.style = style;
3861 }
3862
3863 private static StringBuilder appendHMS(StringBuilder buf, int t) {
3864 return buf.append((char)(t / 10 + '0'))
3865 .append((char)(t % 10 + '0'));
3866 }
3867
3868 @Override
3869 public boolean format(DateTimePrintContext context, StringBuilder buf) {
3870 Long offsetSecs = context.getValue(OFFSET_SECONDS);
3871 if (offsetSecs == null) {
3872 return false;
3873 }
3874 String gmtText = "GMT"; // TODO: get localized version of 'GMT'
3875 buf.append(gmtText);
3876 int totalSecs = Math.toIntExact(offsetSecs);
3877 if (totalSecs != 0) {
3878 int absHours = Math.abs((totalSecs / 3600) % 100); // anything larger than 99 silently dropped
3879 int absMinutes = Math.abs((totalSecs / 60) % 60);
3880 int absSeconds = Math.abs(totalSecs % 60);
3881 buf.append(totalSecs < 0 ? "-" : "+");
3882 if (style == TextStyle.FULL) {
3883 appendHMS(buf, absHours);
3884 buf.append(':');
3885 appendHMS(buf, absMinutes);
3886 if (absSeconds != 0) {
3887 buf.append(':');
3888 appendHMS(buf, absSeconds);
3889 }
3890 } else {
3891 if (absHours >= 10) {
3892 buf.append((char)(absHours / 10 + '0'));
3893 }
3894 buf.append((char)(absHours % 10 + '0'));
3900 appendHMS(buf, absSeconds);
3901 }
3902 }
3903 }
3904 }
3905 return true;
3906 }
3907
3908 int getDigit(CharSequence text, int position) {
3909 char c = text.charAt(position);
3910 if (c < '0' || c > '9') {
3911 return -1;
3912 }
3913 return c - '0';
3914 }
3915
3916 @Override
3917 public int parse(DateTimeParseContext context, CharSequence text, int position) {
3918 int pos = position;
3919 int end = text.length();
3920 String gmtText = "GMT"; // TODO: get localized version of 'GMT'
3921 if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
3922 return ~position;
3923 }
3924 pos += gmtText.length();
3925 // parse normal plus/minus offset
3926 int negative = 0;
3927 if (pos == end) {
3928 return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
3929 }
3930 char sign = text.charAt(pos); // IOOBE if invalid position
3931 if (sign == '+') {
3932 negative = 1;
3933 } else if (sign == '-') {
3934 negative = -1;
3935 } else {
3936 return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
3937 }
3938 pos++;
3939 int h = 0;
3940 int m = 0;
|
1 /*
2 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
68 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
69 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
70 import static java.time.temporal.ChronoField.OFFSET_SECONDS;
71 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
72 import static java.time.temporal.ChronoField.YEAR;
73 import static java.time.temporal.ChronoField.ERA;
74
75 import java.lang.ref.SoftReference;
76 import java.math.BigDecimal;
77 import java.math.BigInteger;
78 import java.math.RoundingMode;
79 import java.text.ParsePosition;
80 import java.time.DateTimeException;
81 import java.time.Instant;
82 import java.time.LocalDate;
83 import java.time.LocalDateTime;
84 import java.time.LocalTime;
85 import java.time.ZoneId;
86 import java.time.ZoneOffset;
87 import java.time.chrono.ChronoLocalDate;
88 import java.time.chrono.Chronology;
89 import java.time.chrono.Era;
90 import java.time.chrono.IsoChronology;
91 import java.time.format.DateTimeTextProvider.LocaleStore;
92 import java.time.temporal.ChronoField;
93 import java.time.temporal.IsoFields;
94 import java.time.temporal.JulianFields;
95 import java.time.temporal.TemporalAccessor;
96 import java.time.temporal.TemporalField;
97 import java.time.temporal.TemporalQueries;
98 import java.time.temporal.TemporalQuery;
99 import java.time.temporal.ValueRange;
100 import java.time.temporal.WeekFields;
101 import java.time.zone.ZoneRulesProvider;
102 import java.util.AbstractMap.SimpleImmutableEntry;
103 import java.util.ArrayList;
104 import java.util.Arrays;
105 import java.util.Collections;
106 import java.util.Comparator;
107 import java.util.HashMap;
108 import java.util.HashSet;
109 import java.util.Iterator;
110 import java.util.LinkedHashMap;
111 import java.util.List;
112 import java.util.Locale;
113 import java.util.Map;
114 import java.util.Map.Entry;
115 import java.util.Objects;
116 import java.util.Set;
117 import java.util.TimeZone;
118 import java.util.concurrent.ConcurrentHashMap;
119 import java.util.concurrent.ConcurrentMap;
120
121 import sun.text.spi.JavaTimeDateTimePatternProvider;
122 import sun.util.locale.provider.CalendarDataUtility;
123 import sun.util.locale.provider.LocaleProviderAdapter;
124 import sun.util.locale.provider.TimeZoneNameUtility;
125
126 /**
127 * Builder to create date-time formatters.
128 * <p>
129 * This allows a {@code DateTimeFormatter} to be created.
130 * All date-time formatters are created ultimately using this builder.
131 * <p>
132 * The basic elements of date-time can all be added:
133 * <ul>
134 * <li>Value - a numeric value</li>
135 * <li>Fraction - a fractional value including the decimal place. Always use this when
136 * outputting fractions to ensure that the fraction is parsed correctly</li>
137 * <li>Text - the textual equivalent for the value</li>
138 * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
139 * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
140 * <li>ZoneText - the name of the time-zone</li>
141 * <li>ChronologyId - the {@linkplain Chronology chronology} id</li>
142 * <li>ChronologyText - the name of the chronology</li>
143 * <li>Literal - a text literal</li>
3852 /**
3853 * Constructor.
3854 *
3855 * @param style the style, not null
3856 */
3857 LocalizedOffsetIdPrinterParser(TextStyle style) {
3858 this.style = style;
3859 }
3860
3861 private static StringBuilder appendHMS(StringBuilder buf, int t) {
3862 return buf.append((char)(t / 10 + '0'))
3863 .append((char)(t % 10 + '0'));
3864 }
3865
3866 @Override
3867 public boolean format(DateTimePrintContext context, StringBuilder buf) {
3868 Long offsetSecs = context.getValue(OFFSET_SECONDS);
3869 if (offsetSecs == null) {
3870 return false;
3871 }
3872 String key = "timezone.gmtZeroFormat";
3873 String gmtText = DateTimeTextProvider.getLocalizedResource(key, context.getLocale());
3874 if(gmtText == null) {
3875 gmtText = "GMT"; // Default to "GMT"
3876 }
3877 buf.append(gmtText);
3878 int totalSecs = Math.toIntExact(offsetSecs);
3879 if (totalSecs != 0) {
3880 int absHours = Math.abs((totalSecs / 3600) % 100); // anything larger than 99 silently dropped
3881 int absMinutes = Math.abs((totalSecs / 60) % 60);
3882 int absSeconds = Math.abs(totalSecs % 60);
3883 buf.append(totalSecs < 0 ? "-" : "+");
3884 if (style == TextStyle.FULL) {
3885 appendHMS(buf, absHours);
3886 buf.append(':');
3887 appendHMS(buf, absMinutes);
3888 if (absSeconds != 0) {
3889 buf.append(':');
3890 appendHMS(buf, absSeconds);
3891 }
3892 } else {
3893 if (absHours >= 10) {
3894 buf.append((char)(absHours / 10 + '0'));
3895 }
3896 buf.append((char)(absHours % 10 + '0'));
3902 appendHMS(buf, absSeconds);
3903 }
3904 }
3905 }
3906 }
3907 return true;
3908 }
3909
3910 int getDigit(CharSequence text, int position) {
3911 char c = text.charAt(position);
3912 if (c < '0' || c > '9') {
3913 return -1;
3914 }
3915 return c - '0';
3916 }
3917
3918 @Override
3919 public int parse(DateTimeParseContext context, CharSequence text, int position) {
3920 int pos = position;
3921 int end = text.length();
3922 String key = "timezone.gmtZeroFormat";
3923 String gmtText = DateTimeTextProvider.getLocalizedResource(key, context.getLocale());
3924 if(gmtText == null) {
3925 gmtText = "GMT"; // Default to "GMT"
3926 }
3927 if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
3928 return ~position;
3929 }
3930 pos += gmtText.length();
3931 // parse normal plus/minus offset
3932 int negative = 0;
3933 if (pos == end) {
3934 return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
3935 }
3936 char sign = text.charAt(pos); // IOOBE if invalid position
3937 if (sign == '+') {
3938 negative = 1;
3939 } else if (sign == '-') {
3940 negative = -1;
3941 } else {
3942 return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
3943 }
3944 pos++;
3945 int h = 0;
3946 int m = 0;
|