PHP gettimeofday() 函数

gettimeofday() 函数返回当前时间的微秒精度信息和时区信息。该函数基于系统的 gettimeofday() 系统调用,提供了比 time() 函数更高的时间精度。

注意:此函数返回的时间信息包含了微秒级精度,适用于需要高精度时间戳的场景。

语法

gettimeofday(bool $return_float = false): mixed

参数

参数 类型 描述
$return_float bool 可选。如果设置为 true,函数返回浮点数(秒.微秒),否则返回数组。默认 false

返回值

根据 $return_float 参数的值,返回不同的结果:

$return_float 值 返回值类型 描述
false(默认) array 返回包含时间信息的关联数组
true float 返回浮点数,表示自Unix纪元以来的秒数(包含微秒)

返回数组结构

$return_float = false 时,返回的数组包含以下键:

键名 类型 描述
sec int 自Unix纪元(1970-01-01 00:00:00 GMT)以来的秒数
usec int 微秒数(0-999999)
minuteswest int 本地时间与格林威治时间(GMT)的分钟偏移量(向西为负数)
dsttime int 夏令时类型(通常为0或1)

示例

示例 1:基本用法 - 获取时间信息

<?php
// 设置时区
date_default_timezone_set('Asia/Shanghai');

// 1. 返回数组格式(默认)
$timeArray = gettimeofday();
echo "1. 数组格式的时间信息:\n";
print_r($timeArray);

// 2. 返回浮点数格式
$timeFloat = gettimeofday(true);
echo "\n2. 浮点数格式的时间戳:\n";
echo $timeFloat . "\n";

// 3. 格式化显示
echo "\n3. 格式化显示:\n";
echo "Unix时间戳(秒): " . $timeArray['sec'] . "\n";
echo "微秒部分: " . $timeArray['usec'] . "\n";
echo "组合时间戳: " . ($timeArray['sec'] + $timeArray['usec'] / 1000000) . "\n";
echo "时区偏移(分钟): " . $timeArray['minuteswest'] . " 分钟\n";
echo "夏令时状态: " . ($timeArray['dsttime'] ? '是' : '否') . "\n";

// 4. 转换为可读时间
$timestamp = $timeArray['sec'];
echo "\n4. 可读时间格式:\n";
echo "标准时间: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "带微秒的时间: " . date('Y-m-d H:i:s', $timestamp) . "." . sprintf('%06d', $timeArray['usec']) . "\n";

// 5. 与time()函数比较
echo "\n5. 与time()函数比较:\n";
echo "time()函数: " . time() . "\n";
echo "gettimeofday()秒部分: " . $timeArray['sec'] . "\n";
echo "差异: " . abs(time() - $timeArray['sec']) . " 秒\n";
?>
                            

输出:


1. 数组格式的时间信息:
Array
(
    [sec] => 1703500245
    [usec] => 123456
    [minuteswest] => -480
    [dsttime] => 0
)

2. 浮点数格式的时间戳:
1703500245.123456

3. 格式化显示:
Unix时间戳(秒): 1703500245
微秒部分: 123456
组合时间戳: 1703500245.123456
时区偏移(分钟): -480 分钟
夏令时状态: 否

4. 可读时间格式:
标准时间: 2023-12-25 14:30:45
带微秒的时间: 2023-12-25 14:30:45.123456

5. 与time()函数比较:
time()函数: 1703500245
gettimeofday()秒部分: 1703500245
差异: 0 秒
                            
示例 2:性能测量和高精度计时

<?php
/**
 * 高精度计时器类
 */
class MicrosecondTimer {
    private $startTime = 0;
    private $endTime = 0;

    /**
     * 开始计时
     */
    public function start(): void {
        $this->startTime = gettimeofday(true);
    }

    /**
     * 结束计时
     */
    public function stop(): void {
        $this->endTime = gettimeofday(true);
    }

    /**
     * 获取经过的时间(秒,含微秒)
     */
    public function getElapsedSeconds(): float {
        if ($this->startTime == 0 || $this->endTime == 0) {
            return 0.0;
        }
        return $this->endTime - $this->startTime;
    }

    /**
     * 获取经过的时间(毫秒)
     */
    public function getElapsedMilliseconds(): float {
        return $this->getElapsedSeconds() * 1000;
    }

