Linux date命令

date 是一个功能强大的Linux命令,用于显示和设置系统的日期和时间。它不仅可以显示当前时间,还可以格式化输出、计算日期、转换时间戳,是系统管理和脚本编程中不可或缺的工具。

注意:设置系统时间通常需要root权限,而显示时间任何用户都可以执行。date命令的输出可以通过多种格式进行自定义。

语法格式

date [选项]... [+格式]
date [选项] [MMDDhhmm[[CC]YY][.ss]]

常用选项

选项 说明
-d, --date=STRING 显示指定字符串描述的时间,而不是当前时间
-s, --set=STRING 设置系统时间为指定时间
-u, --utc, --universal 显示或设置UTC(协调世界时)时间
-r, --reference=FILE 显示指定文件的最后修改时间
-R, --rfc-email 以RFC 5322格式输出日期
--rfc-3339=FMT 以RFC 3339格式输出日期
-I, --iso-8601[=FMT] 以ISO 8601格式输出日期
--help 显示帮助信息
--version 显示版本信息

格式控制符

date命令支持丰富的格式控制符,可以自定义输出格式:

控制符 说明 示例输出
%Y 四位数的年份 2024
%y 两位数的年份 24
%m 月份(01-12) 12
%d 日(01-31) 15
%H 小时(00-23) 14
%I 小时(01-12) 02
%M 分钟(00-59) 30
%S 秒(00-60) 45
%A 完整的星期名 Monday
%a 缩写的星期名 Mon
%B 完整的月份名 December
%b 缩写的月份名 Dec
%p AM 或 PM PM
%Z 时区缩写 CST
%z 时区偏移(+hhmm) +0800
%j 一年中的第几天(001-366) 350
%U 一年中的第几周(周日为一周的开始) 50
%W 一年中的第几周(周一为一周的开始) 50
%w 星期几(0=周日,6=周六) 1
%s 自1970-01-01 00:00:00 UTC以来的秒数(时间戳) 1702607400
%n 换行符
%t 制表符
%% 百分号字符 %

基本使用示例

示例1:显示当前日期和时间

# 显示当前日期和时间
date

# 显示UTC时间
date -u

# 显示当前时间戳
date +%s

示例2:自定义格式输出

# 显示年月日
date +"%Y-%m-%d"

# 显示完整日期时间
date +"%Y-%m-%d %H:%M:%S"

# 显示星期几
date +"%A"

# 显示一年中的第几天
date +"%j"

# 显示时区
date +"%Z"

# 组合多个格式
date +"当前时间: %Y年%m月%d日 %H时%M分%S秒"

示例3:显示特定日期

# 显示明天的日期
date -d "tomorrow"

# 显示昨天的日期
date -d "yesterday"

# 显示下周的日期
date -d "next week"

# 显示上个月的日期
date -d "last month"

# 显示指定天数的日期
date -d "3 days"
date -d "2 weeks"
date -d "1 month"
date -d "1 year"

示例4:设置系统时间

# 设置系统日期和时间(需要root权限)
sudo date -s "2024-12-15 14:30:00"

# 设置系统时间
sudo date -s "14:30:00"

# 设置系统日期
sudo date -s "2024-12-15"

# 通过指定字符串设置
sudo date --set="next Friday"

日期计算和时间运算

示例5:日期加减运算

# 3天后的日期
date -d "+3 days"

# 2周前的日期
date -d "-2 weeks"

# 1个月后的日期
date -d "+1 month"

# 1年后的日期
date -d "+1 year"

# 复杂的日期计算
date -d "+1 year 2 months 3 days"
date -d "next Monday + 2 weeks"

示例6:相对时间计算

# 显示本月最后一天
date -d "$(date +%Y-%m-01) +1 month -1 day"

# 显示本月第一天
date -d "$(date +%Y-%m-01)"

# 显示下周一
date -d "next Monday"

# 显示本月最后一个星期五
date -d "last Friday"

时间戳操作

示例7:时间戳转换

# 获取当前时间戳
timestamp=$(date +%s)
echo "当前时间戳: $timestamp"

# 将时间戳转换为日期
date -d @1702607400
date -d @1702607400 +"%Y-%m-%d %H:%M:%S"

# 将日期转换为时间戳
date -d "2024-12-15 14:30:00" +%s

# 将时间戳转换为指定格式
date -d @1702607400 +"北京时间: %Y年%m月%d日 %H:%M:%S"

示例8:时间戳计算

# 计算24小时前的时间戳
timestamp_24h_ago=$(date -d "24 hours ago" +%s)
echo "24小时前的时间戳: $timestamp_24h_ago"

# 计算7天后的时间戳
timestamp_7d_later=$(date -d "+7 days" +%s)
echo "7天后的时间戳: $timestamp_7d_later"

