Chinaunix

标题: 还是日期计算!! [打印本页]

作者: quakelee    时间: 2003-05-19 15:14
标题: 还是日期计算!!
谁能说说到底改怎么算,我得要求不高是一台
SunOS 5.8
我估计可能不会是GNU date
可能是POSIX的,也可能更原始
看了man page没找到关于日期回溯调整的参数
我现在要求不高,就要能算出前一天的日期就行
但是因为是用在跨月份的那一天,所以不是简单的+1 -1就行了
一定是准确的日期
我希望最好别用脚本,大家有啥办法么
作者: diag    时间: 2003-05-19 16:33
标题: 还是日期计算!!
不用SCRIPT 好像。。有点问题。。。
作者: lao_wang    时间: 2003-05-19 16:46
标题: 还是日期计算!!
#!/opt/perl5/bin/perl

use POSIX;

$time_today=localtime(time);
@time_today=localtime(time);
print "Today Date =  $time_today\n";
print "@time_today\n";

$time_today[3]--;

$time_yesterday=localtime(POSIX::mktime (@time_today));
@time_yesterday=localtime(POSIX::mktime (@time_today));
print "Yesterday Date =  $time_yesterday\n";
print "@time_yesterday\n";
作者: javalee    时间: 2003-05-19 18:48
标题: 还是日期计算!!
javalee//home/javalee/lx>date --date=yesterday;date --date=today;date --date=tomorrow
日  5月 18 18:48:38 CST 2003
一  5月 19 18:48:38 CST 2003
二  5月 20 18:48:38 CST 2003
作者: quakelee    时间: 2003-05-19 19:08
标题: 还是日期计算!!
      
疯了,SunOS不支持上面这个命令
那个脚本不知道行不行,没敢试
作者: 红袖添香    时间: 2003-05-19 20:31
标题: 还是日期计算!!
原帖由 "quakelee" 发表:
...
我现在要求不高,就要能算出前一天的日期就行
但是因为是用在跨月份的那一天,所以不是简单的+1 -1就行了
一定是准确的日期
我希望最好别用脚本...


是啊,要求不是很高,但是却很刁,SunOS 的 date 命令行不提供此功能,又不让用脚本,那怎么办?

好吧,不用脚本就不用脚本。


方法一、自己编译一下


  1. #include <stdio.h>
  2. #include <time.h>

  3. int main()
  4. {
  5.        time_t     today;
  6.        struct tm  yesterday;
  7.        time(&today);
  8.        today = today - 86400;
  9.        yesterday = *localtime(&today);
  10.        yesterday.tm_mon ++;
  11.        printf("%02d %02d\n", yesterday.tm_mon, yesterday.tm_mday);
  12.       return(0);
  13. }

复制代码



方法二、可以设定一下 $TZ ,让时区的 offset 为 -86400 ,不过我现在没法试,而且不建议用这个方法,因为对其它程序可能会有意想不到的后果。
作者: quakelee    时间: 2003-05-19 20:36
标题: 还是日期计算!!
靠,算了用脚本就用脚本吧,红袖jj教教我用脚本怎么弄
因为是用在跨月的时候,就是每个月一号
所以前一天的日期一定要算的准,算错了我可死了
况且我是要符合%Y%m%d的格式
作者: 红袖添香    时间: 2003-05-19 20:45
标题: 还是日期计算!!
原帖由 "quakelee" 发表:
靠,算了用脚本就用脚本吧,红袖jj教教我用脚本怎么弄
因为是用在跨月的时候,就是每个月一号
所以前一天的日期一定要算的准,算错了我可死了
况且我是要符合%Y%m%d的格式


我现在马上要走了,没时间了。

你可以找一下旧帖,以前 nkliyong 写过一套关于日期的函数,也包括你要的“前一天”问题,你可以拿来用。如果还搞不定的的话,回头我再回复。

88
作者: 红袖添香    时间: 2003-05-20 00:59
标题: 还是日期计算!!
也不知道你弄好了没有?