    /**
     * 获取经过的时间(微秒)
     */
    public function getElapsedMicroseconds(): float {
        return $this->getElapsedSeconds() * 1000000;
    }

    /**
     * 格式化显示时间
     */
    public function getFormattedTime(): string {
        $seconds = $this->getElapsedSeconds();

        if ($seconds >= 1) {
            return sprintf("%.3f 秒", $seconds);
        } elseif ($seconds >= 0.001) {
            return sprintf("%.3f 毫秒", $seconds * 1000);
        } else {
            return sprintf("%.3f 微秒", $seconds * 1000000);
        }
    }
}

/**
 * 性能分析器
 */
class PerformanceProfiler {
    private $timers = [];
    private $results = [];

    /**
     * 开始测量一个代码块
     */
    public function start(string $name): void {
        $this->timers[$name] = gettimeofday(true);
    }

    /**
     * 结束测量并记录结果
     */
    public function end(string $name): void {
        if (!isset($this->timers[$name])) {
            return;
        }

        $endTime = gettimeofday(true);
        $elapsed = $endTime - $this->timers[$name];

        if (!isset($this->results[$name])) {
            $this->results[$name] = [
                'total' => 0,
                'count' => 0,
                'min' => PHP_FLOAT_MAX,
                'max' => 0,
                'last' => 0
            ];
        }

        $this->results[$name]['total'] += $elapsed;
        $this->results[$name]['count']++;
        $this->results[$name]['min'] = min($this->results[$name]['min'], $elapsed);
        $this->results[$name]['max'] = max($this->results[$name]['max'], $elapsed);
        $this->results[$name]['last'] = $elapsed;

        unset($this->timers[$name]);
    }

    /**
     * 获取性能报告
     */
    public function getReport(): array {
        $report = [];

        foreach ($this->results as $name => $data) {
            $report[$name] = [
                'name' => $name,
                'total_time' => $data['total'],
                'average_time' => $data['total'] / $data['count'],
                'min_time' => $data['min'],
                'max_time' => $data['max'],
                'last_time' => $data['last'],
                'call_count' => $data['count']
            ];
        }

        return $report;
    }

    /**
     * 格式化报告
     */
    public function formatReport(): string {
        $report = $this->getReport();
        $output = "性能分析报告\n";
        $output .= str_repeat("=", 80) . "\n";
        $output .= sprintf("%-20s %-12s %-12s %-12s %-12s %-12s\n",
            "名称", "总时间(秒)", "平均时间(秒)", "最小时间(秒)", "最大时间(秒)", "调用次数");
        $output .= str_repeat("-", 80) . "\n";

        foreach ($report as $item) {
            $output .= sprintf("%-20s %-12.6f %-12.6f %-12.6f %-12.6f %-12d\n",
                $item['name'],
                $item['total_time'],
                $item['average_time'],
                $item['min_time'],
                $item['max_time'],
                $item['call_count']);
        }

        return $output;
    }
}

// 使用示例
echo "高精度计时器演示\n\n";

// 1. 基本计时器使用
$timer = new MicrosecondTimer();

echo "1. 基本计时器测试:\n";
$timer->start();
// 模拟一些耗时操作
for ($i = 0; $i < 1000000; $i++) {
    // 空循环,模拟计算
}
$timer->stop();

echo "  执行时间: " . $timer->getFormattedTime() . "\n";
echo "  详细时间: " . $timer->getElapsedSeconds() . " 秒\n";
echo "  毫秒表示: " . $timer->getElapsedMilliseconds() . " 毫秒\n";
echo "  微秒表示: " . $timer->getElapsedMicroseconds() . " 微秒\n\n";

// 2. 性能分析器使用
echo "2. 性能分析器测试:\n";
$profiler = new PerformanceProfiler();

// 模拟多个函数调用
$functions = ['process_data', 'generate_report', 'save_to_database'];

for ($i = 0; $i < 5; $i++) {
    foreach ($functions as $func) {
        $profiler->start($func);

        // 模拟不同函数的执行时间
        $sleepTime = mt_rand(1000, 5000); // 1-5毫秒
        usleep($sleepTime);

        $profiler->end($func);
    }
}

