1. 为什么你需要掌握date命令在日常的服务器运维和脚本开发中时间戳就像空气一样无处不在却又容易被忽视。想象一下这样的场景凌晨3点服务器突然报警你需要快速定位问题日志或者你需要定期备份数据库但希望每次备份文件都有唯一标识。这时候date命令就是你的瑞士军刀。我刚开始接触Linux时经常看到同事在脚本里使用date %Y%m%d这样的命令当时觉得很神秘。直到有一次自己写备份脚本才发现这个看似简单的小工具原来这么强大。它不仅能够生成各种格式的时间字符串还能进行日期计算、时区转换甚至可以用来做性能测试的时间标记。在日志管理领域时间戳的重要性更是不言而喻。没有正确的时间标记排查问题就像在黑暗中摸索。我曾经遇到过因为时区设置不当导致日志时间全部错乱的情况那次的教训让我深刻理解了时间戳规范化的必要性。2. date命令基础从显示时间到格式化输出2.1 基本时间显示与格式控制最简单的用法就是直接输入date命令$ date 2023年 08月 15日 星期二 14:30:22 CST但这样的格式在脚本中并不实用。更常见的做法是使用格式化输出$ date %Y-%m-%d %H:%M:%S 2023-08-15 14:30:22这里有几个常用的格式符号需要记住%Y四位年份2023%m两位月份01-12%d两位日期01-31%H24小时制小时00-23%M分钟00-59%S秒00-59我习惯在脚本开头定义一个时间格式变量这样后面可以重复使用TIMESTAMP$(date %Y%m%d_%H%M%S) echo 脚本开始执行时间$TIMESTAMP2.2 日期计算与时间调整date命令的强大之处在于它能进行日期运算。比如想知道3天后的日期$ date -d 3 days %Y-%m-%d 2023-08-18或者上个月的同一天$ date -d -1 month %Y-%m-%d 2023-07-15这在生成周报、月报时特别有用。我曾经写过一个清理过期备份的脚本就是用这个特性来判断哪些备份已经超过保留期限# 保留30天内的备份 OLD_DATE$(date -d -30 days %Y%m%d) rm -f /backups/*_${OLD_DATE}.tar.gz3. 实战应用日志文件的时间管理3.1 自动生成带时间戳的日志文件这是date命令最经典的应用场景。假设我们有一个定时执行的脚本希望每次运行都生成独立的日志文件#!/bin/bash LOG_DIR/var/log/myapp TIMESTAMP$(date %Y%m%d_%H%M%S) LOG_FILE${LOG_DIR}/backup_${TIMESTAMP}.log # 确保日志目录存在 mkdir -p $LOG_DIR echo 开始执行备份 $(date %Y-%m-%d %H:%M:%S) $LOG_FILE # 备份操作... echo 备份完成 $(date %Y-%m-%d %H:%M:%S) $LOG_FILE这样生成的日志文件会像这样backup_20230815_143022.log既清晰又方便排序。3.2 日志轮转与归档随着时间推移日志文件会越来越多我们需要定期归档。比如把30天前的日志打包压缩#!/bin/bash # 获取30天前的日期 ARCHIVE_DATE$(date -d -30 days %Y%m%d) ARCHIVE_DIR/var/log/archives LOG_DIR/var/log/myapp # 创建归档目录 mkdir -p $ARCHIVE_DIR # 查找并归档旧日志 find $LOG_DIR -name *.log -mtime 30 -exec tar -czf $ARCHIVE_DIR/logs_${ARCHIVE_DATE}.tar.gz {} # 删除已归档的日志 find $LOG_DIR -name *.log -mtime 30 -delete这个脚本结合了find和date命令实现了自动化的日志轮转。我在生产环境运行这个脚本已经两年多了从未出过问题。4. 高级技巧时区处理与性能测试4.1 多时区时间转换如果你的服务器分布在不同的时区date命令可以方便地进行时区转换# 显示UTC时间 $ date -u %Y-%m-%d %H:%M:%S 2023-08-15 06:30:22 # 将本地时间转换为纽约时间 $ TZAmerica/New_York date %Y-%m-%d %H:%M:%S 2023-08-15 02:30:22我曾经遇到过因为时区不一致导致的定时任务混乱问题。后来在所有的脚本中都显式指定时区问题就再没出现过#!/bin/bash export TZAsia/Shanghai # 脚本其余部分...4.2 脚本执行时间测量date命令还可以用来测量脚本执行时间这对性能优化很有帮助#!/bin/bash START_TIME$(date %s.%N) # 执行一些耗时操作 sleep 2 END_TIME$(date %s.%N) ELAPSED_TIME$(echo $END_TIME - $START_TIME | bc) echo 脚本执行耗时$ELAPSED_TIME 秒这个技巧在我优化数据库导入脚本时帮了大忙。通过在不同阶段添加时间戳很容易就能找出性能瓶颈所在。5. 避坑指南date命令常见问题5.1 夏令时问题在涉及夏令时的地区每年会有两次时间调整。我曾经写过一个每天凌晨运行的脚本在夏令时切换的那天要么少运行一次要么多运行一次。解决方案是始终使用UTC时间来处理关键任务# 使用UTC时间判断日期 TODAY$(date -u %Y-%m-%d)5.2 月份边界问题日期计算时要注意月份边界问题。比如# 1月31日加一个月是什么 $ date -d 2023-01-31 1 month %Y-%m-%d 2023-03-03这显然不是我们通常想要的结果。对于这种情况可以使用月份的最后一天$ date -d 2023-01-31 1 month -$(date -d 2023-01-31 1 month %d) days %Y-%m-%d 2023-02-285.3 不同系统的兼容性macOS和Linux上的date命令有些差异。比如在macOS上-d选项的语法略有不同。为了脚本的可移植性可以这样处理# 判断系统类型 if [[ $(uname) Darwin ]]; then # macOS NEXT_DAY$(date -v 1d %Y-%m-%d) else # Linux NEXT_DAY$(date -d 1 day %Y-%m-%d) fi6. 综合案例自动化备份系统让我们把这些知识点综合起来构建一个完整的自动化备份系统#!/bin/bash # 配置部分 BACKUP_DIR/data/backups DB_USERappuser DB_PASSpassword DB_NAMEappdb RETENTION_DAYS30 # 创建带时间戳的备份目录 TIMESTAMP$(date %Y%m%d_%H%M%S) BACKUP_PATH${BACKUP_DIR}/${TIMESTAMP} mkdir -p $BACKUP_PATH # 记录开始时间 START_TIME$(date %Y-%m-%d %H:%M:%S) echo 备份开始于$START_TIME ${BACKUP_PATH}/backup.log # 数据库备份 echo 开始数据库备份... ${BACKUP_PATH}/backup.log mysqldump -u$DB_USER -p$DB_PASS $DB_NAME ${BACKUP_PATH}/db.sql 2 ${BACKUP_PATH}/backup.log # 文件备份 echo 开始文件备份... ${BACKUP_PATH}/backup.log tar -czf ${BACKUP_PATH}/files.tar.gz /var/www/html 2 ${BACKUP_PATH}/backup.log # 计算备份大小 BACKUP_SIZE$(du -sh $BACKUP_PATH | cut -f1) # 记录结束时间 END_TIME$(date %Y-%m-%d %H:%M:%S) echo 备份完成于$END_TIME ${BACKUP_PATH}/backup.log echo 备份大小$BACKUP_SIZE ${BACKUP_PATH}/backup.log # 清理旧备份 OLD_DATE$(date -d -${RETENTION_DAYS} days %Y%m%d) find $BACKUP_DIR -type d -name *_* | while read dir; do dir_date$(basename $dir | cut -d_ -f1) if [[ $dir_date $OLD_DATE ]]; then echo 删除过期备份$dir ${BACKUP_PATH}/backup.log rm -rf $dir fi done # 发送通知 echo 备份任务完成详情请查看 ${BACKUP_PATH}/backup.log这个脚本展示了date命令在实际工作中的多种应用创建时间戳目录、记录操作时间、计算备份保留期限等。我在多个项目中使用类似的脚本大大提高了运维效率。