因为你实际上要求的是上个月的最后一天,比较偷懒而且在Solaris上可行的方法可以这样。

  1. #!/bin/sh
  2. if [ $# -ne 0 ]; then
  3.     DateString=$1
  4.     Year=`echo $DateString | cut -b 1-4`
  5.     Month=`echo $DateString | cut -b 5-6`
  6. else
  7.     Year=`date +%Y`
  8.     Month=`date +%m`
  9. fi

  10. if [ $Month -eq 1 ]; then
  11.     Month=12
  12.     Year=`expr $Year - 1`
  13. else
  14.     Month=`expr $Month - 1`
  15. fi

  16. Cal=`cal $Month $Year`
  17. Yesterday=`echo $Cal | awk '{print $NF}'`
  18. echo "$Year/$Month/$Yesterday"
复制代码


假设上面的脚本叫 a.sh 运行:

./a.sh  [200302]

无参数时,默认为当前月份
作者: 红袖添香    时间: 2003-05-20 01:11
标题: 还是日期计算!!
...

楼上的帖子运行结果为

sleeve@magic:~/test[586]$ a.sh
2003/4/30

sleeve@magic:~/test[587]$ a.sh 190003
1900/2/28

sleeve@magic:~/test[588]$ a.sh 200003
2000/2/29

sleeve@magic:~/test[589]$ a.sh 200403
2004/2/29

sleeve@magic:~/test[590]$ a.sh 210003
2100/2/28

sleeve@magic:~/test[591]$ a.sh 200301
2002/12/31
作者: 红袖添香    时间: 2003-05-20 01:24
标题: 还是日期计算!!
...

如果是要做得正规点,加上闰年的算法,不仅仅可以用在上个月的最后一天这种特殊情况,还可以处理一般情况:

  1. #!/bin/sh

  2. if [ $# -ne 0 ]; then
  3.     DateString=$1
  4.     Year=`echo $DateString | cut -b 1-4`
  5.     Month=`echo $DateString | cut -b 5-6`
  6.     Date=`echo $DateString | cut -b 7-8`
  7. else
  8.     Year=`date +%Y`
  9.     Month=`date +%m`
  10.     Date=`date +%d`
  11. fi

  12. Date=`expr $Date - 1`

  13. if [ $Date -eq 0 ]; then

  14.   Month=`expr $Month - 1`

  15.   if [ $Month -eq 0 ]; then
  16.     Year=`expr $Year - 1`
  17.     Month=12
  18.     Date=31

  19.   else
  20.     case $Month in
  21.       1|3|5|7|8|10|12) Date=31;;
  22.              4|6|9|11) Date=30;;
  23.                     2)
  24.         Date=28
  25.         if [  `expr $Year % 4` -eq 0 -a `expr $Year % 100` -ne 0  -o \
  26.               `expr $Year % 400` -eq 0  ]; then
  27.             Date=29
  28.         fi
  29.       ;;
  30.     esac
  31.   fi
  32. fi
复制代码


运行:(假设为 b.sh ,注意,参数比上面那个脚本多了两位,即日期)

sleeve@magic:~/test[594]$ ./b.sh 19960301
1996/2/29

sleeve@magic:~/test[595]$ ./b.sh 20000301
2000/2/29

sleeve@magic:~/test[596]$ ./b.sh 21000301
2100/2/28

sleeve@magic:~/test[597]$ ./b.sh 20030101
2002/12/31

sleeve@magic:~/test[598]$ ./b.sh
2003/05/18

sleeve@magic:~/test[599]$ ./b.sh 20030511
2003/05/10
作者: quakelee    时间: 2003-05-20 08:40
标题: 还是日期计算!!
红袖jj       
感动死了~~~
真是论坛第一大好人+PPMM
HOHO~

不过这个脚本运行起来还有的两个小问题嘿嘿
我就是跟你说一声,我今天有点事,其中一个来不及改了
其中一个问题不会改:(
我在SunOS5.8上run这个脚本的时候
如果输入是200x0301的话
就会出现
./getdate.sh: test: ] missing
我用的是第二个脚本
第二个小问题是,我需要返回的符合%Y%m%d的格式
所以会出现一个问题,需要在小于10的数字前面加个0嘿嘿
不过这个我会啦
作者: suney    时间: 2003-05-20 09:58
标题: 还是日期计算!!
红袖MM真是天下第一大好人+PPMM
又学到好东西了


