2012-03-21 105 views
5

我以编程方式从ldap导出用户。为此,我正在从ldap中检索用户。其中一个属性是whenCreated转换ldap日期

我必须转换的值之一是:20090813145607.0Z直接拆分它我得到以下格式:yyyyMMddHHmmss + .0Z。问题是应用程序正在运行在CET时区,并且存储的时间是UTC,可能由.0Z指示。它是14:56 UTC和当地代表是16:56。夏季似乎是2小时,冬季则是1小时。

我检查了SimpleDateFormat,并且有一个时区占位符,但它的格式不同。

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

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

有没有办法直接转换它?

回答

5

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

我不知道什么.0Z'的'的确切含义是和日期从LDAP我不来了不知道未来会不会改变。我不知道还有什么值得期待的,但它应该是一个ldap标准,并符合其中一个rfcs。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms680924%28v=vs.85%29.aspx – 2012-03-21 14:24:53

+0

NOPE - “.0”与时区没有任何关系。 “Z”表示祖鲁(UTC)时间 - 故事结束。秒后的“.0”表示小数秒。因此,中午过后五十九秒半的时间可能会看起来像“yyyymmdd120059.5Z”。有关更多详细信息,请参阅下面的@Basil Borrque的“ISO 8601”答案。 – 2017-08-01 02:11:47

2

该属性的语法在目录模式中描述。在转换,比较和排序从目录中检索或存储的数据时,应用程序必须使用该模式。如果whenCreated属性的语法为generalizedTime,那么应用程序在转换时必须使用库以获得广义时间。 generalizedTime的语法在RFC4517中描述。

+1

感谢您的信息。你碰巧知道任何这样的库或一些内置的方法吗? – 2012-03-21 15:30:25

6

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

我试图使用Apache UTIL GeneralizedTime http://directory.apache.org/api/gen-docs/1.0.0-M11/apidocs/org/apache/directory/shared/util/GeneralizedTime.html类,结果好坏参半

从当前时间转换为主动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日期

GeneralizedTime gt = new GeneralizedTime(str); 
Date d = gt.getCalendar().getTime(); 
1

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

String ldapDate =“20090813145607.0Z”;

Date date = DateUtils。解析(ldapDate);

String generalizedTime = DateUtils.getGeneralizedTime(date);

4

ISO 8601

作为一对夫妇提到的其他答案的,有问题的日期 - 时间格式由RFC 4517 Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules定义。参见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对象具有纳秒级分辨率,分辨率最高可达9位数。

java.time

java.time框架是建立在Java 8和更高版本。这些课程取代了老的麻烦日期时间课程,如java.util.Date,.Calendar,& java.text.SimpleDateFormat

现在在maintenance modeJoda-Time项目也建议迁移到java.time。请参阅Oracle Tutorial。并搜索堆栈溢出了很多例子和解释。

大部分java.time功能都被移植到Java7中ThreeTen-Backport,并进一步适用于Android的ThreeTenABP

ThreeTen-Extra项目扩展java.time与其他类。这个项目是未来可能增加java.time的一个试验场。

解析

定义的格式设置模式以适合RFC 4517.研究的DateTimeFormatter类的图案编码。这应该工作:uuuuMMddHHmmss[,S][.S]X。方括号表示可选。我们适应点或逗号。注意秒数部分的单数。最后的X允许Zoffset-from-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在意外输入的情况下。

1

这是只有的一段代码,为我工作:

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