【问题标题】:How do I get a hash of start/end dates between a range with perl where the start and end dates are not the beginning/ends of months?如何在 perl 的范围内获取开始/结束日期的哈希值,其中开始日期和结束日期不是月份的开始/结束?
【发布时间】:2014-12-02 10:45:16
【问题描述】:

我要做的是,给定格式为 YYYY-MM-DD 的开始和结束日期,编写一个函数,该函数将返回该格式的日期键/值对,表示中间月份的开始和结束需要注意的是,第一对将以任何开始日期开始,最后一对将以任何结束日期结束。虽然我认为 Date::Manip 或 Date::Calc 可以完成这项工作,但我一直无法找到所需的解决方案。

例如,如果调用看起来像:

&get_date_pairs('2014-08-18', '2014-10-17');

那么函数返回的哈希值如下:

%hash = (
        2014-08-18 => 2014-08-31,
        2014-09-01 => 2014-09-30,
        2014-10-01 => 2014-10-17,

);

【问题讨论】:

  • 这个应用程序是什么?这是你可以很容易地硬编码的东西——设置每月天数的数据结构,等等——但是如果有一些更大的问题要通过这个来解决,那么做这些事情可能更合适一种不同的方式。顺便说一句,哈希结构有点奇怪......对于这种数据,数组数组可能更直观。
  • 旁注:一般来说,don't call functions with an ampersand (&foo) 除非你有充分的理由这样做。
  • 我正在使用一个 API 来获取非常特定范围内所有数据的报告,并且该 API 一次只会返回几个月(或一个月的一小部分)。数组数组就可以了,我只需要以某种易于解析的格式返回成对的开始/结束日期。

标签: perl date hash


【解决方案1】:

你没有说你遇到了什么问题,所以我猜你是在要求一种算法来实现你想要的。

  1. 将 $current_date 设置为 $start_date。
  2. 循环:
    1. 将 $end_of_month 设置为 $current_date 月份的最后一天。
    2. 如果 $end_date 小于或等于 $end_of_month,
      1. 将散列的元素 $current_date 设置为 $end_date。
      2. 退出循环。
    3. 将散列的元素 $current_date 设置为 $end_of_month。
    4. 将 $current_date 设置为 $end_of_month。
    5. 在 $current_date 上加一天。

当我需要处理日期和时间时,我使用DateTime 对象(通常由DateTime::Format::Strptime 构造),但 Date::Calc 也应该能够胜任这项任务。我对 Date::Manip 一无所知。

【讨论】:

    【解决方案2】:

    使用Time::Piece

    use strict;
    use warnings;
    
    use Time::Piece;
    use Time::Seconds;
    
    my $start = '2014-08-18';
    my $end   = '2014-10-17';
    my $fmt   = '%Y-%m-%d';
    
    # Normalized to Noon to avoid DST
    my $month_start = Time::Piece->strptime( $start, $fmt ) + 12 * ONE_HOUR;
    my $period_end  = Time::Piece->strptime( $end,   $fmt );
    
    while (1) {
        print $month_start->strftime($fmt), ' - ';
    
        my $month_end = $month_start + ONE_DAY * ( $month_start->month_last_day - $month_start->mday );
    
        # End of Cycle if current End of Month is greater than or equal to End Date
        if ( $month_end > $period_end ) {
            print $end, "\n";
            last;
        }
    
        # Print End of Month and begin cycle for next month
        print $month_end->strftime($fmt), "\n";
        $month_start = $month_end + ONE_DAY;
    }
    

    输出:

    2014-08-18 - 2014-08-31
    2014-09-01 - 2014-09-30
    2014-10-01 - 2014-10-17
    

    【讨论】:

    • 使用month_last_day 方法可能更简单:perl -MTime::Piece -wE '$t = localtime; say $t->month_last_day' 吐出 31,因为它是(现在)十月。
    • @ThisSuitIsBlackNot 感谢您指出这一点。我在文档中查找了该函数,但在编写解决方案时找不到它。代码简化为现在改为使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2014-03-02
    • 2012-08-19
    • 1970-01-01
    相关资源
    最近更新 更多