唉,我什么时候能到红袖MM的水平啊
能有一半也行啊。
作者: 俺    时间: 2003-05-20 10:10
标题: 还是日期计算!!
红袖老大终于回来了!

俺又长学问了!
作者: 红袖添香    时间: 2003-05-20 22:43
标题: 还是日期计算!!
...

大家过奖了。

To quakelee:

是啊,具体应用过程中是要调试一下的,上面的给出的代码只是个骨架,实际中是应该把可能遇到的情况考虑进去。在这里我给出一些情况,如参数中是否有非法字符、字串太长、太短、含有空格、日期超出范围……等等,但也不可能考虑周全,只能是具体情况具体分析,根据自己的要求来完善。

另外,上面的帖子中漏掉了最后一句打印语句,我今天才看到。居然你也没提起!

修改后代码,供参考:

  1. #!/bin/sh

  2. # since we have to validate the date string more than once
  3. # put the leap year algorithm in subroutine, should be easy
  4. # to be invoked.

  5. leap() {
  6.     case $1 in
  7.             1|3|5|7|8|10|12) Max=31;;
  8.                    4|6|9|11) Max=30;;
  9.                           2) if [ `expr $Year % 4` -eq 0 -a `expr $Year % 100` -ne 0 -o \
  10.                                   `expr $Year % 400` -eq 0 ]; then
  11.                                  Max=29
  12.                              else
  13.                                  Max=28
  14.                              fi
  15.                              ;;
  16.                           *) Max=0
  17.     esac
  18.     echo $Max
  19. }


  20. if [ $# -eq 1 ]; then
  21.     DateString=$1

  22.     # Len=${#DateString}         ## ksh or bash user can use this statement
  23.                                  ## otherwise use the following expression
  24.     Len=`expr "$DateString" : '.*'`

  25.     if [ $Len -gt 8 ]; then
  26.        echo "Date string too long!"
  27.        exit 1
  28.     elif [ $Len -lt 8 ]; then
  29.        echo "Date string too short!"
  30.        exit 1
  31.     fi

  32.     echo $DateString | grep '[^0-9]' > /dev/null 2>&1
  33.     if [ $? -eq 0 ]; then
  34.          echo "Invalid character(s) in date string! "
  35.          exit 1
  36.     fi

  37.     Year=`echo $DateString | cut -b 1-4`
  38.     Month=`echo $DateString | cut -b 5-6`
  39.     Month=`expr $Month - 0`     # remove leading zero
  40.     Date=`echo $DateString | cut -b 7-8`

  41.     DateMax=`leap $Month`

  42.     if [ $Month -gt 12 -o $Month -lt 1 -o $Date -gt $DateMax -o $Date -lt 1 ]; then
  43.          echo "Invalid date string format! either month or date range exceeds. "
  44.          exit 1
  45.     fi
  46.    
  47. else
  48.     Year=`date +%Y`
  49.     Month=`date +%m`
  50.     Date=`date +%d`
  51. fi

  52. Date=`expr $Date - 1`

  53. if [ $Date -eq 0 ]; then

  54.    Month=`expr $Month - 1`

  55.    if [ $Month -eq 0 ]; then
  56.       Year=`expr $Year - 1`
  57.       Month=12
  58.       Date=31

  59.    else
  60.       Date=`leap $Month`
  61.    fi
  62. fi

  63. if [ $# -ge 2 ]; then
  64.     echo "Only ONE argument required!
  65. Parameters will be discarded and use default current date"
  66. fi

  67. printf "%04d/%02d/%02d\n" $Year $Month $Date
复制代码

作者: 红袖添香    时间: 2003-05-20 22:48
标题: 还是日期计算!!
...

运行结果:

sleeve@magic:~/tmp/sh$ b.sh 2003
Date string too short!

sleeve@magic:~/tmp/sh$ b.sh 200312011
Date string too long!

sleeve@magic:~/tmp/sh$ b.sh 200x1201
Invalid character(s) in date string!

sleeve@magic:~/tmp/sh$ b.sh '200 1201'
Invalid character(s) in date string!

sleeve@magic:~/tmp/sh$ b.sh 200 1201
Only ONE argument required!
Parameters will be discarded and use default current date
2003/05/19

sleeve@magic:~/tmp/sh$ b.sh 20030301
2003/02/28

sleeve@magic:~/tmp/sh$ b.sh 20030101
2002/12/31

sleeve@magic:~/tmp/sh$ b.sh
2003/05/19

sleeve@magic:~/tmp/sh$ b.sh 20030707
2003/07/06

sleeve@magic:~/tmp/sh$ b.sh 20040301
2004/02/29

sleeve@magic:~/tmp/sh$ b.sh 20000301
2000/02/29

sleeve@magic:~/tmp/sh$ b.sh 19000301
1900/02/28

sleeve@magic:~/tmp/sh$ b.sh 19000335
Invalid date string format! either month or date range exceeds.

sleeve@magic:~/tmp/sh$ b.sh 20001503
Invalid date string format! either month or date range exceeds.
作者: nkliyong    时间: 2003-05-21 08:48
标题: 还是日期计算!!
红袖真认真.
作者: quakelee    时间: 2003-05-21 13:28
标题: 还是日期计算!!
红袖jj呀,我其实看到了但是昨天改了一下我就懒得说了,这个脚本我运行好像还是有点问题:(
我也不知道怎么回事
这是在freebsd上运行的结果
[: missing ]
3: not found
2003/02/28
值倒是出来了,但是报了两个错误
作者: 红袖添香    时间: 2003-05-21 17:50
标题: 还是日期计算!!
...

原帖由 "nkliyong"] 红袖真认真.[/quote 发表:


蓝酷脚也是呀,

[quote]原帖由 "quakelee" 发表:
这是在freebsd上运行的结果
[: missing ]
3: not found
2003/02/28
值倒是出来了,但是报了两个错误


确实如此,原因是在第11行,因为太长了,分成两行写的,行末原本是个回车

2) if [ `expr $Year % 4` -eq 0 -a `expr $Year % 100` -ne 0 -o \[RETURN]
   `expr $Year % 400` -eq 0 ]; then

但是不知为啥,这个 phpBB 论坛中,从帖中 copy & paste 会在每行的末尾加上补上空格,变成了

2) if [ `expr $Year % 4` -eq 0 -a `expr $Year % 100` -ne 0 -o \[SPACE][RETURN]
   `expr $Year % 400` -eq 0 ]; then

在大多数情况下倒也是无伤大雅的,但是也有时候会出错,比如这里 \ 后面必须跟的是回车,经过转义的回车,表示该语句还没有结束,跟下一行是同一句。

以后,碰到这种情况我会尽量想着提醒一下的。

此外,还有加了空格会出现异常的还有:

... <<EOF
...

EOF

以及

sed '{
  ...
  w file
}
'

等情况。
作者: quakelee    时间: 2003-05-21 23:50
标题: 还是日期计算!!
嘿嘿,我想了个更好的办法,把日志都同步到一台bsd上去处理了
嘿嘿,别生气啊,不过真的谢谢你,shell脚本的编写也学会了不少东西
作者: 红袖添香    时间: 2003-05-22 00:25
标题: 还是日期计算!!
原帖由 "quakelee" 发表:
嘿嘿,我想了个更好的办法,把日志都同步到一台bsd上去处理了
嘿嘿,别生气啊,不过真的谢谢你,shell脚本的编写也学会了不少东西



没问题啊。

对发帖者来说,能最方便地解决问题是最终目的;
对答帖和看帖的来说,交流和互相学习是目的。
作者: nmgzw    时间: 2003-05-22 08:04
标题: 还是日期计算!!
看到同志们都这么谦虚,我就放心了!
同志们辛苦了!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2