echo $profiler->formatReport();

// 3. 比较不同时间函数的精度
echo "\n3. 不同时间函数精度比较:\n";
$tests = 100;
$results = [];

for ($i = 0; $i < $tests; $i++) {
    // 测试microtime()
    $start1 = microtime(true);
    usleep(10); // 10微秒延迟
    $end1 = microtime(true);
    $results['microtime'][] = $end1 - $start1;

    // 测试gettimeofday()
    $start2 = gettimeofday(true);
    usleep(10);
    $end2 = gettimeofday(true);
    $results['gettimeofday'][] = $end2 - $start2;
}

echo "  microtime() 平均耗时: " .
    (array_sum($results['microtime']) / count($results['microtime'])) * 1000000 . " 微秒\n";
echo "  gettimeofday() 平均耗时: " .
    (array_sum($results['gettimeofday']) / count($results['gettimeofday'])) * 1000000 . " 微秒\n";
?>
                            

输出:


高精度计时器演示

1. 基本计时器测试:
  执行时间: 0.025 秒
  详细时间: 0.025123 秒
  毫秒表示: 25.123 毫秒
  微秒表示: 25123.000 微秒

2. 性能分析器测试:
性能分析报告
================================================================================
名称                 总时间(秒)   平均时间(秒) 最小时间(秒)  最大时间(秒)  调用次数
--------------------------------------------------------------------------------
process_data         0.012345     0.002469      0.001234     0.003456     5
generate_report      0.018234     0.003647      0.002345     0.004567     5
save_to_database     0.024567     0.004913      0.003456     0.005678     5

3. 不同时间函数精度比较:
  microtime() 平均耗时: 15.123 微秒
  gettimeofday() 平均耗时: 15.456 微秒
                            
示例 3:实际应用 - 分布式系统时间同步

<?php
/**
 * 分布式时间同步工具
 */
class DistributedTimeSync {
    private $timeServers = [];
    private $localTimeOffset = 0;

    public function __construct(array $timeServers = []) {
        $this->timeServers = $timeServers;
    }

    /**
     * 添加时间服务器
     */
    public function addTimeServer(string $server): void {
        $this->timeServers[] = $server;
    }

    /**
     * 获取高精度本地时间戳
     */
    public function getHighPrecisionTimestamp(): float {
        return gettimeofday(true);
    }

    /**
     * 从服务器获取时间
     */
    private function getTimeFromServer(string $server): ?float {
        // 模拟从时间服务器获取时间
        // 实际应用中这里会发送网络请求
        try {
            // 模拟网络延迟和服务器响应
            $networkLatency = mt_rand(1000, 50000) / 1000000; // 1-50毫秒
            $serverTime = microtime(true) + $networkLatency;

            // 模拟获取服务器时间成功
            return $serverTime;
        } catch (Exception $e) {
            return null;
        }
    }

    /**
     * 同步时间(计算本地时间与服务器时间的偏移量)
     */
    public function syncTime(): bool {
        if (empty($this->timeServers)) {
            return false;
        }

        $responses = [];

        // 向所有时间服务器请求时间
        foreach ($this->timeServers as $server) {
            $localRequestTime = $this->getHighPrecisionTimestamp();
            $serverTime = $this->getTimeFromServer($server);
            $localResponseTime = $this->getHighPrecisionTimestamp();

            if ($serverTime !== null) {
                // 计算往返时间
                $roundTripTime = $localResponseTime - $localRequestTime;

                // 估计单程延迟(假设对称)
                $oneWayLatency = $roundTripTime / 2;

                // 计算服务器时间的估计值
                $estimatedServerTime = $serverTime + $oneWayLatency;

                // 计算本地时间与服务器时间的偏移
                $offset = $estimatedServerTime - $localRequestTime;

                $responses[] = [
                    'server' => $server,
                    'offset' => $offset,
                    'round_trip' => $roundTripTime,
                    'accuracy' => $oneWayLatency
                ];
            }
        }

        if (empty($responses)) {
            return false;
        }

        // 使用加权平均计算最佳偏移量(延迟小的权重高)
        $totalWeight = 0;
        $weightedOffset = 0;

        foreach ($responses as $response) {
            $weight = 1 / ($response['accuracy'] + 0.000001); // 避免除零
            $totalWeight += $weight;
            $weightedOffset += $response['offset'] * $weight;
        }

        $this->localTimeOffset = $weightedOffset / $totalWeight;
        return true;
    }

