Как преобразовать дату арабской строки в объект даты java 8?

Я работаю над проектом веб-мониторинга на арабском языке, и я хочу преобразовать строчную дату, подобную этой:

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

для объекта даты Java 8. Как я могу это сделать?

Ответ 1

Изменить: благодаря тонкому и Мено Хохшильду за вдохновение:

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

Ответ 2

Ответы @Ole и @slim работают, но не по той причине, что они думают.

Первое наблюдение - для данного примера nu-extension не требуется:

Предложение Oles также будет работать для локали new Locale("ar", "SA") вместо Locale.forLanguageTag("ar-SA-u-nu-arab"). Итак, что здесь делает unicode-nu-extension? Ничего. Следующий вопрос:

Что такое nu-расширение, которое предполагается делать здесь?

nu-code-word "arab" заданный консорциумом unicode, чтобы получить цифры арабского знака. Но вход , который должен быть проанализирован, имеет только западные цифры 0-9 (которые исторически обгоняли у арабских людей и обозначались как кодовое слово "latn" - ошибочное слово между прочим). Поэтому, если nu-extension действительно выполнил свою работу здесь, тогда разбор должен был сбой, потому что цифры arabic-indic не 0-9, но:

0 1 2 3 4 5 6 7 8 9

Очевидно, что nu-extension вообще не поддерживается новым API-интерфейсом time-API в Java-8.

Поддерживает ли SimpleDateFormat nu-расширение?

Используя отладку следующего кода, я обнаружил, что 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-расширении. Просто создайте локаль через старомодный способ без расширения юникода и адаптируйте Oles так. Он работает, потому что ваш ввод имеет только западные цифры 0-9.

Для обширной поддержки i18n, включая nu-расширение для различных систем нумерации (если у вас есть такой ввод), вы можете рассмотреть внешние библиотеки (например, ICU4J или my lib Time4J).

Ответ 3

Я не знаю достаточно арабского языка, чтобы понять дату, отформатированную на арабском языке. Однако этот код:

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.

Ответ 4

Одним из решений может быть перевод даты на английский язык и ее анализ:

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 переключаются при разборе.

Или вы смотрите Joda-Time. Возможно, у них есть решение. Это было упомянутое здесь.

Ответ 5

Вы должны указать кодировку при разборе строки, считая, что дата, которую вы хотите проанализировать, всегда будет в том формате, который вы указали, это будет работать:

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