# 计算两个时间戳的差值
start_timestamp=1702607400
end_timestamp=1702693800
difference=$((end_timestamp - start_timestamp))
echo "时间差: $difference 秒"
echo "时间差: $((difference / 3600)) 小时"

文件时间相关操作

示例9:显示文件修改时间

# 显示文件的最后修改时间
date -r /etc/passwd

# 显示文件的最后修改时间(自定义格式)
date -r /etc/passwd +"%Y-%m-%d %H:%M:%S"

# 显示目录的修改时间
date -r /home

# 检查文件是否在今天修改过
file_mod_time=$(date -r /var/log/syslog +%s)
today_start=$(date -d "today 00:00:00" +%s)
if [ $file_mod_time -gt $today_start ]; then
    echo "syslog文件今天被修改过"
fi

示例10:使用文件时间戳

# 创建一个以当前时间戳命名的文件
timestamp=$(date +%s)
touch "backup_${timestamp}.tar.gz"

# 创建以日期格式命名的文件
date_str=$(date +"%Y%m%d_%H%M%S")
touch "log_${date_str}.txt"

# 备份文件,保持原时间戳
cp -p source_file "backup_$(date +%Y%m%d).txt"

标准日期格式

示例11:使用标准日期格式

# RFC 5322格式(电子邮件标准)
date -R

# RFC 3339格式
date --rfc-3339=seconds
date --rfc-3339=date
date --rfc-3339=ns

# ISO 8601格式
date -I
date -Iseconds
date -Iminutes
date -Idate
date -Ihours

# 完整ISO 8601格式
date +"%Y-%m-%dT%H:%M:%S%:z"

脚本编程应用

脚本1:生成带时间戳的日志

#!/bin/bash
# log_with_timestamp.sh - 带时间戳的日志

LOG_FILE="/var/log/myapp_$(date +%Y%m%d).log"

log_message() {
    local message="$1"
    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
    echo "[$timestamp] $message" >> "$LOG_FILE"
}

# 使用示例
log_message "应用程序启动"
log_message "连接到数据库"
log_message "处理用户请求"
log_message "应用程序关闭"

echo "日志已写入: $LOG_FILE"
tail -5 "$LOG_FILE"

脚本2:备份脚本(按日期命名)

#!/bin/bash
# backup_with_date.sh - 按日期备份

BACKUP_DIR="/backup"
DATE_PREFIX=$(date +"%Y%m%d_%H%M%S")
SOURCE_DIR="/var/www/html"
BACKUP_FILE="${BACKUP_DIR}/backup_${DATE_PREFIX}.tar.gz"

echo "开始备份..."
echo "源目录: $SOURCE_DIR"
echo "备份文件: $BACKUP_FILE"

# 创建备份
tar -czf "$BACKUP_FILE" "$SOURCE_DIR"

if [ $? -eq 0 ]; then
    BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    echo "备份成功"
    echo "文件大小: $BACKUP_SIZE"
    echo "备份时间: $(date)"

    # 记录备份日志
    echo "$(date) - 备份完成: $BACKUP_FILE ($BACKUP_SIZE)" >> "${BACKUP_DIR}/backup.log"
else
    echo "备份失败"
    exit 1
fi

# 清理7天前的备份
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +7 -delete
echo "已清理7天前的旧备份"

脚本3:监控脚本执行时间

#!/bin/bash
# monitor_execution_time.sh - 监控脚本执行时间

# 记录开始时间
start_time=$(date +%s)
echo "脚本开始执行: $(date)"

# 模拟耗时操作
echo "执行任务..."
sleep 3
echo "任务1完成"

sleep 2
echo "任务2完成"

# 记录结束时间
end_time=$(date +%s)
execution_time=$((end_time - start_time))

echo "脚本结束执行: $(date)"
echo "总执行时间: ${execution_time}秒"
echo "总执行时间: $((execution_time / 60))分$((execution_time % 60))秒"

脚本4:定时任务调度

#!/bin/bash
# scheduler_check.sh - 检查是否在特定时间运行

CURRENT_HOUR=$(date +%H)
CURRENT_MINUTE=$(date +%M)
CURRENT_DAY=$(date +%u)  # 1=周一, 7=周日

echo "当前时间: $(date +"%Y-%m-%d %H:%M:%S")"
echo "当前小时: $CURRENT_HOUR"
echo "当前分钟: $CURRENT_MINUTE"
echo "当前星期: $CURRENT_DAY"

# 检查是否在工作时间(9:00-18:00)
if [ $CURRENT_HOUR -ge 9 ] && [ $CURRENT_HOUR -lt 18 ]; then
    echo "工作时间,执行任务..."
    # 执行工作时间的任务
