问题 如何将阿拉伯字符串日期转换为java 8日期对象?


我正在使用阿拉伯语进行网络监控项目,我想像这样转换字符串日期:

الاثنين 24 أبريل 2017 - 15:00

到Java 8日期对象。我怎样才能做到这一点?


5988
2018-04-26 14:53


起源

您是否尝试过使用阿拉伯语的国家/地区的语言环境?看到: stackoverflow.com/questions/29154887/... - slim
这是在34次点击时没有解决的问题 寻找“java阿拉伯语日期”? - Basil Bourque


答案:


编辑:感谢苗条和Meno Hochschild的灵感:

String dateTimeString = "الاثنين 24 أبريل 2017 - 15:00";

DateTimeFormatter formatter
        = DateTimeFormatter.ofPattern("EEEE d MMMM uuuu - HH:mm", new Locale("ar"));
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println(dateTime);

这打印:

2017-04-24T15:00

8
2018-04-26 18:37



只需构建没有nu-extension的语言环境。它的工作没有,你的nu扩展应该失败(但没有),请参阅我的回答。 - Meno Hochschild
非常感谢@MenoHochschild。甚至在我的电脑上 new Locale("ar") 工作,所以我把它放在复杂的语言标签。 - Ole V.V.


@Ole和@slim的答案正在发挥作用,但并不是因为他们认为的原因。

第一个观察 - 对于给定的例子,nu扩展是不必要的:

Oles建议也适用于语言环境 new Locale("ar", "SA") 代替 Locale.forLanguageTag("ar-SA-u-nu-arab")。那么unicode-nu-extension在这里是什么?没有。下一个问题:

什么是nu-extension应该在这里做什么?

nu-code-words“arab”是 由unicode财团指定 产生阿拉伯数字。但是 要解析的输入只有西数字0-9 (这在历史上已经从阿拉伯人手中取代并被指定为代码词“latn” - 顺便说一句用词不当)。因此,如果nu-extension真的在这里完成了它的工作 解析应该失败 因为 阿拉伯语数字 不是0-9但是:

0 1 2 3 4 5 6 7 8 9

显然,Java-8中的新时间API通常不支持nu扩展。

是否 SimpleDateFormat 支持nu-extension?

使用以下代码的调试,我发现nu-extension仅支持泰语数字(另见官方javadoc类) java.util.Locale 但不适用于阿拉伯语数字:

SimpleDateFormat sdf = 
    new SimpleDateFormat("EEEE d MMMM yyyy - HH:mm", Locale.forLanguageTag("ar-SA-nu-arab"));
Date d = sdf.parse(dateTimeString);
System.out.println(d);
String formatted = sdf.format(d);
System.out.println(formatted);
System.out.println(sdf.format(d).equals(dateTimeString));

sdf = new SimpleDateFormat("EEEE d MMMM uuuu - HH:mm", Locale.forLanguageTag("ar-SA-u-nu-thai"));
String thai = sdf.format(d);
System.out.println("u-nu-thai: " + thai);

我认为上课了 DateTimeFormatter Java-8也支持泰语数字。

结论:

忘记nu扩展。只需通过老式的方式构建语言环境,不需要unicode扩展,并使Oles以这种方式回答。这是有效的,因为您的输入只有西数0-9。

对于广泛的i18n支持,包括各种编号系统的nu扩展(如果你有这样的输入),你可以考虑外部库(例如ICU4J或我的lib Time4J)。


3
2018-04-29 07:32





我不太了解阿拉伯语以了解阿拉伯语格式的日期。但是这段代码:

Locale arabicLocale = new Locale.Builder().setLanguageTag("ar-SA-u-nu-arab").build();

LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(arabicLocale);

String formatted = date.format(formatter);
System.out.println(formatted);
System.out.println(formatter.parse(formatted));

产生此输出:

26 أبريل, 2017
{},ISO resolved to 2017-04-26

创建代码的代码 Locale 是来自答案 设置阿拉伯语编号系统区域设置不显示阿拉伯数字 

您可以通过定义自己的格式来微调这种格式 FormatStyle


2
2018-04-26 16:28





您必须在解析字符串时指定字符集,假设您要解析的日期始终采用您提供的格式,这将起作用:

