zoukankan      html  css  js  c++  java
  • Linux shell实现阳历转农历

    闲来无事,想在Linux下用shell写一个阳历转农历的脚本,断断续续大概一个星期终于搞定。现在拿出来与大家分享。

    缘由

    本脚本实现原理是查表法(因为公式有误差);基于农历新年为基准,对农历新年前后两个不同的农历进行计算。

    写这个脚本之前是想在Linux 终端命令提示符中加入阳历及农历日期。在Ubuntu中有Lunar软件可以获取农历日期,但在Fedora或CentOS中并没有类似软件,所以就想自己来实现一个,但网上用其他语言写的一大把,如果再写没什么必要。所以就想用shell来写一个。

    功能及使用

    功能:将具体的阳历日期转换为农历日期。

    时间范围:1901~2099,对应农历年时间为4598~4796

    参数格式(无参数默认为当前系统日期):yyyymmdd

    如2013年1月1日:

    $./lunar.sh 20130101

    4709-11-20

    完整数据

    完整数据下载链接:

    https://files.cnblogs.com/snowsolf/lunar-20131202.7z

    包中文件

    lunar.sh 主脚本,具体实现

    datebases 农历元数据

    change.log 更改日志

    readme 脚本说明及注意事项

    主要脚本lunar.sh代码如下

    #!/bin/sh
    
    DATE=$@
    [ "$DATE" = "" ] && DATE=$(date +%Y%m%d)
    
    databases_path=databases
    
    date_year=$(echo $DATE |sed 's/^\(.\{4\}\).*/\1/')
    date_month=$(echo $DATE |sed 's/.*\(..\)..$/\1/')
    date_day=$(echo $DATE |sed 's/.*\(..\)$/\1/')
    date_days=$(date -d $DATE +%j)
    
    lunar_year=$(sed /$date_year/!d $databases_path |sed 's/^\(....\).*/\1/')
    
    lunar_year_data=$(sed /$date_year/!d $databases_path |sed 's/.*\ \(.*\)/\1/')
    lunar_year_data_bin=$(echo "ibase=16;obase=2;$lunar_year_data"|bc |sed -e :a -e 's/^.\{1,23\}$/0&/;ta')
    
    new_year_month_bin=$(echo $lunar_year_data_bin |sed -e 's/^.\{17\}\(.\{2\}\).*/\1/')
    new_year_month=$(echo "ibase=2;$new_year_month_bin"|bc |sed -e :a -e 's/^.\{1,1\}$/0&/;ta')
    
    new_year_day_bin=$(echo $lunar_year_data_bin |sed -e 's/.*\(.\{5\}\)$/\1/')
    new_year_day=$(echo "ibase=2;$new_year_day_bin"|bc |sed -e :a -e 's/^.\{1,1\}$/0&/;ta')
    
    new_year_days=$(date -d $date_year$new_year_month$new_year_day +%j)
    lunar_days=$(expr $date_days - $new_year_days + 1)
    
    befor_or_after=0
    
    if [ "$lunar_days" -le "0" ]; then
       befor_or_after=1
       date_year=$(($date_year - 1))
    
       lunar_year=$(sed /$date_year/!d $databases_path |sed 's/^\(....\).*/\1/')
    
       lunar_year_data=$(sed /$date_year/!d $databases_path |sed 's/.*\ \(.*\)/\1/')
       lunar_year_data_bin=$(echo "ibase=16;obase=2;$lunar_year_data"|bc |sed -e :a -e 's/^.\{1,23\}$/0&/;ta')
    fi
    
    lunar_leap_month_bin=$(echo $lunar_year_data_bin |sed -e 's/^\(.\{4\}\).*/\1/')
    lunar_leap_month=$(echo "ibase=2;$lunar_leap_month_bin"|bc)
    
    lunar_month_all_bin=$(echo $lunar_year_data_bin |sed -e 's/^.\{4\}\(.\{13\}\).*/\1/')
    [ "$lunar_leap_month" = "0" ] && lunar_month_all_bin=$(echo $lunar_year_data_bin |sed -e 's/^.\{4\}\(.\{12\}\).*/\1/')
    lunar_month_all=$(echo $lunar_month_all_bin |sed -e 's/0/29\ /g' |sed -e 's/1/30\ /g')
    
    if [ "$befor_or_after" = "0" ];then
       lunar_month=1
       lunar_day=$lunar_days
       for i in $lunar_month_all
       do
          [ "$lunar_day" -gt "$i" ] && lunar_day=$(($lunar_day - $i)) && lunar_month=$(($lunar_month + 1))
          [ "$lunar_day" = "$i" ] && break
       done
    else
       lunar_month=12
       lunar_day=$((-$lunar_days))
       lunar_month_all_bin=$(echo $lunar_month_all_bin |rev)
       lunar_month_all=$(echo $lunar_month_all_bin |sed -e 's/0/29\ /g' |sed -e 's/1/30\ /g')
       for i in $lunar_month_all
       do
          if [ "$lunar_day" -gt "$i" ]; then
             lunar_day=$(($lunar_day - $i))
             lunar_month=$(($lunar_month - 1))
          else
             lunar_day=$(($i - $lunar_day))
             break
          fi
       done
    fi
    
    if [ "$lunar_leap_month" = "0" ]; then
        echo $lunar_year-$lunar_month-$lunar_day
    else
       if [ "$lunar_leap_month" -ge "$lunar_month" ]; then
          echo $lunar_year-$lunar_month-$lunar_day
       elif [ "$befor_or_after" = "0" ]; then
          if [ "$(($lunar_leap_month + 1))" = "$lunar_month" ];then
             lunar_month=$(($lunar_month - 1))
             echo $lunar_year-*$lunar_month-$lunar_day
          else
             lunar_month=$(($lunar_month - 1))
             echo $lunar_year-$lunar_month-$lunar_day
          fi
       else
          echo $lunar_year-$lunar_month-$lunar_day
       fi
    fi
    lunar.sh

     修改历史

     2013-12-02

    发现bug:如果农历上个月是大月,本月为小月,则上个月的三十输出为本月的初一,原因是上个月剩下30天,这正好是上个月的三十,而本月是29天,29<30,下一次循环的时候又减本月的天数,使得上个月的三十成为本月的初一

    bug修改:添加判断语句,如果农历剩余天数等于当月的天数则不再循环

  • 相关阅读:
    django 项目需要注意的一些点
    VUE之路
    Oracle 表格碎片的查看方法
    RHEL 6.x or 7.x 使用分区绑定ASM 磁盘的方法
    RMAN 修复主库 nologging 操作导致物理备库的坏块
    Oracle 数据库19c 回退降级到 11.2.0.4 方案
    如何评估oracle 数据库rman全备和增量备份大小
    在将Oracle GI和DB升级到19c或降级到以前的版本之前需要应用的补丁 (Doc ID 2668071.1)
    Oracle 数据库坏块处理
    opatch auto 安装11.2.0.4.20190115 PSU遇到 OUI-67133: Execution of PRE script failed,with returen value 1 报错
  • 原文地址:https://www.cnblogs.com/snowsolf/p/lunar.html
Copyright © 2011-2022 走看看