else
    echo "非工作时间,跳过任务..."
fi

# 检查是否在周末
if [ $CURRENT_DAY -eq 6 ] || [ $CURRENT_DAY -eq 7 ]; then
    echo "周末,执行备份..."
    # 执行周末备份任务
fi

# 特定时间执行
if [ "$CURRENT_HOUR:$CURRENT_MINUTE" = "02:00" ]; then
    echo "凌晨2点,执行数据库清理..."
    # 执行夜间维护任务
fi

实际应用场景

场景1:网站时间显示

#!/bin/bash
# generate_time_html.sh - 生成带时间的HTML页面

HTML_FILE="/var/www/html/time.html"
CURRENT_TIME=$(date +"%Y年%m月%d日 %H时%M分%S秒")
WEEKDAYS=("星期日" "星期一" "星期二" "星期三" "星期四" "星期五" "星期六")
WEEKDAY=${WEEKDAYS[$(date +%w)]}

cat > "$HTML_FILE" << EOF



    
    当前时间
    


    

服务器当前时间

$CURRENT_TIME
$WEEKDAY

页面生成时间: $(date +"%Y-%m-%d %H:%M:%S")

EOF echo "HTML页面已生成: $HTML_FILE"

场景2:证书过期检查

#!/bin/bash
# check_cert_expiry.sh - 检查SSL证书过期时间

DOMAIN="example.com"
CERT_FILE="/etc/ssl/certs/${DOMAIN}.crt"

if [ ! -f "$CERT_FILE" ]; then
    echo "证书文件不存在: $CERT_FILE"
    exit 1
fi

# 获取证书过期时间
EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_TIMESTAMP=$(date +%s)

# 计算剩余天数
DAYS_LEFT=$(( (EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP) / 86400 ))

echo "域名: $DOMAIN"
echo "证书过期时间: $EXPIRY_DATE"
echo "当前时间: $(date)"
echo "剩余天数: $DAYS_LEFT 天"

# 警告检查
if [ $DAYS_LEFT -le 30 ]; then
    echo "警告: 证书即将在 $DAYS_LEFT 天后过期!"
    # 发送告警通知
elif [ $DAYS_LEFT -le 0 ]; then
    echo "紧急: 证书已过期!"
    # 发送紧急通知
fi

场景3:生日提醒

#!/bin/bash
# birthday_reminder.sh - 生日提醒

BIRTHDAY_FILE="/home/user/birthdays.txt"
TODAY_MD=$(date +"%m-%d")

echo "=== 生日提醒检查 ==="
echo "检查日期: $(date +"%Y-%m-%d")"
echo ""

while IFS=, read -r name birthday; do
    # 清理空格
    name=$(echo "$name" | xargs)
    birthday=$(echo "$birthday" | xargs)

    # 提取生日月份和日
    birthday_md=$(date -d "$birthday" +"%m-%d" 2>/dev/null)

    if [ "$birthday_md" = "$TODAY_MD" ]; then
        # 计算年龄
        birth_year=$(date -d "$birthday" +%Y)
        current_year=$(date +%Y)
        age=$((current_year - birth_year))

        echo "🎂 今天 ($(date +"%m月%d日")) 是 $name 的生日!"
        echo "   生日: $birthday"
        echo "   年龄: $age 岁"
        echo ""

        # 发送祝福(示例:发送邮件)
        # echo "生日快乐,$name!" | mail -s "生日祝福" user@example.com
    fi
done < "$BIRTHDAY_FILE"

if [ -z "$found" ]; then
    echo "今天没有生日提醒"
fi

时区相关操作

示例12:时区转换

# 显示系统当前时区
timedatectl

# 显示所有可用时区
timedatectl list-timezones

# 转换时区
TZ='America/New_York' date
TZ='Asia/Tokyo' date
TZ='Europe/London' date

# 比较不同时区时间
echo "本地时间: $(date)"
echo "纽约时间: $(TZ='America/New_York' date)"
echo "东京时间: $(TZ='Asia/Tokyo' date)"
echo "伦敦时间: $(TZ='Europe/London' date)"

故障排除

问题1:权限不足

date: cannot set date: Operation not permitted

解决方案:

# 使用sudo设置时间
sudo date -s "2024-12-15 14:30:00"

# 或使用timedatectl(推荐)
sudo timedatectl set-time "2024-12-15 14:30:00"

问题2:日期字符串格式错误

date: invalid date '错误的日期'

解决方案:

# 使用标准格式
date -d "2024-12-15 14:30:00"

# 或使用自然语言
date -d "next Monday"
date -d "tomorrow 14:30"

# 查看支持的日期格式
man date

问题3:时区不正确

# 显示的时间时区不正确

解决方案:

