第二章:Improving On User Commands--22.显示不同时区的时间

  一个日期命令最基本的需求就是显示你所在时区的日期和时间。但是如果你有用户是跨时区的呢?或者,如果你有朋友或是同事时在不同的地区呢?你就会一直搞不清楚那儿现在到底是个什么日子了,比如卡萨布兰卡、梵蒂冈或是悉尼。

   现在大部分的Unix系统都有一个date命令,它的后台是一个时区数据库。它的位置一般是在目录/usr/share/zoneinfo下,它列出了超过250个不同的地区,并且可以明确表示出各个不同地区的时间。因为date命令注重的是时间变量TZ,该变量可以被设置为不同的已知地区,那么核心的功能可以通过如下表示:
TZ="Africa/Casablanca" date
   通过一个shell脚本,我们可以创建一个对用户界面友好的时区数据库:要知道,大部分系统用户并不喜欢临时设置环境变量

代码:

 1 #!/bin/sh
 2 
 3 # timein.sh -- 显示特定时区或是地区的时间.
 4 # 如果没有提供任何参数,就显示 UTC/GMT.
 5 # 使用单词"list"来查看已知地区列表
 6 # 注意:有可能匹配到地区,但只有时区是合法的。
 7 
 8 # 时区数据库网址: http://www.twinsun.com/tz/tz-link.htm
 9 
10 zonedir="/usr/share/zoneinfo"
11 
12 if [ ! -d $zonedir ]; then
13     echo "No time zone database at $zonedir." >&2
14     exit 1
15 fi
16 
17 if [ -d "$zonedir/posix" ]; then
18     zonedir=$zonedir/posix  # 现代Linux系统
19 fi
20 
21 if [ $# -eq 0 ]; then
22     timezone="UTC"
23     mixedzone="UTC"
24 elif [ "$1" = "list" ]; then
25     (echo "All known time zones and regions defined on this system:"
26     cd $zonedir
27     find * -type f -print | xargs -n 2 | \
28     awk '{printf "%-38s %-38s\n", $1, $2}'    
29     ) | more
30     exit 0
31 else
32     region="$(dirname $1)"  # 如果参数格式是 Asia/Beijing,那region是Asia
33     zone="$(basename $1)"   # 如果参数格式是 Beijing,那region就是个点
34 
35     # 恰好可以匹配?非常好。否则我们需要探索一番。
36     # 从计算匹配的个数开始。
37 
38     matchcnt="$(find $zonedir/$region -name $zone -type f -print |
39         wc -l | sed 's/[^[:digit:]]//g')"  #上面的查找路径,应该加上$region,否则查找的不精确。书中没有。
40                                            #比如给出形如 Asia/Beijing 的参数,如果路径中没有Asia,那永远也查不到北京
41 
42     if [ "$matchcnt" -gt 0 ]; then  # 至少一个文件匹配
43         if [ "$matchcnt" -gt 1 ]; then  # 超过一个文件匹配
44             echo "\"$zone\" matches more than one possible time zone record." >&2
45             echo "Please use 'list' to see all known regions and time zones." >&2
46             exit 1
47         fi
48         match="$(find $zonedir -name $zone -type f -print)"
49         mixedzone="$zone"
50     else
51         # 第一个字母大写,其余单词小写: region + zone
52         mixedregion="$(echo ${region%${region#?}} | tr '[[:lower:]]' '[[:upper:]]')\
53 $(echo ${region#?} | tr '[[:upper:]]' '[[:lower:]]')"  #行头千万别留下空格或者制表符
54         mixedzone="$(echo ${zone%${zone#?}} | tr '[[:lower:]]' '[[:upper:]]')\
55 $(echo ${zone#?} | tr '[[:upper:]]' '[[:lower:]]')"    #行头千万别留下空格或者制表符
56 
57         if [ "$mixedregion" != "." ]; then
58             # 只查特定地方
59             # 当有多种可能性时,让用户指定唯一匹配项(比如"Atlantic")
60             match="$(find $zonedir/$mixedregion -name $mixedzone -type f -print)"
61         else
62             match="$(find $zonedir -name $mixedzone -type f -print)"
63         fi
64 
65         if [ -z "$match" ]; then
66             if [ ! -z "$(find $zonedir -name $mixedzone -type d -print)" ]; then
67                 echo \
68                 "The region \"$1\" has more than one time zone. Please use 'list'" >&2
69             else  # 没有一个匹配
70                 echo "Can't find an exact match for \"$1\". Please use 'list'" >&2
71             fi
72             echo "to see all known regions and time zones." >&2
73             exit 1
74         fi
75     fi
76     timezone="$match"
77 fi
78 
79 nicetz=$(echo $timezone | sed "s|$zonedir/||g")
80 
81 echo It\'s $(TZ=$timezone date '+%A, %B %e, %Y, at %l:%M %p') in $nicetz
82 
83 exit 0

 

脚本如何工作:
    这个脚本利用的就是date命令来显示日期和时间。事实上,这整个脚本关注的就是要确认好你给的时区名,这样在脚本的最后才能如期运行好。
这个脚本最复杂的地方来自预测由用户输入的,不匹配时区数据库中的任一个名字的地区名。时区数据库会按照时区名按地区列排好,在有典型的输入问题时,脚本也会试图报有用的错误信息。
    比如,虽然TZ="Casablanca"并不嫩成功的查找到一个匹配的地区,而date命令会演示GMT,城市Casablanca确实是存在于地区数据库中的。可能的名字,Africa/Casablanca,就会被提供给这个脚本。脚本会找到非洲目录下的卡萨布兰卡,然后正确的确认这个地区。指定"Africa",从另一面来说,脚本知道有分区,只提供那些信息不足以唯一指定一个时区。
最后,你同样可以使用一个时区名(比如,UTC、WET)作为脚本参数来查看定义好的时区的子集。
   注意,一个非常棒的时区数据库的参考资料在线:http://www.twinsun.com/tz/tz-link.htm

注:UTC是协调世界时(Universal Time Coordinated)英文缩写,北京时间比UTC时间早8小时。GMT(Greenwich Mean Time)是格林尼治平时。

运行脚本:

 1 ./timein.sh 
 2 It's 星期一, 十二月 24, 2012, at 12:19 上午 in UTC
 3 
 4 ./timein.sh London
 5 It's 星期一, 十二月 24, 2012, at 12:19 上午 in Europe/London
 6 
 7 ./timein.sh Brazil
 8 The region "Brazil" has more than one time zone. Please use 'list'
 9 to see all known regions and time zones.
10 
11 ./timein.sh Pacific/Honolulu
12 It's 星期日, 十二月 23, 2012, at 2:21 下午 in Pacific/Honolulu
13 
14 ./timein.sh WET
15 It's 星期一, 十二月 24, 2012, at 12:21 上午 in WET
16 
17 ./timein.sh mycloset
18 Can't find an exact match for "mycloset". Please use 'list'
19 to see all known regions and time zones.

 

posted @ 2012-12-27 16:32  十舍七匹狼  阅读(153)  评论(0编辑  收藏  举报