Преобразование даты ldap - PullRequest
8 голосов
/ 21 марта 2012

Я экспортирую пользователей из ldap программно. Для этого я извлекаю пользователей из ldap. Одним из атрибутов является whenCreated.

Одно из значений, которые я должен преобразовать: 20090813145607.0Z Непосредственно разделив его, я получаю следующий формат: yyyyMMddHHmmss + .0Z. Проблема заключается в том, что приложение работает в часовом поясе CET, а сохраненное время - UTC, которое, вероятно, указано .0Z. Это 14:56 UTC, а локальное представительство - 16:56. Для летнего времени это, кажется, 2 часа, а для зимнего - 1 час.

Я проверил SimpleDateFormat и там есть местозаполнитель для часового пояса, однако это другой формат.

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
sdf.parse("20090813145607.0Z");

Будет отображать неправильную дату, поскольку она игнорирует часовой пояс даты.

Есть ли способ конвертировать его напрямую?

Ответы [ 7 ]

12 голосов
/ 11 августа 2016

ISO 8601

Как и пара других упомянутых ответов, рассматриваемый формат даты и времени определяется RFC 4517 Облегченный протокол доступа к каталогам (LDAP): синтаксисы и правила сопоставления . См. Раздел 3.3.13, Обобщенное время .

В этом разделе поясняется, что этот формат LDAP является ограниченной версией одного из форматов даты и времени, определенных ISO 8601 . Этот стиль, использующий минимум разделителей, известен как «базовый» в ISO 8601.

В этих форматах Z в конце является коротким для Zulu и означает UTC (в основном то же самое, что и GMT).

Десятичная точка и цифра в конце представляют долю секунды. Обратите внимание, что вместо точки (точки) в RFC 4517 и ISO 8601 возможна запятая. Фактически рекомендуется использовать запятую над точкой в ​​ISO 8601. Спецификация RFC 4517 допускает использование только одной цифры (несколько десятых доли). ) или без точки / запятой и цифры вообще. В отличие от этого: (a) ISO 8601 допускает любое количество дробных цифр и (b) объекты java.time имеют наносекундное разрешение до девяти цифр дробной секунды.

java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют старые проблемные классы даты и времени, такие как java.util.Date, .Calendar и & java.text.SimpleDateFormat.

Теперь в режиме обслуживания , проект Joda-Time также рекомендует перейти на java.time.

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений.

Большая часть функций java.time перенесена в Java 6 & 7 в ThreeTen-Backport и дополнительно адаптирована для Android в ThreeTenABP .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time.

Синтаксический

Определите шаблон форматирования, соответствующий RFC 4517. Изучите класс DateTimeFormatter для кодирования шаблона. Это должно работать: uuuuMMddHHmmss[,S][.S]X. Квадратные скобки означают необязательно . Мы размещаем либо точку, либо запятую. Обратите внимание на единственную цифру за долю секунды. X на конце допускает либо Z, либо смещение от UTC , такое как -08 или -0830 или -08: 30 или -083015 или -08: 30: 15.

String input = "20090813145607.0Z";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "uuuuMMddHHmmss[,S][.S]X" );
OffsetDateTime odt = OffsetDateTime.parse ( input , f );
Instant instant = odt.toInstant ();

Дамп на консоль.

System.out.println ( "input: " + input + " | odt: " + odt + " | instant: " + instant );

input: 20090813145607.0Z | odt: 2009-08-13T14: 56: 07Z | мгновенное: 2009-08-13T14: 56: 07Z

Конечно, вы также должны кодировать проверку для java.time.format.DateTimeParseException в случае неожиданного ввода.

6 голосов
/ 23 марта 2012

При проверке RFC, упомянутой выше, кажется, что использование UTC является рекомендуемым поведением по умолчанию для дат ldap.Для этого я преобразовал это непосредственно:

public Date parseLdapDate(String ldapDate){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

    try {
        return sdf.parse(ldapDate);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}
6 голосов
/ 21 марта 2012

Как насчет использования разделения, которое вы описали выше, затем переформатирование часового пояса 0Z в стандартный формат, затем использование sdf.parse(...)? Может быть, что-то вроде этого (конечно, с соответствующей проверкой ошибок):

String[] parts = inputDateTime.split("[.]");
String dateTimePart = parts[0];
String timeZonePart = "+0" + parts[1].substring(0, parts[1].length() - 1) + "00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssZ");
Date theDate = sdf.parse(dateTimePart + timeZonePart);
2 голосов
/ 13 августа 2014

Вы можете использовать методы org.apache.directory.shared.ldap.util.DateUtils:

String ldapDate = "20090813145607.0Z";

Дата дата = DateUtils.parse (ldapDate);

String generalizedTime = DateUtils.getGeneralizedTime (date);

2 голосов
/ 21 марта 2012

Синтаксис атрибута описан в схеме каталога.Приложения должны использовать схему при преобразовании, сравнении и упорядочении данных, которые были получены или сохранены в каталоге.Если синтаксис атрибута whenCreated равен generalizedTime, то приложения должны использовать библиотеки для обобщенного времени при преобразовании.Синтаксис для generalizedTime описан в RFC4517 .

1 голос
/ 18 сентября 2017

Это кусок кода only , который работал для меня:

static String parseLdapDate(String ldapDate) {

            long nanoseconds = Long.parseLong(ldapDate);   // nanoseconds since target time that you want to convert to java.util.Date

            long mills = (nanoseconds / 10000000);

            long unix = (((1970 - 1601) * 365) - 3 + Math.round((1970 - 1601) / 4)) * 86400L;

            long timeStamp = mills - unix;

            Date date = new Date(timeStamp * 1000L); // *1000 is to convert seconds to milliseconds
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); // the format of your date
    //sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // give a timezone reference for formating (see comment at the bottom
            String formattedDate = sdf.format(date);

            return  formattedDate;
        }
1 голос
/ 10 апреля 2012

Я пытался использовать утилиту apache GeneralizedTime class http://directory.apache.org/api/gen-docs/1.0.0-M11/apidocs/org/apache/directory/shared/util/GeneralizedTime.html со смешанными результатами

для преобразования текущего времени в формат Active Direcotry:

GeneralizedTime gt = new GeneralizedTime(Calendar.getInstance());
String gtADString = gt.toGeneralizedTime(GeneralizedTime.Format.YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION, GeneralizedTime.FractionDelimiter.DOT, 1, GeneralizedTime.TimeZoneFormat.Z).replaceFirst("Z", "\\.0Z");

Единственная проблема заключается вчто это не работает как рекламируется.Длина доли дроби после точки должна быть «1» в соответствии с этим вызовом, но результат все равно будет равен 3. Вместо «20120410011958.6Z» я получу «20120410011958.687Z», поэтому мне все еще нужно получить время всекунд и вставьте «.0» перед Z. Так вот, что вы должны сделать (в моем случае меня не волнует дробь, поэтому я ставлю ноль. AD заботится)

GeneralizedTime gt = new GeneralizedTime(Calendar.getInstance());
String gtADString = gt.toGeneralizedTime(GeneralizedTime.Format.YEAR_MONTH_DAY_HOUR_MIN_SEC, GeneralizedTime.FractionDelimiter.DOT, 1, GeneralizedTime.TimeZoneFormat.Z).replaceFirst("Z", "\\.0Z");

Кстати, этот кодпреобразует строковый формат AD GeneralizedTime в Java Date

 GeneralizedTime gt = new GeneralizedTime(str);
 Date d = gt.getCalendar().getTime();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...