# 查看当前时区
timedatectl

# 设置时区
sudo timedatectl set-timezone Asia/Shanghai

# 临时使用时区
TZ='Asia/Shanghai' date

问题4:夏令时问题

# 夏令时转换导致的时间问题

解决方案:

# 使用UTC时间避免夏令时问题
date -u

# 或使用时区数据库
TZ='America/New_York' date

# 确保系统时区数据库是最新的
sudo apt-get install tzdata  # Debian/Ubuntu
sudo yum install tzdata      # RHEL/CentOS

相关命令

命令 说明
timedatectl systemd的时间日期管理工具
hwclock 硬件时钟管理工具
cal 显示日历
touch 修改文件时间戳
stat 显示文件状态,包括时间戳
sleep 暂停指定时间
at 定时执行任务
crontab 定时任务管理
tzselect 时区选择工具
ntpdate 从NTP服务器同步时间

高级技巧

技巧1:性能测试

#!/bin/bash
# performance_test.sh - 使用date进行性能测试

echo "开始性能测试..."
echo "======================"

# 记录开始时间
start_time=$(date +%s.%N)

# 执行要测试的命令
for i in {1..1000}; do
    echo "Test $i" > /dev/null
done

# 记录结束时间
end_time=$(date +%s.%N)

# 计算执行时间
execution_time=$(echo "$end_time - $start_time" | bc)
echo "执行时间: ${execution_time}秒"
echo "平均每次: $(echo "$execution_time / 1000" | bc -l)秒"

技巧2:生成唯一标识符

# 基于时间戳的唯一ID
unique_id=$(date +"%Y%m%d%H%M%S%N")
echo "唯一ID: $unique_id"

# 基于时间和随机数的ID
timestamp=$(date +%s)
random=$RANDOM
unique_id="${timestamp}_${random}"
echo "唯一ID: $unique_id"

# 用于临时文件的唯一名称
temp_file="/tmp/temp_$(date +%s%N).tmp"
echo "临时文件: $temp_file"

技巧3:时间间隔计算

#!/bin/bash
# calculate_time_diff.sh - 计算时间间隔

# 记录开始时间
start_time=$(date +"%Y-%m-%d %H:%M:%S")
start_timestamp=$(date -d "$start_time" +%s)

echo "任务开始: $start_time"

# 模拟任务执行
sleep 3

# 记录结束时间
end_time=$(date +"%Y-%m-%d %H:%M:%S")
end_timestamp=$(date -d "$end_time" +%s)

echo "任务结束: $end_time"

# 计算时间差
time_diff=$((end_timestamp - start_timestamp))

# 转换为可读格式
days=$((time_diff / 86400))
hours=$(( (time_diff % 86400) / 3600 ))
minutes=$(( (time_diff % 3600) / 60 ))
seconds=$((time_diff % 60))

echo "执行时间: ${time_diff}秒"
echo "执行时间: ${days}天 ${hours}小时 ${minutes}分 ${seconds}秒"

date命令速查表

用途 命令示例
显示当前时间 date
显示当前时间戳 date +%s
显示年月日 date +"%Y-%m-%d"
显示完整时间 date +"%Y-%m-%d %H:%M:%S"
显示明天日期 date -d "tomorrow"
显示昨天日期 date -d "yesterday"
显示下周日期 date -d "next week"
显示UTC时间 date -u
显示文件修改时间 date -r filename
设置系统时间 sudo date -s "2024-12-15 14:30:00"
时间戳转日期 date -d @1702607400
日期转时间戳 date -d "2024-12-15" +%s
RFC 5322格式 date -R
ISO 8601格式 date -I

注意事项

  1. 权限问题:设置系统时间需要root权限
  2. 时区设置:确保系统时区设置正确
  3. 硬件时钟:系统时间更改后,可能需要同步到硬件时钟
  4. 网络时间:生产环境建议使用NTP同步时间
  5. 脚本可移植性:不同系统的date命令可能略有差异
  6. 夏令时:注意夏令时对时间计算的影响
  7. 闰秒:date命令处理闰秒的能力有限
  8. 性能:频繁调用date命令可能影响脚本性能

最佳实践

date命令使用最佳实践:
  1. 使用标准格式:在脚本中使用标准日期格式(如ISO 8601)
  2. 时间戳存储:存储时间戳而不是格式化字符串,便于计算和转换
  3. 时区明确:在涉及多时区的应用中使用UTC时间
  4. 错误处理:验证date命令的返回值,处理可能的错误
  5. 性能优化:避免在循环中频繁调用date命令
  6. 文档说明:在脚本中注释日期格式的含义
  7. 备份时间:修改系统时间前备份当前时间
  8. 定期同步:定期使用NTP同步系统时间