    /**
     * 获取同步后的时间戳
     */
    public function getSyncedTimestamp(): float {
        return $this->getHighPrecisionTimestamp() + $this->localTimeOffset;
    }

    /**
     * 获取时间同步报告
     */
    public function getSyncReport(): array {
        return [
            'local_time' => $this->getHighPrecisionTimestamp(),
            'synced_time' => $this->getSyncedTimestamp(),
            'time_offset' => $this->localTimeOffset,
            'synced' => ($this->localTimeOffset != 0),
            'server_count' => count($this->timeServers)
        ];
    }

    /**
     * 生成唯一ID(基于时间戳)
     */
    public function generateTimeBasedId(string $prefix = ''): string {
        $timestamp = $this->getSyncedTimestamp();
        $microseconds = intval(($timestamp - floor($timestamp)) * 1000000);

        // 格式: 前缀 + 秒数 + 微秒 + 随机数
        $random = mt_rand(1000, 9999);
        return sprintf("%s%d%06d%04d", $prefix, floor($timestamp), $microseconds, $random);
    }
}

/**
 * 日志系统 - 使用高精度时间戳
 */
class HighPrecisionLogger {
    private $logFile;

    public function __construct(string $logFile) {
        $this->logFile = $logFile;
    }

    /**
     * 记录带微秒时间戳的日志
     */
    public function log(string $level, string $message, array $context = []): void {
        $timeInfo = gettimeofday();
        $timestamp = $timeInfo['sec'] + $timeInfo['usec'] / 1000000;

        $logEntry = [
            'timestamp' => $timestamp,
            'level' => $level,
            'message' => $message,
            'context' => $context,
            'time_human' => date('Y-m-d H:i:s', $timeInfo['sec']) . '.' . sprintf('%06d', $timeInfo['usec'])
        ];

        $logLine = json_encode($logEntry, JSON_UNESCAPED_UNICODE) . "\n";
        file_put_contents($this->logFile, $logLine, FILE_APPEND);
    }

    /**
     * 获取日志时间分析
     */
    public function analyzeLogTimes(): array {
        $logs = file($this->logFile, FILE_IGNORE_NEW_LINES);
        $analysis = [
            'total_logs' => count($logs),
            'time_range' => 0,
            'log_rate' => 0,
            'time_distribution' => []
        ];

        if (count($logs) > 1) {
            $firstLog = json_decode($logs[0], true);
            $lastLog = json_decode($logs[count($logs) - 1], true);

            $analysis['time_range'] = $lastLog['timestamp'] - $firstLog['timestamp'];
            $analysis['log_rate'] = count($logs) / $analysis['time_range'];
        }

        return $analysis;
    }
}

// 使用示例
echo "分布式系统时间同步演示\n\n";

// 1. 时间同步工具
echo "1. 分布式时间同步:\n";
$timeSync = new DistributedTimeSync([
    'time.server1.example.com',
    'time.server2.example.com',
    'time.google.com'
]);

if ($timeSync->syncTime()) {
    $report = $timeSync->getSyncReport();
    echo "  时间同步成功\n";
    echo "  本地时间: " . date('Y-m-d H:i:s', (int)$report['local_time']) . "\n";
    echo "  同步时间: " . date('Y-m-d H:i:s', (int)$report['synced_time']) . "\n";
    echo "  时间偏移: " . sprintf("%.6f", $report['time_offset']) . " 秒\n";

    // 生成基于时间的ID
    echo "  生成时间ID: " . $timeSync->generateTimeBasedId('ORDER_') . "\n";
    echo "  生成时间ID: " . $timeSync->generateTimeBasedId('LOG_') . "\n\n";
} else {
    echo "  时间同步失败\n\n";
}

// 2. 高精度日志系统
echo "2. 高精度日志系统:\n";
$logger = new HighPrecisionLogger('app.log');

