我有一个格式为YYYY-MM-DD的n
字符串(例如“2010-10-31”)。使用Perl,如何比较YYYY-MM-DD形式的日期?
如何将日期与此数组中的字符串进行比较?
例如,30多天前删除字符串?
我有一个格式为YYYY-MM-DD的n
字符串(例如“2010-10-31”)。使用Perl,如何比较YYYY-MM-DD形式的日期?
如何将日期与此数组中的字符串进行比较?
例如,30多天前删除字符串?
use strict; use warnings;
use DateTime();
use DateTime::Duration();
use DateTime::Format::Natural();
my $parser = DateTime::Format::Natural->new;
my $now = DateTime->now;
my $delta = DateTime::Duration->new(days => 30);
my $cutoff = $now->subtract_duration($delta);
my @new_dates = map { $_->[1] }
grep { -1 == $_->[0] }
map {
chomp;
[
DateTime->compare(
$parser->parse_datetime($_),
$cutoff
),
$_
]
} <DATA>;
print "@new_dates";
__DATA__
2010-07-31
2010-08-31
2010-09-30
2010-10-31
现在只需使用'my $ now = DateTime->;'不需要解析'localtime'的输出。 – daotoad 2010-10-12 04:57:09
感谢daotoad。 – 2010-10-12 05:01:46
OP寻找'YYYY-MM-DD'格式,而不是'YYYY/MM/DD' – 2010-10-12 05:57:04
一个好的开始是阅读The Many Dates of Perl和DateTime网站。
YYYY-MM-DD格式是ISO 8601日期表示形式。有些变体被认为是可以接受的,例如YYYY-MM-DD
和YYYYMMDD
,甚至是旧数据中的YYMM
。在选择比较这些日期的方法之前,您应该查看definitive list。
如果ISO 8601日期字符串是:1)有效日期; 2)使用或不使用-
分隔符的相同格式; 3)缺少主要和尾随空白,一个有吸引力的属性是,你可以排序或比较字符串与简单的词典字符串比较。
一般则:
---否则---
决定一个CPAN模块上的解析您的日期字符串(或自己与之相匹配),
转换,如果,如果你的日期大纪元(或使用CPAN模块进行大尺寸日期/时间操作,如Date :: Manip或Date :: Calc)
对时间类型(历元时间,绝对天数, whateve R)
转换的时间回到你想要的格式...
这里是代码,不会说:
use warnings; use strict;
use Date::Calc qw/:all/;
my (@date_strings, @abs_days);
my $target=Date_to_Days(2010, 1, 15);
# set @date_string to "YYYY-MM-DAY" between some dates
for my $AbsDay(Date_to_Days(2009,1,1)..Date_to_Days(2011,12,31)) {
my ($year, $mon, $day)=Add_Delta_Days(1,1,1,$AbsDay-1);
my $s="$year-$mon-$day";
push @date_strings, $s;
}
foreach my $s (@date_strings) {
my ($year, $mon, $day);
if(($year, $mon, $day)=$s=~/^(\d+)-(\d+)-(\d+)/) {
my $days=Date_to_Days($year, $mon, $day);
push @abs_days, $days
if ($target-$days <= 30 && $target-$days >= -30);
}
}
print "absolute day way:\n";
foreach my $days (@abs_days) {
my ($year, $mon, $day)=Add_Delta_Days(1,1,1,$days-1);
print "$year-$mon-$day\n";
}
工作太多! :) – 2010-10-12 14:38:07
@brian d foy:恭敬地,我不同意。我的代码并不是很美,但使用经过良好测试的CPAN库(如Date :: Calc(用C语言编写)或Date :: Time)是值得的。这里的大部分工作只是生成要测试的字符串! : - }对于你所倡导的词典解决方案,你仍然需要检查(或者希望)你输入的是相同的分隔符,是一个有效的日期,并且没有前导或尾随空格。一旦你这样做,它真的不那么工作? – dawg 2010-10-12 20:41:32
是的,我一直处于工作量较少的情况,以及在合理时间内完成和从未完成的区别。 – 2010-10-12 23:51:15
您可以使用Time::ParseDate模块,
use strict;
use warning;
use Time::ParseDate;
my @dates = ('2010-10-12', '2010-09-14', '2010-08-12', '2010-09-13');
my @dates =
grep {parsedate($_, NO_RELATIVE => 1, UK => 1) > parsedate('-30 days') }@dates;
#output: 2010-10-12 2010-09-14
猜猜不止一种方法去做一件事,但我喜欢Date::Simple对于这样的东西..
从文档的一个例子:
use Date::Simple ('date', 'today');
# Difference in days between two dates:
$diff = date('2001-08-27') - date('1977-10-05');
# Offset $n days from now:
$date = today() + $n;
print "$date\n"; # uses ISO 8601 format (YYYY-MM-DD)
这是伟大的物体上做++运算。
只有日期但,没有小时,分钟或秒
伟大的事情有关YYYY-MM-DD
- 格式化日期是,你可以使用简单的字符串比较比较。在Perl中,这是lt
和gt
运营商。
在这种情况下,听起来你只是想检查数组中的日期是早于还是晚于给定的目标日期(恰好是“30天前”)。对于这种情况,我会采取的方法是首先确定30天前的日期,然后将其作为字符串与数组中的每个日期进行比较。我不会介绍将所有YYYY-MM-DD
字符串转换为“正确的”日期对象,时代等,并仅仅为了测试代表早期日期而引入的开销。
#!/usr/bin/env perl
use strict;
use warnings;
my $thirty_days = 30 * 24 * 60 * 60;
my ($old_day, $old_month, $old_year) = (localtime(time - $thirty_days))[3..5];
my $cutoff = sprintf('%04d-%02d-%02d',
$old_year + 1900, $old_month + 1, $old_day);
my @dates = ('2010-10-12', '2010-09-12', '2010-08-12', '2010-09-13');
for my $date (@dates) {
print "$date\n" if $date gt $cutoff;
}
我很惊讶有这么多人跳到这种复杂的膝盖混乱的解决方案。我们在_Effective Perl Programming_中有一个这样的解决方案。 :) – 2010-10-12 14:41:44
这假定源日期没有错误,例如'2010-02-29',它会按照字典顺序进行比较,但仍然是错误的日期。日期包会指出源日期错误,这似乎是脚本工作的一部分,不是吗? – dawg 2010-10-12 15:53:30
测试'$ date gt $ cutoff'将失败:1)'sprintf'中使用的'-'以外的分隔符; 2)在应该匹配的字符串上带有空白字符; 3)用不应该匹配的字符串拖尾空格。几乎所有的CPAN日期解析库都可以处理这三种情况,还有很多更多。一旦你检查了分隔符并删除前后的空格,你真的可以节省那么多的“开销”或代码吗? Date :: Calc是用C编写的,速度非常快。 Date :: Time功能非常丰富。两者都检查有效的日期输入,而这种方法没有。 – dawg 2010-10-12 20:17:09
我这样做,有点冗长,但很容易理解并完成工作。 @ out2是一个2d数组,我正在使用for循环读取值。每个循环都会将输入与@ out2进行比较,以查看它是早期还是晚期时间/日期。如果是,那么我将值写入数组,然后比较下一个输入。
if ($year < $out2[$j][7]) {
$lt = 1;
goto JUMP;
}
if ($year > $out2[$j][7]) {
$gt = 1;
goto JUMP;
}
if ($month < $out2[$j][5]) {
$lt = 1;
goto JUMP;
}
if ($month > $out2[$j][5]) {
$gt = 1;
goto JUMP;
}
if ($day < $out2[$j][6]) {
$lt = 1;
goto JUMP;
}
if ($day > $out2[$j][6]) {
$gt = 1;
goto JUMP;
}
if ($time < $out2[$j][4]) {
$lt = 1;
goto JUMP;
}
if ($time > $out2[$j][4]) {
$gt = 1;
goto JUMP;
}
JUMP:
if ($lt == 1) {
$out2[$j][2] = "$dtime $month\/$day\/$year";
$out2[$j][4] = $time;
$out2[$j][5] = $month;
$out2[$j][6] = $day;
$out2[$j][7] = $year;
$lt = 0;
}
if ($gt == 1) {
$out2[$j][3] = "$dtime $month\/$day\/$year";
$out2[$j][4] = $time;
$out2[$j][5] = $month;
$out2[$j][6] = $day;
$out2[$j][7] = $year;
$gt = 0;
}
为什么不自5.10 Time::Piece和Time::Seconds核心,而不是CPAN搜索的前几个结果吗?
use strict;
use warnings;
use Time::Piece(); # we don't need to include overloaded locatime
use Time::Seconds;
use Data::Dumper;
my @dates = qw/2010-10-31 2012-10-16 2011-09-08/;
my $now = Time::Piece::localtime();
my @date_objects = map {
Time::Piece->strptime($_, '%F') # %F is the same as %Y-%m-%d
} @dates;
my @filtered_dates = grep {
$now - $_ < (ONE_DAY * 30)
} @date_objects;
print Dumper(map($_->strftime('%F'), @filtered_dates));
要找到一个循环的最小日期:
var minDate = ...;
var maxDate = ...;
foreach my $date (@$dates) {
if ($minDate gt $date){ # Less than.
$minDate = $date; # Minimal date.
}
if ($minDate lt $date){ # Greater than.
$minDate = $date; # Maxamal date.
}
}
这与这个问题有什么关系? – Toto 2013-10-31 08:05:07
为什么被否决?公平的问题,是吗? – Xailor 2010-10-12 02:41:40
我很喜欢这个问题如何引发纯粹主义者和实用主义者之间的争论。 – paddy 2012-10-29 13:50:08