有没有一种实现方法可以将 ISO 8601 周期转换为 Java 中人类可读的翻译字符串?

问题描述 投票:0回答:2

有没有办法将以 ISO 8601 句点格式给出的字符串转换为人类可读的格式,并翻译为指定的语言? 示例:

  • P1W
    --
    en
    -->
    1 Week
  • P2W
    --
    en
    -->
    2 Weeks
  • P1W
    --
    pl
    -->
    1 Tydzień
  • P2W
    --
    pl
    -->
    2 Tygodnie

我正在寻找一个已经实施的解决方案,无需定义周期翻译。

java iso8601
2个回答
3
投票

Unicode 通用区域设置数据存储库(通常称为 CLDR)是一个权威的存储库,用于存储各种本地化信息(包括翻译)。

自 Java 9 以来,Java SE 已将 CLDR 用于许多(如果不是全部)本地化功能。但我不知道使用 CLDR 数据文件对 java.time.Period 实例进行任何本地化格式化。

CLDR 有自己的 Java 工具,但我对编译后的 .jar 进行了几个小时的实验,但不知道如何使用它。除了(非常短的)命令行帮助之外,我找不到任何文档。如果它有一个用于格式化句点的 API,我肯定会喜欢使用它。

但是CLDR 数据文件 仍然是获取此信息的最佳位置。 (它们也可以从 https://github.com/unicode-org/cldr 克隆)因此,考虑到这一点,我编写了一个(相当长的)类来使用 CLDR 数据文件格式化 period 实例。

涉及几个步骤:

  • 首先,代码必须确定特定数字的语言基数。在英语中,只有两种选择:单数和复数。其他语言可能更复杂。 CLDR 中的
    common/supplemental/plurals.xml
    文件包含所有语言环境的所有数据;它的格式记录在 unicode.org.
  • 大多数本地化数据位于 CLDR 的
    common/main
    目录中,作为按语言环境命名的 .xml 文件。与周期相关的元素在
    <ldml>
    <units>
    <unitLength type="long">
    <unit type="duration-week">
    ,以及 type="duration-year"、type="duration-month" 和 type="duration-day" 。单元元素内有
    <unitPattern>
    元素,每个元素都有一个
    count
    属性引用上述基数。
  • 最后,
    common/main
    中的相同语言环境特定文件包含
    <listPattern>
    元素,这些元素描述如何格式化项目列表,包括用于组装周期部分列表的
    <listPattern type="unit">
    此处描述了此数据的用途。

请注意,Period.parse 接受 ISO 8601 格式,包括周,但 period 类本身不跟踪周,因此如果需要输出周,代码必须将 period 的天数除以 7。

这就是我的想法。解析不稳健,并且对正确的 CLDR 数据做出了很多假设。可能有一些方法可以加快 XML 文件的读取速度,例如缓存最近使用的文件,因此请将此视为概念证明:

public class PeriodFormatter {
    public enum Count {
        EXACTLY0("0"),
        EXACTLY1("1"),
        ZERO,
        ONE,
        TWO,
        FEW,
        MANY,
        OTHER;

        private final String attributeValue;

        Count() {
            this.attributeValue = name().toLowerCase(Locale.US);
        }

        Count(String attributeValue) {
            this.attributeValue = attributeValue;
        }

        String attributeValue() {
            return attributeValue;
        }

        static Count forAttributeValue(String attrValue) {
            for (Count count : values()) {
                if (count.attributeValue.equals(attrValue)) {
                    return count;
                }
            }
            throw new IllegalArgumentException(
                "No Count with attribute value \"" + attrValue + "\"");
        }
    }

    private static class Range {
        final long start;
        final long end;

        Range(long value) {
            this(value, value);
        }

        Range(long start,
              long end) {
            this.start = start;
            this.end = end;
        }

        boolean contains(long value) {
            return value >= start && value <= end;
        }

        boolean contains(double value) {
            return value >= start && value <= end;
        }
    }

    private enum Operand {
        ABSOLUTE_VALUE("n"),
        INTEGER_PART("i"),
        FRACTIONAL_PRECISION("v"),
        FRACTIONAL_PRECISION_TRIMMED("w"),
        FRACTIONAL_PART("f"),
        FRACTIONAL_PART_TRIMMED("t"),
        EXPONENT_PART("c", "e");

        final String[] tokens;

        private Operand(String... tokens) {
            this.tokens = tokens;
        }

        static Operand forToken(String token) {
            for (Operand op : values()) {
                if (Arrays.asList(op.tokens).contains(token)) {
                    return op;
                }
            }
            throw new IllegalArgumentException(
                "No Operand for token \"" + token + "\"");
        }
    }

    private static class Expression {
        final Operand operand;
        final Long modValue;

        Expression(Operand operand,
                   Long modValue) {
            this.operand = operand;
            this.modValue = modValue;
        }

        double evaluate(BigDecimal value) {
            switch (operand) {
                case ABSOLUTE_VALUE:
                    return Math.abs(value.doubleValue());
                case INTEGER_PART:
                    return value.longValue();
                case FRACTIONAL_PRECISION:
                    return Math.max(value.scale(), 0);
                case FRACTIONAL_PRECISION_TRIMMED:
                    return Math.max(value.stripTrailingZeros().scale(), 0);
                case FRACTIONAL_PART:
                    BigDecimal frac = value.remainder(BigDecimal.ONE);
                    frac = frac.movePointRight(Math.max(0, frac.scale()));
                    return frac.doubleValue();
                case FRACTIONAL_PART_TRIMMED:
                    BigDecimal trimmed =
                        value.stripTrailingZeros().remainder(BigDecimal.ONE);
                    trimmed = trimmed.movePointRight(
                        Math.max(0, trimmed.scale()));
                    return trimmed.longValue();
                case EXPONENT_PART:
                    String expStr = String.format("%e", value);
                    return Long.parseLong(
                        expStr.substring(expStr.indexOf('e') + 1));
                default:
                    break;
            }
            throw new RuntimeException("Unknown operand " + operand);
        }
    }

    private static abstract class Relation {
        boolean negated;
        Expression expr;

        abstract boolean matches(BigDecimal value);

        final boolean matchIfIntegral(BigDecimal value,
                                      LongPredicate test) {
            double evaluatedValue = expr.evaluate(value);
            long rounded = Math.round(evaluatedValue);
            return Math.abs(evaluatedValue - rounded) < 0.000001
                && test.test(rounded);
        }
    }

    private static class IsRelation
    extends Relation {
        long value;

        @Override
        boolean matches(BigDecimal value) {
            return matchIfIntegral(value, n -> n == this.value);
        }
    }

    private static class InRelation
    extends Relation {
        final List<Range> ranges = new ArrayList<>();

        @Override
        boolean matches(BigDecimal value) {
            return ranges.stream().anyMatch(
                range -> matchIfIntegral(value, n -> range.contains(n)));
        }
    }

    private static class WithinRelation
    extends Relation {
        final List<Range> ranges = new ArrayList<>();

        @Override
        boolean matches(BigDecimal value) {
            return ranges.stream().anyMatch(r -> r.contains(value.longValue()));
        }
    }

    private static class Condition {
        final List<Relation> relations = new ArrayList<>();

        boolean matches(BigDecimal value) {
            return relations.stream().allMatch(r -> r.matches(value));
        }
    }

    private static class AndConditionSequence {
        final List<Condition> conditions = new ArrayList<>();

        boolean matches(BigDecimal value) {
            return conditions.stream().allMatch(c -> c.matches(value));
        }
    }

    private static class PluralRule {
        final Count count;
        final List<AndConditionSequence> conditions = new ArrayList<>();

        PluralRule(String countSpec,
                   String ruleSpec) {

            this.count = Count.forAttributeValue(countSpec);

            Scanner scanner = new Scanner(ruleSpec);

            AndConditionSequence andSequence = new AndConditionSequence();
            Condition condition = new Condition();
            andSequence.conditions.add(condition);
            this.conditions.add(andSequence);

            while (true) {
                String token = scanner.findWithinHorizon("\\S", 0);
                if (token.equals("@")) {
                    // Ignore samples.
                    break;
                }

                Operand operand = Operand.forToken(token);
                Long modValue = null;

                token = scanner.findWithinHorizon(
                    "mod|%|is|in|within|!?=|not", 0);
                if (token.equals("mod") || token.equals("%")) {
                    modValue = Long.valueOf(
                        scanner.findWithinHorizon("\\d+", 0));
                    token = scanner.findWithinHorizon(
                        "is|in|within|!?=|not", 0);
                }

                Relation relation;

                boolean negated = false;
                if (token.equals("not")) {
                    token = scanner.findWithinHorizon("in|within", 0);
                    if (token.equals("within")) {
                        WithinRelation within = new WithinRelation();
                        relation = within;
                        within.negated = true;
                        parseRanges(within.ranges, scanner);
                    } else {
                        InRelation in = new InRelation();
                        relation = in;
                        in.negated = true;
                        parseRanges(in.ranges, scanner);
                    }
                    relation.negated = true;
                } else if (token.equals("is")) {
                    IsRelation is = new IsRelation();
                    relation = is;
                    token = scanner.findWithinHorizon("not|\\d+", 0);
                    if (token.equals("not")) {
                        is.negated = true;
                        token = scanner.findWithinHorizon("\\d+", 0);
                    }
                    is.value = Long.valueOf(token);
                } else if (token.endsWith("=")) {
                    InRelation in = new InRelation();
                    relation = in;
                    in.negated = token.startsWith("!");
                    parseRanges(in.ranges, scanner);
                } else {
                    throw new RuntimeException(
                        "Unexpected token '" + token + "'");
                }

                relation.expr = new Expression(operand, modValue);
                condition.relations.add(relation);

                if (!scanner.hasNext("and|or")) {
                    break;
                }

                token = scanner.next();
                if (token.equals("and")) {
                    condition = new Condition();
                    andSequence.conditions.add(condition);
                } else {
                    andSequence = new AndConditionSequence();
                    this.conditions.add(andSequence);
                }
            }
        }

        static void parseRanges(Collection<Range> ranges,
                                Scanner scanner) {

            boolean first = true;
            while (true) {
                if (!first) {
                    if (!scanner.hasNext(",.*")) {
                         break;
                    }
                    scanner.findWithinHorizon(",", 0);
                }

                String token =
                    scanner.findWithinHorizon("\\d+(?:\\.\\.\\d+)?", 0);

                int period = token.indexOf('.');
                if (period > 0) {
                    long start = Long.parseLong(token.substring(0, period));
                    long end = Long.parseLong(token.substring(period + 2));
                    ranges.add(new Range(start, end));
                } else {
                    long value = Long.parseLong(token);
                    ranges.add(new Range(value));
                }

                first = false;
            }
        }

        boolean matches(BigDecimal value) {
            return conditions.stream().anyMatch(c -> c.matches(value));
        }
    }

    private static final Map<Locale, List<PluralRule>> pluralRules =
        new HashMap<>();

    private static final Map<Locale, Path> dataFiles = new HashMap<>();

    private static final Path cldrDir;

    static {
        String dir = System.getProperty("cldr");
        if (dir == null) {
            throw new RuntimeException(
                "\"cldr\" system property must be set to root directory"
                + " of CLDR data.  That data can be downloaded from"
                + "https://cldr.unicode.org/index/downloads or"
                + "https://github.com/unicode-org/cldr .");
        }
        cldrDir = Paths.get(dir);
    }

    private final XPath xpath;

    public PeriodFormatter() {
        this.xpath = XPathFactory.newInstance().newXPath();
    }

    private static InputSource createSource(Path path) {
        return new InputSource(path.toUri().toASCIIString());
    }

    private Count countFor(BigDecimal amount,
                           Locale locale) {

        synchronized (pluralRules) {
            if (pluralRules.isEmpty()) {
                Path pluralsFile = cldrDir.resolve(
                    Paths.get("common", "supplemental", "plurals.xml"));

                NodeList rulesElements;
                try {
                    rulesElements = (NodeList) xpath.evaluate(
                        "//plurals[@type='cardinal']/pluralRules",
                        createSource(pluralsFile),
                        XPathConstants.NODESET);
                } catch (XPathException e) {
                    throw new RuntimeException(e);
                }

                int count = rulesElements.getLength();
                for (int i = 0; i < count; i++) {
                    Element rulesElement = (Element) rulesElements.item(i);
                    String[] localeNames =
                        rulesElement.getAttribute("locales").split("\\s+");

                    NodeList ruleElements =
                        rulesElement.getElementsByTagName("pluralRule");
                    int ruleCount = ruleElements.getLength();
                    List<PluralRule> ruleList = new ArrayList<>(ruleCount);
                    for (int j = 0; j < ruleCount; j++) {
                        Element ruleElement = (Element) ruleElements.item(j);
                        ruleList.add(new PluralRule(
                            ruleElement.getAttribute("count"),
                            ruleElement.getTextContent()));
                    }

                    for (String localeName : localeNames) {
                        localeName = localeName.replace('_', '-');
                        pluralRules.put(
                            Locale.forLanguageTag(localeName),
                            ruleList);
                    }
                }
            }
        }

        Locale availableLocale = Locale.lookup(
            Locale.LanguageRange.parse(locale.toLanguageTag()),
            pluralRules.keySet());

        if (availableLocale == null) {
            availableLocale = Locale.ROOT;
        }

        List<PluralRule> rulesOfLocale = pluralRules.get(availableLocale);
        for (PluralRule rule : rulesOfLocale) {
            if (rule.matches(amount)) {
                return rule.count;
            }
        }
        throw new IllegalArgumentException("No plural rule matches " + amount);
    }

    private static List<Locale> listWithFallbacks(Locale locale) {
        Collection<Locale> locales = new LinkedHashSet<>();
        locales.add(locale);

        Locale.Builder builder = new Locale.Builder();
        builder.setLanguageTag(locale.toLanguageTag());

        locales.add(builder.setVariant(null).build());
        locales.add(builder.setRegion(null).build());
        locales.add(builder.setScript(null).build());
        locales.add(Locale.ROOT);

        return new ArrayList<>(locales);
    }

    private Iterable<Path> dataFilesFor(Locale locale) {
        synchronized (dataFiles) {
            if (dataFiles.isEmpty()) {
                Path dataFileDir = cldrDir.resolve(Paths.get("common", "main"));
                try (DirectoryStream<Path> dir =
                    Files.newDirectoryStream(dataFileDir, "*.xml")) {

                    for (Path dataFile : dir) {
                        InputSource source = createSource(dataFile);

                        NodeList identityElements = (NodeList)
                            xpath.evaluate("/ldml/identity", source,
                                XPathConstants.NODESET);
                        Element identity = (Element) identityElements.item(0);

                        String lang =
                            xpath.evaluate("language/@type", identity);
                        String script =
                            xpath.evaluate("script/@type", identity);
                        String region =
                            xpath.evaluate("territory/@type", identity);
                        String variant =
                            xpath.evaluate("variant/@type", identity);

                        Locale dataFileLocale;
                        if (lang.equals("root")) {
                            dataFileLocale = Locale.ROOT;
                        } else {
                            Locale.Builder builder = new Locale.Builder();
                            builder.setLanguage(lang);
                            builder.setScript(script);
                            builder.setRegion(region);
                            builder.setVariant(variant);
                            dataFileLocale = builder.build();
                        }

                        dataFiles.put(dataFileLocale, dataFile);
                    }
                } catch (IOException | XPathException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        Collection<Locale> locales = listWithFallbacks(locale);

        Collection<Path> dataFilesForLocale = new ArrayList<>();
        for (Locale localeToCheck : locales) {
            Path dataFile = dataFiles.get(localeToCheck);
            if (dataFile != null) {
                dataFilesForLocale.add(dataFile);
            }
        }
        return dataFilesForLocale;
    }

    private Optional<Element> locateElement(Object source,
                                            String path) {

        try {
            Element element = null;
            while (true) {
                NodeList elements;
                if (source instanceof InputSource) {
                    elements = (NodeList) xpath.evaluate(path,
                        (InputSource) source, XPathConstants.NODESET);
                } else {
                    elements = (NodeList) xpath.evaluate(path,
                        source, XPathConstants.NODESET);
                }
                if (elements.getLength() < 1) {
                    break;
                }

                element = (Element) elements.item(0);

                NodeList list = (NodeList) xpath.evaluate("alias", element,
                    XPathConstants.NODESET);
                if (list.getLength() == 0) {
                    // No more aliases to follow, so we've found our target.
                    break;
                }

                Element alias = (Element) list.item(0);
                path = alias.getAttribute("path");
                source = element;
            }

            return Optional.ofNullable(element);
        } catch (XPathException e) {
            throw new RuntimeException(e);
        }
    }

    private Optional<String> readElement(Iterable<? extends Path> dataFiles,
                                         String... paths)
    throws XPathException {

        Optional<Element> element = Optional.empty();
        for (Path dataFile : dataFiles) {
            Object source = createSource(dataFile);

            element = Optional.empty();
            for (String path : paths) {
                element = locateElement(source, path);
                if (!element.isPresent()) {
                    break;
                }

                source = element.get();
            }

            if (element.isPresent()) {
                break;
            }
        }

        return element.map(Element::getTextContent);
    }

    private String format(ChronoUnit units,
                          BigDecimal amount,
                          Locale locale) {

        String type = null;
        switch (units) {
            case YEARS:
                type = "duration-year";
                break;
            case MONTHS:
                type = "duration-month";
                break;
            case WEEKS:
                type = "duration-week";
                break;
            case DAYS:
                type = "duration-day";
                break;
            default:
                throw new IllegalArgumentException(
                    "Valid units are YEARS, MONTHS, WEEKS, and DAYS.");
        }

        Count count = countFor(amount, locale);

        try {
            Optional<String> formatPattern = readElement(dataFilesFor(locale),
                "/ldml/units" +
                    "/unitLength[@type='long']" +
                    "/unit[@type='" + type + "']",
                "unitPattern[@count='" + count.attributeValue() + "']");

            if (formatPattern.isPresent()) {
                String patternStr = formatPattern.get();
                if (!patternStr.isEmpty()) {
                    MessageFormat format =
                        new MessageFormat(patternStr, locale);
                    return format.format(new Object[] { amount });
                }
            }
        } catch (XPathException e) {
            throw new RuntimeException(e);
        }

        throw new IllegalArgumentException(
                "Could not find pattern for units " + units +
                ", amount " + amount + ", locale " + locale.toLanguageTag());
    }

    public String format(Period period,
                         Locale locale) {
        return format(period, false, locale);
    }

    public String format(Period period,
                         boolean includeWeeks,
                         Locale locale) {

        int years = period.getYears();
        int months = period.getMonths();
        int days = period.getDays();

        List<String> parts = new ArrayList<>(4);

        if (years != 0) {
            BigDecimal value = BigDecimal.valueOf(years);
            String yearStr = format(ChronoUnit.YEARS, value, locale);
            parts.add(yearStr);
        }
        if (months != 0) {
            BigDecimal value = BigDecimal.valueOf(months);
            String monthStr = format(ChronoUnit.MONTHS, value, locale);
            parts.add(monthStr);
        }
        if (includeWeeks) {
            int weeks = days / 7;
            if (weeks != 0) {
                days %= 7;
                BigDecimal value = BigDecimal.valueOf(weeks);
                String weekStr = format(ChronoUnit.WEEKS, value, locale);
                parts.add(weekStr);
            }
        }
        if (days != 0) {
            BigDecimal value = BigDecimal.valueOf(days);
            String dayStr = format(ChronoUnit.DAYS, value, locale);
            parts.add(dayStr);
        }

        return formatList(parts, locale);
    }

    private String formatList(List<?> parts,
                              Locale locale) {

        if (parts.isEmpty()) {
            return "";
        }
        int size = parts.size();
        if (size == 1) {
            return String.valueOf(parts.get(0));
        }

        Map<String, String> patternsByType = new HashMap<>();
        for (Path dataFile : dataFilesFor(locale)) {
            Object source = createSource(dataFile);

            Optional<Element> listPatterns =
                locateElement(source, "/ldml/listPatterns");

            if (!listPatterns.isPresent()) {
                continue;
            }

            Optional<Element> listPattern =
                locateElement(listPatterns.get(), "listPattern[@type='unit']");

            if (!listPattern.isPresent()) {
                continue;
            }

            NodeList partList =
                listPattern.get().getElementsByTagName("listPatternPart");

            int count = partList.getLength();
            for (int i = 0; i < count; i++) {
                Element part = (Element) partList.item(i);
                String type = part.getAttribute("type");
                String pattern = part.getTextContent();
                patternsByType.putIfAbsent(type, pattern);
            }
        }

        if (size == 2 || size == 3) {
            String pattern = patternsByType.get(String.valueOf(size));
            if (pattern != null) {
                MessageFormat format =new MessageFormat(pattern, locale);
                return format.format(parts.toArray());
            }
        }

        MessageFormat startFormat = new MessageFormat(
            patternsByType.get("start"), locale);
        MessageFormat middleFormat = new MessageFormat(
            patternsByType.get("middle"), locale);
        MessageFormat endFormat = new MessageFormat(
            patternsByType.get("end"), locale);

        String text = endFormat.format(
            new Object[] { parts.get(size - 2), parts.get(size - 1) });

        int index = size - 2;
        while (--index > 0) {
            text = middleFormat.format(new Object[] { parts.get(index), text });
        }
        text = startFormat.format(new Object[] { parts.get(index), text });

        return text;
    }

    public static void main(String[] args) {
        String localeStr = System.getProperty("locale");
        Locale locale = localeStr != null ?
            Locale.forLanguageTag(localeStr) : Locale.getDefault();

        boolean showWeeks = Boolean.getBoolean("weeks");

        PeriodFormatter formatter = new PeriodFormatter();

        for (String arg : args) {
            Period period = Period.parse(arg);
            String s = formatter.format(period, showWeeks, locale);
            System.out.println(arg + " => " + s);
        }
    }
}

-2
投票

抱歉,似乎两次,但我将这篇文章留在这里,这个问题对于日历显示名称字段来说是一个可怕的恐惧,早在 2010 年,我花了几天时间寻找小时,分钟,秒显示名称,直到我得到来自 Sun Microsystems 论坛的信息,其中一些没有名字。 API 文档信息几乎都是这么说的,只是不太清楚。它没有清楚地说明 java.time.temporal.TemporalField 和 java.time.temporal.ChronoField 及其方法 getDisplayName(Locale locale) 抱歉(删除了其他答案),我以为你的意思是“时间”本身,你的意思是“时间单位”是java的一部分TemporalUnit的持续时间是一个具有TemporalUnit的时间并且确实有“名称检索方法”但翻译, 不。 然而,java.util.Calendar也有“时间单位”并且可以用Locale实例化,并且应该具有返回“时间单位”外语名称的类字段和方法

这是一个测试打印机类,用于具有显示名称的字段。注释掉的代码打印 getDisplayName() 返回的“null”

// CalendarTest.java
public class CalendarTest{

int[] ipt = {java.util.Calendar.DAY_OF_WEEK,java.util.Calendar.MONTH,java.util.Calendar.ERA,java.util.Calendar.AM_PM};

public CalendarTest(){

//java.time.LocalDateTime tm = java.time.LocalDateTime.now();   +java.util.Calendar.HOUR   DAY_OF_WEEK

for(int sd=0;sd<ipt.length;sd++){
pr(ipt[sd],"fr");
}

for(int sd1=0;sd1<ipt.length;sd1++){
pr(ipt[sd1],"zh");
}

for(int sd2=0;sd2<ipt.length;sd2++){
pr(ipt[sd2],"ar");
}

/*
//java.util.Date dt = cal.getTime();
System.out.println(""+cal.get(java.util.Calendar.HOUR));
String fieldname = cal.getDisplayName(java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.SHORT, new java.util.Locale("en"));
System.out.println(fieldname);
fieldname = cal.getDisplayName(java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.LONG, new java.util.Locale("en"));
System.out.println(fieldname);
*/
}//enconstr

public void pr(int fieldint,String loc){
java.util.Calendar cal = java.util.Calendar.getInstance(new java.util.Locale(loc));
java.util.Map<String,Integer> mp = cal.getDisplayNames(fieldint , java.util.Calendar.ALL_STYLES, new java.util.Locale(loc));
if(mp.isEmpty()==true){
System.out.println("Is Empty");
}else{
System.out.println("Contains");
}
java.util.Set<String> st = mp.keySet();
Object[] sta = st.toArray();
for(int fs=0;fs<sta.length;fs++){
System.out.println("A VALUE : "+sta[fs]);
}

}//enmeth

public static void main(String[] args){
new CalendarTest();
}//enmain

}//enclss


/* prints Special field values and in Locale but not field names

bash-5.1$ java CalendarTest
Contains
A VALUE : dimanche
A VALUE : mercredi
A VALUE : vendredi
A VALUE : samedi
A VALUE : jeudi
A VALUE : lundi
A VALUE : mardi
A VALUE : dim.
A VALUE : jeu.
A VALUE : lun.
A VALUE : mar.
A VALUE : mer.
A VALUE : sam.
A VALUE : ven.
Contains
A VALUE : septembre
A VALUE : décembre
A VALUE : novembre
A VALUE : février
A VALUE : janvier
A VALUE : juillet
A VALUE : octobre
A VALUE : avril
A VALUE : févr.
A VALUE : janv.
A VALUE : juil.
A VALUE : sept.
A VALUE : août
A VALUE : avr.
A VALUE : déc.
A VALUE : juin
A VALUE : mars
A VALUE : nov.
A VALUE : oct.
A VALUE : mai
Contains
A VALUE : ap. J.-C.
A VALUE : av. J.-C.
A VALUE : BC
A VALUE : A
A VALUE : B
Contains
A VALUE : AM
A VALUE : PM
A VALUE : a
A VALUE : p
Contains
A VALUE : 星期一
A VALUE : 星期三
A VALUE : 星期二
A VALUE : 星期五
A VALUE : 星期六
A VALUE : 星期四
A VALUE : 星期日
A VALUE : 一
A VALUE : 三
A VALUE : 二
A VALUE : 五
A VALUE : 六
A VALUE : 四
A VALUE : 日
Contains
A VALUE : 10月
A VALUE : 11月
A VALUE : 12月
A VALUE : 十一月
A VALUE : 十二月
A VALUE : 10
A VALUE : 11
A VALUE : 12
A VALUE : 1月
A VALUE : 2月
A VALUE : 3月
A VALUE : 4月
A VALUE : 5月
A VALUE : 6月
A VALUE : 7月
A VALUE : 8月
A VALUE : 9月
A VALUE : 一月
A VALUE : 七月
A VALUE : 三月
A VALUE : 九月
A VALUE : 二月
A VALUE : 五月
A VALUE : 八月
A VALUE : 六月
A VALUE : 十月
A VALUE : 四月
A VALUE : 1
A VALUE : 2
A VALUE : 3
A VALUE : 4
A VALUE : 5
A VALUE : 6
A VALUE : 7
A VALUE : 8
A VALUE : 9
Contains
A VALUE : 公元前
A VALUE : AD
A VALUE : BC
A VALUE : 公元
A VALUE : A
A VALUE : B
Contains
A VALUE : 上午
A VALUE : 下午
A VALUE : a
A VALUE : p
Contains
A VALUE : الأربعاء
A VALUE : الثلاثاء
A VALUE : الاثنين
A VALUE : الجمعة
A VALUE : الخميس
A VALUE : الأحد
A VALUE : السبت
A VALUE : ث
A VALUE : ج
A VALUE : ح
A VALUE : خ
A VALUE : ر
A VALUE : س
A VALUE : ن
Contains
A VALUE : أكتوبر
A VALUE : ديسمبر
A VALUE : سبتمبر
A VALUE : فبراير
A VALUE : نوفمبر
A VALUE : أبريل
A VALUE : أغسطس
A VALUE : يناير
A VALUE : يوليو
A VALUE : يونيو
A VALUE : مارس
A VALUE : مايو
A VALUE : أبر
A VALUE : أغس
A VALUE : أكت
A VALUE : ديس
A VALUE : سبت
A VALUE : فبر
A VALUE : مار
A VALUE : ماي
A VALUE : نوف
A VALUE : ينا
A VALUE : يول
A VALUE : يون
A VALUE : أ
A VALUE : ب
A VALUE : د
A VALUE : س
A VALUE : غ
A VALUE : ف
A VALUE : ك
A VALUE : ل
A VALUE : م
A VALUE : ن
A VALUE : و
A VALUE : ي
Contains
A VALUE : ق.م
A VALUE : A
A VALUE : B
A VALUE : م
Contains
A VALUE : a
A VALUE : p
A VALUE : ص
A VALUE : م
bash-5.1$ 


*/

下面的代码不起作用(如 OleV.V. 所说),因为某些字段没有获得短或长显示名称。

java.util.Calendar cal =  java.util.Calendar.getInstance( java.util.TimeZone.getTimeZone("Asia/Shanghai") , java.util.Locale.CHINA);
String hourof = cal.getDisplayName(java.util.Calendar.HOUR , java.util.Calendar.LONG , java.util.Locale.CHINA);

在 html 中显示它,在文本渲染元素标签中使用属性 lang="zh",例如div , 输入 , td UTF-8 是绑定到语言环境的普通字符集,但对于中文来说可能是 UTF-16

查看 java.util.Calendar 的 API 文档中的“字段摘要”。

Week,似乎是一个问题,但 int SHORT 也许可以简单地显示“week”。

© www.soinside.com 2019 - 2024. All rights reserved.