文档章节

农历的那些事儿(一)

YougaKing
 YougaKing
发布于 2016/10/17 16:28
字数 1267
阅读 210
收藏 0

由于项目中日历需要加一个农历的功能,github关于农历也蛮多,但大都是集成在View中,换个日历View成本太高,所以copy其中一个农历转换代码集成在项目中。但是发现数据不准确,竟然两个初一连在一起。。。所以准备仔细研究一下农历和公历时如何转换的。

农历不像公历那么有规律,农历的数据貌似都是天文台的观测结果然后整理发布出来的。google的结果只有南京紫金山天文台香港天文台捣鼓这事儿。

网上流传的农历数据都是

像这样的16进制数组,不知道数据的来源是什么,我根据此博客copy出来的数据换算过来总是相差那么一两天,所以我要自己挖掘农历数据源。google、百度都没什么结果,唯一有用的结果就是香港天文台贴出的1901-2100年公农历PDF。

首先先把这200年的pdf下载下来,无赖没有提供打包下载,只能一张张下载。手动点击太慢了吧,此时需要一个类似迅雷的下载软件。

循环地址下载地址

        String url = "http://www.hko.gov.hk/gts/time/calendar/pdf/";
        for (int i = 1901; i < 2101; i++) {
            System.out.println(url + i + ".pdf");
        }

复制到迅雷

下载很快结束了。

此时需要Adobe Acrobat DC软件,这玩意儿是付费软件,不过可以免费使用30天,此软件功能强大,值得拥有。Acrobat 把200张pdf合并成一个pdf,为毛要合并?因为随后需要把pdf转成excel,我可不想一张张转换。合并:工具--合并文件

选择所有pdf文件,合并。然后导出excel就可以,当然也可以导出xml什么。看你怎么方便怎么处理

此时Excel文件怎么才能变成我们想要的数据比如json,或者类似上面的16进制数据呢?很简单读取excel文件进行转换就行了嘛。对于咋android程序猿来说不是难事儿,纯java代码就跑出来嘛。当然你也可以来点有些挑战性的,直接搞个PC应用程序来读取excel。以前闲着没事儿捣鼓一点JavaFx,于是就开搞。

先拖个界面出来

输出路径为读取excel后输出我们想要的数据文件。直接开搞代码

