一. 前言
我在读取客户提供的excel中发现某几列时间是数值类型,最开始还以为客户给错了,最后才发现这属于一种时间格式,一起来看看如果遇到这种该怎么处理吧
二. 分析这种时间
假如在我们excel中有一列数据,我们需要读取出来,使用POI读取一下试试
1 //获取字符串 2 public static String getCellValueString(Cell cell) { 3 if (cell == null) return ""; 4 cell.setCellType(CellType.STRING); 5 return cell.getRichStringCellValue().getString().trim(); 6 } 7 //获取时间 8 public static Long getCellValueLong(Cell cell) throws Exception { 9 if (cell == null) return null; 10 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 11 Date cellD = cell.getDateCellValue(); 12 if (cellD == null) return null; 13 long res = cellD.getTime(); 14 String format = simpleDateFormat.format(res); 15 Date parse = simpleDateFormat.parse(format); 16 // Long long1 = Long.valueOf(format); 17 return parse.getTime(); 18 } 19 public static void main(String[] args){ 20 String path = "时间测试.xlsx"; 21 try { 22 FileInputStream fileInputStream = new FileInputStream(new File(path)); 23 Map<String, Integer> titleIndexMap = new HashMap<>(); 24 XSSFWorkbook hssfWorkbook = new XSSFWorkbook(fileInputStream); 25 XSSFSheet sheet = hssfWorkbook.getSheetAt(0); 26 XSSFRow titleRow = sheet.getRow(0); 27 int lastRowNum = sheet.getLastRowNum(); 28 for (int j = 0; j <= titleRow.getLastCellNum(); j++) { 29 titleIndexMap.put(getCellValueString(titleRow.getCell(j)), j); 30 } 31 String time1 = ""; 32 Long time2 = null; 33 for (int k = 1; k <= lastRowNum; k++) { 34 XSSFRow rowTemp = sheet.getRow(k); 35 if (null == rowTemp) { 36 continue; 37 } 38 time1 = getCellValueString(rowTemp.getCell(titleIndexMap.get("日期"))); 39 System.out.println(time1); 40 //time2 = getCellValueLong(rowTemp.getCell(titleIndexMap.get("日期"))); 41 //System.out.println(time2); 42 } 43 hssfWorkbook.close(); 44 fileInputStream.close(); 45 }catch (Exception e){ 46 e.printStackTrace(); 47 } 49 }
第一种通过读取字符串来读取,结果如下
我们可以看到是数字,这种时间类型当时可能不太理解,这里我们可以直接用第二种Long类型来读取,如果读取出来是时间戳,那么就不需要转换,但是有些时候excel的数据就是这些数字,这时候就必须开始转换了,如果在强行读取会报错,下边看看如何转换,提供两个方法,两种方式都可以
三.转换数字类型时间为时间戳
1 public static String getDateByString(String value){ 2 SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd"); 3 //Excel读取日期读到全为数字,数字是从1900年到该日期的天数 4 if(value.matches("^[0-9]+$")){ 5 Long dayNum=Long.valueOf(value); 6 //获取初始时间 7 Calendar calendar=new GregorianCalendar(1900,0,-1); 8 Date initDate=calendar.getTime(); 9 //获取相差秒数 10 Long addTime=dayNum*24*60*60*1000; 11 //得到当前时间 12 Long time=initDate.getTime()+addTime; 13 Date actualDate=new Date(time); 14 return simpleDateFormat.format(actualDate); 15 } 16 //if(value.contains("-")){ 17 // try{ 18 // Date temp=simpleDateFormat.parse(value); 19 // return simpleDateFormat.format(temp); 20 // }catch (Exception e){ 21 // e.printStackTrace(); 22 // } 23 //} 24 //if(value.contains("无")){ 25 // return ""; 26 //} 27 //return ""; 28 return ""; 29 } 30 public static String HSSFDateFormat(String value){ 31 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 32 //这里使用POI自带方法传入数字,自动转换为Date 33 Date javaDate = HSSFDateUtil.getJavaDate(Double.parseDouble(value)); 34 //System.out.println(javaDate.getTime()); 35 String format = simpleDateFormat.format(javaDate); 36 return format; 37 }
这里我调用这两个方法,看看效果
传入的参数就是读取到的第一个数字日期,2016-3-5
结果就是格式化后的String类型的日期,时间戳同理,这里我们就可以存入数据库或者其他的操作了
四. 大家可能不知道这种时间是如何出现,简单说一下,如果有兴趣,可以看一下
这个时间是1900年1月1日到某个日期经过了多少天,例如1900-1-1到2016-3-5经过了42434天,要考虑到平闰年的差值,那么我们可以简单得出一个理论
我们推断一个算法,X=当前年 Y=当前月 N=当前日 Z = (X-1900)中闰年的数量 那么我们需要 (X-1900)*365 + Z + Y(闰年中当前月需要判断月份)+ N 即可
下边用代码实现,大部分内容为 https://blog.csdn.net/weixin_49689284/article/details/108168783 其中做了一些修改
1 public static void main(String[] args) { 2 //Scanner sc = new Scanner(System.in); 3 //System.out.println("输入年份:"); 4 //int year = sc.nextInt(); 5 //System.out.println("输入月份:"); 6 //int month = sc.nextInt(); 7 //System.out.println("输入日期:"); 8 //int days = sc.nextInt(); 9 int year = 2020; 10 int month = 5; 11 int days = 20; 12 /*1,年:(闰年能将4整除,不能将100整除) 13 1.1,按平年算,每年365天 14 1.2,每个闰年加1天,若输入的那年是闰年,2月后,要加1天,反之不用*/ 15 int yDays = (year -1900)*365; 16 17 int rDays = 0;//每个润年加1 18 for (int i = 1900; i <=year ; i++) { 19 if (DateUtil.isLeapYear(i)) { 20 rDays++; 21 if (month < 3) {//若输入的年份为润,判断其是否过了2月,没过减1 22 rDays = rDays - 1; 23 } 24 } 25 } 26 27 /*2,月:按照平年每个月的天数:31,28,31,30,31,30,31,31,30,31,30,31*/ 28 int[] months = {31,28,31,30,31,30,31,31,30,31,30,31}; 29 int mDays = 0; 30 //如果当前 年是闰年并且月份大于3,那么月份需要先累加+1 31 if(DateUtil.isLeapYear(year)&&month>3){ 32 mDays++; 33 } 34 if (month == 1){//如果等于1月份,不算月份直接加天数即可 35 mDays = 0; 36 }else{ 37 for (int i = 0; i <month-1 ; i++){ //减1,因为当月没过,按下面的日期来算 38 mDays += months[i]; //累加当月之前的天数 39 } 40 } 41 /*4,日期: 天数直接相加*/ 42 int sum = yDays + rDays + mDays +days; 43 System.out.println(yDays); 44 System.out.println(rDays); 45 System.out.println(mDays); 46 System.out.println(days); 47 System.out.println(sum); 48 }
//改用DataUtil判断平润,下边是maven
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.9</version>
</dependency>
可以用前边的代码,验证一下