首页 > 系统 > Linux > 正文

Linux-shell实现阳历转农历(序)

2024-06-28 13:25:52
字体:
来源:转载
供稿:网友
linux-shell实现阳历转农历(序)

好些天没有登陆邮箱,前几天上班打开一看垃圾箱中有一封邮件让我好激动,还是国外友人的英文邮件。^_^大概内容是我早些时候写的一个阳历转农历的shell小程序,他在用的时候发现了bug,但是这个bug我在去年年底就修改了。而且,他给了此程序的具体出处,但并不是我发布此程序的地址,显然是XX拷贝过去的(管它XX是人还是机器),庆幸的是我在程序的log文件中加入了我的邮箱地址,此友人才能找到我。废话少说,入正题。

缘由

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

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

主要功能

将阳历转换为农历。

Ubuntu 12.04 LTS dash和bash都测试通过(在此系统中,默认的/bin/sh是连接到/bin/dash的,dash是一个小而相容于POSIX标准的Unix shell,bash进行了扩展)

CentOS 6.4 测试通过(很久以前的事了,限于手中的资源,现在就不再在此系统上测试,不知道现在的版本还能否通过)

Fedora 18 测试通过(很久以前的事了,限于手中的资源,现在就不再在此系统上测试,不知道现在的版本还能否通过)

参数要求
  • 参数数据为8位,其中年为4位,月和日各2位,不足前面补0,如2013年1月1号:20130101
  • 无参数时默认当前系统日期为需转换日期

农历是通过观测及推算而得出的历法,所以通过通用公式计算得到的农历时间多少会有误差,特别是时间范围比较大的时候,这种误差就不好再无视它了。

基本算法:以每年的农历新年为基准。新年后的农历年份对应于阳历所在的年份;新年前为上一个农历年份。

验证

如果想验证可通过以下网址进行验证:

http://www.herongyang.com/Year_zh/PRogram-Chinese-Calendar-Algorithm.html

数据来源

以下关键的农历元数据来源于:

http://www.cppblog.com/ctou45/archive/2012/08/21/187846.html

