识别电子表格中的日期类型::ParseExcel

识别电子表格中的日期类型::ParseExcel,excel,perl,parsing,spreadsheet,Excel,Perl,Parsing,Spreadsheet,我们正在从基于MS Excel OLE的模块迁移到电子表格::ParseExcel(或类似)。由于我们有数百个程序使用我们的模块,我们更希望我们提供一个替换,即返回的数据是相同的 问题是日期-使用Excel,我们得到类型为VT\u DATE的Win32::OLE::Variant对象。作为一种解决方法,我们可以通过检查$cell->type()eq'Date'并返回该对象来手动构造该对象 问题是类型设置不可靠,因此我们不能总是这样做。 日期类型在两个位置设置。这是FmtDefault.pm中使用

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

问题是日期-使用Excel,我们得到类型为
VT\u DATE
Win32::OLE::Variant
对象。作为一种解决方法,我们可以通过检查
$cell->type()eq'Date'
并返回该对象来手动构造该对象

问题是类型设置不可靠,因此我们不能总是这样做。

日期
类型在两个位置设置。这是
FmtDefault.pm
中使用的逻辑:

if (   ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) )
    || ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) )
{
    return "Date";
}
if ( $FmtStr =~ m{^[dmy][-\\/dmy]*$}i ) {
    $rhKey{Type} = "Date";
}
但是,许多常用格式字符串不起作用,例如:

[$-C09]dddd\\,\\ d\\ mmmm\\ yyyy;@ i.e. Sunday, 24 January 1982
d/m/yyyy;@ i.e. 24/1/1982
我已经在openoffice.org上查看了Excel规范,还阅读了一些指南,例如,下面的规则似乎与日期格式字符串匹配:

带有d、m或y字符的字符串,不在“”或[]之间,除非它是\\,否则前面不带\且后面不带-或*

这似乎非常复杂且容易出错。有更好的方法吗?


似乎
电子表格::ParseExcel::实用工具::ExcelFmt()
$format\u模式下标记日期格式
,因此可能可以修改此逻辑以返回该标记?但是如果可能的话,我更喜欢不改变
电子表格::ParseExcel
模块就可以使用的东西。

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

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

$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,类似这样(未经测试):


请务必将其提交给,以便在以后的版本中包含。

不幸的是,它完全是任意的。现有的代码库只是读取Excel并将每一行作为由列名键入的值的散列返回。我们在变量上使用“ref”或类似方法检测日期,并在需要时调用->Date(…)对其进行格式化。对于新的工作,我们当然可以要求程序员提供一个类型,但它不适用于遗留代码库。感谢我倾向于这样做,可能使用$$date\u格式来避免修改返回值。我会看看是否有其他人有更好的想法,否则我会很快接受。
--- 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 {