转换ldap日期

我正在以编程方式从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"); 

将显示错误的日期,因为它忽略了日期时区。

有没有办法直接转换它?

如何使用上面描述的拆分,然后将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); 

检查上面提到的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; } 

ISO 8601

正如提到的其他几个答案,所讨论的日期时间格式由RFC 4517 轻量级目录访问协议(LDAP)定义:语法和匹配规则 。 见3.3.13, 广义时间

该部分解释了此LDAP格式是ISO 8601定义的日期时间格式之一的受限版本。 使用最少分隔符的这种样式在ISO 8601中称为“基本”。

在这些格式中,最后的ZZulu缩写,意思是UTC (基本上与GMT相同)。

最后的小数点和数字代表一小部分秒。 请注意,在RFC 4517和ISO 8601中都可以使用逗号而不是点(句点)。实际上建议使用逗号来表示ISO 8601中的点.RFC 4517规范仅允许单个数字部分(十分之一的十分之一) )或者根本没有点/逗号和数字。 请注意,相反:(a)ISO 8601允许任意数量的小数位数,(b)java.time对象具有纳秒分辨率,最多可达9位小数秒。

java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了旧的麻烦的日期时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat

现在处于维护模式 , Joda-Time项目还建议迁移到java.time。

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。

大部分java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7,并进一步适应了ThreeTenABP中的 Android。

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 ); 

输入:20090813145607.0Z | odt:2009-08-13T14:56:07Z | 时间:2009-08-13T14:56:07Z

当然,如果出现意外输入,您还应编写java.time.format.DateTimeParseException检查代码。

目录模式中描述了该属性的语法。 应用程序必须在转换,比较和排序从目录中检索或存储的数据时使用模式。 如果whenCreated属性的语法是generalizedTime ,则应用程序必须在转换时使用库作为通用时间。 RFC4517中描述了generalizedTime的语法。

您可以使用org.apache.directory.shared.ldap.util.DateUtils的方法:

String ldapDate =“20090813145607.0Z”;

日期日期= DateUtils.parse(ldapDate);

String generalizedTime = DateUtils.getGeneralizedTime(date);

这是唯一适合我的代码:

 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; } 

我尝试使用apache util GeneralizedTime类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”所以我仍然需要得到时间秒并在Z之前插入“.0”。所以这就是你要做的事情(在我的情况下我不关心分数所以我把零.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();