// 记录一些日志
$logger->log('INFO', '应用程序启动', ['version' => '1.0.0']);
usleep(100000); // 100毫秒
$logger->log('DEBUG', '处理用户请求', ['user_id' => 123, 'action' => 'login']);
usleep(50000); // 50毫秒
$logger->log('ERROR', '数据库连接失败', ['error_code' => 1001]);

echo "  日志已记录到 app.log\n";

// 模拟分析日志
$analysis = $logger->analyzeLogTimes();
echo "  日志分析:\n";
echo "    总日志数: " . $analysis['total_logs'] . "\n";
echo "    时间范围: " . sprintf("%.3f", $analysis['time_range']) . " 秒\n";
echo "    日志频率: " . sprintf("%.2f", $analysis['log_rate']) . " 条/秒\n\n";

// 3. 时间窗口限制器(防止重复请求)
echo "3. 时间窗口限制器:\n";
class RateLimiter {
    private $requests = [];
    private $windowSize; // 窗口大小(秒)
    private $maxRequests; // 最大请求数

    public function __construct(float $windowSize, int $maxRequests) {
        $this->windowSize = $windowSize;
        $this->maxRequests = $maxRequests;
    }

    public function isAllowed(string $key): bool {
        $currentTime = gettimeofday(true);

        // 清理过期的请求记录
        $this->requests[$key] = array_filter(
            $this->requests[$key] ?? [],
            function($time) use ($currentTime) {
                return $currentTime - $time < $this->windowSize;
            }
        );

        // 检查是否超过限制
        if (count($this->requests[$key]) >= $this->maxRequests) {
            return false;
        }

        // 记录当前请求
        $this->requests[$key][] = $currentTime;
        return true;
    }

    public function getRemaining(string $key): int {
        $currentTime = gettimeofday(true);
        $this->requests[$key] = array_filter(
            $this->requests[$key] ?? [],
            function($time) use ($currentTime) {
                return $currentTime - $time < $this->windowSize;
            }
        );

        return max(0, $this->maxRequests - count($this->requests[$key]));
    }
}

// 测试频率限制
$limiter = new RateLimiter(1.0, 5); // 1秒内最多5次请求

echo "  测试频率限制(1秒内最多5次请求):\n";
for ($i = 1; $i <= 10; $i++) {
    $allowed = $limiter->isAllowed('user_123');
    $remaining = $limiter->getRemaining('user_123');
    echo "    请求 {$i}: " . ($allowed ? '允许' : '拒绝') .
        " (剩余: {$remaining})\n";

    usleep(100000); // 100毫秒间隔
}
?>

输出:


分布式系统时间同步演示

1. 分布式时间同步:
  时间同步成功
  本地时间: 2023-12-25 14:30:45
  同步时间: 2023-12-25 14:30:45
  时间偏移: 0.000123 秒
  生成时间ID: ORDER_17035002451234561000
  生成时间ID: LOG_17035002451234562000

2. 高精度日志系统:
  日志已记录到 app.log
  日志分析:
    总日志数: 3
    时间范围: 0.150 秒
    日志频率: 20.00 条/秒

3. 时间窗口限制器:
  测试频率限制(1秒内最多5次请求):
    请求 1: 允许 (剩余: 4)
    请求 2: 允许 (剩余: 3)
    请求 3: 允许 (剩余: 2)
    请求 4: 允许 (剩余: 1)
    请求 5: 允许 (剩余: 0)
    请求 6: 拒绝 (剩余: 0)
    请求 7: 拒绝 (剩余: 0)
    请求 8: 拒绝 (剩余: 0)
    请求 9: 拒绝 (剩余: 0)
    请求 10: 拒绝 (剩余: 0)
                            
gettimeofday() 与 microtime() 对比
gettimeofday() 函数
  • 返回值选项:数组或浮点数
  • 精度:微秒(10^-6秒)
  • 额外信息:包含时区偏移和夏令时信息
  • 系统调用:调用系统 gettimeofday()
  • 示例:
    
    $time = gettimeofday();
    $usec = $time['usec'];
    $offset = $time['minuteswest'];
                                                
microtime() 函数
  • 返回值选项:字符串或浮点数
  • 精度:微秒(10^-6秒)
  • 额外信息:仅时间信息,无时区信息
  • 系统调用:可能使用不同的系统调用
  • 示例:
    
    $time = microtime(true);
    $usec = ($time - floor($time)) * 1000000;
                                                
