树莓派开始,玩转Linux7:时间的故事
对于电子设备来说,时间都是基础性的功能,很容易被人忽视。20世纪的"千年虫"问题,就是时间方面设计缺陷造成的。对于网络连接的多设备来说,保持时间同步是一个新的问题。对于树莓派的众多应用场景来说,时间的准确性都至关重要。树莓派提供了NTP服务,通过网络来校正时间。即使在断网的情况下,也可以通过物理计时来校正时间。而树莓派使用的Linux系统,也提供了date命令这样便利的时间工具。
1.NTP服务:
树莓派中内置了NTP服务,所以连上网之后就可以自动调整时间。NTP是网络时间协议(Network Time Protocol)的简称,主要用于网络时间的同步。NTP协议早在20世纪80年代就已经诞生了,至今仍是互联网的基础性协议之一。NTP通信分为服务器和客户端两方。客户端发出的数据包包含发出时客户端的时间。服务器收到数据包并回复。在回复的数据包中,附加了服务器收到和发出数据包的时间。客户端收到回复后就可以获得网络延迟时间,以及自己和服务器的时间差。客户端据此调整自己的时钟,就可以与服务器时间保持同步。
你可以通过下面的命令来查询当前使用的NTP服务器:
命令返回:
行首加*号的是当前服务器。此外,还列出了网络延迟时间(Delay)、与服务器时间差(Offset)等关键的NTP时间数据。单位是毫秒(Millisecond)。
如果NTP服务出现问题,就会造成树莓派时间错误,可以强制要求NTP对表:
上面的第一句和第三句分别用于停止和启动NTP服务。
即使不使用NTP,也可以手动调整系统时间:
即把系统时间调整为2017年1月1日00:00:00。
然后用date命令来显示系统当前时间:
可以看到,时间已经调整成功。
2.时区设置:
因为地球自西向东转动,所以全球不同经度地点的日出、日落及正午的时间不同。人们又习惯用同样的12点来代表正午,这意味着不同经度的人要用不一样的表。可是,如果每时每刻都要根据经度调表,就会非常麻烦。因此,地球以15°的经度来划分时区,一个时区内用统一的时间,向东跨过一个时区,就需要把表调快1小时。当然,时区不是严格按照15°划分的。比如,一些地跨多个时区的国家有可能统一用一个时区,例如中国。
对于不同地区的用户来说,往往需要把树莓派调整成当地的时区。你可以用raspi-config进入树莓派的设置页面,
在"4 LocalisationOptions"→"I2 Change Timezone"页面中修改时区。
当然,也可以用下面的命令手动修改:
目录/user/share/zoneinfo中有多个以各大洲名字命名的文件夹,里面的文件以该州的主要城市命名。把对应城市的文件复制到/etc/localtime,就可以把系统的时区设成该城市所用的时区。这里把时区修改为"Shanghai",也就是上海。修改之后,用date命令查看时间,可以看到时区简写变成CST,也就是"上海时间"的缩写:
用date命令查看UTC时间:
显示的时间正好相差8个小时:
3.实时时钟:
大多数电脑的主板上包含了一个实时时钟(RTC,Real TimeClock)。实时时钟是一个有电源的表,能在电脑断电时继续计时。因此,电脑断电后一天再开机,你会发现电脑的时钟也往前走了一天。树莓派并不包含一个实时时钟,因此,如果树莓派断电一天再开机,在NTP服务校正时间之前,树莓派的时间还停留在一天前。为了解决这一问题,可以给树莓派附加一个实时时钟,比如PiFace专门为树莓派设计的实时时钟。
这个实时时钟被设计成一个使用纽扣电池的电路板。把PiFace电路板的孔对准树莓派的GPIO针脚插入,就可以使用了。插入位置如图所示。插入正确的情况下,电池正好在树莓派CPU的上方。网上也有人诟病这一设计,认为电池的发热会影响树莓派CPU的散热。不过笔者在使用中并没有遇到太大问题。
为了使用这款实时时钟,还需要进行一些设置。首先,这块电路板是通过I2C接口与树莓派通信的,所以要在raspi-config的页面中打开I2C接口。然后,安装所需的工具包:
接下来,赋予用户pi使用I2C接口的权限:
打开文件/etc/modules,这里面列出了系统可以加载的模块。检查是否有如下两行,如果没有请添加:
下面一段程序修改自官网程序,用来让树莓派在开机时自动加载实时时钟。把下面程序保存为rtc.bash,并运行:
完成后重启电脑。此时树莓派应该已经自动通过I2C接口加载了实时时钟。可以通过下面的命令来检查实时时钟是否就位:
如果实时时钟就位,那么60开头的行会有一个"UU"的标准位。通过下面的命令,可以读出实时时钟的时间:
通过下面的命令可以把当前系统时间写入实时时钟:
有了实时时钟,就可以在无网环境下保持时间的连续性了。PiFace的产品卖得有些贵,淘宝上有一些便宜的实时时钟可以选购。
4.date的用法:
date是UNIX系统下常用的时间命令工具,能提供非常丰富的时间功能,比如以特定格式显示时间:
+号后面的字符串代表了时间显示格式,%开头的标识符会用时间信息填充。%Y代表年,%m代表月份,%d代表日期,所以上面的命令会返回:
用于控制date输出格式的标识符还有很多:
· %a,显示一周中星期几的缩写,比如Thu。
· %A,显示一周中星期几,比如Thursday。
· %b,显示月份的缩写,比如Feb。
· %B,显示月份,比如February。
· %d,显示一个月的哪一天,比如09。
· %D,显示日期,月/日/年,比如02/07/17。
· %F,显示日期,年-月-日,比如2017-02-07。
· %H,显示24小时制的小时,比如23。
· %I,显示12小时制的小时,比如11。
· %j,显示一年中的天数,比如138。
· %m,显示月份,比如02。
· %M,显示分钟,比如14。
· %S,显示秒,比如47。
· %N,显示纳秒,比如264587606。
· %T,显示24小时制的时间,时:分:秒,比如23:44:17。
· %u,显示一周中的哪一天,周一是1。
· %U,显示一年中的周数,而周日是一周的开始,比如47。
· %Y,显示完整的年份,比如2013。
· %Z,显示时区的缩写。
除了显示当前时间,date还可以用来显示用户输入的时间:
配合上面介绍的格式控制,这个功能可以实现日期格式的转换。这个功能还可以用于时间推算。比如下面的命令就可以用于推算2016年11月12日之前1个月的时间:
除了"-1 month",还可以是"+1 second""-2 day"等多种时间差,能满足各种各样的时间推算需求。