2010-12-10 42 views
31

Mã nói một triệu chữ:PHP DateTime :: createFromFormat không phân tích theo tiêu chuẩn ISO 8601 thời gian ngày

php > echo strtotime("2010-12-07T23:00:00.000Z"); 
1291762800 
echo date('c', 1291762800); 
2010-12-08T00:00:00+01:00 
php > var_dump(DateTime::createFromFormat('c', "2010-12-07T23:00:00.000Z")); 
bool(false) 
php > var_dump(DateTime::createFromFormat(DateTime::ISO8601, "2010-12-07T23:00:00.000Z")); 
bool(false) 

Bất cứ ý tưởng gì đang xảy ra?

Btw, vâng, DateTime mới ("2010-12-07T23: 00: 00.000Z") hoạt động tốt. Nhưng tôi thích biết những gì đầu vào tôi nhận được.

+3

giây phân đoạn của bạn không nằm trong định dạng. 'DateTime :: ISO8601' là một chuỗi có giá trị' Y-m-d \ TH: i: sO'. – salathe

+4

WikiPedia không đồng ý: Phân số thập phân cũng có thể được thêm vào bất kỳ phần tử nào trong ba yếu tố thời gian. Dấu thập phân, dấu phẩy hoặc dấu chấm (không có bất kỳ tùy chọn nào được nêu gần đây nhất ở độ phân giải 10 của Hội nghị chung CGPM lần thứ 22 năm 2003), được sử dụng làm dấu phân tách giữa phần tử thời gian và phần của nó. Một phần chỉ có thể được thêm vào phần tử thời gian đặt hàng thấp nhất trong biểu diễn. – Jake

+0

'public static DateTime DateTime :: createFromFormat (chuỗi $ format, string $ time [, DateTimeZone $ timezone])', có thể là do bao gồm múi giờ – ajreal

Trả lời

32

Có một báo cáo lỗi mà chính xác mô tả vấn đề của bạn :)

https://bugs.php.net/bug.php?id=51950

Kể từ 2016/08/07, báo cáo lỗi đã được đánh dấu là "không phải là một lỗi". Bạn cần sử dụng strtotime hoặc new DateTime để thay thế.

Các hằng số đã được xác định áp dụng cho cả định dạng và phân tích cú pháp theo cách tương tự, tác động theo cách của bạn.

+2

Thực sự đáng thất vọng. Tại sao lại đặt tên là hằng số "ISO8601" nếu nó không thực sự tuân thủ tiêu chuẩn đó. Đây là lý do tại sao tôi không thích PHP nhiều. – jlh

+0

Đẫm máu 7 năm sau và điều này vẫn còn tồn tại .... và thậm chí còn được đánh dấu là không phải là lỗi? 'Nếu bạn muốn chấp nhận các định dạng ngày/giờ khác nhau ISO-8601'. Định dạng ISO-8601 khác nhau ?? Tại sao tôi không thích php trong một nutshell. –

+0

Cảm thấy nỗi đau quá –

1

Điều rất lạ và đáng thất vọng là lỗi này vẫn còn thực tế. Đây là một mô hình phù hợp với ngày phân tích với micro trong phần thập phân của giây:

Y-m-d\TH:i:s.uO 

Cách sử dụng:

$dateStr = '2015-04-29T11:42:56.000+0400' 
$ISO = 'Y-m-d\TH:i:s.uO' 
$date = DateTime::createFromFormat($ISO, $dateStr) 
+1

Thực ra, công việc này chỉ khi phần thập phân của giây có mặt. Hơn nữa, nó chỉ hoạt động nếu chỉ có 1 đến 6 chữ số chính xác. Nếu phần thập phân bị bỏ qua hoặc nếu nó là chính xác hơn, false được trả về. – Glutexo

6

thử điều này:

ngày
DateTime::createFromFormat('Y-m-d\TH:i:sP', $date) 
10

Parsing ISO8601, và cũng có thể chuyển đổi múi giờ:

// create ISO8601 dateTime 
$date = DateTime::createFromFormat(DateTime::ISO8601, '2016-07-27T19:30:00Z'); 

// set to user's timezone 
$date -> setTimeZone('Asia/Singapore'); 

echo $date -> format(DateTime::ISO8601); 
// prints '2016-07-28T03:30:00+0800' 
+0

sao chép mã của bạn và nó in: "2016-07-27T19: 30: 00 + 0000" bằng cách sử dụng PHP 5.6.10 –

+0

@AlexAngelico Đầu ra cho 'echo DateTime :: ISO8601; 'là gì? Nó in 'Y-m-d \ TH: i: sO' cho tôi. – a20

+0

có, Ngày giờ :: ISO8601 in Y-m-d \ TH: i: sO Tôi đang sử dụng mã này để thay đổi thời gian thành Múi giờ chính xác. Tôi đang theo GMT-5 '$ fecha_str = '2017-04-12T21: 43: 54 + 02: 00'; \t $ date = strtotime ($ fecha_str); \t ngày lặp lại ("Y-m-d h: i: s", $ ngày); \t/output => 2017-04-12 07:43:54 ' –

2

Không ai đề cập đến sử dụng DATE_ATOM đó là như xa như tôi biết PHPs thực hiện đúng nhất của ISO 8601. Cần ít nhất làm việc cho qua 3 trong số đó:

<?php 

$dates = array(
    "2010-12-07T23:00:00.000Z", 
    "2010-12-07T23:00:00", 
    "2010-12-07T23:00:00Z", 
    "2010-12-07T23:00:00+01:00", 
    (new \DateTime("now"))->format(DATE_ATOM) 
); 

foreach($dates as $d) { 

    $res = \DateTime::createFromFormat(DATE_ATOM, $d); 

    echo "try $d: \n"; 
    var_dump($res); 
    echo "\n\n"; 
} 

?> 

Để có thể phân tích tất cả chúng tôi viết một chức năng nhỏ:

<?php 

function parse_iso_8601($iso_8601_string) { 
    $results = array(); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s.u",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s.uP",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:sP",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat(DATE_ATOM,$iso_8601_string); 

    $success = array_values(array_filter($results)); 
    if(count($success) > 0) { 
     return $success[0]; 
    } 
    return false; 
} 

// Test 
$dates = array(
    "2010-12-07T23:00:00.000Z", 
    "2010-12-07T23:00:00", 
    "2010-12-07T23:00:00Z", 
    "2010-12-07T23:00:00+01:00", 
    (new \DateTime("now"))->format(DATE_ATOM) 
); 

foreach($dates as $d) { 

    $res = parse_iso_8601($d); 

    echo "try $d: \n"; 
    var_dump($res); 
    echo "\n\n"; 
} 

?> 

Như @Glutexo đề cập đến nó chỉ hoạt động nếu chỉ có 1-6 chữ số chính xác cho phần thập phân, quá. Cảm thấy tự do để cải thiện nó.

0

Đối với câu trả lời được liệt kê tại đây https://stackoverflow.com/a/14849503/2425651 , chúng tôi có thể sử dụng định dạng này "Y-m-d \ TH: i: s.u +" để giữ micro giây.

$format = 'Y-m-d\TH:i:s.u+'; 
$value = '2017-09-21T10:11:19.026Z'; // jsDate.toUTCString(); 
var_dump(\DateTime::createFromFormat($format, $value)); 
0

một này làm việc cho tôi:

$date = (new DateTime)->setTimestamp(strtotime('2017-12-31T23:00:00.000Z')); 
Các vấn đề liên quan