分页: 1 / 1

【已解决】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-12 22:04
yq-ysy
问题是从公历6月8日开始的,这一天应该是农历五月初一,但程序仍计算为四月三十。
某些民间推算的万年历也说公历6月8日是四月三十。但是因为今年2013年的农历四月是小月,所以只有29天。
多一天少一天,下一次“满月、月食、日食”的时间肯定就跟着错,因此谁对谁错,很明显,到时一眼能看出来。
官方公布的农历,相信是经过严格的天文学计算的,所以还是应该以官方的农历为准。

麻烦的是,这个“小月”的出现好像没有什么特定的规律,似乎是什么时候觉得误差大了,该小月就小月了,
所以写程序的话,处理起来就比较麻烦。
网上搜索了一下,不单是这个程序有错误,就连微软的outlook 2010版在这里也出错了。
这个用在conky上的农历程序不知道应该怎么修改,补回这一天?
谢谢

代码: 全选

#!/bin/bash
DOM=(0xd4a8 0xd4a0 0xda50 0x5aa8 0x56a0 0xaad8 0x25d0 0x92d0 0xc958 0xa950
    0xb4a0 0xb550 0xb550 0x55a8 0x4ba0 0xa5b0 0x52b8 0x52b0 0xa930 0x74a8
    0x6aa0 0xad50 0x4da8 0x4b60 0x9570 0xa4e0 0xd260 0xe930 0xd530 0x5aa0
    0x6b50 0x96d0 0x4ae8 0x4ad0 0xa4d0 0xd258 0xd250 0xd520 0xdaa0 0xb5a0
    0x56d0 0x4ad8 0x49b0 0xa4b8 0xa4b0 0xaa50 0xb528 0x6d20 0xada0 0x55b0)
LMOY=(0x40 0x02 0x07 0x00 0x50
     0x04 0x09 0x00 0x60 0x04
     0x00 0x20 0x60 0x05 0x00
     0x30 0xb0 0x06 0x00 0x50
     0x02 0x07 0x00 0x50 0x03)
START=2001; END=2050
# $1: 2001-2050
get_leap_month()
{
   sft=$(( $1 - $START )); dom=${LMOY[$(( $sft >> 1 ))]}
   echo $(( $(( sft & 1 ))?$(( $dom & 0x0f )):$(( $dom >> 4 )) ))
}
# $1: 2001-2050, $2: 1-12
get_days_of_month()
{
   y=$1; m=$2; high=0; low=29; sft=$(( 16 - $m ))
   dom=${DOM[$(( $y - $START ))]}; lmoy=$(get_leap_month $y)
   [ $m -gt $lmoy -a $lmoy -gt 0 ] && let "sft--"
   [ $(( $dom & $(( 1 << $sft )) )) -gt 0 ] && let "low++"
   if [ $m -eq $lmoy ]; then
      let "sft--"
      high=$(( $(( $dom & ( 1 << $sft ) ))?30:29 ))
   fi
   echo $(( low + ( high << 16) ))
}
# $1: 2001-2050
get_days_of_year()
{
   y=$1; d=0
   for i in {1..12}; do
      tmp=$(get_days_of_month $y $i)
      let "d+=$(( $(( $tmp >> 16)) & 0xffff ))"
      let "d+=$(( $tmp & 0xffff ))"
   done
   echo $d
}
#
parse_year()
{
   HS="甲乙丙丁戊己庚辛壬癸"; EB="子丑寅卯辰巳午未申酉戌亥"
   echo "${HS:$(( ($1 - 4) % 10 )):1}${EB:$(( ($1 - 4) % 12 )):1}"
}   
#
parse_month()
{
   LM=('' '正' '二' '三' '四' '五' '六' '七' '八' '九' '十' '十一' '十二')
   echo "${LM[$1]}"
}
#
parse_day()
{
   PREFIX="初十廿"; DAY="一二三四五六七八九十"
   d=$1
   if [ $d -eq 20 ]; then
      echo "二十"
   elif [ $d -eq 30 ]; then
      echo "三十"
   else
      echo "${PREFIX:$(( ($d - 1) / 10 )):1}${DAY:$(( ($d - 1) % 10 )):1}"
   fi
}
parse_date()
{
#   d=${*:-$(date)}; leap=
  d=${*:-$(date +"%Y/%m/%d")}; leap=
  sft=$(( ( $(date -d "$d" +%s) - $(date -d "${START}/01/01" +%s) ) / 60 / 60 / 24 ))
   if [ $sft -lt 23 ]; then
      ly=2000
      lm=12
      ld=$(( $sft + 7 ))
   else
      let "sft-=23"; ly=2001; lm=1; ld=1
      tmp=$(get_days_of_year $ly)
      while [ $sft -ge $tmp ]; do
         let "sft-=$tmp"
         let "ly++"
         tmp=$(get_days_of_year $ly)
      done
      tmp=$(( $(get_days_of_month $ly $lm) & 0xffff ))
      while [ $sft -ge $tmp ]; do
         let "sft-=$tmp"
         if [ $lm -eq $(get_leap_month $ly) ]; then
            tmp=$(( $(get_days_of_month $ly $lm) >> 16 ))
            if [ $sft -lt $tmp ]; then
               test $tmp -gt 0 && leap="闰"
               break
            fi
            let "sft-=$tmp"
         fi
         let "lm++"
         tmp=$(( $(get_days_of_month $ly $lm) & 0xffff ))
      done
      let "ld+=$sft"
   fi
   echo "$(parse_year $ly)年${leap}$(parse_month $lm)月$(parse_day $ld)"
}
parse_date "$*"

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-12 22:29
qy117121
我感觉吧,这玩意还是从数据库里读取的好
比如像ee这样的 viewtopic.php?f=63&t=309740&start=231

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-12 22:42
qy117121
去看了下万年历,貌似10年12年的四月也都是小月啊,特地把本地时间改为了10年6月12日(五月初一),没出错

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-13 10:11
eexpress
农历历来要手动调整的啊。准确的说,没算法的。

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-13 10:14
daf3707
http://www.nongli.com/item3/
这里的6.8是初一
手动也有规律吧,四舍五入? :em05

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-13 10:19
和羞走
eexpress 写了:农历历来要手动调整的啊。准确的说,没算法的。

Re: 【求助】今年的6月8日恰逢农历4月是小月,只有29天,造成农历程序错误少了一天,怎么补回来?

发表于 : 2013-06-16 21:21
yq-ysy
手动调整农历程序,修正误差:
修改这一行 sft=$(( ( $(date -d "$d" +%s) - $(date -d "${START}/01/01" +%s) ) / 60 / 60 / 24 ))
在最后的双括号之内加上(或者减去)误差的天数即可:
修改后 sft=$(( ( $(date -d "$d" +%s) - $(date -d "${START}/01/01" +%s) ) / 60 / 60 / 24 +1 ))