2011-11-22 38 views
5

Tôi có định dạng ngày tháng này bằng chuỗi "11:56:41, 11/22/2011".Làm thế nào để so sánh thời gian ngày chuỗi trong perl?

Đây là những gì tôi muốn:

So sánh hai chuỗi ngày tháng như thế nào.

$date1 = "11:56:41, 11/22/2011"; 
$date2 = "11:20:41, 11/20/2011"; 
if($date2 < $date1) { 
    do something... 
} else { 
    do nothing... 
} 

Bất kỳ ý tưởng nào tôi có thể đạt được điều này trong perl?

Trả lời

11

Một phương pháp hiệu quả là sắp xếp lại các trường thành một thứ tương tự.

sub to_comparable { 
    my ($date) = @_; 
    my ($H,$M,$S,$d,$m,$Y) = $date =~ m{^([0-9]{2}):([0-9]{2}):([0-9]{2}), ([0-9]{2})/([0-9]{2})/([0-9]{4})\z} 
     or die; 
    return "$Y$m$d$H$M$S"; 
} 

if (to_comparable($date2) lt to_comparable($date1)) { 
    ... 
} else { 
    ... 
} 
+3

vì chúng ta không biết từ câu hỏi cho dù số ngày/tháng/giờ/phút đơn sẽ là 0-đệm, có thể tốt hơn là trả về sprintf ('% 04d% 02d% 02d% 02d% 02d $ 02d' , $ Y, $ m, $ d, $ H, $ M, $ S) – bigiain

+0

@ikegami Cảm ơn! đây là câu trả lời đơn giản nhất và nó đã hoạt động! – quinekxi

+0

@ bigiain Tôi đã gặp phải một vấn đề nhỏ, chỉ là một câu hỏi đơn giản (tôi đoán không cần phải làm một câu hỏi khác) làm thế nào về ngày mà tôi sắp sửa so sánh là một vùng không độn? – quinekxi

1

Chuyển đổi datetimes (trong trường hợp của bạn đây là datetimes địa phương vì họ không có múi giờ) vào ISO8601 thì bạn có thể so sánh chuỗi thông thường.

Để thực hiện việc chuyển đổi, bạn nên giải nén sáu thành phần từ định dạng của bạn

HH:MM:SS, mm/DD/YYYY 

và Lắp ráp lại chúng vào ISO 8601:

YYYY-MM-DDTHH:MM:SS 

Sau đó, so sánh tự từ điển bình thường sẽ làm việc.

Xem http://codepad.org/berle9um

Lặp đi lặp lại ở đây:

sub my_format_to_iso8601 { 
    $_[0] =~ /(\d\d):(\d\d):(\d\d), (\d\d)\/(\d\d)\/(\d\d\d\d)/; 
    return "$6-$4-$5T$1:$2:$3"; 
} 

$date1 = "11:56:41, 11/22/2011"; 
$date2 = "11:20:41, 11/20/2011"; 
$d1 = my_format_to_iso8601($date1); 
$d2 = my_format_to_iso8601($date2); 
print "first is $d1\n"; 
print "second is $d2\n"; 
if ($d2 < $d1) { 
    print "second is earlier\n"; 
} else { 
    print "first is earlier\n"; 
} 

PHỤ LỤC Perl mã

  • Ikegami là tốt hơn nhiều.
  • Thư viện ngày sẽ là bạn của bạn ở đây; chỉ cần chỉ định một chuỗi định dạng và sử dụng chức năng phân tích cú pháp của thư viện để lấy đối tượng ngày của bạn, sau đó nó sẽ có thể so sánh trực tiếp. (Điều đó nói rằng, luôn luôn thú vị khi chỉ ra rằng ISO8601 là, theo thiết kế, có thể sắp xếp theo dạng chuỗi.)
+0

cảm ơn, nó chắc chắn phù hợp với tôi. không có sự khác biệt lớn giữa mã của bạn và của ikegami. cả hai đều hoạt động tốt. : D – quinekxi

1

Trong trường hợp này, tôi đã luôn luôn sử dụng Date::Calc:

use Date::Calc; 