public static Date getDate(String strDate) throws Exception{
    strDate=new String(strDate.getBytes(),"UTF-8");

    Map<String, Integer> months = new HashMap<>();

    String JAN =  new String("يناير".getBytes(), "UTF-8");
    String FEB =  new String("فبراير".getBytes(), "UTF-8");
    String MAR =  new String("مارس".getBytes(), "UTF-8");
    String APR =  new String("أبريل".getBytes(), "UTF-8");
    String APR_bis =  new String("ابريل".getBytes(), "UTF-8");
    String MAY =  new String("ماي".getBytes(), "UTF-8");
    String JUN =  new String("بونيو".getBytes(), "UTF-8");
    String JUN_bis =  new String("يونيه".getBytes(), "UTF-8");
    String JUL =  new String("يوليوز".getBytes(), "UTF-8");
    String AUG =  new String("غشت".getBytes(), "UTF-8");
    String SEP =  new String("شتنبر".getBytes(), "UTF-8");
    String SEP_bis =  new String("سبتمبر".getBytes(), "UTF-8");
    String OCT =  new String("أكتوبر".getBytes(), "UTF-8");
    String OCT_bis =  new String("اكتوبر".getBytes(), "UTF-8");
    String NOV =  new String("نونبر".getBytes(), "UTF-8");
    String NOV_bis =  new String("نوفمبر".getBytes(), "UTF-8");
    String DEC =  new String("دجنبر".getBytes(), "UTF-8");
    String DEC_bis =  new String("ديسمبر".getBytes(), "UTF-8");



    months.put(JAN, 0);
    months.put(FEB, 1);
    months.put(MAR, 2);
    months.put(APR, 3);
    months.put(APR_bis, 3);
    months.put(MAY, 4);
    months.put(JUN, 5);
    months.put(JUN_bis, 5);
    months.put(JUL, 6);
    months.put(AUG, 7);
    months.put(SEP, 8);
    months.put(SEP_bis, 8);
    months.put(OCT, 9);
    months.put(OCT_bis, 9);
    months.put(NOV, 10);
    months.put(NOV_bis, 10);
    months.put(DEC, 11);
    months.put(DEC_bis, 11);


    StringTokenizer stringTokenizer = new StringTokenizer(strDate);

    Calendar calendar = Calendar.getInstance();


    while(stringTokenizer.hasMoreElements()) {

        stringTokenizer.nextElement();// to skip the first string which is the name of the day

        int day = Integer.parseInt(stringTokenizer.nextElement().toString().trim());

        String strMonth = stringTokenizer.nextElement().toString().trim();

        int month = months.get(strMonth);

        int year = Integer.parseInt(stringTokenizer.nextElement().toString().trim());

        calendar.set(year, month, day);


    }
    return calendar.getTime();

}

它给出了这个输出:

  Fri Oct 20 15:26:47 WEST 2017

0
2018-04-27 14:27



我错过了你的字符串转换中的重点。在我的电脑上 new String("يناير".getBytes(), "UTF-8") 产生与刚才相同的字符串 "يناير"。所有其他月份名称相同。在具有不同默认字符集的计算机上,结果可能不同。 - Ole V.V.
是啊@ OleV.V。它被添加以指定想要的字符集 UTF-8 - мυѕτавєւмo


一种解决方案可能是将日期翻译成英语并解析它:

private final static Map<String, Integer> monthMapping = new HashMap<>();
static {
    // list of all month.
    monthMapping.put("أبريل", "4");
}


public Date fromArabicToDate(String arabicInput) throws ParseException {
    String[] parts = arabicInput.split(" ");
    if (parts.length != 4) 
        throw new IllegalArgumentException();

    String dateInput = parts[0] + "-" + monthMapping.get(parts[1]) + "-" + parts[2];
    SimpleDateFormat parser = new SimpleDateFormat("YYYY-MM-DD");
    return parser.parse(dateInput);
}

我试图复制这个月,但我不相信我做得对。的论点 put 解析时切换。

或者你看看 乔达时间。也许他们有一个解决方案。它是 这里提到的


0
2018-04-26 15:32



哦......过时的信息。你永远不会停止学习。谢谢@Hulk。这是我脑海中的某个地方。我发现它说的相同,但它已超过4年了: stackoverflow.com/a/14439397/2097191  (我改变了我的回答) - Obenland
你所指的答案似乎是关于限制的 一个特定的构造函数 SimpleDateFormat:“使用给定模式和默认FORMAT语言环境的默认日期格式符号构造SimpleDateFormat。注意:此构造函数可能不支持所有语言环境。对于完全覆盖,请使用DateFormat类中的工厂方法。” - Hulk