使用Perl内置模块Time::Piece与Time::Seconds完美处理日期时间
2016-09-25 21:48:23 阿炯

本站赞助商链接,请多关照。 在Perl 5.10以后,Time::Piece与Time::Seconds这两个核心模块配合,可以完成现在绝大多数的日期时间的计算。Perl 以一种很容易地操作内部格式来存储日期和时间,如果有一个'YYYYMMDD'格式的日期,你需要做的是什么:


 Convert your date (which is in YYYYMMDD format) into Perl's date/time storage format.
 Use Perl to manipulate this date and time.
 When you want to output the results, you have to convert it back into the format you want.

my $date = Time::Piece->strptime($str1, '%Y%m%d');

$date现在将输入的日期和时间按在Perl看来是可以理解和操作的格式存储。%Y%m%d是一个描述格式,所以Perl知道在哪里可以找到年份、月和月的日。可以参考strftime查看各种格式参数。在上页的例子:
 %Y - represents the year with the century, such as 2016.
 %m - Represents the month as a two digit number such as 03 or 12.
 %d - Represents the date of the month as a two digit number from 01 to 31 if there are that many days in the month.

接下来:操作日期

可以使用另一个模块称为Time::Seconds会带来极大的方便。Time::Seconds定义一些常量像一天(ONE_DAY)使的操作更容易:
my $date = $date - ONE_DAY;

然后将新的对象转化为想要的格式:
$date->ymd("");

This converts $date into a string in the Year-month-day format.

最终:

use Time::Piece # For manipulating and storing the date
use Time::Seconds # For the nice constants such as ONE_DAY and ONE_WEEK

my $date = Time::Piece->strptime($str1, '%Y%m%d');
my $date = $date - ONE_DAY;
my $str2 = $date->ymd('');


日期时间对比

初始化两个 Time::Piece 对象,可支持这些操作符 (<, <=, ==, >=, > and <=>). 示例如下:

use Time::Piece;

my $today = Time::Piece->new;
my $thaterday = Time::Piece->strptime('01/09/2016', '%m/%d/%Y');

if ($today > $thaterday) {
    ...
}

日期时间计算

Time::Piece对象是不可变的,所以对他们进行的任何操作将返回一个新对象。它提供了操作月及年的加减函数 months and years (“add_months”, “add_years”) ,示例如下:

my $datetime = Time::Piece->new;
my $nextMonth   = $datetime->add_months(1);   # plus one month
my $lastQuarter = $datetime->add_months(-3);  # minus three months
my $nextDecade  = $datetime->add_years(10);   # plus 10 years
my $lastYear    = $datetime->add_years(-1);   # minus 1 year

如果需要更加细度的日期时间计算,你就需要调用Time::Seconds模块来实现,该模块提供如下一些运算符: ONE_MINUTE, ONE_HOUR, ONE_DAY, ONE_WEEK, ONE_MONTH, ONE_YEAR, ONE_FINANCIAL_MONTH, LEAP_YEAR, NON_LEAP_YEAR.

use Time::Piece;
use Time::Seconds;

my $time = Time::Piece->new;
my $tomorrow  = $time + ONE_DAY;
my $lastWeek  = $time - ONE_WEEK;
my $lastMonth = $time - ONE_MONTH;

直接对对象进行加减,是对秒为单位的操作:

my $now = Time::Piece->new;
my $oneminago = $now - 60;

示例一

use v5.12;
use autodie;

use Time::Piece;
use Time::Seconds;

my $date = "25-jan-2016";

#Create the "date object". The `%d-%b-%Y" is format the date is in
my $my_date = Time::Piece->strptime($date, "%d-%b-%Y");

#得到10天前
$my_date -= ( 10 * ONE_DAY );  #Constant from Time::Seconds

say $my_date;#Prints out Tue Jan 15 00:00:00 2013

#Printing it out in dd-mmm-yyyy format you had
say $my_date->mday . "-" . $my_date->monname . "-" . $my_date->year;


示例二

use Time::Piece;
use Time::Seconds;

my $format = '%Y%m%d';
my $str1 = '20160704';

my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = $dt1 - ONE_DAY;
my $str2 = $dt2->strftime($format);
say $str2;


示例三

计算当前和之前半小时的日期时间及一周前的同样时间段
use v5.12;
use utf8;
use Encode;
use Time::Piece;
use Data::Dumper;
use Time::Seconds;

my $dt;
my $cdt=localtime;
my $pdt=$cdt - ONE_WEEK;

say $cdt->datetime;
#say 'month:'.pluspair($cdt->mon).',hour:'.$cdt->hour.',min:'.$cdt->min;
my ($chalfhour,$phalfhour)=($cdt - 30 * ONE_MINUTE,$pdt - 30 * ONE_MINUTE);
say 'Current half hour:'.$chalfhour->datetime;
push @{$dt->{cdt}},$chalfhour->ymd.' '.$chalfhour->hms;
push @{$dt->{cdt}},$cdt->ymd.' '.$cdt->hms;

say $pdt->datetime;
say 'One week half hour:'.$phalfhour->datetime;
push @{$dt->{pdt}},$phalfhour->ymd.' '.$phalfhour->hms;
push @{$dt->{pdt}},$pdt->ymd.' '.$pdt->hms;

say Dumper ($dt);

#retrun double dig(如果是一位的话,在前面补足'0')
sub pluspair{
 my $givein=shift;
 return (length($givein)>1)?$givein:'0'.$givein;
}

将Unix时间戳转为当前本地系统时间

从HBase中取得记录的时戳,由于是毫秒级的,需要转换一下:

my $rcv=int($row->{'value'}/1000);
my $dt = Time::Piece->strptime($rcv,"%s");
$dt += 8 * ONE_HOUR; #转换为本地时区(cst)
return $dt->datetime;


其它可参考的日期时间计算

使用POSIX模块的'strftime'函数来实现日期格式化计算

This is a simple strptime/strftime roundtrip. Since strftime normalises inputs it is simply to just subtract 1 from the mday field.

use POSIX 'strftime';
use POSIX::strptime 'strptime';

my $fmt = "%Y%m%d";
my @t = strptime "20160704", $fmt;
$t[3] -= 1;  # 定义到昨天
my $str2 = strftime $fmt, @t;



参考来源:

Perl日期时间处理模块之Time::Piece