文件选择框

        JFileChooser fileChooser = new JFileChooser();
        //设置选择路径模式
        fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        //设置对话框标题
        fileChooser.setDialogTitle("请选择Excel文件");
        //设置过滤器
        fileChooser.setFileFilter(new ExcelFilter());

        if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(null)) {//用户点击了确定
            String path = fileChooser.getSelectedFile().getAbsolutePath();//取得路径选择
            System.out.println("path:" + path);
            try {
                readCalendarExcel(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

获得excel文件对象

FileInputStream fis = new FileInputStream(new File(path));

应该是获取第一张表的意思。。。没深究api的用法,因为这不是重点,能用就行。。。

XSSFWorkbook book = new XSSFWorkbook(fis);
XSSFSheet sheet = book.getSheetAt(0);

然后就是根据表中数据循环读取,此是分析表中数据,由于是pdf转换而来,存在多个表头,每一年有一个人表头。

excel提供数数据是从公历1901-01-01到2100-12-31,相对应的农历是1900-11-11到2100-12-01,表头是公历1-31日:左边第一列是公历的月份。单元格对应的就是农历的日期。

读取单元格内容

List<String> rowArray = new ArrayList<>();
while (cellIterator.hasNext()) {
    Cell cell = cellIterator.next();
    switch (cell.getCellType()) {
        case Cell.CELL_TYPE_STRING:
            String cellString = cell.getStringCellValue();
            if (!cellString.isEmpty()) {
                cellString = cellString.replaceAll("\\s*", "");
                rowArray.add(cellString);
            }
            break;
        case Cell.CELL_TYPE_NUMERIC:
            int cellInt = (int) cell.getNumericCellValue();
            rowArray.add(String.valueOf(cellInt));
            break;
        case Cell.CELL_TYPE_BOOLEAN:
            rowArray.add(String.valueOf(cell.getBooleanCellValue()));
            break;
        default:
    }
}

首先把表头读取出来存入List<Strnig>,不要重复读取做个判断,然后循环读取数据

if (!rowArray.isEmpty() && stringSet.isEmpty() && "公曆日期".equals(rowArray.get(0))) {
    stringSet.addAll(rowArray);
}
if (!rowArray.isEmpty() && rowArray.get(0).endsWith("月")) {
    String solarMonth = rowArray.get(0).substring(0, rowArray.get(0).length() - 1);
    boolean first = true;
    for (int i = 2; i < rowArray.size() - 1; i++) {
        String lunarDay = rowArray.get(i);
        int lunarMonth = 0;
        int leapMonth = 0;
        if (lunarDay.endsWith("月")) {
            if (lunarDay.startsWith("閏")) {
                lunarDay = lunarDay.replace("閏", "");
                lunarMonth = 13;
                leapMonth = mMonths.indexOf(lunarDay.substring(0, lunarDay.indexOf("月")));
            } else {
                lunarMonth = mMonths.indexOf(lunarDay.substring(0, lunarDay.indexOf("月")));
            }
            lunarDay = "初一";
        } else {
            if (!calendarSet.isEmpty())
                lunarMonth = calendarSet.get(calendarSet.size() - 1).lunarMonth;
        }
        String s = lunarDay.substring(0, 1);
        String e = lunarDay.substring(1, 2);
        if (calendarSet.isEmpty()) {
            calendarSet.add(new Calendar(1901, Integer.valueOf(solarMonth), Integer.valueOf(stringSet.get(i - 1)),
                    1900, 11, mExtra.indexOf(s) * 10 + mNumbers.indexOf(e), leapMonth));
        } else {
            Calendar calendar = calendarSet.get(calendarSet.size() - 1);
            int lunarYear, solarYear;
            if ("正月".equals(rowArray.get(i))) {
                lunarYear = calendar.lunarYear + 1;
            } else {
                lunarYear = calendar.lunarYear;
            }
            if ("1月".equals(rowArray.get(0)) && calendar.solarMonth == 12 && first) {
                solarYear = calendar.solarYear + 1;
                first = false;
            } else {
                solarYear = calendar.solarYear;
            }
            calendarSet.add(new Calendar(solarYear, Integer.valueOf(solarMonth), Integer.valueOf(stringSet.get(i - 1)),
                    lunarYear, lunarMonth, (mExtra.indexOf(s) == -1) ? 20 :
                    mExtra.indexOf(s) * 10 + (mExtra.indexOf(s) == 3 ? 0 : mNumbers.indexOf(e)), leapMonth));
        }
    }
}

然后再拆分成单独年月,转换成16进制数组。然后写入文件输出,OK,运行看看。

OK,转换完毕,去看下结果吧。

此时只需要验证一下OK了。JavaFxReadExcel 读取excel转换都上传github上,有兴趣请自行下载。农历pdf和excel包括转换后的文件也再项目中

公农历转换,数据正确性验证见下一篇博客,农历的那些事儿(二)

关于作者

© 著作权归作者所有

共有 人打赏支持
YougaKing
粉丝 6
博文 7
码字总数 6795
作品 0
西安
程序员
看到百度的那个万年历了吗,咱们也来做一个吧。

原创声明,转载请注明出处。 咱先来看看具体效果吧, https://dorsey.oss-cn-hangzhou.aliyuncs.com/PC/module/module/calendar.html 细心的你会发现好像只有这一天是初几,没有月份,嗯是的...

dorseyCh
07/11
0
0
MVP那些事儿(1) 用场景说话

目录 MVP那些事儿(1)……用场景说话 MVP那些事儿(2)……MVC架构初探 MVP那些事儿(3)……在Android中使用MVC(上) MVP那些事儿(4)……在Android中使用MVC(下) MVP那些事儿(5)……中介者模式...

叫我丹尼尔
2017/12/02
0
0
谈谈历法知识

新春期间,我忍不住又想到了一个老问题: 为什么每年春节的日期都不一样? 从2007年到2010年,春节的日期分别为2月18日、2月7日、1月26日、2月14日和2月3日。为什么会这样?到底是怎么计算的...

阮一峰
2009/01/26
0
0
UbuntuKylin 上的那些定制软件

UbuntuKylin 是Ubuntu 官方与中国的麒麟操作系统合作定制的中文Ubuntu衍生版。既然是中文定制版必然会提供一系列的适合中国人使用的软件应用。 Dash中的在线音乐搜索: 更加简单、方便的音乐搜...

罗树鹏
2013/03/19
3.5K
17
书荐——《项目管理那些事儿》

跟《项目经理成长手记》不同,这是一本类似于“最佳实践/解决方案”的书。这么说并不是说这真的是最佳的那个实践,而是说这本书记录的是:那个人(驱动者),在那个时候(环境/上下文),为了...

悟空太多啦
01/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

区块链100讲:盘点那些常用的加密算法原理

在开发过程中,常常用到各种加密方法和算法,本文总结了几种常用加密方法的原理。 1 对称加密 原理:加密和解密数据使用同一个密钥,适合对大量数据进行加解密 安全性:关键是密钥的保存方式...

HiBlock
21分钟前
0
0
zookeeper基本常识

一、Zookeeper基础知识 1 zookeeper是一个类似hdfs的树形文件结构,zookeeper可以用来保证数据在(zk)集群之间的数据的事务性一致。2 zookeeper有watch事件,是一次性触发的,当watch监视的数...

啃不动地大坚果
27分钟前
0
0
Forrester企业级容器平台权威排行出炉,小初创Rancher缘何成为领导者?

全球著名的调研机构Forrester Research近日发布了《The Forrester New Wave: Enterprise Container Platform Software Suites, Q4 2018》报告,对企业级容器平台(ECP)市场进行全面评估,希...

RancherLabs
30分钟前
0
0
【三 异步HTTP编程】 2. 流式HTTP响应

标准响应及Content-Length头 自HTTP1.1以来,服务器为了在一个链接中处理多个HTTP请求及响应,必须随response一起返回合适的Content-Length值。 默认情况下,对于简单请求你无需返回 Conten...

Landas
今天
0
0
Java后端技术栈,到底如何深入学习?

Java,是现阶段中国互联网公司中,覆盖度最广的研发语言。有不少朋友问,如何深入学习Java后端技术栈,今天分享一个,互联网牛人整理出来的Java深入学习路线图,以及免费学习资料。 一 。性能...

别打我会飞
今天
1
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部