//0~4 共5bit 春节日//5~6 共2bit 春节月//7~19 共13bit 13个月的大小月情况(如果无闰月,最后位无效),大月为1,小月为0(从左到右)//20~23 共4bit 记录闰月的月份,如果没有闰月为00x04AE53,0x0A5748,0x5526BD,0x0D2650,0x0D9544,0x46AAB9,0x056A4D,0x09AD42,0x24AEB6,0x04AE4A, //1901-19100x6A4DBE,0x0A4D52,0x0D2546,0x5D52BA,0x0B544E,0x0D6A43,0x296D37,0x095B4B,0x749BC1,0x049754, //1911-19200x0A4B48,0x5B25BC,0x06A550,0x06D445,0x4ADAB8,0x02B64D,0x095742,0x2497B7,0x04974A,0x664B3E, //1921-19300x0D4A51,0x0EA546,0x56D4BA,0x05AD4E,0x02B644,0x393738,0x092E4B,0x7C96BF,0x0C9553,0x0D4A48, //1931-19400x6DA53B,0x0B554F,0x056A45,0x4AADB9,0x025D4D,0x092D42,0x2C95B6,0x0A954A,0x7B4ABD,0x06CA51, //1941-19500x0B5546,0x555ABB,0x04DA4E,0x0A5B43,0x352BB8,0x052B4C,0x8A953F,0x0E9552,0x06AA48,0x7AD53C, //1951-19600x0AB54F,0x04B645,0x4A5739,0x0A574D,0x052642,0x3E9335,0x0D9549,0x75AABE,0x056A51,0x096D46, //1961-19700x54AEBB,0x04AD4F,0x0A4D43,0x4D26B7,0x0D254B,0x8D52BF,0x0B5452,0x0B6A47,0x696D3C,0x095B50, //1971-19800x049B45,0x4A4BB9,0x0A4B4D,0xAB25C2,0x06A554,0x06D449,0x6ADA3D,0x0AB651,0x093746,0x5497BB, //1981-19900x04974F,0x064B44,0x36A537,0x0EA54A,0x86B2BF,0x05AC53,0x0AB647,0x5936BC,0x092E50,0x0C9645, //1991-20000x4D4AB8,0x0D4A4C,0x0DA541,0x25AAB6,0x056A49,0x7AADBD,0x025D52,0x092D47,0x5C95BA,0x0A954E, //2001-20100x0B4A43,0x4B5537,0x0AD54A,0x955ABF,0x04BA53,0x0A5B48,0x652BBC,0x052B50,0x0A9345,0x474AB9, //2011-20200x06AA4C,0x0AD541,0x24DAB6,0x04B64A,0x69573D,0x0A4E51,0x0D2646,0x5E933A,0x0D534D,0x05AA43, //2021-20300x36B537,0x096D4B,0xB4AEBF,0x04AD53,0x0A4D48,0x6D25BC,0x0D254F,0x0D5244,0x5DAA38,0x0B5A4C, //2031-20400x056D41,0x24ADB6,0x049B4A,0x7A4BBE,0x0A4B51,0x0AA546,0x5B52BA,0x06D24E,0x0ADA42,0x355B37, //2041-20500x09374B,0x8497C1,0x049753,0x064B48,0x66A53C,0x0EA54F,0x06B244,0x4AB638,0x0AAE4C,0x092E42, //2051-20600x3C9735,0x0C9649,0x7D4ABD,0x0D4A51,0x0DA545,0x55AABA,0x056A4E,0x0A6D43,0x452EB7,0x052D4B, //2061-20700x8A95BF,0x0A9553,0x0B4A47,0x6B553B,0x0AD54F,0x055A45,0x4A5D38,0x0A5B4C,0x052B42,0x3A93B6, //2071-20800x069349,0x7729BD,0x06AA51,0x0AD546,0x54DABA,0x04B64E,0x0A5743,0x452738,0x0D264A,0x8E933E, //2081-20900x0D5252,0x0DAA47,0x66B53B,0x056D4F,0x04AE45,0x4A4EB9,0x0A4D4C,0x0D1541,0x2D92B5 //2091-2099
View Code

主要代码

因为时常更新,所以打包文件不再提供,只提供github。

github地址:

https://github.com/snowsolf/lunar

此程序包括如下几个文件:

  • lunar.sh 主脚本,具体实现
  • datebases 农历元数据
  • change.log 更改日志
  • readme 脚本说明及注意事项
  • shengxiao 生肖数据
主脚本

lunar.sh代码如下:

########################################################################## File Name: lunar.sh# Author: snowsolf# E-mail: snowsolf@hotmail.com# Created Time: 2013年07月***********##########################################################################!/bin/shVersion=1.0Editor=snowsolfEmail=snowsolf@hotmail.com# print helpfunction Usage(){   cat << EOF==============================================================Valid date: 19010101 ~ 20991231But 'date' program support: 19011215 ~ 20380119  -h, --help              display this help and exit  -V, --version           output version information and exitUsage: $0 [-h|--help|-V|--version] | [date(yyyymmdd)]Examples:Usage input time:    $0 20130101Usage system time:    $0Editor: $EditorE-mail: $EmailEOF   exit 0}##################################################################get year,month,day and day of year#system 'date' program support:19011215 ~ 20380119#################################################################function Date_data(){   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)}DATE=$@# handle difference inputcase "$#" in   0)      echo "No parameters!"      echo -e "Usage system time: $(date +%Y-%m-%d)/n"      DATE=$(date +%Y%m%d)      Date_data   ;;   1)       date -d $DATE +%j > /dev/null || ((Usage && exit 0))      case "$1" in         -h|--help)            Usage         ;;         -V|--version)            echo "$0: Version $Version"            echo "Editor: $Editor"            echo "E-mail: $Email"            exit 0         ;;         [1][9][0-9][0-9][0-9][0-9][0-9][0-9]|[2][0][0-9][0-9][0-9][0-9][0-9][0-9])            [ "$1" -ge "19010101" ] && [ "$1" -lt "19011215" ] || [ "$1" -gt "20380119" ] && [ "$1" -le "20991231" ] /            && echo -e "'date' program no support: $1/n" && Usage            [ "$1" -ge "19000000" ] && [ "$1" -lt "19010101" ] || [ "$1" -gt "20991231" ] && [ "$1" -le "20999999" ] /            && echo -e "Invalid parameter: $1/n" && Usage            Date_data         ;;         *)            echo -e "Invalid parameter: $1/n"            Usage         ;;      esac   ;;   *)      echo -e "The number of parameter greater than one !/n"      Usage   ;;esac# lunar databasesdatabases_path=databases# get lunar yearlunar_year=$(sed /$date_year/!d $databases_path |sed 's/^/(..../).*//1/')# get all for lunar year, and form hexadecimal to binary# include lunar year, month, day, and leap monthlunar_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)# flagbefor_or_after=0if [ "$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')filunar_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" -eq "$i" ] && break      [ "$lunar_day" -gt "$i" ] && lunar_day=$(($lunar_day - $i)) && lunar_month=$(($lunar_month + 1))   doneelse   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      [ "$lunar_day" -eq "$i" ] && break      if [ "$lunar_day" -gt "$i" ]; then         lunar_day=$(($lunar_day - $i))         lunar_month=$(($lunar_month - 1))      else         lunar_day=$(($i - $lunar_day))         break      fi   donefi# outputif [ "$lunar_leap_month" = "0" ]; then    echo $lunar_year-$lunar_month-$lunar_dayelse   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   fifised -n $(($(($lunar_year - 4598 + 2)) % 12))p shengxiao
lunar.sh

