在Spreadsheet :: ParseExcel中识别日期类型

时间:2014-12-17 00:18:42

标签: excel perl parsing spreadsheet

我们正在从基于MS Excel OLE的模块迁移到Spreadsheet::ParseExcel(或类似)。由于我们有数百个使用我们模块的程序,我们更倾向于提供替换,即返回的数据相同。

问题是日期 - 使用Excel我们得到一个类型为Win32::OLE::Variant的{​​{1}}对象。作为一种解决方法,我们可以通过检查VT_DATE并返回对象来手动构建它。

问题是类型设置不可靠,所以我们始终无法做到这一点。

$cell->type() eq 'Date'类型设置在两个地方。这是Date中使用的逻辑:

FmtDefault.pm

如果此检查失败并且我们获得if ( ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) ) || ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) ) { return "Date"; } ,那么它会在Numeric进行备份检查:

ParseExcel.pm

但是许多常见的格式字符串不起作用,例如:

if ( $FmtStr =~ m{^[dmy][-\\/dmy]*$}i ) {
    $rhKey{Type} = "Date";
}

我已经在openoffice.org检查了Excel规范,并且还阅读了http://jonvonderheyden.net/excel/a-comprehensive-guide-to-number-formats-in-excel/#date_code等指南,似乎以下规则将匹配日期格式字符串:

带有d,m或y字符的字符串,不在&#34;&#34;之间。或[],之前没有\,除非它是\\,而不是 - 或*。

这看起来非常复杂且容易出错。有更好的方法吗?

似乎[$-C09]dddd\\,\\ d\\ mmmm\\ yyyy;@ i.e. Sunday, 24 January 1982 d/m/yyyy;@ i.e. 24/1/1982 标记Spreadsheet::ParseExcel::Utility::ExcelFmt()下的日期格式,所以也许可以修改此逻辑以返回标志?但是,如果可能的话,我更愿意在不更改$format_mode模块的情况下准备好。

1 个答案:

答案 0 :(得分:2)

你知道哪些列应该是日期吗?

在我的使用中,我这样做,并将其转换为:

$val = $cell->unformatted();
# if it was properly set as a Date cell, the value will be a number of days since 1900 or 1904
# that we can convert to a date, regardless of the format they were shown.
if ( $val =~ /^[0-9]{5}(?:\.[0-9]+)?\z/ ) {
    $date = Spreadsheet::ParseExcel::Utility::ExcelFmt( 'YYYY-MM-DD', $val, $wb->{'Flg1904'} );
}
else {
    $val = $cell->value();
    $val =~ s/^'//;
    # try parsing it with Date::Manip, which handles all common formats (see its ParseDateString doc)
    use Date::Manip ();
    Date::Manip::Date_Init("TZ=GMT","DateFormat=US");
    $date = Date::Manip::UnixDate( $val, '%Y-%m-%d' );
}

更新:听起来你最好修改ExcelFmt,就像这样(未经测试):

--- Utility.pm.orig 2014-12-17 07:16:06.609942082 -0800
+++ Utility.pm  2014-12-17 07:18:14.453965764 -0800
@@ -69,7 +69,7 @@
 #
 sub ExcelFmt {

-    my ( $format_str, $number, $is_1904, $number_type, $want_subformats ) = @_;
+    my ( $format_str, $number, $is_1904, $number_type, $want_subformats, $want_format_mode ) = @_;

     # Return text strings without further formatting.
     return $number unless $number =~ $qrNUMBER;
@@ -956,8 +956,14 @@
     $result =~ s/^\$\-/\-\$/;
     $result =~ s/^\$ \-/\-\$ /;

-    # Return color and locale strings if required.
-    if ($want_subformats) {
+    # Return format mode and/or color and locale strings if required.
+    if ( $want_subformats && $want_format_mode ) {
+        return ( $result, $color, $locale, $format_mode );
+    }
+    elsif ($want_format_mode) {
+        return ( $result, $format_mode );
+    }
+    elsif ($want_subformats) {
         return ( $result, $color, $locale );
     }
     else {

请务必将其提交至maintainer以包含在以后的版本中。