An LDAP (or Active Directory) timestamp is the number of 100-nanosecond intervals since Jan 1, 1601 UTC. The number is usually 18 digits like yours.
java.time
I recommend that you use java.time, the modern Java date and time API. for your date and time work. While the following conversion is not shorter than yours, I find it much more readable. Let’s first define some constants both for use in the conversion and for formatting afterward.
private static final Instant LDAP_EPOCH = Instant.parse("1601-01-01T00:00:00Z");
// A unit in LDAP time is 100 nanoseconds
private static final int UNITS_PER_SECOND = 10_000_000;
private static final long NANOS_PER_UNIT = Duration.ofSeconds(1).toNanos() / UNITS_PER_SECOND;
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss zzz", Locale.US);
Now the conversion can go like this:
long units = 132_590_231_990_000_000L; // Targeted Time
long seoncds = units / UNITS_PER_SECOND;
long nanos = units % UNITS_PER_SECOND * NANOS_PER_UNIT;
Duration sinceLdapEpoch = Duration.ofSeconds(seoncds, nanos);
ZonedDateTime dateTime = LDAP_EPOCH.plus(sinceLdapEpoch).atZone(ZoneOffset.UTC);
String formattedDate = dateTime.format(FORMATTER);
System.out.println(formattedDate);
Output is:
2021-02-28 21:59:59 Z
It’s the same point in time as I get from your code.
Explaining your code
Since LDAP time units are 100 nanoseconds, when your code uses the variable name nanoseconds
, it’s wrong. First you divide by 10 000 000 (10 million), which gets you seconds, so the variable name mills
is wrong too. The formula you asked about in your title, (((1970-1601) * 365) - 3 + Math.round((1970-1601)/4) ) * 86400L
calculates the number of seconds from the LDAP eopch in 1601 to the Unix and Java epoch in 1970. It does this by first calculating the number of days, taking into account that one fourth of the years are leap years, and then multiplying by the number of seconds in a day in UTC, 86 400. I agree with you that it’s very hard to read and understand. Subtracting this number form the seconds you had in the ill-names mills
variable gives you the number of seconds since the Java epoch of January 1, 1970 at 00:00 UTC. Finally you multiply by 1000 to convert from seconds to milliseconds since this is what the constructor of the outdated Date
class requires.
Links