Ver Mensaje Individual
  #11 (permalink)  
Antiguo 21/03/2012, 05:58
Henkka
 
Fecha de Ingreso: abril-2008
Ubicación: Santa Fe, Argentina
Mensajes: 41
Antigüedad: 15 años, 11 meses
Puntos: 14
Respuesta: formato de fechas

El problema es que '2/3/2012' es ambiguo. Es d/m/Y? O m/d/Y? En el segundo caso, 31 como primer argumento no tendría sentido, porque sólo hay 12 meses. Es por esto que te da la fecha inicial Unix. Ambiguedades similares ocurrirían si usásemos 2 dígitos para el año en lugar de 4.

Ésta deficiencia es mencionada en la [URL="http://php.net/manual/es/function.strtotime.php"]entrada de strtotime en el manual oficial[/URL].

Para esto existe la muy útil e inusualmente inutilizada [URL="http://www.php.net/manual/es/class.datetime.php"]clase DateTime[/URL], la navaja suiza de la fecha en PHP >= 5.3.0. Con sus métodos createFromFormat y Format podemos especificar y mostrar una fecha, respectivamente.


Código PHP:
Ver original
  1. <?php
  2.  
  3. // Nuestro parseador, utilizando la funcion strtotime
  4. function parseFecha_strtotime($fecha)
  5. {
  6.         return date('Ymd', strtotime($fecha));
  7. }
  8.  
  9. // Nuestro parseador, utilizando el objeto DateTime
  10. function parseFecha_DateTime($fecha)
  11. {
  12.         return DateTime::createFromFormat('d/m/Y', $fecha)->format('Ymd');
  13. }
  14.  
  15. // Juego de valores usando barra
  16. $test1 = array('2/3/12', '2/03/12', '02/3/12', '02/03/12', '2/3/2012',
  17.                 '2/03/2012', '02/3/2012', '02/03/2012', '31/03/2012');
  18.  
  19. // Juego de valores usando guion
  20. $test2 = array('2-3-12', '2-03-12', '02-3-12', '02-03-12', '2-3-2012',
  21.                 '2-03-2012', '02-3-2012', '02-03-2012', '31-03-2012');
  22.  
  23. // Unir ambos juegos
  24. $fechas = array_merge($test1, $test2);
  25.  
  26. // Probar con nuestro parseador strtotime
  27. foreach ($fechas as $fecha)
  28.         echo parseFecha_strtotime($fecha) . ' (' . $fecha . ')<br />';
  29.  
  30. echo 'Ahora con DateTime! <br />';
  31.  
  32. // Probar con nuestro parseador DateTime
  33. foreach ($fechas as $fecha)
  34.         echo parseFecha_DateTime($fecha) . ' (' . $fecha . ') <br />';
  35.  
  36. ?>

La salida producida será:

Código HTML:
Ver original
  1. 20120203 (2/3/12)
  2. 20120203 (2/03/12)
  3. 20120203 (02/3/12)
  4. 20120203 (02/03/12)
  5. 20120203 (2/3/2012)
  6. 20120203 (2/03/2012)
  7. 20120203 (02/3/2012)
  8. 20120203 (02/03/2012)
  9. 19691231 (31/03/2012)
  10. 20020312 (2-3-12)
  11. 20020312 (2-03-12)
  12. 20020312 (02-3-12)
  13. 20020312 (02-03-12)
  14. 20120302 (2-3-2012)
  15. 20120302 (2-03-2012)
  16. 20120302 (02-3-2012)
  17. 20120302 (02-03-2012)
  18. 20120331 (31-03-2012)
  19. Ahora con DateTime!
  20. 00120302 (2/3/12)
  21. 00120302 (2/03/12)
  22. 00120302 (02/3/12)
  23. 00120302 (02/03/12)
  24. 20120302 (2/3/2012)
  25. 20120302 (2/03/2012)
  26. 20120302 (02/3/2012)
  27. 20120302 (02/03/2012)
  28. 20120331 (31/03/2012)
  29. Fatal error: Call to a member function format() on a non-object in /var/www/fecha.php on line 9

Podemos apreciar que el parseador strtotime funciona para todos los casos, excepto en '31/03/2012'. Esto está explicado en la entrada del manual de strtotime, se debe a que la barra implica formato americano y 31 no es un mes válido. Sin embargo '31-03-2012' es correctamente convertido tomando 31 como día.

En el parseador DateTime, como en los argumentos pusimos Y en lugar de y, espera 4 dígitos de año y al recibir sólo 2 convierte el año a 0012. Como nuestro formato contempla barras y no guiones, muere al intentar procesar el segundo juego de fechas. Claramente no es para nada indulgente, y si quisiésemos arreglar estas fallas deberíamos hacer un poco más inteligente a nuestra función.

Recapitulando:

Código PHP:
Ver original
  1. <?php
  2.  
  3. // Para pasar de formato en paradigma OO
  4. $fecha = DateTime::createFromFormat('d/m/Y', '2/3/2012');
  5. echo $fecha->format('Ymd') . '<br />';
  6.  
  7. // Para pasar en forma procedural
  8. $fecha = date_create_from_format('d/m/Y', '2/3/2012');
  9. echo date_format($fecha, 'Ymd');
  10.  
  11. ?>

Su salida:

Código HTML:
Ver original
  1. 20120302
  2. 20120302

Ambos paradigmas producen la misma salida, y se pueden encadenar los 2 métodos en el paradigma OO como en el primer ejemplo, o primero asignarlo a una variable y luego mostrar con formato esa variable. Difieren en el tratamiento de errores, pero me imagino que las excepciones se escapan de tu conocimiento.