数据文件

databases文件中存储了日期的元数据。为了更容易查表,此文件对元数据进行了处理。

4598 1901 04AE534599 1902 0A57484600 1903 5526BD4601 1904 0D26504602 1905 0D95444603 1906 46AAB94604 1907 056A4D4605 1908 09AD424606 1909 24AEB64607 1910 04AE4A4608 1911 6A4DBE4609 1912 0A4D524610 1913 0D25464611 1914 5D52BA4612 1915 0B544E4613 1916 0D6A434614 1917 296D374615 1918 095B4B4616 1919 749BC14617 1920 0497544618 1921 0A4B484619 1922 5B25BC4620 1923 06A5504621 1924 06D4454622 1925 4ADAB84623 1926 02B64D4624 1927 0957424625 1928 2497B74626 1929 04974A4627 1930 664B3E4628 1931 0D4A514629 1932 0EA5464630 1933 56D4BA4631 1934 05AD4E4632 1935 02B6444633 1936 3937384634 1937 092E4B4635 1938 7C96BF4636 1939 0C95534637 1940 0D4A484638 1941 6DA53B4639 1942 0B554F4640 1943 056A454641 1944 4AADB94642 1945 025D4D4643 1946 092D424644 1947 2C95B64645 1948 0A954A4646 1949 7B4ABD4647 1950 06CA514648 1951 0B55464649 1952 555ABB4650 1953 04DA4E4651 1954 0A5B434652 1955 352BB84653 1956 052B4C4654 1957 8A953F4655 1958 0E95524656 1959 06AA484657 1960 7AD53C4658 1961 0AB54F4659 1962 04B6454660 1963 4A57394661 1964 0A574D4662 1965 0526424663 1966 3E93354664 1967 0D95494665 1968 75AABE4666 1969 056A514667 1970 096D464668 1971 54AEBB4669 1972 04AD4F4670 1973 0A4D434671 1974 4D26B74672 1975 0D254B4673 1976 8D52BF4674 1977 0B54524675 1978 0B6A474676 1979 696D3C4677 1980 095B504678 1981 049B454679 1982 4A4BB94680 1983 0A4B4D4681 1984 AB25C24682 1985 06A5544683 1986 06D4494684 1987 6ADA3D4685 1988 0AB6514686 1989 0937464687 1990 5497BB4688 1991 04974F4689 1992 064B444690 1993 36A5374691 1994 0EA54A4692 1995 86B2BF4693 1996 05AC534694 1997 0AB6474695 1998 5936BC4696 1999 092E504697 2000 0C96454698 2001 4D4AB84699 2002 0D4A4C4700 2003 0DA5414701 2004 25AAB64702 2005 056A494703 2006 7AADBD4704 2007 025D524705 2008 092D474706 2009 5C95BA4707 2010 0A954E4708 2011 0B4A434709 2012 4B55374710 2013 0AD54A4711 2014 955ABF4712 2015 04BA534713 2016 0A5B484714 2017 652BBC4715 2018 052B504716 2019 0A93454717 2020 474AB94718 2021 06AA4C4719 2022 0AD5414720 2023 24DAB64721 2024 04B64A4722 2025 69573D4723 2026 0A4E514724 2027 0D26464725 2028 5E933A4726 2029 0D534D4727 2030 05AA434728 2031 36B5374729 2032 096D4B4730 2033 B4AEBF4731 2034 04AD534732 2035 0A4D484733 2036 6D25BC4734 2037 0D254F4735 2038 0D52444736 2039 5DAA384737 2040 0B5A4C4738 2041 056D414739 2042 24ADB64740 2043 049B4A4741 2044 7A4BBE4742 2045 0A4B514743 2046 0AA5464744 2047 5B52BA4745 2048 06D24E4746 2049 0ADA424747 2050 355B374748 2051 09374B4749 2052 8497C14750 2053 0497534751 2054 064B484752 2055 66A53C4753 2056 0EA54F4754 2057 06B2444755 2058 4AB6384756 2059 0AAE4C4757 2060 092E424758 2061 3C97354759 2062 0C96494760 2063 7D4ABD4761 2064 0D4A514762 2065 0DA5454763 2066 55AABA4764 2067 056A4E4765 2068 0A6D434766 2069 452EB74767 2070 052D4B4768 2071 8A95BF4769 2072 0A95534770 2073 0B4A474771 2074 6B553B4772 2075 0AD54F4773 2076 055A454774 2077 4A5D384775 2078 0A5B4C4776 2079 052B424777 2080 3A93B64778 2081 0693494779 2082 7729BD4780 2083 06AA514781 2084 0AD5464782 2085 54DABA4783 2086 04B64E4784 2087 0A57434785 2088 4527384786 2089 0D264A4787 2090 8E933E4788 2091 0D52524789 2092 0DAA474790 2093 66B53B4791 2094 056D4F4792 2095 04AE454793 2096 4A4EB94794 2097 0A4D4C4795 2098 0D15414796 2099 2D92B5
databases