my $date1 = "11:56:41, 11/22/2011"; 
my $date2 = "11:20:41, 11/20/2011"; 

my @date1arr=split /[^\d]/, $date1 if($date1 =~ m!\d{2}:\d{2}:\d{2}, \d{2}/\d{2}/\d{4}!; 
my @date2arr=split /[^\d]/, $date2 if($date2 =~ m!\d{2}:\d{2}:\d{2}, \d{2}/\d{2}/\d{4}!; 

my @diff = Delta_DHMS(@date1arr, @date2arr); 
my $less; 
foreach my $d (@diff) { $less = 1 if $d < 0; } 

if($less) { ... } 
+0

Đó là công trình, nhưng Ngày :: Calc là khá nặng cho trường hợp đơn giản ở đây. giải pháp của ikegami hoạt động (ít nhất là trong không gian vấn đề hạn chế được đưa ra trong câu hỏi) cũng như không cần tải tất cả Date :: Calc (có lẽ không đáng kể ~ 300 hoặc hơn ms trên máy của tôi ở đây ...) – bigiain

12

Thêm một giải pháp mà sử dụng sự so sánh quá tải sau khi chuyển đổi thời gian để Time::Piece đối tượng. Việc tạo ra các đối tượng có thể là quá mức cần thiết cho một cái gì đó đơn giản, nhưng chúng có thể trở nên rất hữu ích nếu bạn cần phải làm những việc khác với thời gian.

use Time::Piece; 

my $dateformat = "%H:%M:%S, %m/%d/%Y"; 

my $date1 = "11:56:41, 11/22/2011"; 
my $date2 = "11:20:41, 11/20/2011"; 

$date1 = Time::Piece->strptime($date1, $dateformat); 
$date2 = Time::Piece->strptime($date2, $dateformat); 

if ($date2 < $date1) { 
    do something... 
} else { 
    do nothing... 
} 
+1

+1 [Thời gian :: Mảnh] (https://metacpan.org/module/JHI/perl-5.7.2/ext/Time/Piece/Piece.pm), một mô-đun quản lý ngày đã được tích hợp vào Perl –

5

gì, đã 4 giờ và không phải là một đơn DateTime (tất cả mưa đá DateTime hùng mạnh) câu trả lời trong tầm nhìn? Bạn chưa xong, thuê bao ... ☻

use DateTime::Format::Strptime qw(); 
my $p = DateTime::Format::Strptime->new(pattern => '%T, %D', on_error => 'croak',); 

my $date1 = $p->parse_datetime('11:56:41, 11/22/2011'); 
my $date2 = $p->parse_datetime('11:20:41, 11/20/2011'); 

if($date2 < $date1) { 
    say "$date2 comes before $date1"; 
} else { 
    say "$date2 does not come before $date1"; 
} 

Phương pháp parse_datetime trả về trường hợp của DateTime mà so sánh các nhà khai thác và stringification đang quá tải để DTRT.

+0

hoạt động nhưng unfornutely, yêu cầu của tôi là tôi sẽ không sử dụng một mô-đun cài đặt ngoại trừ cho đã có trong gói cài đặt của perl. anyways. cảm ơn cho đầu vào của bạn: D – quinekxi

+0

Mưa đá Ngày giờ mạnh mẽ! –

+1

Bởi vì nó quá mức cần thiết cho công việc trong tầm tay. – ikegami

2

Tôi sử dụng unixtime.:)

tôi chuyển đổi cả hai lần để unixtime và sau đó tôi chỉ có hai số nguyên để so sánh và vì vậy tôi có thể sử dụng các toán tử <, ==,> vv

ví dụ chuyển đổi thành unixtime như sau

my $timestamp = "2014-03-25 12:33:32"; # (We assume localtime) 

# 
# To split on the space character, it's best to use the regex// 
# 
my ($date, $time) = split (/ /, $timestamp); 
my ($year, $mon, $mday) = split ('-', $date); 
my ($hour, $min, $sec) = split (':', $time); 

my $unixtime = timelocal($sec, $min, $hour, $mday, $mon-1, $year); 
Các vấn đề liên quan