/** * Copyright (c) 2012-2016 AndrĂ© Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.objects.intl; /** * <h1>Unicode Locale Data Markup Language (LDML)</h1> * <p> * Date Format Patterns * <ul> * <li>Date Field Symbol Table * </ul> * <p> * Version: 28 * * @see <a href="http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns">Date Format Patterns * </a> * @see <a href="http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table">Date Field Symbol& * nbsp;Table</a> */ final class DateFieldSymbolTable { private DateFieldSymbolTable() { } static final class Skeleton { private final char[] symbols; private final FieldWeight[] fieldWeights; private final boolean hour12; public Skeleton(String skeleton) { char[] symbols = new char[DateField.LENGTH]; FieldWeight[] weights = new FieldWeight[DateField.LENGTH]; boolean hour12 = false, quote = false; for (int i = 0, len = skeleton.length(); i < len;) { char sym = skeleton.charAt(i++); if (sym == '\'') { if (i < len && skeleton.charAt(i) == '\'') { i += 1; } else { quote = !quote; } continue; } if (quote || !(('A' <= sym && sym <= 'Z') || ('a' <= sym && sym <= 'z'))) { continue; } int length = 1; for (; i < len && skeleton.charAt(i) == sym; ++i) { length += 1; } DateField field = DateField.forSymbol(sym); FieldWeight weight = field.getWeight(sym, length); int index = field.ordinal(); if (symbols[index] != 0) { throw new IllegalArgumentException(); } symbols[index] = sym; weights[index] = weight; if (field == DateField.Hour) { hour12 = (sym == 'h' || sym == 'K'); } } this.symbols = symbols; this.fieldWeights = weights; this.hour12 = hour12; } public boolean has(DateField field) { return fieldWeights[field.ordinal()] != null; } public char getSymbol(DateField field) { return symbols[field.ordinal()]; } public FieldWeight getWeight(DateField field) { return fieldWeights[field.ordinal()]; } public boolean isHour12() { return hour12; } public boolean isDate() { return has(DateField.Year) || has(DateField.Month) || has(DateField.Day); } public boolean isTime() { return has(DateField.Hour) || has(DateField.Minute) || has(DateField.Second); } } enum FieldWeight { TwoDigit(1, 2), Numeric(2, 1), Narrow(3, 5), Short(4, 3), Long(5, 4); // relative index per abstract operation BasicFormatMatcher, step 11.c.vii.1 private final int index; // length in output string private final int length; private FieldWeight(int index, int length) { this.index = index; this.length = length; } public int index() { return index; } public int length() { return length; } @Override public String toString() { switch (this) { case TwoDigit: return "2-digit"; case Numeric: return "numeric"; case Narrow: return "narrow"; case Short: return "short"; case Long: return "long"; default: throw new AssertionError(); } } public static FieldWeight forName(String name) { if (name == null) { return null; } switch (name) { case "numeric": return Numeric; case "2-digit": return TwoDigit; case "short": return Short; case "long": return Long; case "narrow": return Narrow; default: throw new IllegalArgumentException(name); } } } enum DateField { Era('G') { @Override public FieldWeight getWeight(char symbol, int count) { assert symbol == 'G'; if (symbol == 'G') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count == 5) { return FieldWeight.Narrow; } } throw new IllegalArgumentException(); } }, Year('y') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'U') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count == 5) { return FieldWeight.Narrow; } } else if (symbol == 'y' || symbol == 'Y' || symbol == 'u' || symbol == 'r') { if (count == 2) { return FieldWeight.TwoDigit; } if (count >= 1) { return FieldWeight.Numeric; } } throw new IllegalArgumentException(); } }, Quarter('Q') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'Q' || symbol == 'q') { if (count >= 1 && count <= 2) { return FieldWeight.Numeric; } if (count == 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count == 5) { return FieldWeight.Narrow; } } throw new IllegalArgumentException(); } }, Month('M') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'M' || symbol == 'L') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } if (count == 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count == 5) { return FieldWeight.Narrow; } } throw new IllegalArgumentException(); } }, Week('w') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'w') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } } else if (symbol == 'W') { if (count == 1) { return FieldWeight.Numeric; } } throw new IllegalArgumentException(); } }, Day('d') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'd') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } } else if (symbol == 'D') { if (count >= 1 && count <= 3) { return FieldWeight.Numeric; } } else if (symbol == 'F') { if (count == 1) { return FieldWeight.Numeric; } } else if (symbol == 'g') { if (count >= 1) { return FieldWeight.Numeric; } } throw new IllegalArgumentException(); } }, Weekday('E') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'E') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count >= 5 && count <= 6) { return FieldWeight.Narrow; } } else if (symbol == 'e') { if (count >= 1 && count <= 2) { return FieldWeight.Numeric; } if (count == 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count >= 5 && count <= 6) { return FieldWeight.Narrow; } } else if (symbol == 'c') { if (count == 1) { return FieldWeight.Numeric; } if (count == 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count >= 5 && count <= 6) { return FieldWeight.Narrow; } } throw new IllegalArgumentException(); } }, Period('a') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'a' || symbol == 'b' || symbol == 'B') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } if (count == 5) { return FieldWeight.Narrow; } } throw new IllegalArgumentException(); } }, Hour('j') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'h' || symbol == 'H' || symbol == 'K' || symbol == 'k') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } } throw new IllegalArgumentException(); } @Override public void append(StringBuilder sb, FieldWeight weight, Boolean hour12) { append(sb, weight, hour12 != null ? hour12 ? 'h' : 'H' : symbol); } }, Minute('m') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'm') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } } throw new IllegalArgumentException(); } }, Second('s') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 's') { if (count == 1) { return FieldWeight.Numeric; } if (count == 2) { return FieldWeight.TwoDigit; } } else if (symbol == 'S' || symbol == 'A') { if (count >= 1) { return FieldWeight.Numeric; } } throw new IllegalArgumentException(); } }, Timezone('z') { @Override public FieldWeight getWeight(char symbol, int count) { if (symbol == 'z') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } } else if (symbol == 'Z') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count >= 4 && count <= 5) { return FieldWeight.Long; } } else if (symbol == 'O' || symbol == 'v') { if (count == 1) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } } else if (symbol == 'V') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count == 4) { return FieldWeight.Long; } } else if (symbol == 'X' || symbol == 'x') { if (count >= 1 && count <= 3) { return FieldWeight.Short; } if (count >= 4 && count <= 5) { return FieldWeight.Long; } } throw new IllegalArgumentException(); } }; static final int LENGTH = values().length; protected final char symbol; private DateField(char symbol) { this.symbol = symbol; } @Override public String toString() { switch (this) { case Era: return "era"; case Year: return "year"; case Quarter: return "quarter"; case Month: return "month"; case Week: return "week"; case Day: return "day"; case Weekday: return "weekday"; case Period: return "period"; case Hour: return "hour"; case Minute: return "minute"; case Second: return "second"; case Timezone: return "timeZoneName"; default: throw new AssertionError(); } } protected final void append(StringBuilder sb, FieldWeight weight, char c) { if (weight != null) { int n = weight.length(); sb.ensureCapacity(sb.length() + n); for (int i = 0; i < n; ++i) { sb.append(c); } } } public abstract FieldWeight getWeight(char symbol, int count); public void append(StringBuilder sb, FieldWeight weight, Boolean option) { throw new UnsupportedOperationException(); } public final void append(StringBuilder sb, FieldWeight weight) { append(sb, weight, symbol); } public static DateField forSymbol(char symbol) { switch (symbol) { case 'G': return Era; case 'y': case 'Y': case 'u': case 'U': case 'r': return Year; case 'Q': case 'q': return Quarter; case 'M': case 'L': return Month; case 'w': case 'W': return Week; case 'd': case 'D': case 'F': case 'g': return Day; case 'E': case 'e': case 'c': return Weekday; case 'a': case 'b': case 'B': return Period; case 'h': case 'H': case 'K': case 'k': return Hour; case 'm': return Minute; case 's': case 'S': case 'A': return Second; case 'z': case 'Z': case 'O': case 'v': case 'V': case 'X': case 'x': return Timezone; case 'l': case 'j': case 'J': case 'C': default: throw new IllegalArgumentException(Character.toString(symbol)); } } } }