【问题标题】:Convert serial value to date in perl将串行值转换为迄今为止
【发布时间】:2014-09-13 10:49:16
【问题描述】:

我在 Linux 上使用 Spreadsheet::XLSX 将 XLSX 转换为 CSV。 自定义日期字段正在转换为数字。我知道 XLSX 将自定义日期存储为序列值。我需要找到将这些值转换为日期/时间的方法。

例子:

CSV:  40829
XLSX: 10/13/2011 0:00

所以我想弄清楚如何将40829 转换为10/13/2011 0:00

我做了一些研究,但找不到任何 (Perl) 解决方案。 如果需要,我可以提供代码。

请指教。

谢谢你, -安德烈

【问题讨论】:

    标签: perl date csv xlsx


    【解决方案1】:

    Excel 将日期和时间存储为一个数字,表示自 1900-Jan-0 以来的天数,加上一天 24 小时的小数部分:ddddd.tttttt

    您可以编写一个函数来自己进行计算,或者您可以查看 cpan 上已经发布的一些模块来执行此操作,DateTime::Format::Excel 应该可以满足您的需求,DateTimeX::Format::Excel 看起来也可以。

    【讨论】:

    • 这可以节省一天的时间。我花了很多时间试图找到类似的东西,没有找到这个模块。谢谢!
    【解决方案2】:

    根据上一篇文章,这似乎是自 1900 年 1 月 1 日以来的天数。通过将 1900 年 1 月的 40828 设为 1900 年 1 月0th),我们得到:

    use POSIX 'mktime'
    
    my $epoch = mktime 0,0,0, 40829-1,0,0;
    
    print scalar localtime($epoch);
    

    给予

    Thu Oct 13 00:00:00 2011
    

    【讨论】:

    • 似乎是一个不错的解决方案。我更喜欢接受的一个,因为它创建了 DateTime 对象,并且我已经在使用 DateTime 来处理所有日期操作。所以这是一个完美的契合。谢谢。
    【解决方案3】:

    或者您可以使用自己的函数将EXCEL datevalue中的日期转换回来

    sub date2excelvalue {
      my($day1, $month, $year, $hour, $min, $sec) = @_;
      my @cumul_d_in_m = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365);
      my $doy = $cumul_d_in_m[$month - 1] + $day1;
    
      #
      full years + your day
      for my $y(1900..$year) {
        if ($y == $year) {
          if ($month <= 2) {
    
            #
            dont add manually extra date
            if inJanuary or February
            last;
          }
          if ((($y % 4 == 0) && ($y % 100 != 0)) || ($y % 400 == 0) || ($y == 1900)) {
            $doy++;#
            leap year
          }
        } else {#
          full years
          $doy += 365;
          if ((($y % 4 == 0) && ($y % 100 != 0)) || ($y % 400 == 0) || ($y == 1900)) {
            $doy++;#
            leap year
          }
    
        }
      }#
      end
      for y# calculate second parts as a fraction of 86400 seconds
      my $excel_decimaltimepart = 0;
      my $total_seconds_from_time = ($hour * 60 * 60 + $min * 60 + $sec);
      if ($total_seconds_from_time == 86400) {
        $doy++;#
        just add a day
      } else {#
        add decimal in excel
        $excel_decimaltimepart = $total_seconds_from_time / (86400);
        $excel_decimaltimepart = ~s / 0\. //;
      }
      return "$doy\.$excel_decimaltimepart";
    
    }
    
    sub excelvalue2date {
      my($excelvalueintegerpart, $excelvaluedecimalpart) = @_;
      my @cumul_d_in_m = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365);
      my @cumul_d_in_m_leap = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366);
      my @cumul_d_in_m_selected;
      my($day1, $month, $year, $hour, $min, $sec);
      $day1 = 0;#
      all days all years
      my $days_in_year;
      my $acumdays_per_month;
      my $daysinmonth;
      my $day;
    
      #
      full years + your day
      for my $y(1900. .3000) {
        my $leap_year = 0;#
        leap year
        my $leap_year_mask = 0;#
        leap year
        if ((($y % 4 == 0) && ($y % 100 != 0)) || ($y % 400 == 0) || ($y == 1900)) {
          $leap_year = 1;#
          leap year
          @cumul_d_in_m_selected = @cumul_d_in_m_leap;
    
        } else {
          $leap_year = 0;#
          leap year
          @cumul_d_in_m_selected = @cumul_d_in_m;
        }
    
        if (($day1 + (365 + $leap_year)) > $excelvalueintegerpart) {
    
          #
          found this year $y
          $year = $y;
          print "year $y\n";
    
          $days_in_year = $excelvalueintegerpart - $day1;
          $acumdays_per_month = 0;
          print "excelvalueintegerpart  $excelvalueintegerpart\n";
          print "day1  $day1\n";
          print "daysinyear $days_in_year\n";
          for my $i(0..$# cumul_d_in_m) {
            if ($i == $# cumul_d_in_m) {
              $month = $i + 1;#
              month 12 December
              $day = $days_in_year - $cumul_d_in_m_selected[$i];
              last;
    
            } else {
    
              if (($days_in_year > ($cumul_d_in_m_selected[$i])) && ($days_in_year <= ($cumul_d_in_m_selected[$i + 1]))) {
                $month = $i + 1;
                $day = $days_in_year - $cumul_d_in_m_selected[$i];
                last;
              }
    
            }
    
          }#
          end
          for $i months
    
          # end year
          last;
    
        } else {#
          full years
          $day1 += (365 + $leap_year);
        }
    
      }#
      end
      for years interger part comparator
    
      my $total_seconds_inaday;
      $total_seconds_inaday = "0\.$excelvaluedecimalpart" * 86400;
    
      $sec = $total_seconds_inaday;
      $hour = int($sec / (60 * 60));
      $sec -= $hour * (60 * 60);
      $min = int($sec / 60);
      $sec -= $min * (60);
      $sec = int($sec);
      return ($day, $month, $year, $hour, $min, $sec);
    
    }
    my $excelvariable = date2excelvalue(1, 3, 2018, 14, 14, 30);
    print "Excel variable: $excelvariable\n";
    my($integerpart, $decimalwithoutzero) = ($1, $2) if ($excelvariable = ~m / (\d + )\.(\d + ) / );
    my($day1, $month, $year, $hour, $min, $sec) = excelvalue2date($integerpart, $decimalwithoutzero);
    print "Excel Date from value: $day1, $month, $year, $hour, $min, $sec\n";
    

    尽情享受吧!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-07
      • 2011-04-18
      • 1970-01-01
      • 2017-08-14
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      相关资源
      最近更新 更多