2010-03-15 9 views
10

Tôi không thể tin rằng tôi chưa bao giờ gặp phải điều này trước đây.Cách tạo ngày phân tích strtotime theo định dạng Úc (nghĩa là Vương quốc Anh): dd/mm/yyyy?

Về cơ bản, tôi đang phân tích văn bản trong tài liệu văn bản do con người tạo và một trong các trường tôi cần phân tích là ngày và giờ. Vì tôi ở Úc, ngày được định dạng như dd/mm/yyyy nhưng strtotime chỉ muốn phân tích cú pháp đó là ngày được định dạng ở Hoa Kỳ. Ngoài ra, phát nổ bởi / sẽ không hoạt động vì, như tôi đã đề cập, các tài liệu này được nhập bằng tay và một số trong số đó có dạng d M yy.

Tôi đã thử nhiều kết hợp của setlocale nhưng bất kể tôi cố gắng làm gì, ngôn ngữ luôn được đặt thành tiếng Anh Mỹ.

Tôi khá chắc chắn setlocale là chìa khóa ở đây, nhưng tôi dường như không thể tấn công đúng mã. Cố gắng này:

  • au
  • au-en
  • EN_AU
  • australia
  • aus

Bất cứ điều gì khác tôi có thể thử?

Để rõ ràng: Tôi đang chạy trên IIS bằng hộp Windows.

Cảm ơn rất nhiều :)

Iain

Ví dụ:

$mydatetime = strtotime("9/02/10 2.00PM"); 
echo date('j F Y H:i', $mydatetime); 

Tạo

2 September 2010 14:00 

Tôi muốn nó để sản xuất:

9 February 2010 14:00 

Giải pháp của tôi

Tôi đang đưa ra các đánh dấu vào một trong những câu trả lời ở đây vì nó là một giải pháp dễ dàng hơn để đọc nhiều để tôi, nhưng đây là những gì tôi đã đưa ra:

$DateTime = "9/02/10 2.00PM"; 
$USDateTime = preg_replace('%([0-3]?[0-9]{1})\s*?[\./ ]\s*?((?:1[0-2])|0?[0-9])\s*?[./ ]\s*?(\d{4}|\d{2})%', '${2}/${1}/${3}', $DateTime); 
echo date('j F Y H:i',strtotime($USDateTime)); 

Bởi vì tôi không thể dựa vào người dùng để phù hợp với mục ngày của họ, tôi đã thực hiện regex của tôi một chút phức tạp hơn:

  • 0 hoặc 1 chữ số từ 0 đến 3
  • 1 chữ số từ 0 đến 9 - có điều này sẽ khớp với 37 là ngày hợp lệ nhưng tôi nghĩ rằng regex đã đủ lớn!
  • Có thể là một số khoảng trắng
  • Xác định ký tự (a '.'Một '/' hoặc' ')
  • thể có một số khoảng trắng
  • Hoặc:
    • Một số từ 10 đến 12 HOẶC
    • Một số từ 1 đến 9 với một tùy chọn hàng đầu 0
  • thể có một số ký tự khoảng trắng
  • khoanh vùng (một ' ' một '/' hoặc'')
  • thể có một số khoảng trắng
  • Hoặc:
    • Một số dài 2 chữ số HOẶC
    • Một số 4 chữ số dài

Hy vọng rằng điều này sẽ phù hợp với hầu hết các phong cách của ngày viết ...

+0

Bạn có muốn sản xuất '9 tháng 2 năm 2010 14: 00' không? Hay các bạn chỉ có 11 tháng trong năm? –

+0

Có, nhận thấy điều này và thay đổi nó. Cà phê vẫn chưa khởi động. :) –

+0

Câu hỏi này có thể giúp bạn hiểu http://stackoverflow.com/questions/5597833/strange-behaviour-of-my-code-with-strtotime/5597905#5597905 – Twelve47

Trả lời

19

Có một sửa chữa nhanh chóng mà dường như để buộc PHP strtotime vào sử dụng định dạng ngày Vương quốc Anh. Tức là: thay thế tất cả '/' trong chuỗi đến bằng dấu '-'.

Ví dụ:

date('Y-m-d', strtotime('01/04/2011')); 

Sẽ sản xuất: 2011-01-04

date('Y-m-d', strtotime('01-04-2011')); 

Sẽ sản xuất: 2011-04-01

Bạn có thể sử dụng để đạt được str_replace điều này.

Ví dụ:

str_replace('/', '-', '01/04/2011'); 

EDIT:

Như đã trình bày trong các ý kiến, công trình này vì PHP giải thích dấu gạch chéo như Mỹ và chấm/dấu gạch ngang như châu Âu.

Tôi đã sử dụng thủ thuật này một cách rộng rãi và không có vấn đề gì cho đến nay.

Nếu bất kỳ ai có bất kỳ lý do chính đáng nào không sử dụng điều này, vui lòng nhận xét.

+2

http://solidgone.org/PHP-strtotime-assumptions-with-European-and-American-date-formats mô tả "lý luận" đằng sau điều này. Dấu gạch nối gợi ý định dạng ngày ISO, dấu chấm đề xuất Châu Âu và dấu gạch chéo là chữ Hoa Kỳ. Câu hỏi tiếp theo: nhưng tại sao lại như vậy? –

+0

Câu hỏi là về thứ tự khác nhau của tháng và ngày trong ngày không phải về dấu chấm và dấu gạch ngang. –

+0

@VladimirSerykh Đọc lại câu hỏi. Nó nêu rõ "ngày được định dạng như dd/mm/yyyy" có nghĩa là ngày của người hỏi được định dạng bằng dấu gạch chéo nhưng thứ tự đã sai. Tôi đề nghị để chuyển đổi những dấu gạch chéo vào dấu gạch ngang mà sửa chữa thứ tự. –

