1 module hunt.time.format.WeekBasedFieldPrinterParser; 2 3 import hunt.time.format.DateTimeParseContext; 4 import hunt.time.format.DateTimePrinterParser; 5 import hunt.time.format.DateTimePrintContext; 6 import hunt.time.format.NumberPrinterParser; 7 import hunt.time.format.ReducedPrinterParser; 8 import hunt.time.format.SignStyle; 9 import hunt.time.temporal.TemporalField; 10 import hunt.time.temporal.WeekFields; 11 12 import hunt.util.StringBuilder; 13 14 import hunt.Exceptions; 15 import hunt.util.Locale; 16 17 //----------------------------------------------------------------------- 18 /** 19 * Prints or parses a localized pattern from a localized field. 20 * The specific formatter and parameters is not selected until 21 * the field is to be printed or parsed. 22 * The locale is needed to select the proper WeekFields from which 23 * the field for day-of-week, week-of-month, or week-of-year is selected. 24 * Hence the inherited field NumberPrinterParser.field is unused. 25 */ 26 static final class WeekBasedFieldPrinterParser : NumberPrinterParser 27 { 28 private char chr; 29 private int count; 30 31 /** 32 * Constructor. 33 * 34 * @param chr the pattern format letter that added this PrinterParser. 35 * @param count the repeat count of the format letter 36 * @param minWidth the minimum field width, from 1 to 19 37 * @param maxWidth the maximum field width, from minWidth to 19 38 */ 39 this(char chr, int count, int minWidth, int maxWidth) 40 { 41 this(chr, count, minWidth, maxWidth, 0); 42 } 43 44 /** 45 * Constructor. 46 * 47 * @param chr the pattern format letter that added this PrinterParser. 48 * @param count the repeat count of the format letter 49 * @param minWidth the minimum field width, from 1 to 19 50 * @param maxWidth the maximum field width, from minWidth to 19 51 * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater, 52 * -1 if fixed width due to active adjacent parsing 53 */ 54 this(char chr, int count, int minWidth, int maxWidth, int subsequentWidth) 55 { 56 super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth); 57 this.chr = chr; 58 this.count = count; 59 } 60 61 /** 62 * Returns a new instance with fixed width flag set. 63 * 64 * @return a new updated printer-parser, not null 65 */ 66 override WeekBasedFieldPrinterParser withFixedWidth() 67 { 68 if (subsequentWidth == -1) 69 { 70 return this; 71 } 72 return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth, -1); 73 } 74 75 /** 76 * Returns a new instance with an updated subsequent width. 77 * 78 * @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater 79 * @return a new updated printer-parser, not null 80 */ 81 override WeekBasedFieldPrinterParser withSubsequentWidth(int subsequentWidth) 82 { 83 return new WeekBasedFieldPrinterParser(chr, count, minWidth, 84 maxWidth, this.subsequentWidth + subsequentWidth); 85 } 86 87 override public bool format(DateTimePrintContext context, StringBuilder buf) 88 { 89 return printerParser(context.getLocale()).format(context, buf); 90 } 91 92 override public int parse(DateTimeParseContext context, string text, int position) 93 { 94 return printerParser(context.getLocale()).parse(context, text, position); 95 } 96 97 /** 98 * Gets the printerParser to use based on the field and the locale. 99 * 100 * @param locale the locale to use, not null 101 * @return the formatter, not null 102 * @throws IllegalArgumentException if the formatter cannot be found 103 */ 104 private DateTimePrinterParser printerParser(Locale locale) 105 { 106 WeekFields weekDef = WeekFields.of(locale); 107 TemporalField field = null; 108 switch (chr) 109 { 110 case 'Y': 111 field = weekDef.weekBasedYear(); 112 if (count == 2) 113 { 114 return new ReducedPrinterParser(field, 2, 2, 0, 115 ReducedPrinterParser.BASE_DATE, this.subsequentWidth); 116 } 117 else 118 { 119 return new NumberPrinterParser(field, count, 19, (count < 4) 120 ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, this.subsequentWidth); 121 } 122 case 'e': 123 case 'c': 124 field = weekDef.dayOfWeek(); 125 break; 126 case 'w': 127 field = weekDef.weekOfWeekBasedYear(); 128 break; 129 case 'W': 130 field = weekDef.weekOfMonth(); 131 break; 132 default: 133 throw new IllegalStateException("unreachable"); 134 } 135 return new NumberPrinterParser(field, minWidth, maxWidth, 136 SignStyle.NOT_NEGATIVE, this.subsequentWidth); 137 } 138 139 override public string toString() 140 { 141 StringBuilder sb = new StringBuilder(30); 142 sb.append("Localized("); 143 if (chr == 'Y') 144 { 145 if (count == 1) 146 { 147 sb.append("WeekBasedYear"); 148 } 149 else if (count == 2) 150 { 151 sb.append("ReducedValue(WeekBasedYear,2,2,2000-01-01)"); 152 } 153 else 154 { 155 sb.append("WeekBasedYear,").append(count).append(",") 156 .append(19).append(",").append((count < 4) 157 ? SignStyle.NORMAL.name() : SignStyle.EXCEEDS_PAD.name()); 158 } 159 } 160 else 161 { 162 switch (chr) 163 { 164 case 'c': 165 case 'e': 166 sb.append("DayOfWeek"); 167 break; 168 case 'w': 169 sb.append("WeekOfWeekBasedYear"); 170 break; 171 case 'W': 172 sb.append("WeekOfMonth"); 173 break; 174 default: 175 break; 176 } 177 sb.append(","); 178 sb.append(count); 179 } 180 sb.append(")"); 181 return sb.toString(); 182 } 183 }