KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > DateTimePatternGenerator


1 //##header 1189099963000 FOUNDATION
2
//#ifndef FOUNDATION
3
//##/*
4
//## *******************************************************************************
5
//## * Copyright (C) 2006, Google, International Business Machines Corporation and *
6
//## * others. All Rights Reserved. *
7
//## *******************************************************************************
8
//## *
9
//## * $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/text/DateTimePatternGenerator.java,v $
10
//## * $Date: 2006/09/15 18:09:24 $
11
//## * $Revision: 1.9 $
12
//## *
13
//## *******************************************************************************
14
//## */
15
//##package com.ibm.icu.text;
16
//##
17
//##import java.util.ArrayList;
18
//##import java.util.Arrays;
19
//##import java.util.BitSet;
20
//##import java.util.Collection;
21
//##import java.util.Collections;
22
//##import java.util.Enumeration;
23
//##import java.util.HashMap;
24
//##import java.util.HashSet;
25
//##import java.util.Iterator;
26
//##import java.util.LinkedHashMap;
27
//##import java.util.LinkedHashSet;
28
//##import java.util.List;
29
//##import java.util.Map;
30
//##import java.util.Set;
31
//##import java.util.TreeMap;
32
//##import java.util.TreeSet;
33
//##
34
//##//import org.unicode.cldr.util.Utility;
35
//##
36
//##import com.ibm.icu.impl.CalendarData;
37
//##import com.ibm.icu.impl.PatternTokenizer;
38
//##import com.ibm.icu.impl.Utility;
39
//##import com.ibm.icu.text.MessageFormat;
40
//##import com.ibm.icu.text.Transliterator;
41
//##import com.ibm.icu.text.UnicodeSet;
42
//##import com.ibm.icu.util.Calendar;
43
//##import com.ibm.icu.util.Freezable;
44
//##import com.ibm.icu.util.ULocale;
45
//##import com.ibm.icu.util.UResourceBundle;
46
//##
47
//##/**
48
//## * This class provides flexible generation of date format patterns, like "yy-MM-dd". The user can build up the generator
49
//## * by adding successive patterns. Once that is done, a query can be made using a "skeleton", which is a pattern which just
50
//## * includes the desired fields and lengths. The generator will return the "best fit" pattern corresponding to that skeleton.
51
//## * <p>The main method people will use is getBestPattern(String skeleton),
52
//## * since normally this class is pre-built with data from a particular locale. However, generators can be built directly from other data as well.
53
//## * <p><i>Issue: may be useful to also have a function that returns the list of fields in a pattern, in order, since we have that internally.
54
//## * That would be useful for getting the UI order of field elements.</i>
55
//## * @draft ICU 3.6
56
//## * @provisional This API might change or be removed in a future release.
57
//## */
58
//##public class DateTimePatternGenerator implements Freezable, Cloneable {
59
//## // debugging flags
60
//## //static boolean SHOW_DISTANCE = false;
61
//## // TODO add hack to fix months for CJK, as per bug 1099
62
//## // http://dev.icu-project.org/cgi-bin/locale-bugs/incoming?findid=1099
63
//##
64
//## /**
65
//## * Create empty generator, to be constructed with add(...) etc.
66
//## * @draft ICU 3.6
67
//## * @provisional This API might change or be removed in a future release.
68
//## */
69
//## public static DateTimePatternGenerator newInstance() {
70
//## return new DateTimePatternGenerator();
71
//## }
72
//##
73
//## /**
74
//## * Only for use by subclasses
75
//## * @draft ICU 3.6
76
//## * @provisional This API might change or be removed in a future release.
77
//## */
78
//## protected DateTimePatternGenerator() {
79
//## }
80
//##
81
//## /**
82
//## * Construct a flexible generator according to data for a given locale.
83
//## * @draft ICU 3.6
84
//## * @provisional This API might change or be removed in a future release.
85
//## */
86
//## public static DateTimePatternGenerator getInstance() {
87
//## return getInstance(ULocale.getDefault());
88
//## }
89
//##
90
//## /**
91
//## * Construct a flexible generator according to data for a given locale.
92
//## * @param uLocale
93
//## * @draft ICU 3.6
94
//## * @provisional This API might change or be removed in a future release.
95
//## */
96
//## public static DateTimePatternGenerator getInstance(ULocale uLocale) {
97
//## DateTimePatternGenerator result = new DateTimePatternGenerator();
98
//## PatternInfo returnInfo = new PatternInfo();
99
//## String hackPattern = null;
100
//## // first load with the ICU patterns
101
//## for (int i = DateFormat.FULL; i <= DateFormat.SHORT; ++i) {
102
//## SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(i, uLocale);
103
//## result.add(df.toPattern(), false, returnInfo);
104
//## df = (SimpleDateFormat) DateFormat.getTimeInstance(i, uLocale);
105
//## result.add(df.toPattern(), false, returnInfo);
106
//## // HACK for hh:ss
107
//## if (i == DateFormat.MEDIUM) {
108
//## hackPattern = df.toPattern();
109
//## }
110
//## }
111
//## UResourceBundle rb = UResourceBundle.getBundleInstance("com.ibm.icu.impl.data.DateData$MyDateResources", uLocale);
112
//## //ResourceBundle rb = ResourceBundle.getBundle("com.ibm.icu.impl.data.DateData$MyDateResources", ULocale.FRENCH.toLocale());
113
//## for (Enumeration en = rb.getKeys(); en.hasMoreElements();) {
114
//## String key = (String) en.nextElement();
115
//## String value = rb.getString(key);
116
//## String [] keyParts = key.split("/");
117
//## if (keyParts[0].equals("pattern")) {
118
//## result.add(value, false, returnInfo);
119
//## } else if (keyParts[0].equals("append")) {
120
//## result.setAppendItemFormats(getAppendFormatNumber(keyParts[1]), value);
121
//## } else if (keyParts[0].equals("field")) {
122
//## result.setAppendItemNames(getAppendNameNumber(keyParts[1]), value);
123
//## }
124
//## }
125
//##
126
//## // assume it is always big endian (ok for CLDR right now)
127
//## // some languages didn't add mm:ss or HH:mm, so put in a hack to compute that from the short time.
128
//## if (hackPattern != null) {
129
//## hackTimes(result, returnInfo, hackPattern);
130
//## }
131
//##
132
//## // set the datetime pattern. This is ugly code -- there should be a public interface for this
133
//## Calendar cal = Calendar.getInstance(uLocale);
134
//## CalendarData calData = new CalendarData(uLocale, cal.getType());
135
//## String[] patterns = calData.get("DateTimePatterns").getStringArray();
136
//## result.setDateTimeFormat(patterns[8]);
137
//##
138
//## // decimal point for seconds
139
//## DecimalFormatSymbols dfs = new DecimalFormatSymbols(uLocale);
140
//## result.setDecimal(String.valueOf(dfs.getDecimalSeparator()));
141
//## return result;
142
//## }
143
//##
144
//## private static void hackTimes(DateTimePatternGenerator result, PatternInfo returnInfo, String hackPattern) {
145
//## result.fp.set(hackPattern);
146
//## String mmss = new String();
147
//## // to get mm:ss, we strip all but mm literal ss
148
//## boolean gotMm = false;
149
//## for (int i = 0; i < result.fp.items.size(); ++i) {
150
//## Object item = result.fp.items.get(i);
151
//## if (item instanceof String) {
152
//## if (gotMm) {
153
//## mmss += result.fp.quoteLiteral(item.toString());
154
//## }
155
//## } else {
156
//## char ch = item.toString().charAt(0);
157
//## if (ch == 'm') {
158
//## gotMm = true;
159
//## mmss += item;
160
//## } else if (ch == 's') {
161
//## if (!gotMm) {
162
//## break; // failed
163
//## }
164
//## mmss += item;
165
//## result.add(mmss, false, returnInfo);
166
//## break;
167
//## } else if (gotMm || ch == 'z' || ch == 'Z' || ch == 'v' || ch == 'V') {
168
//## break; // failed
169
//## }
170
//## }
171
//## }
172
//## // to get hh:mm, we strip (literal ss) and (literal S)
173
//## // the easiest way to do this is to mark the stuff we want to nuke, then remove it in a second pass.
174
//## BitSet variables = new BitSet();
175
//## BitSet nuke = new BitSet();
176
//## for (int i = 0; i < result.fp.items.size(); ++i) {
177
//## Object item = result.fp.items.get(i);
178
//## if (item instanceof VariableField) {
179
//## variables.set(i);
180
//## char ch = item.toString().charAt(0);
181
//## if (ch == 's' || ch == 'S') {
182
//## nuke.set(i);
183
//## for (int j = i-1; j >= 0; ++j) {
184
//## if (variables.get(j)) break;
185
//## nuke.set(i);
186
//## }
187
//## }
188
//## }
189
//## }
190
//## String hhmm = getFilteredPattern(result.fp, nuke);
191
//## result.add(hhmm, false, returnInfo);
192
//## }
193
//##
194
//## private static String getFilteredPattern(FormatParser fp, BitSet nuke) {
195
//## String result = new String();
196
//## for (int i = 0; i < fp.items.size(); ++i) {
197
//## if (nuke.get(i)) continue;
198
//## Object item = fp.items.get(i);
199
//## if (item instanceof String) {
200
//## result += fp.quoteLiteral(item.toString());
201
//## } else {
202
//## result += item.toString();
203
//## }
204
//## }
205
//## return result;
206
//## }
207
//##
208
//## private static int getAppendNameNumber(String string) {
209
//## for (int i = 0; i < CLDR_FIELD_NAME.length; ++i) {
210
//## if (CLDR_FIELD_NAME[i].equals(string)) return i;
211
//## }
212
//## return -1;
213
//## }
214
//##
215
//## private static int getAppendFormatNumber(String string) {
216
//## for (int i = 0; i < CLDR_FIELD_APPEND.length; ++i) {
217
//## if (CLDR_FIELD_APPEND[i].equals(string)) return i;
218
//## }
219
//## return -1;
220
//##
221
//## }
222
//##
223
//## /**
224
//## * Return the best pattern matching the input skeleton. It is guaranteed to
225
//## * have all of the fields in the skeleton.
226
//## *
227
//## * @param skeleton
228
//## * The skeleton is a pattern containing only the variable fields.
229
//## * For example, "MMMdd" and "mmhh" are skeletons.
230
//## * @draft ICU 3.6
231
//## * @provisional This API might change or be removed in a future release.
232
//## */
233
//## public String getBestPattern(String skeleton) {
234
//## //if (!isComplete) complete();
235
//## current.set(skeleton, fp);
236
//## String best = getBestRaw(current, -1, _distanceInfo);
237
//## if (_distanceInfo.missingFieldMask == 0 && _distanceInfo.extraFieldMask == 0) {
238
//## // we have a good item. Adjust the field types
239
//## return adjustFieldTypes(best, current, false);
240
//## }
241
//## int neededFields = current.getFieldMask();
242
//## // otherwise break up by date and time.
243
//## String datePattern = getBestAppending(neededFields & DATE_MASK);
244
//## String timePattern = getBestAppending(neededFields & TIME_MASK);
245
//##
246
//## if (datePattern == null) return timePattern == null ? "" : timePattern;
247
//## if (timePattern == null) return datePattern;
248
//## return MessageFormat.format(getDateTimeFormat(), new Object[]{datePattern, timePattern});
249
//## }
250
//##
251
//## /**
252
//## * PatternInfo supplies output parameters for add(...). It is used because
253
//## * Java doesn't have real output parameters. It is treated like a struct (eg
254
//## * Point), so all fields are public.
255
//## *
256
//## * @draft ICU 3.6
257
//## * @provisional This API might change or be removed in a future release.
258
//## */
259
//## public static final class PatternInfo { // struct for return information
260
//## /**
261
//## * @draft ICU 3.6
262
//## * @provisional This API might change or be removed in a future release.
263
//## */
264
//## public static final int OK = 0;
265
//##
266
//## /**
267
//## * @draft ICU 3.6
268
//## * @provisional This API might change or be removed in a future release.
269
//## */
270
//## public static final int BASE_CONFLICT = 1;
271
//##
272
//## /**
273
//## * @draft ICU 3.6
274
//## * @provisional This API might change or be removed in a future release.
275
//## */
276
//## public static final int CONFLICT = 2;
277
//##
278
//## /**
279
//## * @draft ICU 3.6
280
//## * @provisional This API might change or be removed in a future release.
281
//## */
282
//## public int status;
283
//##
284
//## /**
285
//## * @draft ICU 3.6
286
//## * @provisional This API might change or be removed in a future release.
287
//## */
288
//## public String conflictingPattern;
289
//##
290
//## /**
291
//## * Simple constructor, since this is treated like a struct.
292
//## * @draft ICU 3.6
293
//## * @provisional This API might change or be removed in a future release.
294
//## */
295
//## public PatternInfo() {
296
//## }
297
//## }
298
//##
299
//## static Transliterator fromHex = Transliterator.getInstance("hex-any");
300
//##
301
//## /**
302
//## * Adds a pattern to the generator. If the pattern has the same skeleton as
303
//## * an existing pattern, and the override parameter is set, then the previous
304
//## * value is overriden. Otherwise, the previous value is retained. In either
305
//## * case, the conflicting information is returned in PatternInfo.
306
//## * <p>
307
//## * Note that single-field patterns (like "MMM") are automatically added, and
308
//## * don't need to be added explicitly!
309
//## *
310
//## * @param override
311
//## * when existing values are to be overridden use true, otherwise
312
//## * use false.
313
//## * @draft ICU 3.6
314
//## * @provisional This API might change or be removed in a future release.
315
//## */
316
//## public DateTimePatternGenerator add(String pattern, boolean override, PatternInfo returnInfo) {
317
//## checkFrozen();
318
//## if (pattern.indexOf("\\u") >= 0) {
319
//## String oldPattern = pattern;
320
//## pattern = fromHex.transliterate(pattern);
321
//## }
322
//## DateTimeMatcher matcher = new DateTimeMatcher().set(pattern, fp);
323
//## String basePattern = matcher.getBasePattern();
324
//## String previousPatternWithSameBase = (String)basePattern_pattern.get(basePattern);
325
//## if (previousPatternWithSameBase != null) {
326
//## returnInfo.status = PatternInfo.BASE_CONFLICT;
327
//## returnInfo.conflictingPattern = previousPatternWithSameBase;
328
//## if (!override) return this;
329
//## }
330
//## String previousValue = (String)skeleton2pattern.get(matcher);
331
//## if (previousValue != null) {
332
//## returnInfo.status = PatternInfo.CONFLICT;
333
//## returnInfo.conflictingPattern = previousValue;
334
//## if (!override) return this;
335
//## }
336
//## returnInfo.status = PatternInfo.OK;
337
//## returnInfo.conflictingPattern = "";
338
//## skeleton2pattern.put(matcher, pattern);
339
//## basePattern_pattern.put(basePattern, pattern);
340
//## return this;
341
//## }
342
//##
343
//## /**
344
//## * Utility to return a unique skeleton from a given pattern. For example,
345
//## * both "MMM-dd" and "dd/MMM" produce the skeleton "MMMdd".
346
//## *
347
//## * @param pattern
348
//## * Input pattern, such as "dd/MMM"
349
//## * @return skeleton, such as "MMMdd"
350
//## * @draft ICU 3.6
351
//## * @provisional This API might change or be removed in a future release.
352
//## */
353
//## public String getSkeleton(String pattern) {
354
//## synchronized (this) { // synchronized since a getter must be thread-safe
355
//## current.set(pattern, fp);
356
//## return current.toString();
357
//## }
358
//## }
359
//##
360
//## /**
361
//## * Utility to return a unique base skeleton from a given pattern. This is
362
//## * the same as the skeleton, except that differences in length are minimized
363
//## * so as to only preserve the difference between string and numeric form. So
364
//## * for example, both "MMM-dd" and "d/MMM" produce the skeleton "MMMd"
365
//## * (notice the single d).
366
//## *
367
//## * @param pattern
368
//## * Input pattern, such as "dd/MMM"
369
//## * @return skeleton, such as "MMMdd"
370
//## * @draft ICU 3.6
371
//## * @provisional This API might change or be removed in a future release.
372
//## */
373
//## public String getBaseSkeleton(String pattern) {
374
//## synchronized (this) { // synchronized since a getter must be thread-safe
375
//## current.set(pattern, fp);
376
//## return current.getBasePattern();
377
//## }
378
//## }
379
//##
380
//## /**
381
//## * Return a list of all the skeletons (in canonical form) from this class,
382
//## * and the patterns that they map to.
383
//## *
384
//## * @param result
385
//## * an output Map in which to place the mapping from skeleton to
386
//## * pattern. If you want to see the internal order being used,
387
//## * supply a LinkedHashMap. If the input value is null, then a
388
//## * LinkedHashMap is allocated.
389
//## * <p>
390
//## * <i>Issue: an alternate API would be to just return a list of
391
//## * the skeletons, and then have a separate routine to get from
392
//## * skeleton to pattern.</i>
393
//## * @return the input Map containing the values.
394
//## * @draft ICU 3.6
395
//## * @provisional This API might change or be removed in a future release.
396
//## */
397
//## public Map getSkeletons(Map result) {
398
//## if (result == null) result = new LinkedHashMap();
399
//## for (Iterator it = skeleton2pattern.keySet().iterator(); it.hasNext();) {
400
//## DateTimeMatcher item = (DateTimeMatcher) it.next();
401
//## String pattern = (String) skeleton2pattern.get(item);
402
//## if (CANONICAL_SET.contains(pattern)) continue;
403
//## result.put(item.toString(), pattern);
404
//## }
405
//## return result;
406
//## }
407
//##
408
//## /**
409
//## * Return a list of all the base skeletons (in canonical form) from this class
410
//## * @draft ICU 3.6
411
//## * @provisional This API might change or be removed in a future release.
412
//## */
413
//## public Set getBaseSkeletons(Set result) {
414
//## if (result == null) result = new HashSet();
415
//## result.addAll(basePattern_pattern.keySet());
416
//## return result;
417
//## }
418
//##
419
//## /**
420
//## * Adjusts the field types (width and subtype) of a pattern to match what is
421
//## * in a skeleton. That is, if you supply a pattern like "d-M H:m", and a
422
//## * skeleton of "MMMMddhhmm", then the input pattern is adjusted to be
423
//## * "dd-MMMM hh:mm". This is used internally to get the best match for the
424
//## * input skeleton, but can also be used externally.
425
//## *
426
//## * @param pattern
427
//## * input pattern
428
//## * @param skeleton
429
//## * @return pattern adjusted to match the skeleton fields widths and
430
//## * subtypes.
431
//## * @draft ICU 3.6
432
//## * @provisional This API might change or be removed in a future release.
433
//## */
434
//## public String replaceFieldTypes(String pattern, String skeleton) {
435
//## synchronized (this) { // synchronized since a getter must be thread-safe
436
//## return adjustFieldTypes(pattern, current.set(skeleton, fp), false);
437
//## }
438
//## }
439
//##
440
//## /**
441
//## * The date time format is a message format pattern used to compose date and
442
//## * time patterns. The default value is "{0} {1}", where {0} will be replaced
443
//## * by the date pattern and {1} will be replaced by the time pattern.
444
//## * <p>
445
//## * This is used when the input skeleton contains both date and time fields,
446
//## * but there is not a close match among the added patterns. For example,
447
//## * suppose that this object was created by adding "dd-MMM" and "hh:mm", and
448
//## * its datetimeFormat is the default "{0} {1}". Then if the input skeleton
449
//## * is "MMMdhmm", there is not an exact match, so the input skeleton is
450
//## * broken up into two components "MMMd" and "hmm". There are close matches
451
//## * for those two skeletons, so the result is put together with this pattern,
452
//## * resulting in "d-MMM h:mm".
453
//## *
454
//## * @param dateTimeFormat
455
//## * message format pattern, here {0} will be replaced by the date
456
//## * pattern and {1} will be replaced by the time pattern.
457
//## * @draft ICU 3.6
458
//## * @provisional This API might change or be removed in a future release.
459
//## */
460
//## public void setDateTimeFormat(String dateTimeFormat) {
461
//## checkFrozen();
462
//## this.dateTimeFormat = dateTimeFormat;
463
//## }
464
//##
465
//## /**
466
//## * Getter corresponding to setDateTimeFormat.
467
//## *
468
//## * @return pattern
469
//## * @draft ICU 3.6
470
//## * @provisional This API might change or be removed in a future release.
471
//## */
472
//## public String getDateTimeFormat() {
473
//## return dateTimeFormat;
474
//## }
475
//##
476
//## /**
477
//## * The decimal value is used in formatting fractions of seconds. If the
478
//## * skeleton contains fractional seconds, then this is used with the
479
//## * fractional seconds. For example, suppose that the input pattern is
480
//## * "hhmmssSSSS", and the best matching pattern internally is "H:mm:ss", and
481
//## * the decimal string is ",". Then the resulting pattern is modified to be
482
//## * "H:mm:ss,SSSS"
483
//## *
484
//## * @param decimal
485
//## * @draft ICU 3.6
486
//## * @provisional This API might change or be removed in a future release.
487
//## */
488
//## public void setDecimal(String decimal) {
489
//## checkFrozen();
490
//## this.decimal = decimal;
491
//## }
492
//##
493
//## /**
494
//## * Getter corresponding to setDecimal.
495
//## * @return string corresponding to the decimal point
496
//## * @draft ICU 3.6
497
//## * @provisional This API might change or be removed in a future release.
498
//## */
499
//## public String getDecimal() {
500
//## return decimal;
501
//## }
502
//##
503
//## /**
504
//## * Redundant patterns are those which if removed, make no difference in the
505
//## * resulting getBestPattern values. This method returns a list of them, to
506
//## * help check the consistency of the patterns used to build this generator.
507
//## *
508
//## * @param output
509
//## * stores the redundant patterns that are removed. To get these
510
//## * in internal order, supply a LinkedHashSet. If null, a
511
//## * collection is allocated.
512
//## * @return the collection with added elements.
513
//## * @deprecated
514
//## * @internal
515
//## */
516
//## public Collection getRedundants(Collection output) {
517
//## synchronized (this) { // synchronized since a getter must be thread-safe
518
//## if (output == null) output = new LinkedHashSet();
519
//## for (Iterator it = skeleton2pattern.keySet().iterator(); it.hasNext();) {
520
//## DateTimeMatcher current = (DateTimeMatcher) it.next();
521
//## String pattern = (String) skeleton2pattern.get(current);
522
//## if (CANONICAL_SET.contains(pattern)) continue;
523
//## skipMatcher = current;
524
//## String trial = getBestPattern(current.toString());
525
//## if (trial.equals(pattern)) {
526
//## output.add(pattern);
527
//## }
528
//## }
529
//## if (false) { // ordered
530
//## DateTimePatternGenerator results = new DateTimePatternGenerator();
531
//## PatternInfo pinfo = new PatternInfo();
532
//## for (Iterator it = skeleton2pattern.keySet().iterator(); it.hasNext();) {
533
//## DateTimeMatcher current = (DateTimeMatcher) it.next();
534
//## String pattern = (String) skeleton2pattern.get(current);
535
//## if (CANONICAL_SET.contains(pattern)) continue;
536
//## //skipMatcher = current;
537
//## String trial = results.getBestPattern(current.toString());
538
//## if (trial.equals(pattern)) {
539
//## output.add(pattern);
540
//## } else {
541
//## results.add(pattern, false, pinfo);
542
//## }
543
//## }
544
//## }
545
//## return output;
546
//## }
547
//## }
548
//##
549
//## // Field numbers, used for AppendItem functions
550
//##
551
//## /**
552
//## * @draft ICU 3.6
553
//## * @provisional This API might change or be removed in a future release.
554
//## */
555
//## static final public int ERA = 0;
556
//##
557
//## /**
558
//## * @draft ICU 3.6
559
//## * @provisional This API might change or be removed in a future release.
560
//## */
561
//## static final public int YEAR = 1;
562
//##
563
//## /**
564
//## * @draft ICU 3.6
565
//## * @provisional This API might change or be removed in a future release.
566
//## */
567
//## static final public int QUARTER = 2;
568
//##
569
//## /**
570
//## * @draft ICU 3.6
571
//## * @provisional This API might change or be removed in a future release.
572
//## */
573
//## static final public int MONTH = 3;
574
//##
575
//## /**
576
//## * @draft ICU 3.6
577
//## * @provisional This API might change or be removed in a future release.
578
//## */
579
//## static final public int WEEK_OF_YEAR = 4;
580
//##
581
//## /**
582
//## * @draft ICU 3.6
583
//## * @provisional This API might change or be removed in a future release.
584
//## */
585
//## static final public int WEEK_OF_MONTH = 5;
586
//##
587
//## /**
588
//## * @draft ICU 3.6
589
//## * @provisional This API might change or be removed in a future release.
590
//## */
591
//## static final public int WEEKDAY = 6;
592
//##
593
//## /**
594
//## * @draft ICU 3.6
595
//## * @provisional This API might change or be removed in a future release.
596
//## */
597
//## static final public int DAY = 7;
598
//##
599
//## /**
600
//## * @draft ICU 3.6
601
//## * @provisional This API might change or be removed in a future release.
602
//## */
603
//## static final public int DAY_OF_YEAR = 8;
604
//##
605
//## /**
606
//## * @draft ICU 3.6
607
//## * @provisional This API might change or be removed in a future release.
608
//## */
609
//## static final public int DAY_OF_WEEK_IN_MONTH = 9;
610
//##
611
//## /**
612
//## * @draft ICU 3.6
613
//## * @provisional This API might change or be removed in a future release.
614
//## */
615
//## static final public int DAYPERIOD = 10;
616
//##
617
//## /**
618
//## * @draft ICU 3.6
619
//## * @provisional This API might change or be removed in a future release.
620
//## */
621
//## static final public int HOUR = 11;
622
//##
623
//## /**
624
//## * @draft ICU 3.6
625
//## * @provisional This API might change or be removed in a future release.
626
//## */
627
//## static final public int MINUTE = 12;
628
//##
629
//## /**
630
//## * @draft ICU 3.6
631
//## * @provisional This API might change or be removed in a future release.
632
//## */
633
//## static final public int SECOND = 13;
634
//##
635
//## /**
636
//## * @draft ICU 3.6
637
//## * @provisional This API might change or be removed in a future release.
638
//## */
639
//## static final public int FRACTIONAL_SECOND = 14;
640
//##
641
//## /**
642
//## * @draft ICU 3.6
643
//## * @provisional This API might change or be removed in a future release.
644
//## */
645
//## static final public int ZONE = 15;
646
//##
647
//## /**
648
//## * @draft ICU 3.6
649
//## * @provisional This API might change or be removed in a future release.
650
//## */
651
//## static final public int TYPE_LIMIT = 16;
652
//##
653
//## /**
654
//## * An AppendItem format is a pattern used to append a field if there is no
655
//## * good match. For example, suppose that the input skeleton is "GyyyyMMMd",
656
//## * and there is no matching pattern internally, but there is a pattern
657
//## * matching "yyyyMMMd", say "d-MM-yyyy". Then that pattern is used, plus the
658
//## * G. The way these two are conjoined is by using the AppendItemFormat for G
659
//## * (era). So if that value is, say "{0}, {1}" then the final resulting
660
//## * pattern is "d-MM-yyyy, G".
661
//## * <p>
662
//## * There are actually three available variables: {0} is the pattern so far,
663
//## * {1} is the element we are adding, and {2} is the name of the element.
664
//## * <p>
665
//## * This reflects the way that the CLDR data is organized.
666
//## *
667
//## * @param field
668
//## * such as ERA
669
//## * @param value
670
//## * pattern, such as "{0}, {1}"
671
//## * @draft ICU 3.6
672
//## * @provisional This API might change or be removed in a future release.
673
//## */
674
//## public void setAppendItemFormats(int field, String value) {
675
//## checkFrozen();
676
//## appendItemFormats[field] = value;
677
//## }
678
//##
679
//## /**
680
//## * Getter corresponding to setAppendItemFormats. Values below 0 or at or
681
//## * above TYPE_LIMIT are illegal arguments.
682
//## *
683
//## * @param field
684
//## * @return append pattern for field
685
//## * @draft ICU 3.6
686
//## * @provisional This API might change or be removed in a future release.
687
//## */
688
//## public String getAppendItemFormats(int field) {
689
//## return appendItemFormats[field];
690
//## }
691
//##
692
//## /**
693
//## * Sets the names of fields, eg "era" in English for ERA. These are only
694
//## * used if the corresponding AppendItemFormat is used, and if it contains a
695
//## * {2} variable.
696
//## * <p>
697
//## * This reflects the way that the CLDR data is organized.
698
//## *
699
//## * @param field
700
//## * @param value
701
//## * @draft ICU 3.6
702
//## * @provisional This API might change or be removed in a future release.
703
//## */
704
//## public void setAppendItemNames(int field, String value) {
705
//## checkFrozen();
706
//## appendItemNames[field] = value;
707
//## }
708
//##
709
//## /**
710
//## * Getter corresponding to setAppendItemNames. Values below 0 or at or above
711
//## * TYPE_LIMIT are illegal arguments.
712
//## *
713
//## * @param field
714
//## * @return name for field
715
//## * @draft ICU 3.6
716
//## * @provisional This API might change or be removed in a future release.
717
//## */
718
//## public String getAppendItemNames(int field) {
719
//## return appendItemNames[field];
720
//## }
721
//##
722
//## /**
723
//## * Determines whether a skeleton contains a single field
724
//## *
725
//## * @param skeleton
726
//## * @return true or not
727
//## * @deprecated
728
//## * @internal
729
//## */
730
//## public static boolean isSingleField(String skeleton) {
731
//## char first = skeleton.charAt(0);
732
//## for (int i = 1; i < skeleton.length(); ++i) {
733
//## if (skeleton.charAt(i) != first) return false;
734
//## }
735
//## return true;
736
//## }
737
//##
738
//## /**
739
//## * Boilerplate for Freezable
740
//## * @draft ICU 3.6
741
//## * @provisional This API might change or be removed in a future release.
742
//## */
743
//## public boolean isFrozen() {
744
//## return frozen;
745
//## }
746
//##
747
//## /**
748
//## * Boilerplate for Freezable
749
//## * @draft ICU 3.6
750
//## * @provisional This API might change or be removed in a future release.
751
//## */
752
//## public Object freeze() {
753
//## frozen = true;
754
//## return this;
755
//## }
756
//##
757
//## /**
758
//## * Boilerplate for Freezable
759
//## * @draft ICU 3.6
760
//## * @provisional This API might change or be removed in a future release.
761
//## */
762
//## public Object cloneAsThawed() {
763
//## DateTimePatternGenerator result = (DateTimePatternGenerator) (this.clone());
764
//## frozen = false;
765
//## return result;
766
//## }
767
//##
768
//## /**
769
//## * Boilerplate
770
//## * @draft ICU 3.6
771
//## * @provisional This API might change or be removed in a future release.
772
//## */
773
//## public Object clone() {
774
//## try {
775
//## DateTimePatternGenerator result = (DateTimePatternGenerator) (super.clone());
776
//## result.skeleton2pattern = (TreeMap) skeleton2pattern.clone();
777
//## result.basePattern_pattern = (TreeMap) basePattern_pattern.clone();
778
//## result.appendItemFormats = (String[]) appendItemFormats.clone();
779
//## result.appendItemNames = (String[]) appendItemNames.clone();
780
//## result.current = new DateTimeMatcher();
781
//## result.fp = new FormatParser();
782
//## result._distanceInfo = new DistanceInfo();
783
//##
784
//## result.frozen = false;
785
//## return result;
786
//## } catch (CloneNotSupportedException e) {
787
//## throw new IllegalArgumentException("Internal Error");
788
//## }
789
//## }
790
//##
791
//## /**
792
//## * Utility class for FormatParser. Immutable class.
793
//## * @deprecated
794
//## * @internal
795
//## */
796
//## public static class VariableField {
797
//## private String string;
798
//## /**
799
//## * Create a variable field
800
//## * @param string
801
//## * @deprecated
802
//## * @internal
803
//## */
804
//## public VariableField(String string) {
805
//## this.string = string;
806
//## }
807
//## /**
808
//## * Get the internal results
809
//## * @deprecated
810
//## * @internal
811
//## */
812
//## public String toString() {
813
//## return string;
814
//## }
815
//## }
816
//##
817
//## /**
818
//## * Class providing date formatting
819
//## * @deprecated
820
//## * @internal
821
//## */
822
//## static public class FormatParser {
823
//## private transient PatternTokenizer tokenizer = new PatternTokenizer()
824
//## .setSyntaxCharacters(new UnicodeSet("[a-zA-Z]"))
825
//## //.setEscapeCharacters(new UnicodeSet("[^\\u0020-\\u007E]")) // WARNING: DateFormat doesn't accept \\uXXXX
826
//## .setUsingQuote(true);
827
//## private List items = new ArrayList();
828
//##
829
//## /**
830
//## * Set the string to parse
831
//## * @param string
832
//## * @return this, for chaining
833
//## * @deprecated
834
//## * @internal
835
//## */
836
//## public FormatParser set(String string) {
837
//## items.clear();
838
//## if (string.length() == 0) return this;
839
//## tokenizer.setPattern(string);
840
//## StringBuffer buffer = new StringBuffer();
841
//## StringBuffer variable = new StringBuffer();
842
//## while (true) {
843
//## buffer.setLength(0);
844
//## int status = tokenizer.next(buffer);
845
//## if (status == PatternTokenizer.DONE) break;
846
//## if (status == PatternTokenizer.SYNTAX) {
847
//## if (variable.length() != 0 && buffer.charAt(0) != variable.charAt(0)) {
848
//## addVariable(variable);
849
//## }
850
//## variable.append(buffer);
851
//## } else {
852
//## addVariable(variable);
853
//## items.add(buffer.toString());
854
//## }
855
//## }
856
//## addVariable(variable);
857
//## return this;
858
//## }
859
//##
860
//## private void addVariable(StringBuffer variable) {
861
//## if (variable.length() != 0) {
862
//## items.add(new VariableField(variable.toString()));
863
//## variable.setLength(0);
864
//## }
865
//## }
866
//##
867
//## /** Return a collection of fields. These will be a mixture of Strings and VariableFields. Any "a" variable field is removed.
868
//## * @param output List to append the items to. If null, is allocated as an ArrayList.
869
//## * @return list
870
//## */
871
//## private List getVariableFields(List output) {
872
//## if (output == null) output = new ArrayList();
873
//## main:
874
//## for (Iterator it = items.iterator(); it.hasNext();) {
875
//## Object item = it.next();
876
//## if (item instanceof VariableField) {
877
//## String s = item.toString();
878
//## switch(s.charAt(0)) {
879
//## //case 'Q': continue main; // HACK
880
//## case 'a': continue main; // remove
881
//## }
882
//## output.add(s);
883
//## }
884
//## }
885
//## //System.out.println(output);
886
//## return output;
887
//## }
888
//##
889
//## /**
890
//## * @return a string which is a concatenation of all the variable fields
891
//## * @deprecated
892
//## * @internal
893
//## */
894
//## public String getVariableFieldString() {
895
//## List list = getVariableFields(null);
896
//## StringBuffer result = new StringBuffer();
897
//## for (Iterator it = list.iterator(); it.hasNext();) {
898
//## String item = (String) it.next();
899
//## result.append(item);
900
//## }
901
//## return result.toString();
902
//## }
903
//##
904
//## /**
905
//## * Returns modifiable list which is a mixture of Strings and VariableFields, in the order found during parsing.
906
//## * @return modifiable list of items.
907
//## * @deprecated
908
//## * @internal
909
//## */
910
//## public List getItems() {
911
//## return items;
912
//## }
913
//##
914
//## /** Provide display form of formatted input
915
//## * @return printable output string
916
//## * @deprecated
917
//## * @internal
918
//## */
919
//## public String toString() {
920
//## return toString(0, items.size());
921
//## }
922
//##
923
//## /**
924
//## * Provide display form of formatted input
925
//## * @param start item to start from
926
//## * @param limit last item +1
927
//## * @return printable output string
928
//## * @deprecated
929
//## * @internal
930
//## */
931
//## public String toString(int start, int limit) {
932
//## StringBuffer result = new StringBuffer();
933
//## for (int i = start; i < limit; ++i) {
934
//## result.append(items.get(i).toString());
935
//## }
936
//## return result.toString();
937
//## }
938
//##
939
//## /**
940
//## * Internal method <p>
941
//## * Returns true if it has a mixture of date and time fields
942
//## * @return true or false
943
//## * @deprecated
944
//## * @internal
945
//## */
946
//## public boolean hasDateAndTimeFields() {
947
//## int foundMask = 0;
948
//## for (Iterator it = items.iterator(); it.hasNext();) {
949
//## Object item = it.next();
950
//## if (item instanceof VariableField) {
951
//## int type = getType(item);
952
//## foundMask |= 1 << type;
953
//## }
954
//## }
955
//## boolean isDate = (foundMask & DATE_MASK) != 0;
956
//## boolean isTime = (foundMask & TIME_MASK) != 0;
957
//## return isDate && isTime;
958
//## }
959
//##
960
//## /**
961
//## * Internal routine
962
//## * @param value
963
//## * @param result
964
//## * @return list
965
//## * @deprecated
966
//## * @internal
967
//## */
968
//## public List getAutoPatterns(String value, List result) {
969
//## if (result == null) result = new ArrayList();
970
//## int fieldCount = 0;
971
//## int minField = Integer.MAX_VALUE;
972
//## int maxField = Integer.MIN_VALUE;
973
//## for (Iterator it = items.iterator(); it.hasNext();) {
974
//## Object item = it.next();
975
//## if (item instanceof VariableField) {
976
//## try {
977
//## int type = getType(item);
978
//## if (minField > type) minField = type;
979
//## if (maxField < type) maxField = type;
980
//## if (type == ZONE || type == DAYPERIOD || type == WEEKDAY) return result; // skip anything with zones
981
//## fieldCount++;
982
//## } catch (Exception e) {
983
//## return result; // if there are any funny fields, return
984
//## }
985
//## }
986
//## }
987
//## if (fieldCount < 3) return result; // skip
988
//## // trim from start
989
//## // trim first field IF there are no letters around it
990
//## // and it is either the min or the max field
991
//## // first field is either 0 or 1
992
//## for (int i = 0; i < items.size(); ++i) {
993
//## Object item = items.get(i);
994
//## if (item instanceof VariableField) {
995
//## int type = getType(item);
996
//## if (type != minField && type != maxField) break;
997
//##
998
//## if (i > 0) {
999
//## Object previousItem = items.get(0);
1000
//## if (alpha.containsSome(previousItem.toString())) break;
1001
//## }
1002
//## int start = i+1;
1003
//## if (start < items.size()) {
1004
//## Object nextItem = items.get(start);
1005
//## if (nextItem instanceof String) {
1006
//## if (alpha.containsSome(nextItem.toString())) break;
1007
//## start++; // otherwise skip over string
1008
//## }
1009
//## }
1010
//## result.add(toString(start, items.size()));
1011
//## break;
1012
//## }
1013
//## }
1014
//## // now trim from end
1015
//## for (int i = items.size()-1; i >= 0; --i) {
1016
//## Object item = items.get(i);
1017
//## if (item instanceof VariableField) {
1018
//## int type = getType(item);
1019
//## if (type != minField && type != maxField) break;
1020
//## if (i < items.size() - 1) {
1021
//## Object previousItem = items.get(items.size() - 1);
1022
//## if (alpha.containsSome(previousItem.toString())) break;
1023
//## }
1024
//## int end = i-1;
1025
//## if (end > 0) {
1026
//## Object nextItem = items.get(end);
1027
//## if (nextItem instanceof String) {
1028
//## if (alpha.containsSome(nextItem.toString())) break;
1029
//## end--; // otherwise skip over string
1030
//## }
1031
//## }
1032
//## result.add(toString(0, end+1));
1033
//## break;
1034
//## }
1035
//## }
1036
//##
1037
//## return result;
1038
//## }
1039
//##
1040
//## private static UnicodeSet alpha = new UnicodeSet("[:alphabetic:]");
1041
//##
1042
//## private int getType(Object item) {
1043
//## String s = item.toString();
1044
//## int canonicalIndex = getCanonicalIndex(s);
1045
//## if (canonicalIndex < 0) {
1046
//## throw new IllegalArgumentException("Illegal field:\t"
1047
//## + s);
1048
//## }
1049
//## int type = types[canonicalIndex][1];
1050
//## return type;
1051
//## }
1052
//##
1053
//## /**
1054
//## * produce a quoted literal
1055
//## * @param string
1056
//## * @return string with quoted literals
1057
//## * @deprecated
1058
//## * @internal
1059
//## */
1060
//## public Object quoteLiteral(String string) {
1061
//## return tokenizer.quoteLiteral(string);
1062
//## }
1063
//##
1064
//## /**
1065
//## * Simple constructor, since this is treated like a struct.
1066
//## * @deprecated
1067
//## * @internal
1068
//## */
1069
//## public FormatParser() {
1070
//## super();
1071
//## // TODO Auto-generated constructor stub
1072
//## }
1073
//## }
1074
//## // ========= PRIVATES ============
1075
//##
1076
//## private TreeMap skeleton2pattern = new TreeMap(); // items are in priority order
1077
//## private TreeMap basePattern_pattern = new TreeMap(); // items are in priority order
1078
//## private String decimal = "?";
1079
//## private String dateTimeFormat = "{0} {1}";
1080
//## private String[] appendItemFormats = new String[TYPE_LIMIT];
1081
//## private String[] appendItemNames = new String[TYPE_LIMIT];
1082
//## {
1083
//## for (int i = 0; i < TYPE_LIMIT; ++i) {
1084
//## appendItemFormats[i] = "{0} \u251C{2}: {1}\u2524";
1085
//## appendItemNames[i] = "F" + i;
1086
//## }
1087
//## }
1088
//##
1089
//## private transient DateTimeMatcher current = new DateTimeMatcher();
1090
//## private transient FormatParser fp = new FormatParser();
1091
//## private transient DistanceInfo _distanceInfo = new DistanceInfo();
1092
//## private transient boolean isComplete = false;
1093
//## private transient DateTimeMatcher skipMatcher = null; // only used temporarily, for internal purposes
1094
//## private transient boolean frozen = false;
1095
//##
1096
//## private static final int FRACTIONAL_MASK = 1<<FRACTIONAL_SECOND;
1097
//## private static final int SECOND_AND_FRACTIONAL_MASK = (1<<SECOND) | (1<<FRACTIONAL_SECOND);
1098
//##
1099
//## private void checkFrozen() {
1100
//## if (isFrozen()) {
1101
//## throw new UnsupportedOperationException("Attempt to modify frozen object");
1102
//## }
1103
//## }
1104
//##
1105
//## /**
1106
//## * We only get called here if we failed to find an exact skeleton. We have broken it into date + time, and look for the pieces.
1107
//## * If we fail to find a complete skeleton, we compose in a loop until we have all the fields.
1108
//## */
1109
//## private String getBestAppending(int missingFields) {
1110
//## String resultPattern = null;
1111
//## if (missingFields != 0) {
1112
//## resultPattern = getBestRaw(current, missingFields, _distanceInfo);
1113
//## resultPattern = adjustFieldTypes(resultPattern, current, false);
1114
//##
1115
//## while (_distanceInfo.missingFieldMask != 0) { // precondition: EVERY single field must work!
1116
//##
1117
//## // special hack for SSS. If we are missing SSS, and we had ss but found it, replace the s field according to the
1118
//## // number separator
1119
//## if ((_distanceInfo.missingFieldMask & SECOND_AND_FRACTIONAL_MASK) == FRACTIONAL_MASK
1120
//## && (missingFields & SECOND_AND_FRACTIONAL_MASK) == SECOND_AND_FRACTIONAL_MASK) {
1121
//## resultPattern = adjustFieldTypes(resultPattern, current, true);
1122
//## _distanceInfo.missingFieldMask &= ~FRACTIONAL_MASK; // remove bit
1123
//## continue;
1124
//## }
1125
//##
1126
//## int startingMask = _distanceInfo.missingFieldMask;
1127
//## String temp = getBestRaw(current, _distanceInfo.missingFieldMask, _distanceInfo);
1128
//## temp = adjustFieldTypes(temp, current, false);
1129
//## int foundMask = startingMask & ~_distanceInfo.missingFieldMask;
1130
//## int topField = getTopBitNumber(foundMask);
1131
//## resultPattern = MessageFormat.format(getAppendFormat(topField), new Object[]{resultPattern, temp, getAppendName(topField)});
1132
//## }
1133
//## }
1134
//## return resultPattern;
1135
//## }
1136
//##
1137
//## private String getAppendName(int foundMask) {
1138
//## return "'" + appendItemNames[foundMask] + "'";
1139
//## }
1140
//## private String getAppendFormat(int foundMask) {
1141
//## return appendItemFormats[foundMask];
1142
//## }
1143
//##
1144
//## /**
1145
//## * @param current2
1146
//## * @return
1147
//## */
1148
//## private String adjustSeconds(DateTimeMatcher current2) {
1149
//## // TODO Auto-generated method stub
1150
//## return null;
1151
//## }
1152
//##
1153
//## /**
1154
//## * @param foundMask
1155
//## * @return
1156
//## */
1157
//## private int getTopBitNumber(int foundMask) {
1158
//## int i = 0;
1159
//## while (foundMask != 0) {
1160
//## foundMask >>>= 1;
1161
//## ++i;
1162
//## }
1163
//## return i-1;
1164
//## }
1165
//##
1166
//## /**
1167
//## *
1168
//## */
1169
//## private void complete() {
1170
//## PatternInfo patternInfo = new PatternInfo();
1171
//## // make sure that every valid field occurs once, with a "default" length
1172
//## for (int i = 0; i < CANONICAL_ITEMS.length; ++i) {
1173
//## char c = (char)types[i][0];
1174
//## add(String.valueOf(CANONICAL_ITEMS[i]), false, patternInfo);
1175
//## }
1176
//## isComplete = true;
1177
//## }
1178
//## {
1179
//## complete();
1180
//## }
1181
//##
1182
//## /**
1183
//## *
1184
//## */
1185
//## private String getBestRaw(DateTimeMatcher source, int includeMask, DistanceInfo missingFields) {
1186
//##// if (SHOW_DISTANCE) System.out.println("Searching for: " + source.pattern
1187
//##// + ", mask: " + showMask(includeMask));
1188
//## int bestDistance = Integer.MAX_VALUE;
1189
//## String bestPattern = "";
1190
//## DistanceInfo tempInfo = new DistanceInfo();
1191
//## for (Iterator it = skeleton2pattern.keySet().iterator(); it.hasNext();) {
1192
//## DateTimeMatcher trial = (DateTimeMatcher) it.next();
1193
//## if (trial.equals(skipMatcher)) continue;
1194
//## int distance = source.getDistance(trial, includeMask, tempInfo);
1195
//##// if (SHOW_DISTANCE) System.out.println("\tDistance: " + trial.pattern + ":\t"
1196
//##// + distance + ",\tmissing fields: " + tempInfo);
1197
//## if (distance < bestDistance) {
1198
//## bestDistance = distance;
1199
//## bestPattern = (String) skeleton2pattern.get(trial);
1200
//## missingFields.setTo(tempInfo);
1201
//## if (distance == 0) break;
1202
//## }
1203
//## }
1204
//## return bestPattern;
1205
//## }
1206
//##
1207
//## /**
1208
//## * @param fixFractionalSeconds TODO
1209
//## *
1210
//## */
1211
//## private String adjustFieldTypes(String pattern, DateTimeMatcher inputRequest, boolean fixFractionalSeconds) {
1212
//## fp.set(pattern);
1213
//## StringBuffer newPattern = new StringBuffer();
1214
//## for (Iterator it = fp.getItems().iterator(); it.hasNext();) {
1215
//## Object item = it.next();
1216
//## if (item instanceof String) {
1217
//## newPattern.append(fp.quoteLiteral((String)item));
1218
//## } else {
1219
//## String field = ((VariableField) item).string;
1220
//## int canonicalIndex = getCanonicalIndex(field);
1221
//## if (canonicalIndex < 0) {
1222
//## continue; // don't adjust
1223
//## }
1224
//## int type = types[canonicalIndex][1];
1225
//## if (fixFractionalSeconds && type == SECOND) {
1226
//## String newField = inputRequest.original[FRACTIONAL_SECOND];
1227
//## field = field + decimal + newField;
1228
//## } else if (inputRequest.type[type] != 0) {
1229
//## String newField = inputRequest.original[type];
1230
//## // normally we just replace the field. However HOUR is special; we only change the length
1231
//## if (type != HOUR) {
1232
//## field = newField;
1233
//## } else if (field.length() != newField.length()){
1234
//## char c = field.charAt(0);
1235
//## field = "";
1236
//## for (int i = newField.length(); i > 0; --i) field += c;
1237
//## }
1238
//## }
1239
//## newPattern.append(field);
1240
//## }
1241
//## }
1242
//## //if (SHOW_DISTANCE) System.out.println("\tRaw: " + pattern);
1243
//## return newPattern.toString();
1244
//## }
1245
//##
1246
//##// public static String repeat(String s, int count) {
1247
//##// StringBuffer result = new StringBuffer();
1248
//##// for (int i = 0; i < count; ++i) {
1249
//##// result.append(s);
1250
//##// }
1251
//##// return result.toString();
1252
//##// }
1253
//##
1254
//## /**
1255
//## * internal routine
1256
//## * @param pattern
1257
//## * @return field value
1258
//## * @deprecated
1259
//## * @internal
1260
//## */
1261
//## public String getFields(String pattern) {
1262
//## fp.set(pattern);
1263
//## StringBuffer newPattern = new StringBuffer();
1264
//## for (Iterator it = fp.getItems().iterator(); it.hasNext();) {
1265
//## Object item = it.next();
1266
//## if (item instanceof String) {
1267
//## newPattern.append(fp.quoteLiteral((String)item));
1268
//## } else {
1269
//## newPattern.append("{" + getName(item.toString()) + "}");
1270
//## }
1271
//## }
1272
//## return newPattern.toString();
1273
//## }
1274
//##
1275
//## private static String showMask(int mask) {
1276
//## String result = "";
1277
//## for (int i = 0; i < TYPE_LIMIT; ++i) {
1278
//## if ((mask & (1<<i)) == 0) continue;
1279
//## if (result.length() != 0) result += " | ";
1280
//## result += FIELD_NAME[i] + " ";
1281
//## }
1282
//## return result;
1283
//## }
1284
//##
1285
//## static private String[] CLDR_FIELD_APPEND = {
1286
//## "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",
1287
//## "Day", "*", "*", "*",
1288
//## "Hour", "Minute", "Second", "*", "Timezone"
1289
//## };
1290
//##
1291
//## static private String[] CLDR_FIELD_NAME = {
1292
//## "era", "year", "quarter", "month", "week", "*", "weekday",
1293
//## "day", "*", "*", "dayperiod",
1294
//## "hour", "minute", "second", "*", "zone"
1295
//## };
1296
//##
1297
//## static private String[] FIELD_NAME = {
1298
//## "Era", "Year", "Quarter", "Month", "Week_in_Year", "Week_in_Month", "Weekday",
1299
//## "Day", "Day_Of_Year", "Day_of_Week_in_Month", "Dayperiod",
1300
//## "Hour", "Minute", "Second", "Fractional_Second", "Zone"
1301
//## };
1302
//##
1303
//##
1304
//## static private String[] CANONICAL_ITEMS = {
1305
//## "G", "y", "Q", "M", "w", "W", "e",
1306
//## "d", "D", "F",
1307
//## "H", "m", "s", "S", "v"
1308
//## };
1309
//##
1310
//## static private Set CANONICAL_SET = new HashSet(Arrays.asList(CANONICAL_ITEMS));
1311
//##
1312
//## static final private int
1313
//## DATE_MASK = (1<<DAYPERIOD) - 1,
1314
//## TIME_MASK = (1<<TYPE_LIMIT) - 1 - DATE_MASK;
1315
//##
1316
//## static final private int // numbers are chosen to express 'distance'
1317
//## DELTA = 0x10,
1318
//## NUMERIC = 0x100,
1319
//## NONE = 0,
1320
//## NARROW = -0x100,
1321
//## SHORT = -0x101,
1322
//## LONG = -0x102,
1323
//## EXTRA_FIELD = 0x10000,
1324
//## MISSING_FIELD = 0x1000;
1325
//##
1326
//##
1327
//## static private String getName(String s) {
1328
//## int i = getCanonicalIndex(s);
1329
//## String name = FIELD_NAME[types[i][1]];
1330
//## int subtype = types[i][2];
1331
//## boolean string = subtype < 0;
1332
//## if (string) subtype = -subtype;
1333
//## if (subtype < 0) name += ":S";
1334
//## else name += ":N";
1335
//## return name;
1336
//## }
1337
//##
1338
//## static private int getCanonicalIndex(String s) {
1339
//## int len = s.length();
1340
//## int ch = s.charAt(0);
1341
//## for (int i = 0; i < types.length; ++i) {
1342
//## int[] row = types[i];
1343
//## if (row[0] != ch) continue;
1344
//## if (row[3] > len) continue;
1345
//## if (row[row.length-1] < len) continue;
1346
//## return i;
1347
//## }
1348
//## return -1;
1349
//## }
1350
//##
1351
//## static private int[][] types = {
1352
//## // the order here makes a difference only when searching for single field.
1353
//## // format is:
1354
//## // pattern character, main type, weight, min length, weight
1355
//## {'G', ERA, SHORT, 1, 3},
1356
//## {'G', ERA, LONG, 4},
1357
//##
1358
//## {'y', YEAR, NUMERIC, 1, 20},
1359
//## {'Y', YEAR, NUMERIC + DELTA, 1, 20},
1360
//## {'u', YEAR, NUMERIC + 2*DELTA, 1, 20},
1361
//##
1362
//## {'Q', QUARTER, NUMERIC, 1, 2},
1363
//## {'Q', QUARTER, SHORT, 3},
1364
//## {'Q', QUARTER, LONG, 4},
1365
//##
1366
//## {'M', MONTH, NUMERIC, 1, 2},
1367
//## {'M', MONTH, SHORT, 3},
1368
//## {'M', MONTH, LONG, 4},
1369
//## {'M', MONTH, NARROW, 5},
1370
//## {'L', MONTH, NUMERIC + DELTA, 1, 2},
1371
//## {'L', MONTH, SHORT - DELTA, 3},
1372
//## {'L', MONTH, LONG - DELTA, 4},
1373
//## {'L', MONTH, NARROW - DELTA, 5},
1374
//##
1375
//## {'w', WEEK_OF_YEAR, NUMERIC, 1, 2},
1376
//## {'W', WEEK_OF_MONTH, NUMERIC + DELTA, 1},
1377
//##
1378
//## {'e', WEEKDAY, NUMERIC + DELTA, 1, 2},
1379
//## {'e', WEEKDAY, SHORT - DELTA, 3},
1380
//## {'e', WEEKDAY, LONG - DELTA, 4},
1381
//## {'e', WEEKDAY, NARROW - DELTA, 5},
1382
//## {'E', WEEKDAY, SHORT, 1, 3},
1383
//## {'E', WEEKDAY, LONG, 4},
1384
//## {'E', WEEKDAY, NARROW, 5},
1385
//## {'c', WEEKDAY, NUMERIC + 2*DELTA, 1, 2},
1386
//## {'c', WEEKDAY, SHORT - 2*DELTA, 3},
1387
//## {'c', WEEKDAY, LONG - 2*DELTA, 4},
1388
//## {'c', WEEKDAY, NARROW - 2*DELTA, 5},
1389
//##
1390
//## {'d', DAY, NUMERIC, 1, 2},
1391
//## {'D', DAY_OF_YEAR, NUMERIC + DELTA, 1, 3},
1392
//## {'F', DAY_OF_WEEK_IN_MONTH, NUMERIC + 2*DELTA, 1},
1393
//## {'g', DAY, NUMERIC + 3*DELTA, 1, 20}, // really internal use, so we don't care
1394
//##
1395
//## {'a', DAYPERIOD, SHORT, 1},
1396
//##
1397
//## {'H', HOUR, NUMERIC + 10*DELTA, 1, 2}, // 24 hour
1398
//## {'k', HOUR, NUMERIC + 11*DELTA, 1, 2},
1399
//## {'h', HOUR, NUMERIC, 1, 2}, // 12 hour
1400
//## {'K', HOUR, NUMERIC + DELTA, 1, 2},
1401
//##
1402
//## {'m', MINUTE, NUMERIC, 1, 2},
1403
//##
1404
//## {'s', SECOND, NUMERIC, 1, 2},
1405
//## {'S', FRACTIONAL_SECOND, NUMERIC + DELTA, 1, 1000},
1406
//## {'A', SECOND, NUMERIC + 2*DELTA, 1, 1000},
1407
//##
1408
//## {'v', ZONE, SHORT - 2*DELTA, 1},
1409
//## {'v', ZONE, LONG - 2*DELTA, 4},
1410
//## {'z', ZONE, SHORT, 1, 3},
1411
//## {'z', ZONE, LONG, 4},
1412
//## {'Z', ZONE, SHORT - DELTA, 1, 3},
1413
//## {'Z', ZONE, LONG - DELTA, 4},
1414
//## };
1415
//##
1416
//## private static class DateTimeMatcher implements Comparable {
1417
//## //private String pattern = null;
1418
//## private int[] type = new int[TYPE_LIMIT];
1419
//## private String[] original = new String[TYPE_LIMIT];
1420
//## private String[] baseOriginal = new String[TYPE_LIMIT];
1421
//##
1422
//## // just for testing; fix to make multi-threaded later
1423
//## // private static FormatParser fp = new FormatParser();
1424
//##
1425
//## public String toString() {
1426
//## StringBuffer result = new StringBuffer();
1427
//## for (int i = 0; i < TYPE_LIMIT; ++i) {
1428
//## if (original[i].length() != 0) result.append(original[i]);
1429
//## }
1430
//## return result.toString();
1431
//## }
1432
//##
1433
//## String getBasePattern() {
1434
//## StringBuffer result = new StringBuffer();
1435
//## for (int i = 0; i < TYPE_LIMIT; ++i) {
1436
//## if (baseOriginal[i].length() != 0) result.append(baseOriginal[i]);
1437
//## }
1438
//## return result.toString();
1439
//## }
1440
//##
1441
//## DateTimeMatcher set(String pattern, FormatParser fp) {
1442
//## if (pattern.indexOf("\\u") >= 0) {
1443
//## String oldPattern = pattern;
1444
//## pattern = fromHex.transliterate(pattern);
1445
//## }
1446
//## for (int i = 0; i < TYPE_LIMIT; ++i) {
1447
//## type[i] = NONE;
1448
//## original[i] = "";
1449
//## baseOriginal[i] = "";
1450
//## }
1451
//## fp.set(pattern);
1452
//## for (Iterator it = fp.getVariableFields(new ArrayList()).iterator(); it.hasNext();) {
1453
//## String field = (String) it.next();
1454
//## if (field.charAt(0) == 'a') continue; // skip day period, special cass
1455
//## int canonicalIndex = getCanonicalIndex(field);
1456
//## if (canonicalIndex < 0) {
1457
//## throw new IllegalArgumentException("Illegal field:\t"
1458
//## + field + "\t in " + pattern);
1459
//## }
1460
//## int[] row = types[canonicalIndex];
1461
//## int typeValue = row[1];
1462
//## if (original[typeValue].length() != 0) {
1463
//## throw new IllegalArgumentException("Conflicting fields:\t"
1464
//## + original[typeValue] + ", " + field + "\t in " + pattern);
1465
//## }
1466
//## original[typeValue] = field;
1467
//## char repeatChar = (char)row[0];
1468
//## int repeatCount = row[3];
1469
//## if (repeatCount > 3) repeatCount = 3; // hack to discard differences
1470
//## if ("GEzvQ".indexOf(repeatChar) >= 0) repeatCount = 1;
1471
//## baseOriginal[typeValue] = Utility.repeat(String.valueOf(repeatChar),repeatCount);
1472
//## int subTypeValue = row[2];
1473
//## if (subTypeValue > 0) subTypeValue += field.length();
1474
//## type[typeValue] = (byte) subTypeValue;
1475
//## }
1476
//## return this;
1477
//## }
1478
//##
1479
//## /**
1480
//## *
1481
//## */
1482
//## int getFieldMask() {
1483
//## int result = 0;
1484
//## for (int i = 0; i < type.length; ++i) {
1485
//## if (type[i] != 0) result |= (1<<i);
1486
//## }
1487
//## return result;
1488
//## }
1489
//##
1490
//## /**
1491
//## *
1492
//## */
1493
//## void extractFrom(DateTimeMatcher source, int fieldMask) {
1494
//## for (int i = 0; i < type.length; ++i) {
1495
//## if ((fieldMask & (1<<i)) != 0) {
1496
//## type[i] = source.type[i];
1497
//## original[i] = source.original[i];
1498
//## } else {
1499
//## type[i] = NONE;
1500
//## original[i] = "";
1501
//## }
1502
//## }
1503
//## }
1504
//##
1505
//## int getDistance(DateTimeMatcher other, int includeMask, DistanceInfo distanceInfo) {
1506
//## int result = 0;
1507
//## distanceInfo.clear();
1508
//## for (int i = 0; i < type.length; ++i) {
1509
//## int myType = (includeMask & (1<<i)) == 0 ? 0 : type[i];
1510
//## int otherType = other.type[i];
1511
//## if (myType == otherType) continue; // identical (maybe both zero) add 0
1512
//## if (myType == 0) { // and other is not
1513
//## result += EXTRA_FIELD;
1514
//## distanceInfo.addExtra(i);
1515
//## } else if (otherType == 0) { // and mine is not
1516
//## result += MISSING_FIELD;
1517
//## distanceInfo.addMissing(i);
1518
//## } else {
1519
//## result += Math.abs(myType - otherType); // square of mismatch
1520
//## }
1521
//## }
1522
//## return result;
1523
//## }
1524
//##
1525
//## public int compareTo(Object o) {
1526
//## DateTimeMatcher that = (DateTimeMatcher) o;
1527
//## for (int i = 0; i < original.length; ++i) {
1528
//## int comp = original[i].compareTo(that.original[i]);
1529
//## if (comp != 0) return -comp;
1530
//## }
1531
//## return 0;
1532
//## }
1533
//##
1534
//## public boolean equals(Object other) {
1535
//## if (other == null) return false;
1536
//## DateTimeMatcher that = (DateTimeMatcher) other;
1537
//## for (int i = 0; i < original.length; ++i) {
1538
//## if (!original[i].equals(that.original[i])) return false;
1539
//## }
1540
//## return true;
1541
//## }
1542
//## public int hashCode() {
1543
//## int result = 0;
1544
//## for (int i = 0; i < original.length; ++i) {
1545
//## result ^= original[i].hashCode();
1546
//## }
1547
//## return result;
1548
//## }
1549
//## }
1550
//##
1551
//## private static class DistanceInfo {
1552
//## int missingFieldMask;
1553
//## int extraFieldMask;
1554
//## void clear() {
1555
//## missingFieldMask = extraFieldMask = 0;
1556
//## }
1557
//## /**
1558
//## *
1559
//## */
1560
//## void setTo(DistanceInfo other) {
1561
//## missingFieldMask = other.missingFieldMask;
1562
//## extraFieldMask = other.extraFieldMask;
1563
//## }
1564
//## void addMissing(int field) {
1565
//## missingFieldMask |= (1<<field);
1566
//## }
1567
//## void addExtra(int field) {
1568
//## extraFieldMask |= (1<<field);
1569
//## }
1570
//## public String toString() {
1571
//## return "missingFieldMask: " + DateTimePatternGenerator.showMask(missingFieldMask)
1572
//## + ", extraFieldMask: " + DateTimePatternGenerator.showMask(extraFieldMask);
1573
//## }
1574
//## }
1575
//##}
1576
//#endif
1577
//eof
1578
Popular Tags