Excel 日期时间格式讲解
来源:互联网 发布:除螨仪有用吗 知乎 编辑:程序博客网 时间:2024/05/22 10:22
1.Excel中日期时间
1.1 存储格式
- Excel中日期时间格式单元格类型为Numeric,表示Excel日期时间内部以double数值存储
- Excel中日期时间以浮点值存储,以1900-01-01 00:00:00为起点
- 浮点值整数部分代表日期,表示自1900-01-01起的天数
- 浮点值小数部分代表时间
- 浮点值1.0表示1900-01-01 00:00:00
Excel提供了将浮点值d转换为日期时间date的方法
a. d在区间(-~, 0) 表示无效日期时间
b. d在区间[0, 1) 转换为 日期时间区间[1899-12-31 00:00:00, 1900-01-01 00:00:00)
c. d在区间[1, +~) 转换为 日期时间区间[1900-01-01 00:00:00, yyyy-MM-dd HH:mm:ss)Excel提供了将日期时间date转换为浮点值d的方法
a. date在区间(-~, 1900-01-01 00:00:00) 转换为 d = -1,表示无效日期时间
b. date = 1900-01-01 00:00:00 转换为 d = 1.0
c. date在区间(1900-01-01 00:00:00, +~) 转换为 d > 1.0
1.2 日期时间转double方法
org.apache.poi.ss.usermodel.DateUtil
/** * 将一个给的的日期转换为一个double类型的数值,代表日期在Excel内部的表现形式 * double的整数部分表示自1900年1月1日以来的天数,小数表示时分秒 * @param date : date * @param use1904windowing : true-使用1904年的日期窗口,false-使用1900年的日期窗口 * @return 返回日期的Excel表示(如果错误 -检查小于0.1, 返回-1) * */public static double getExcelDate(Date date) // 默认使用1900窗口public static double getExcelDate(Date date, boolean use1904windowing)
1.3 日期时间转double实例
package org.apache.poi.util;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.poi.ss.usermodel.DateUtil;public class Date2DoubleTest { public static void main(String[] args) throws Exception { System.out.println("小于1900-01-01 00:00:00的日期返回-1"); System.out.println("日期1800-01-01 00:00:00 转换为double值为: " + formatDouble("1800-01-01 00:00:00")); System.out.println("日期1899-01-01 00:00:00 转换为double值为: " + formatDouble("1899-01-01 00:00:00")); System.out.println("日期1899-12-31 23:24:25 转换为double值为: " + formatDouble("1899-12-31 23:24:25")); System.out.println("日期1900-01-01 00:00:00 转换为double值为: " + formatDouble("1900-01-01 00:00:00")); System.out.println("日期1900-01-01 11:11:11 转换为double值为: " + formatDouble("1900-01-01 11:11:11")); System.out.println("日期1900-01-01 22:22:22 转换为double值为: " + formatDouble("1900-01-01 22:22:22")); System.out.println("日期1900-01-01 23:22:22 转换为double值为: " + formatDouble("1900-01-01 23:22:22")); System.out.println("日期1900-01-02 00:00:00 转换为double值为: " + formatDouble("1900-01-02 00:00:00")); System.out.println("日期1900-01-03 00:00:00 转换为double值为: " + formatDouble("1900-01-03 00:00:00")); System.out.println("日期2017-11-12 13:14:15 转换为double值为: " + formatDouble("2017-11-12 13:14:15")); } public static double formatDouble (String dateStr) throws Exception { SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = dateFormat2.parse(dateStr); return formatDouble(date); } /** * 将java.util.Date转换为double值 * */ public static double formatDouble (Date date) { double excelDate = DateUtil.getExcelDate(date); return excelDate; }}
执行结果:
小于1900-01-01 00:00:00的日期返回-1日期1800-01-01 00:00:00 转换为double值为: -1.0日期1899-01-01 00:00:00 转换为double值为: -1.0日期1899-12-31 23:24:25 转换为double值为: -1.0日期1900-01-01 00:00:00 转换为double值为: 1.0日期1900-01-01 11:11:11 转换为double值为: 1.466099537037037日期1900-01-01 22:22:22 转换为double值为: 1.9321990740740742日期1900-01-01 23:22:22 转换为double值为: 1.9738657407407407日期1900-01-02 00:00:00 转换为double值为: 2.0日期1900-01-03 00:00:00 转换为double值为: 3.0日期2017-11-12 13:14:15 转换为double值为: 43051.5515625
1.4 double转日期时间方法
org.apache.poi.ss.usermodel.DateUtil
/** * 将一个double类型的数值根据Excel内部日期格式转换为一个java.util.Date * * 注意: * Excel日期和时间存储没有任何时区(TimeZone)信息 * 如果默认的TimeZone使用了夏令时(Daylight Saving Time),则转换回Excel日期可能不会产生相同的值 * * @param date Excel内部日期值,一个double类型的数值 * @param use1904windowing true-使用1904年的日期窗口,false-使用1900年的日期窗口 * @param tz 对应的时区,如果为null,使用系统默认时区 * @param roundSeconds 是否round最接近的秒,默认false * @return 日期的Java表示形式,如果日期不是有效的Excel日期,则为null * */public static Date getJavaDate(double date)public static Date getJavaDate(double date, boolean use1904windowing)public static Date getJavaDate(double date, TimeZone tz) // 使用时区tz去格式化日期public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz)public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz, boolean roundSeconds)
1.5 double转日期时间实例
package org.apache.poi.util;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.poi.ss.usermodel.DateUtil;public class Double2DateTest { public static void main(String[] args) { /** * double转换为java.util.Date * */ System.out.println("double : -1.0 转换为日期时间为: " + formatDate(-1)); System.out.println("double : 0.00000000000001 转换为日期时间为: " + formatDate(0.00000000000001)); System.out.println("double : 0.55555555555555 转换为日期时间为: " + formatDate(0.55555555555555)); System.out.println("double : 0.77777777777777 转换为日期时间为: " + formatDate(0.77777777777777)); System.out.println("double : 1.0 转换为日期时间为: " + formatDate(1.0)); System.out.println("double : 1.466099537037037 转换为日期时间为: " + formatDate(1.466099537037037)); System.out.println("double : 1.9321990740740742 转换为日期时间为: " + formatDate(1.9321990740740742)); System.out.println("double : 1.9738657407407407 转换为日期时间为: " + formatDate(1.9738657407407407)); System.out.println("double : 2.0 转换为日期时间为: " + formatDate(2.0)); System.out.println("double : 3.0 转换为日期时间为: " + formatDate(3.0)); System.out.println("double : 43051.5515625 转换为日期时间为: " + formatDate(43051.5515625)); } /** * 将double值转换为java.util.Date * 1. 负数 -> 小于0,表示无效日期 * 2. 1 -> 1900-1-1 00:00:00 * 3. 43081.5091898148 -> 2017-12-12 12:13:14 * @param value * */ public static String formatDate(double value) { if (!DateUtil.isValidExcelDate(value)) { // value<0表示是无效日期 return "小于0,表示无效日期"; } // HH表示24进制,hh是12进制 return formatDate(value, "yyyy-MM-dd HH:mm:ss"); } public static String formatDate(double value, String formatString) { SimpleDateFormat sdf = new SimpleDateFormat(formatString);// Date date = DateUtil.getJavaDate(value); // 以1900-1-1 00:00::00为起点 Date date = DateUtil.getJavaDate(value, false); // 以1900-1-1 00:00::00为起点// Date date = DateUtil.getJavaDate(value, true); return sdf.format(date); }}
执行结果:
以1900-1-1 00:00:00为起点
double : -1.0 转换为日期时间为: 小于0,表示无效日期double : 0.00000000000001 转换为日期时间为: 1899-12-31 00:00:00double : 0.55555555555555 转换为日期时间为: 1899-12-31 13:20:00double : 0.77777777777777 转换为日期时间为: 1899-12-31 18:40:00double : 1.0 转换为日期时间为: 1900-01-01 00:00:00double : 1.466099537037037 转换为日期时间为: 1900-01-01 11:11:11double : 1.9321990740740742 转换为日期时间为: 1900-01-01 22:22:22double : 1.9738657407407407 转换为日期时间为: 1900-01-01 23:22:22double : 2.0 转换为日期时间为: 1900-01-02 00:00:00double : 3.0 转换为日期时间为: 1900-01-03 00:00:00double : 43051.5515625 转换为日期时间为: 2017-11-12 13:14:15
2.Excel日期单元格样式
- Excel支持日期单元格
- 日期值对应的是Excel内部日期double值的证书部分,表示自1900-1-1以来的天数
2.1 Excel日期样式
使用Excel或WPS设置单元格样式,会看到已经定义了日期样式
2.1.1 对话框-已定义日期样式
2.1.2 对话框-自定义日期样式
2.2 Excel中已定义日期样式
[$-804]表示国家或地区(语言)编号,一般可以不填。如804 汉语 (中国)809 英语(英国)409 英语(美国)如果电脑上没有装相应的语言(可以设),把804改掉都不会影响显示结果。[$-F800]相对于是 yyyy-m-d"[$-F400]相对于是 h:mm:ss[dbnum1]是将阿拉伯数字转换为汉字,如:123转换为一二三[dbbun2]是转换成大写汉字,如:123转换为壹贰叁[dbnum3]是转换为全角数字,如:123转换为 123d代表日期之中的日,m日期中的月,y日期中的年,h日期中的小时,m日期中的分,s是日期中的秒[$-F800]dddd, mmmm dd, yyyy[DBNum1][$-804]yyyy"年"m"月"d"日";@[DBNum1][$-804]yyyy"年"m"月";@[DBNum1][$-804]m"月"d"日";@yyyy"年"m"月"d"日";@yyyy"年"m"月";@m"月"d"日";@[$-804]aaaa;@[$-804]aaa;@yyyy/m/d;@[$-409]yyyy/m/d h:mm AM/PM;@yyyy/m/d h:mm;@yy/m/d;@m/d;@m/d/yy;@mm/dd/yy;@[$-409]d-mmm;@[$-409]d-mmm-yy;@[$-409]dd-mmm-yy;@[$-409]mmm-yy;@[$-409]mmmm-yy;@[$-409]mmmm-yy;@[$-409]mmmmm;@[$-409]mmmmm-yy;@
2.3 Excel 2007中日期样式存储格式
2.3.1 当前Sheet日期单元格
2.3.2 当前Sheet存储XML
2.3.3 当前Sheet单元格样式存储XML
2.4 验证日期样式字符串
org.apache.poi.ss.usermodel.DateUtil提供方法验证
package org.apache.poi.util;import org.apache.poi.ss.usermodel.DateUtil;/** * 验证Excel中已定义的日期格式 * org.apache.poi.ss.usermodel.DateUtil * * [$-804]表示国家或地区(语言)编号,一般可以不填。 * 如804 汉语 (中国) * 809 英语(英国) * 409 英语(美国) * 如果电脑上没有装相应的语言(可以设),把804改掉都不会影响显示结果。 * * [$-F800]相对于是 yyyy-m-d" * [$-F400]相对于是 h:mm:ss * * [dbnum1]是将阿拉伯数字转换为汉字,如:123转换为一二三 * [dbbun2]是转换成大写汉字,如:123转换为壹贰叁 * [dbnum3]是转换为全角数字,如:123转换为 123 * d代表日期之中的日,m日期中的月,y日期中的年,h日期中的小时,m日期中的分,s是日期中的秒 * */public class DateFormatTest { public static void main(String[] args) { System.out.println("字符串 - [$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy 是否是日期格式: " + DateUtil.isADateFormat(176, "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy")); System.out.println("字符串 - [DBNum1][$-804]yyyy\"年\"m\"月\"d\"日 是否是日期格式: " + DateUtil.isADateFormat(177, "[DBNum1][$-804]yyyy\"年\"m\"月\"d\"日")); System.out.println("字符串 - [DBNum1][$-804]yyyy\"年\"m\"月\";@ 是否是日期格式: " + DateUtil.isADateFormat(178, "[DBNum1][$-804]yyyy\"年\"m\"月\";@")); System.out.println("字符串 - [DBNum1][$-804]m\"月\"d\"日\";@ 是否是日期格式: " + DateUtil.isADateFormat(179, "[DBNum1][$-804]m\"月\"d\"日\";@")); System.out.println("字符串 - yyyy\"年\"m\"月\"d\"日\";@ 是否是日期格式: " + DateUtil.isADateFormat(180, "yyyy\"年\"m\"月\"d\"日\";@")); System.out.println("字符串 - yyyy\"年\"m\"月\";@ 是否是日期格式: " + DateUtil.isADateFormat(181, "yyyy\"年\"m\"月\";@")); System.out.println("字符串 - m\"月\"d\"日\";@ 是否是日期格式: " + DateUtil.isADateFormat(182, "m\"月\"d\"日\";@")); System.out.println("字符串 - [$-804]aaaa;@ 是否是日期格式: " + DateUtil.isADateFormat(183, "[$-804]aaaa;@")); System.out.println("字符串 - [$-804]aaa;@ 是否是日期格式: " + DateUtil.isADateFormat(184, "[$-804]aaa;@")); System.out.println("字符串 - yyyy/m/d;@ 是否是日期格式: " + DateUtil.isADateFormat(185, "yyyy/m/d;@")); System.out.println("字符串 - [$-409]yyyy/m/d\\ h:mm\\ AM/PM;@ 是否是日期格式: " + DateUtil.isADateFormat(186, "[$-409]yyyy/m/d\\ h:mm\\ AM/PM;@")); System.out.println("字符串 - yyyy/m/d\\ h:mm;@ 是否是日期格式: " + DateUtil.isADateFormat(187, "yyyy/m/d\\ h:mm;@")); System.out.println("字符串 - yy/m/d;@ 是否是日期格式: " + DateUtil.isADateFormat(188, "yy/m/d;@")); System.out.println("字符串 - m/d;@ 是否是日期格式: " + DateUtil.isADateFormat(189, "m/d;@")); System.out.println("字符串 - m/d/yy;@ 是否是日期格式: " + DateUtil.isADateFormat(190, "m/d/yy;@")); System.out.println("字符串 - mm/dd/yy;@ 是否是日期格式: " + DateUtil.isADateFormat(191, "mm/dd/yy;@")); System.out.println("字符串 - [$-409]d\\-mmm;@ 是否是日期格式: " + DateUtil.isADateFormat(192, "[$-409]d\\-mmm;@")); System.out.println("字符串 - [$-409]d\\-mmm\\-yy;@ 是否是日期格式: " + DateUtil.isADateFormat(193, "[$-409]d\\-mmm\\-yy;@")); System.out.println("字符串 - [$-409]dd\\-mmm\\-yy;@ 是否是日期格式: " + DateUtil.isADateFormat(194, "[$-409]dd\\-mmm\\-yy;@")); System.out.println("字符串 - [$-409]mmm\\-yy;@ 是否是日期格式: " + DateUtil.isADateFormat(195, "[$-409]mmm\\-yy;@")); System.out.println("字符串 - [$-409]mmmm\\-yy;@ 是否是日期格式: " + DateUtil.isADateFormat(196, "[$-409]mmmm\\-yy;@")); System.out.println("字符串 - [$-409]mmmmm;@ 是否是日期格式: " + DateUtil.isADateFormat(197, "[$-409]mmmmm;@")); System.out.println("字符串 - [$-409]mmmmm\\-yy;@ 是否是日期格式: " + DateUtil.isADateFormat(198, "[$-409]mmmmm\\-yy;@")); }}
执行结果:
字符串 - [$-F800]dddd\,\ mmmm\ dd\,\ yyyy 是否是日期格式: true字符串 - [DBNum1][$-804]yyyy"年"m"月"d"日 是否是日期格式: true字符串 - [DBNum1][$-804]yyyy"年"m"月";@ 是否是日期格式: true字符串 - [DBNum1][$-804]m"月"d"日";@ 是否是日期格式: true字符串 - yyyy"年"m"月"d"日";@ 是否是日期格式: true字符串 - yyyy"年"m"月";@ 是否是日期格式: true字符串 - m"月"d"日";@ 是否是日期格式: true字符串 - [$-804]aaaa;@ 是否是日期格式: false字符串 - [$-804]aaa;@ 是否是日期格式: false字符串 - yyyy/m/d;@ 是否是日期格式: true字符串 - [$-409]yyyy/m/d\ h:mm\ AM/PM;@ 是否是日期格式: true字符串 - yyyy/m/d\ h:mm;@ 是否是日期格式: true字符串 - yy/m/d;@ 是否是日期格式: true字符串 - m/d;@ 是否是日期格式: true字符串 - m/d/yy;@ 是否是日期格式: true字符串 - mm/dd/yy;@ 是否是日期格式: true字符串 - [$-409]d\-mmm;@ 是否是日期格式: true字符串 - [$-409]d\-mmm\-yy;@ 是否是日期格式: true字符串 - [$-409]dd\-mmm\-yy;@ 是否是日期格式: true字符串 - [$-409]mmm\-yy;@ 是否是日期格式: true字符串 - [$-409]mmmm\-yy;@ 是否是日期格式: true字符串 - [$-409]mmmmm;@ 是否是日期格式: true字符串 - [$-409]mmmmm\-yy;@ 是否是日期格式: true
3. Excel 时间单元格样式
- Excel单元格也支持时间单元格
- 时间值对应的是Excel内部时间double值的小数部分
3.1 Excel时间样式
使用Excel或WPS设置单元格样式,会看到已经定义了时间样式,我们主要讲解的就是这些时间样式:
3.1.1 对话框-已定义时间样式
3.1.2 对话框-自定义时间样式
3.2 Excel中已定义时间样式
两种设置时间样式一共有19种已经定义的时间样式,内置的时间样式索引小于50,自定义样式索引从164开始:
- 索引 时间样式字符串 - 18, "h:mm AM/PM" - 19, "h:mm:ss AM/PM" - 20, "h:mm" - 21, "h:mm:ss" - 22, "m/d/yy h:mm" - 45, "mm:ss" - 46, "[h]:mm:ss" - 47, "mm:ss.0" - - 176 [DBNum1][$-804]上午/下午h"时"mm"分";@ - 177 [DBNum1][$-804]h"时"mm"分";@ - 178 [$-409]h:mm:ss\ AM/PM;@ - 179 [$-409]h:mm\ AM/PM;@ - 180 [$-F400]h:mm:ss\ AM/PM - 181 h:mm;@ - 182 h:mm:ss;@ - 183 h"时"mm"分";@ - 184 h"时"mm"分"ss"秒";@ - 185 上午/下午h"时"mm"分";@ - 186 上午/下午h"时"mm"分"ss"秒";@
3.3 Excel 2007中时间样式存储格式
3.3.1 当前Sheet时间单元格
3.3.2 当前Sheet存储XML
3.3.3 当前Sheet单元格样式存储XML
3.4 验证时间样式字符串
提供方法实现验证一个单元格是否为一个时间单元格:
- 时间单元格原始值为double
- 时间单元格样式为时间字符串
这里提供方法解析单元格样式字符串,验证其是否为时间样式字符串,工具类:
package org.apache.poi.util;import java.util.regex.Pattern;/** * 主要用于处理导入excel中日期时间格式, * 参考org.apache.poi.ss.usermodel.DateUtil * */public class DateTimeUtil { protected DateTimeUtil() { // no instances of this class } // 描述无效的日期// private static final int BAD_DATE = -1; public static final int SECONDS_PER_MINUTE = 60; public static final int MINUTES_PER_HOUR = 60; public static final int HOURS_PER_DAY = 24; // 一天等于86400秒 public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE); // 一天等于86400 * 1000毫秒 public static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;// private static final Pattern TIME_SEPARATOR_PATTERN = Pattern.compile(":"); /** * 符号. : 匹配除换行符 \n 之外的任何单字符 * 符号* : 匹配前面的子表达式零次或多次 * 符号+ : 匹配前面的子表达式一次或多次 * 符号? : 匹配前面的子表达式零次或一次 * * *、 +限定符都是贪婪的,因为它们会尽可能多的匹配文字 * 通过在 *、 + 或 ? 限定符之后放置 ?(*?、 +?、 ??),该表达式从"贪心"表达式转换为"非贪心"表达式或者最小匹配 * */ // ^[\$\-.*?] : 匹配以[$-开头,中间为除换行符 \n 之外的任何单字符,结尾为]的字符串,非贪心匹配 private static final Pattern date_ptrn1 = Pattern.compile("^\\[\\$\\-.*?\\]"); /** * 红色 : \u7ea2\u8272 * 黑色 :\u9ed1\u8272 * 黄色 : \u9ec4\u8272 * 绿色 : \u7eff\u8272 * 白色 : \u9ed1\u8272 * 蓝色 : \u84dd\u8272 * 青色 : \u9752\u8272 * 洋红 : \u6d0b\u7ea2 * */ // ^[[a-zA-Z]+] : 匹配以[开头, ]结尾, 中间至少一个字母的字符串,如颜色 private static final Pattern date_ptrn2 = Pattern.compile("^\\[[a-zA-Z\u7ea2\u9ed1\u9ec4\u7eff\u84dd\u9752\u6d0b\u7ea2\u8272]+\\]"); // [yYmMdDhHsS] : 匹配中括号里任一字母, 匹配一个 private static final Pattern date_ptrn3a = Pattern.compile("[mhHsS]"); /** * 为中文/日文日期格式添加Unicode编码:如2017 \u5e74 2 \u6708 7 \u65e5 * Unicode编码 : 中文 * \u5e74 : 年 * \u6708 : 月 * \u65e5 : 日 * \u4e0a : 上 * \u4e0b : 下 * \u5348 : 午 * * ^[\[\]mhHsS\-T/时分秒(上午/下午),. :"\\]+0*[ampAMP/]*$ * */ private static final Pattern date_ptrn3b = Pattern.compile("^[\\[\\]yYmMdDhHsS\\-T/\u65f6\u5206\u79d2(\u4e0a\u5348/\u4e0b\u5348),. :\"\\\\]+0*[ampAMP/]*$"); // ^\[([hH]+|[mM]+|[sS]+)] : 匹配以[开头, 以]结尾, 中间为时、分或秒的时间字符 private static final Pattern date_ptrn4 = Pattern.compile("^\\[([hH]+|[mM]+|[sS]+)\\]"); // 匹配以[DBNum1]、[DBNum2]或[DBNum3]开头的中文日期 private static final Pattern date_ptrn5 = Pattern.compile("^\\[DBNum(1|2|3)\\]"); /** * 性能优化的变量: * 如果一个相同的日期格式字符串被多次传递,避免重复检查DataUtil.isADateFormat(int, String) * https://issues.apache.org/bugzilla/show_bug.cgi?id=55611 * */ private static ThreadLocal<Integer> lastFormatIndex = new ThreadLocal<Integer>() { protected Integer initialValue() { return -1; } }; private static ThreadLocal<String> lastFormatString = new ThreadLocal<String>(); private static ThreadLocal<Boolean> lastCachedResult = new ThreadLocal<Boolean>(); /** * 当前格式是否缓存过 * @param formatString 格式化字符串 * @param formatIndex 格式化索引 * */ private static boolean isCached(String formatString, int formatIndex) { String cachedFormatString = lastFormatString.get(); return cachedFormatString != null && formatIndex == lastFormatIndex.get() && formatString.equals(cachedFormatString); } /** * 缓存当前格式 * @param formatString 格式化字符串 * @param formatIndex 格式化索引 * @param cached 是否已经缓存过 * */ private static void cache(String formatString, int formatIndex, boolean cached) { lastFormatIndex.set(formatIndex); lastFormatString.set(formatString); lastCachedResult.set(Boolean.valueOf(cached)); } /** * 检查给定格式ID及其格式String是否表示时间格式。 * 1. 调用此方法之前org.apache.poi.ss.usermodel.DateUtil.isADateFormat(formatIndex, formatString) * 首先确保是一个日期格式 * 2. 再检查是否为时间格式 * * @param formatIndex 格式索引 * @param formatString 格式字符串 */ public static boolean isADateTimeFormat(int formatIndex, String formatString) { if(isInternalDateTimeFormat(formatIndex)) { cache(formatString, formatIndex, true); return true; } if(formatString == null || formatString.length() == 0) { return false; } // 检查是否缓存过,提高性能 if (isCached(formatString, formatIndex)) { return lastCachedResult.get(); } String fs = formatString; final int length = fs.length(); StringBuilder sb = new StringBuilder(length); for (int i = 0; i < length; i++) { char c = fs.charAt(i); if (i < length - 1) { char nc = fs.charAt(i + 1); if (c == '\\') {// 处理转义字符 switch (nc) { case '-': // \-表示 case ',': case '.': case ' ': case '\\': // skip current '\' and continue to the next char continue; } } else if (c == ';' && nc == '@') {// 跳过;@ i++; continue; } } sb.append(c); } fs = sb.toString(); // short-circuit if it indicates elapsed time: [h], [m] or [s] if(date_ptrn4.matcher(fs).matches()){ cache(formatString, formatIndex, true); return true; } // 处理以[DBNum1]、 [DBNum2]或[DBNum3]开头的时间格式:[DBNum1][$-804]h"时"mm"分";@ fs = date_ptrn5.matcher(fs).replaceAll(""); // 处理匹配[$-...]的时间格式:[$-F400]h:mm:ss\ AM/PM fs = date_ptrn1.matcher(fs).replaceAll(""); // 匹配以[开头, ]结尾, 中间至少一个字母的字符串,如带颜色的时间格式:[Yellow]h:mm:ss AM/PM fs = date_ptrn2.matcher(fs).replaceAll(""); // 日期格式为dd / mm / yy; [red] dd / mm / yy,只处理第一个 final int separatorIndex = fs.indexOf(';'); if(0 < separatorIndex && separatorIndex < fs.length()-1) { fs = fs.substring(0, separatorIndex); } // 处理时间格式 if (! date_ptrn3a.matcher(fs).find()) { return false; } /** * 到了这里,检查它只是由以下组成: m h s - \ /,。 :[] T * 可选地跟随AM / PM * */ boolean result = date_ptrn3b.matcher(fs).matches(); cache(formatString, formatIndex, result); return result; } /** * 给定的日期格式索引是否为Excel内置日期时间格式 * @param format 日期格式索引 */ public static boolean isInternalDateTimeFormat(int format) { switch(format) { // Excel内部时间格式 // 0x12, "h:mm AM/PM" // 0x13, "h:mm:ss AM/PM" // 0x14, "h:mm" // 0x15, "h:mm:ss" // 0x16, "m/d/yy h:mm" // 0x2d, "mm:ss" // 0x2e, "[h]:mm:ss" // 0x2f, "mm:ss.0" case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x2d: case 0x2e: case 0x2f: return true; } return false; } /** * 检查给定的double数值是否是有效的Excel日期 * value>=0,表示是有效日期 */ public static boolean isValidExcelDate(double value) { return (value > -Double.MIN_VALUE); } /************************ 以下是org.apache.poi.ss.usermodel.DateUtil常用方法 ******************************/ /** * 将一个给的的日期转换为一个double类型的数值,代表日期在Excel内部的表现形式 * double的整数部分表示自1900年1月1日以来的天数,小数表示时分秒 * @param date : date * @param use1904windowing : true-使用1904年的日期窗口,false-使用1900年的日期窗口 * @return 返回日期的Excel表示(如果错误 -检查小于0.1, 返回-1) * */// public static double getExcelDate(Date date) // 默认使用1900窗口// public static double getExcelDate(Date date, boolean use1904windowing) /** * 将一个double类型的数值根据Excel内部日期格式转换为一个java.util.Date * * 注意: * Excel日期和时间存储没有任何时区(TimeZone)信息 * 如果默认的TimeZone使用了夏令时(Daylight Saving Time),则转换回Excel日期可能不会产生相同的值 * * @param date Excel内部日期值,一个double类型的数值 * @param use1904windowing true-使用1904年的日期窗口,false-使用1900年的日期窗口 * @param tz 对应的时区,如果为null,使用系统默认时区 * @param roundSeconds 是否round最接近的秒,默认false * @return 日期的Java表示形式,如果日期不是有效的Excel日期,则为null * */// public static Date getJavaDate(double date)// public static Date getJavaDate(double date, boolean use1904windowing)// public static Date getJavaDate(double date, TimeZone tz) // 使用时区tz去格式化日期// public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz)// public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz, boolean roundSeconds) /** * 将一个格式为HH:MM或HH:MM:SS的时间字符串转换为Excel日期格式的double数值,一个小数 * @param timeStr 如12:12、 12:12:12,timeStr长度小于4或大于8都会抛出异常 * @return 返回一个0~1之间的数 */// public static double convertTime(String timeStr)// private static double convertTimeInternal(String timeStr)}
测试类:
package org.apache.poi.util;/** * * 索引 时间样式字符串 * 18, "h:mm AM/PM" * 19, "h:mm:ss AM/PM" * 20, "h:mm" * 21, "h:mm:ss" * 22, "m/d/yy h:mm" * 45, "mm:ss" * 46, "[h]:mm:ss" * 47, "mm:ss.0" * * 176 [DBNum1][$-804]上午/下午h"时"mm"分";@ * 177 [DBNum1][$-804]h"时"mm"分";@ * 178 [$-409]h:mm:ss\ AM/PM;@ * 179 [$-409]h:mm\ AM/PM;@ * 180 [$-F400]h:mm:ss\ AM/PM * 181 h:mm;@ * 182 h:mm:ss;@ * 183 h"时"mm"分";@ * 184 h"时"mm"分"ss"秒";@ * 185 上午/下午h"时"mm"分";@ * 186 上午/下午h"时"mm"分"ss"秒";@ * */public class TimeFormatTest { public static void main(String[] args) { System.out.println("Excel已定义时间格式字符串: "); System.out.println("字符串 - h:mm AM/PM 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(18, "h:mm AM/PM")); System.out.println("字符串 - h:mm:ss AM/PM 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(19, "h:mm:ss AM/PM")); System.out.println("字符串 - h:mm 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(20, "h:mm")); System.out.println("字符串 - h:mm:ss 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(21, "h:mm:ss")); System.out.println("字符串 - m/d/yy h:mm 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(22, "m/d/yy h:mm")); System.out.println("字符串 - mm:ss 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(45, "mm:ss")); System.out.println("字符串 - [h]:mm:ss 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(46, "[h]:mm:ss")); System.out.println("字符串 - mm:ss.0 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(47, "mm:ss.0")); System.out.println("字符串 - [DBNum1][$-804]上午/下午h\"时\"mm\"分\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(176, "[DBNum1][$-804]上午/下午h\"时\"mm\"分\";@")); System.out.println("字符串 - [DBNum1][$-804]h\"时\"mm\"分\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(177, "[DBNum1][$-804]h\"时\"mm\"分\";@")); System.out.println("字符串 - [$-409]h:mm:ss\\ AM/PM;@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(178, "[$-409]h:mm:ss\\ AM/PM;@")); System.out.println("字符串 - [$-409]h:mm\\ AM/PM;@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(179, "[$-409]h:mm\\ AM/PM;@")); System.out.println("字符串 - [$-F400]h:mm:ss\\ AM/PM 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(180, "[$-F400]h:mm:ss\\ AM/PM")); System.out.println("字符串 - h:mm;@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(181, "h:mm;@")); System.out.println("字符串 - h:mm:ss;@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(182, "h:mm:ss;@")); System.out.println("字符串 - h\"时\"mm\"分\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(183, "h\"时\"mm\"分\";@")); System.out.println("字符串 - h\"时\"mm\"分\"ss\"秒\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(184, "h\"时\"mm\"分\"ss\"秒\";@")); System.out.println("字符串 - 上午/下午h\"时\"mm\"分\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(185, "上午/下午h\"时\"mm\"分\";@")); System.out.println("字符串 - 上午/下午h\"时\"mm\"分\"ss\"秒\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(186, "上午/下午h\"时\"mm\"分\"ss\"秒\";@")); System.out.println(); System.out.println("Excel自定义时间格式字符串:"); System.out.println("字符串 - [红色]上午/下午h\"时\"mm\"分\"ss\"秒\";@ 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(187, "[红色]上午/下午h\"时\"mm\"分\"ss\"秒\";@")); System.out.println("字符串 - [绿色]yyyy/mm/dd hh:mm 是否是时间格式: " + DateTimeUtil.isADateTimeFormat(188, "[绿色]yyyy/mm/dd hh:mm")); }}
执行结果:
Excel已定义时间格式字符串: 字符串 - h:mm AM/PM 是否是时间格式: true字符串 - h:mm:ss AM/PM 是否是时间格式: true字符串 - h:mm 是否是时间格式: true字符串 - h:mm:ss 是否是时间格式: true字符串 - m/d/yy h:mm 是否是时间格式: true字符串 - mm:ss 是否是时间格式: true字符串 - [h]:mm:ss 是否是时间格式: true字符串 - mm:ss.0 是否是时间格式: true字符串 - [DBNum1][$-804]上午/下午h"时"mm"分";@ 是否是时间格式: true字符串 - [DBNum1][$-804]h"时"mm"分";@ 是否是时间格式: true字符串 - [$-409]h:mm:ss\ AM/PM;@ 是否是时间格式: true字符串 - [$-409]h:mm\ AM/PM;@ 是否是时间格式: true字符串 - [$-F400]h:mm:ss\ AM/PM 是否是时间格式: true字符串 - h:mm;@ 是否是时间格式: true字符串 - h:mm:ss;@ 是否是时间格式: true字符串 - h"时"mm"分";@ 是否是时间格式: true字符串 - h"时"mm"分"ss"秒";@ 是否是时间格式: true字符串 - 上午/下午h"时"mm"分";@ 是否是时间格式: true字符串 - 上午/下午h"时"mm"分"ss"秒";@ 是否是时间格式: trueExcel自定义时间格式字符串:字符串 - [红色]上午/下午h"时"mm"分"ss"秒";@ 是否是时间格式: true字符串 - [绿色]yyyy/mm/dd hh:mm 是否是时间格式: true
4.注意
4.1 只有时间
- 在Excel一个Sheet单元格中输入:11:12:13
- 设置单元格样式为时间:h:mm:ss;@
- 11:12:13单元格为Numeric类型,以double值存储,不是一个字符串单元格
因为只有时间,而没有日期,所以double只有小数,整部部分为0,存储的值是一个小于1的数。
当前Sheet的时间单元格:
存储:
4.2 日期小于1900-1-1
- 一个单元格为:1899/12/31,一个为:1900/1/1
- 设置单元格样式为日期:yyyy”年”m”月”d”日”;@
- 1899/12/31会以字符串存储,日期样式不起效
- 1900/1/1会以double值存储,日期样式起效,显示为1900年1月1日
- sheet1.xml存储Sheet单元格信息
- SharedStrings.xml存储Excel中所有Sheet字符型单元格的文本值
- styles.xml存储Excel中所有Sheet的所有单元格样式信息
- Excel 日期时间格式讲解
- 用EXCEL实现时间戳格式和日期格互转
- EXCEL 日期格式
- Excel中文日期格式
- excel日期格式
- EXCEL 修改日期格式
- 时间日期格式-国家标准
- 时间日期格式-ISO8601
- 时间日期格式-W3C
- 时间和日期格式
- 日期时间格式
- Java日期时间格式
- Sql日期时间格式
- 日期时间格式说明
- 日期时间格式处理
- SimpleDateFormat日期时间格式
- 时间日期格式转换
- 时间日期格式
- SQL Server的作业中用PowerShell调用bat文件简单Demo
- Android 资源混淆工具
- 配置邮件客户端(无SSL/TLS加密)
- Linux 安装gcc
- 英伟达tk1板的串口数据收发出错问题
- Excel 日期时间格式讲解
- 数据科学虚拟机镜像正式上线
- 模糊C均值聚类算法
- 51nod 1043 幸运号码 数位dp
- JavaWeb从入门到放弃(9)-实现一个客户端上传文件到服务端
- CreateFileMappingW x64 位调用方法
- Linux 中断上下文为什么不允许睡眠?
- poj2195 Going Home KM算法
- python3中format函数