1

setlocale () hút cho chính xác lý do bạn mô tả: Bạn không bao giờ biết những gì bạn sẽ nhận được. Tốt nhất để xử lý chuỗi theo cách thủ công.

Hình Zend_Date của Zend Framework là một cách xử lý ngày chính xác và nhất quán hứa hẹn thay thế. Tôi chưa có kinh nghiệm với nó, chỉ mới bắt đầu làm việc với nó, nhưng cho đến nay, tôi thích nó.

+0

Vâng, đó là những gì tôi đã làm cuối cùng . Vâng, thực sự tôi chỉ định dạng lại chuỗi để ngày của Anh trở thành ngày của Mỹ và cho đến nay nó đã làm việc trên tất cả các trường hợp thử nghiệm của tôi - yay! –

3

Vấn đề là strtotime không tham số định dạng đối số. Còn khoảng strptime thì sao?

+0

Dang, rất muốn thử điều này nhưng tôi đang ở trong một môi trường WIMP: ( –

1

Ah, vấn đề cũ mà người Úc may mắn có được.

Những gì tôi đã làm trong quá khứ là một cái gì đó như thế này

public static function getTime($str) { // 3/12/2008 

     preg_match_all('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $str, $matches); 

     return (isset($matches[0][0])) ? strtotime($matches[3][0] . '-' . $matches[2][0] . '-' . $matches[1][0]) : NULL; 

    } 

Mặc dù điều này phụ thuộc vào những ngày ở định dạng này dd/mm/yyyy.

Bạn có thể sử dụng một regex khác hoặc để chuyển đổi từ d M yy hoặc sử dụng một sửa đổi. Tôi không biết nếu điều này sẽ là đúng nhưng nó có thể là một sự khởi đầu:

/^(\d{1,2})(?:\/|\s)(\d{1,2})(?:\/|\s)(\d{2,4})$/

+0

Cảm ơn người bạn đời nỗ lực. Tôi không chắc tại sao bạn lại bị bỏ phiếu. Tôi đoán chỉ trích của tôi về phương pháp này là nó rất cụ thể vì bản chất của các yếu tố đầu vào có thể - nhưng đó là vấn đề của tôi, tôi chắc chắn đây là một số mã chung mà bạn đã nói dối trong hộp công cụ của mình cho các vấn đề với đầu vào thống nhất hơn. nhưng thay vì trả lại một trận đấu được định dạng, tôi chỉ chuyển đổi chuỗi Úc của mình sang định dạng Hoa Kỳ –

+0

Ngoài ra, với người đó đã xuống hạng ... Tôi muốn được biết lý do tại sao? Không trolling, tôi chỉ muốn biết - Tôi có thể học một cái gì đó :) –

+0

Vâng, nó dựa trên một định dạng, ngoại trừ nó đến từ một hàm trợ giúp tôi đã viết rằng chỉ có một định dạng. Trong ví dụ trên, tôi không trả về một kết quả được định dạng, nhưng thời gian unix từ ngày được chuyển thành tiêu chuẩn ISO (sử dụng cùng một MySQL và PHP có thể dễ dàng sử dụng trong 'strtotime()'). Tôi không chắc chắn của downvote, có lẽ nó là nguyên nhân tôi đã sử dụng một regex khi một số người sẽ ưa thích 'nổ()'. – alex

0
$date = date_create_from_format('d/m/Y', $date_string); 
$unix_timestamp = $date->getTimestamp(); 

hoặc

$date = DateTime::createFromFormat('d/m/Y', $date_string); 
$unix_timestamp = $date->getTimestamp(); 
0

Đối với độc giả trong tương lai, hãy thử như sau để phân tích số ngày từ đầu vào người sử dụng unstrusted, mà strptime() là quá cứng nhắc. Nó xuất ra các chuỗi ngày ISO mà bạn có thể chuyển đến new Date(), strtotime(), v.v. hoặc sai cho các ngày không hợp lệ hoặc null cho không có đầu vào có thể sử dụng. Bạn sẽ phải điều chỉnh nó để xử lý thời gian. Nó cũng chấp nhận năm 2 chữ số và đầu vào ngày ISO.

function parseUserDate($input, $allow_zero = false) { 
    if (!is_string($input)) { 
     return $input === null ? null : false; 
    } 
    $input = preg_split('/\\D+/', $input, null, PREG_SPLIT_NO_EMPTY); 
    if (!$input) { 
     return null;# no date 
    } 
    if (count($input) == 3) { 
     list($od, , $oy) = $input; 
     if (strlen($od) > 2 && strlen($oy) < 3) {# assume ISO 
      $oy = $od; 
      $input = array_reverse($input); 
     } 
     $intify = function($dig) { 
      return (int) ltrim($dig, '0');# prevent octals 
     }; 
     list($d, $m, $y) = array_map($intify, $input); 
     if (strlen($oy) < 3) { 
      $current_year = date('Y'); 
      $current_year_2 = $intify(substr($current_year, -2)); 
      $diff = $y - $current_year_2; 
      if ($diff > 50) { 
       $diff -= 100; 
      } 
      elseif ($diff < -50) { 
       $diff += 100; 
      } 
      $y = $diff + $current_year; 
     } 
     if (
      ($allow_zero && $d == 0 && $m == 0 && $y == 0) 
      || checkdate($m, $d, $y)# murrican function 
     ) { 
      return sprintf('%04d-%02d-%02d', $y, $m, $d); 
     } 
    } 
    return false;# invalid date 
}