2016-06-08 305 views
0

我正在解析AD的时间。有两种格式,即whenCreated的YMD LDAP时间戳,whenChanged,lastLogonTimestamp的18位LDAP/FILETIME时间戳,pwdLastSet等。因为我需要在时间上分析数据。获得当地时间是有道理的。以下是我编写的两个解析两种不同格式的函数。在第二函数的计算我从Convert 18-digit LDAP Timestamps To Human Teadable Date Using Java在解析LDAP日期和时间戳时设置了与GMT不一致的时区

public static String parseLdapDate(String ldapDate) { 
    String[] parts = ldapDate.split("[.]"); 
    String dateTimePart = parts[0]; //take the date string before .0Z 
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss"); 
    sdf.setTimeZone(TimeZone.getTimeZone("GMT")); //Z means UTC time, to the local timezone 
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

    try { 
     Date tempDate = sdf.parse(dateTimePart); //parse the string to a date 
     return formatter.format(tempDate); //format it as what we want 
    } catch (ParseException ex) { 
     System.out.println("Parsing LDAP Date exception \n"); 
     ex.printStackTrace(); 
    } 
    return null; 
} 

public static String parseLdapTimestamp(String ldapTimestamp) { 
    long nanoseconds = Long.parseLong(ldapTimestamp); // 100 nanoseconds 
    long mills = (nanoseconds/10000000); // To seconds 
    long unix = (((1970-1601)*365)-3+Math.round((1970-1601)/4))*86400L; 
    long timeStamp = mills - unix; 

    Date date = new Date(timeStamp*1000L); // To milliseconds 
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
    sdf.setTimeZone(TimeZone.getTimeZone("GMT")); 

    return sdf.format(date); 
} 

参考I有一个例子20150520143936.0Z,它被转换为“2015年5月20日16点39分36秒”。 对于示例131097986571852097,它被转换为“2016-06-07 18:44:17”,而http://www.epochconverter.com/ldap告诉我,这是GMT时间,当地时间是“2016-06-07 20:44:17”。如果我评论设置时区的代码,我将获得当地时间。

所以现在我很困惑,sdf.setTimeZone(TimeZone.getTimeZone("GMT"));给我当地的时区或世界时。我在想,如果在世界时创建AD时,在当地时间创建lastLogonTimestamp。但在函数中,我将它们解析为字符串。没有关于时区的符号。如果我在第二个函数中评论这个句子,当我在另一个地方访问一个LDAP目录时,我是否会获得两个属性的本地时间。

+0

在第二个函数中注释了'setTimeZone'。当解析的参数是0时,即1601-01-01 00:00:00 GMT,返回的值是1601-01-01 01:00:00。根据http://www.epochconverter.com/ldap,我的时区中的真实值为1601-01-01,00:53:28。大致正确。 –

+0

类似:[转换ldap日期](http://stackoverflow.com/q/9806329/642706) –

回答

2

在第二种情况下,你构建Date,然后将它告诉给格式在UTC,历史可 - 而在第一种情况下,你在UTC解析,但在当地时间格式化。你已经假设时间戳记是自Unix时代开始存储的一系列时钟,这是一个时区中性格式。

如果目的是在当地时间产生字符串表示,那么您应该删除sdf.setTimeZone调用。我认为parse方法应该返回Date,尽管如此,而不是String。或者更好的是,返回一个java.time.Instant ...

+0

谢谢。这很清楚。所以这里的重点是当我从毫秒中构造一个Date时,它返回本地机器上的结果?我不明白的是,当我将时区设置为“GMT”时,它将我再次指向“GMT + 00”。 –

+0

@MonikaDiao:不,从毫秒构造一个“Date”总是“自Unix纪元以来的毫秒数”。系统默认时区不相关。如果您将注释基于Date.toString()的结果,请忽略它,它会将Date值(这只是一个即时即时)转换为系统默认时区。但是这并不意味着'Date'对象本身有任何时区信息。 –

+0

然后,它将它格式化为字符串,将其转换为系统的默认时区。那么GMT设置呢?在第一个函数中,我将字符串格式化为我想要的日期字符串。没有时区。当我设置GMT时,它似乎在GMT + 00时处理日期字符串,并返回本地时间GMT + 02。在第二个函数中,日期字符串已经是本地时间,它会在GMT + 00返回我的时间。 –