生肖数据

shengxiao文件中是生肖:

鼠牛虎兔龙蛇马羊猴鸡狗猪
shengxiao

下个功能点

下个功能点是阳历日期的实现,因为系统中date程序支持的时间范围是1901-12-15到2038-01-19,显然有时此时间段并不能满足一些人的要求。所以,下一步需要单独实现如date程序功能的代码,以支持更大的时间段。

但你可知道1752年的9月是有问题的,具体缘由你可以google(话说这些天已经不好使了,我只能说,是不是被玩坏了!)或者baidu。

下个shell程序

Ubuntu 14.04 LTS出来的时候,我就迫不及待的将12.04 LTS升级到14.04 LTS,但是除了问题TMD还是问题:

*开机情况下合起笔记本盖子再打开时X僵死了,好烦躁!*蓝牙适配器不能用了!*每次打开电脑都会有系统错误提示,还不止一个!

所以,前天晚上将必要的数据备份后还是装回12.04,感觉整个人都舒服了。

之前UbuntuKylin出来的时候就下了天气插件使用,但不管12.04还是14.04上都会莫名其妙的死掉,所以就萌生了用shell实现一个天气察看程序,但不知道天气元数据怎么获取(中国气象局的数据),之前看了UbuntuKylin的天气插件源码,但没找到。

最后

农历是通过观测及推算而得出的历法,一直没有找到元数据的出处,这个应该天文台有,但网上找不到。

还有天气数据是从那里获取?

还望知道的大哥大姐小弟小妹告诉我。不胜感激!

更新

2014-08-01

将此脚本托管到github上,并将readme内容更新到README.md文件中。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表