选择建议:当需要时区信息时使用 gettimeofday(),当只需要时间戳时两者都可使用,性能差异通常很小。
时间精度说明
常用时间单位
  • 秒(second):1 秒
  • 毫秒(millisecond):10^-3 秒
  • 微秒(microsecond):10^-6 秒
  • 纳秒(nanosecond):10^-9 秒
PHP时间函数精度
  • time():秒
  • microtime():微秒
  • gettimeofday():微秒
  • hrtime():纳秒(PHP 7.3+)
应用场景
  • 日志记录:毫秒级足够
  • 性能分析:微秒级推荐
  • 科学计算:纳秒级可能需要
  • 金融交易:微秒级重要
常见错误和注意事项
1. 误解返回值类型

<?php
// 错误:未指定返回值类型
$time = gettimeofday(); // 返回数组
echo $time; // 这会产生警告

// 正确:根据需求选择返回值类型
$timeArray = gettimeofday(false); // 明确返回数组
$timeFloat = gettimeofday(true);  // 明确返回浮点数

echo "数组格式: ";
print_r($timeArray);
echo "浮点数格式: " . $timeFloat . "\n";
?>
                            
2. 忽略时区信息

<?php
// 错误:直接使用minuteswest计算时间
$timeInfo = gettimeofday();
$localTimestamp = $timeInfo['sec']; // 这是UTC时间,不是本地时间

// 正确:使用date()函数考虑时区
date_default_timezone_set('Asia/Shanghai');
$timeInfo = gettimeofday();
echo "UTC时间戳: " . $timeInfo['sec'] . "\n";
echo "本地时间: " . date('Y-m-d H:i:s', $timeInfo['sec']) . "\n";

// minuteswest的意义
echo "本地时间与GMT的分钟偏移: " . $timeInfo['minuteswest'] . "\n";
echo "本地时间与GMT的小时偏移: " . ($timeInfo['minuteswest'] / 60) . "\n";
?>
                            
3. 性能测试中的陷阱

<?php
// 错误:在循环中频繁调用高精度时间函数
$iterations = 1000000;
$start = gettimeofday(true);

for ($i = 0; $i < $iterations; $i++) {
    // 错误:每次迭代都调用时间函数
    // $currentTime = gettimeofday(true);
}

$end = gettimeofday(true);
echo "执行时间: " . ($end - $start) . " 秒\n";

// 正确:合理使用时间函数
$start = gettimeofday(true);
$lastLogTime = $start;

for ($i = 0; $i < $iterations; $i++) {
    // 只有需要时才获取当前时间
    if ($i % 100000 == 0) {
        $currentTime = gettimeofday(true);
        $elapsed = $currentTime - $lastLogTime;
        // echo "进度: {$i}/{$iterations}, 耗时: {$elapsed} 秒\n";
        $lastLogTime = $currentTime;
    }
}

$end = gettimeofday(true);
echo "优化后执行时间: " . ($end - $start) . " 秒\n";
?>
                            

注意事项

  • 返回值类型:注意 $return_float 参数对返回值类型的影响。
  • 时区处理:sec 字段是UTC时间戳,不是本地时间。使用时需要结合时区信息。
  • 精度限制:虽然提供微秒精度,但实际精度受操作系统和硬件限制。
  • 性能开销:高精度时间函数调用有一定开销,避免在密集循环中频繁调用。
  • 时间单调性:系统时间可能被调整(如NTP同步),可能导致时间戳不单调递增。
  • 32位系统限制:浮点数时间戳在32位系统上可能精度不足。
  • 夏令时:dsttime 字段表示夏令时类型,但具体含义可能因系统而异。
  • 跨平台一致性:不同操作系统上的实现可能略有差异。

相关函数

microtime()

返回当前Unix时间戳的微秒数

time()

返回当前的Unix时间戳(秒)

hrtime()

返回系统的高分辨率时间(纳秒精度)

date()

格式化本地时间/日期

strtotime()

将英文文本日期时间解析为Unix时间戳

DateTime::format()

面向对象风格的日期格式化方法