从给定日期减去月份

时间:2014-06-05 11:56:23

标签: perl date unix ksh

我将来会有一个日期,我必须每次减去3个月,直到达到当前日期。

  • 扣除月份后达到的日期必须最接近当前日期,但必须在将来。
  • 该月的日期始终是第23天

即:

  • 未来日期= 2015/01/23
  • 当前日期= 2014/06/05
  • result = 2014/07/23

我正在运行Solaris,因此无法访问GNU日期。

我尝试在Perl中执行此操作,但不幸的是我只能使用Time::Local模块:

#!/bin/ksh

m_date="2019/05/23"
m_year=$(echo $m_date|cut -d/ -f1)
m_month=$(echo $m_date|cut -d/ -f2)
m_day=$(echo $m_date|cut -d/ -f3)
export m_year m_month m_day

perl -MTime::Local -le '
  $time = timelocal(localtime);
  $i = 3;
  while (timelocal(0, 0, 0, $ENV{'m_day'}, $ENV{'m_month'} - $i, $ENV{'m_year'}) > $time) {
    print scalar(localtime(timelocal(0, 0, 0, $ENV{'m_day'}, $ENV{'m_month'} - $i, $ENV{'m_year'})));
    $i += 3;
  }
'

这仅在一年内有效。还有其他办法吗?

4 个答案:

答案 0 :(得分:4)

分割日期字符串并对字段进行算术很简单。

use strict;
use warnings;
use 5.010;

my $future = '2015/01/23';
my $current = do {
  my @current = localtime;
  $current[3] += 1;
  $current[5] += 1900;
  sprintf '%04d/%02d/%02d', @current[5,4,3];
};
my $result;

for (my $test = $future; $test gt $current; ) {
  $result = $test;
  my @test = split /\//, $test;
  if (($test[1] -= 3) < 1) {
    --$test[0];
    $test[1] += 12;
  }
  $test = sprintf '%04d/%02d/%02d', @test;
}

say $result;

<强>输出

2014/07/23

或者,您可以只进行除法计算要减去的整数四分之一,例如

use strict;
use warnings;
use 5.010;

my $future = '2015/01/23';

my @current = (localtime)[5,4,3];
$current[1] += 1;
$current[0] += 1900;

my @future  = split /\//, $future;

my $months = ($future[0] - $current[0]) * 12 + $future[1] - $current[1];
$months -= 1 if $current[2] >= 23;

my @result = @current;
$result[2] = 23;
$result[1] += $months % 3;
$result[0] += int(($result[1] - 1) / 12);
$result[1] = ($result[1] - 1) % 12 + 1;
my $result = sprintf '%04d/%02d/%02d', @result;

say $result;

输出与前一代码的输出相同

答案 1 :(得分:1)

这是您的脚本已更改,因此它应该可以使用多年,

perl -MTime::Local -le'
  sub nextm {
    $ENV{m_year}--, $ENV{m_month} +=12 if ($ENV{m_month} -= 3) <1;
    timelocal(0, 0, 0, $ENV{m_day}, $ENV{m_month}, $ENV{m_year});
  }
  my $time = timelocal(localtime);
  while ((my $c=nextm()) > $time) {
    print scalar localtime($c);
  }
'

答案 2 :(得分:0)

尝试类似:

#!/usr/bin/perl -w
# just convert the real date that you have to epoch
my $torig = 1558569600; 
my $tnow = time;
# 3 months in seconds to use the epoch everywhere
my $estep = 3 * 30 * 24 * 3600;
while(($torig - $estep) > $tnow){
  $torig -= $estep;
}
print $torig,"\n";
print scalar localtime($torig),"\n";

这里唯一的问题是月份是近似值,如果你需要同一天但是减去3个月,你可以使用DateCalc

答案 3 :(得分:0)

由于Borodin的逻辑,我最终用KSH而不是perl来编写脚本。

#!/bin/ksh

set -A c_date $(date '+%Y %m %d')

IFS=/ d="2019/05/23"
set -A m_date $d

[[ ${c_date[2]} -gt ${m_date[2]} ]] && ((c_date[1]+=1))
c_date[2]=${m_date[2]}

c_date[1]=$(( (((${m_date[0]} - ${c_date[0]}) * 12) + (${m_date[1]} - ${c_date[1]})) % 3 + ${c_date[1]} ))

if [[ ${c_date[1]} -gt 12 ]] ; then
        ((c_date[0]+=1))
        ((c_date[1]-=12))
fi

echo ${c_date[@]}