PHP : 如何将 LDAP 中的 Windows FILETIME 字符串转换为可读的 DATE?

PHP : How to convert a Windows FILETIME String from LDAP into a readable DATE?

我正在查询 MS LDAP,一些关于用户的日期字段具有这种值:132497313049180481

它似乎是 Windows FILETIME 格式,用于 LDAP 和 Active Directory 中的某些信息作为 timestamp.

如何将其转换成可读的日期?

将Windows FILETIME(例如:132497313049180481转换为人类可读的日期时间(在此案例:“2020-11-13 08:55:04”)。

希望有用:

$filetime = "132497313049180481";
echo filetimeToStr($filetime); // Will display "2020-11-13 08:55:04"

function filetimeToStr($filetime){
  date_default_timezone_set ("UTC"); //For a result not depending on server time zone.
  $resp = (int)($filetime / 10000000); //Number of seconds since 1601-01-01.
  $diff = 11644473600; //Number of seconds between FILETIME & Unix timestamp.
  $resp = $resp - $diff; //Actual Unix timestamp matching your filetime.
  $resp = date("Y-m-d H:i:s", $resp);
  return $resp;
}

想知道 11644473600 来自哪里?

MSDN 说 FILETIME :

Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). https://docs.microsoft.com/fr-be/windows/win32/api/minwinbase/ns-minwinbase-filetime?redirectedfrom=MSDN

关于 Unix 时间戳:

Unix epoch is the time 00:00:00 UTC on 1 January 1970 ... every day is treated as if it contains exactly 86400 seconds. https://en.wikipedia.org/wiki/Unix_time

date_default_timezone_set ("UTC"); //For a result not depending on server time zone.
$start_date = date_create("1601-01-01");
$end_date = date_create("1970-01-01");
$diff = date_diff($start_date, $end_date);
$diff = (int)$diff->format("%a"); //Number of days between FILETIME & Unix timestamp
$diff = ($diff * 86400); //Number of seconds between FILETIME & Unix timestamp
echo $diff; //Will display 11644473600

已编辑

为不依赖于服务器时区的结果添加了 date_default_timezone_set ("UTC");(感谢 @jspit)。

createDateTimeFromSystemTime() 函数returns 一个 DateTime 对象。它可以通用,也可以在 32 位系统下工作。通过$basis和$resolution的其他参数,该函数还可以处理其他时间戳(LabVIEW Timestamp, Mac Timestamp ..)

function createDateTimeFromSystemTime(
  $time,  //num.String, integer or float
  $basis = '1601-1-1',
  $resolution = 1.E-7,
  $timeZone = 'UTC'
){
  return date_create($basis.' UTC')
    ->modify(round($time * $resolution).' Seconds')
    ->setTimeZone(new DateTimeZone($timeZone));
}

如何使用 LDAP 时间戳:

$ldapTimestamp = "132497313049180481";

$dateTime = createDateTimeFromSystemTime($ldapTimestamp);

echo $dateTime->format('Y-m-d H:i:s T');
//2020-11-13 08:55:05 UTC

算法来源于此class.