Make partial dates in XMP not have the ommitted fields fulled out to 1's (reported...
authorBrian Wolff <bawolff@users.mediawiki.org>
Sat, 8 Oct 2011 18:40:00 +0000 (18:40 +0000)
committerBrian Wolff <bawolff@users.mediawiki.org>
Sat, 8 Oct 2011 18:40:00 +0000 (18:40 +0000)
Basically, in XMP you can specify partial date (for example 2011-04 for april 2011 with no day).
We were extracting that, and fulling out the day to 01 if it wasn't present (My original resoning when writing
the code was that the nice localized date functions need a full date, but that's a pretty poor rationale for displaying
wrong date). This changes it to just display such year-month things as YYYY:MM.

includes/media/FormatMetadata.php
includes/media/XMPValidate.php
tests/phpunit/includes/media/XMPValidateTest.php [new file with mode: 0644]

index 47fc1ad..bd992a2 100644 (file)
@@ -233,10 +233,19 @@ class FormatMetadata {
                                        if ( $val == '0000:00:00 00:00:00' || $val == '    :  :     :  :  ' ) {
                                                $val = wfMsg( 'exif-unknowndate' );
                                        } elseif ( preg_match( '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D', $val ) ) {
+                                               // Full date.
                                                $time = wfTimestamp( TS_MW, $val );
                                                if ( $time && intval( $time ) > 0 ) {
                                                        $val = $wgLang->timeanddate( $time );
                                                }
+                                       } elseif ( preg_match( '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
+                                               // No second field. Still format the same
+                                               // since timeanddate doesn't include seconds anyways,
+                                               // but second still available in api
+                                               $time = wfTimestamp( TS_MW, $val . ':00' );
+                                               if ( $time && intval( $time ) > 0 ) {
+                                                       $val = $wgLang->timeanddate( $time );
+                                               }
                                        } elseif ( preg_match( '/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
                                                // If only the date but not the time is filled in.
                                                $time = wfTimestamp( TS_MW, substr( $val, 0, 4 )
index 0f1d375..600d99d 100644 (file)
@@ -201,10 +201,20 @@ class XMPValidate {
        }
 
        /**
-       * function to validate date properties, and convert to Exif format.
+       * function to validate date properties, and convert to (partial) Exif format.
+       *
+       * Dates can be one of the following formats:
+       * YYYY
+       * YYYY-MM
+       * YYYY-MM-DD
+       * YYYY-MM-DDThh:mmTZD
+       * YYYY-MM-DDThh:mm:ssTZD
+       * YYYY-MM-DDThh:mm:ss.sTZD
        *
        * @param $info Array information about current property
        * @param &$val Mixed current value to validate. Converts to TS_EXIF as a side-effect.
+       *       in cases where there's only a partial date, it will give things like
+       *       2011:04.
        * @param $standalone Boolean if this is a simple property or array
        */
        public static function validateDate( $info, &$val, $standalone ) {
@@ -240,25 +250,41 @@ class XMPValidate {
                                $val = null;
                                return;
                        }
-                       //if month, etc unspecified, full out as 01.
-                       $res[2] = isset( $res[2] ) ? $res[2] : '01'; //month
-                       $res[3] = isset( $res[3] ) ? $res[3] : '01'; //day
+
                        if ( !isset( $res[4] ) ) { //hour
-                               //just have the year month day
-                               $val = $res[1] . ':' . $res[2] . ':' . $res[3];
+                               //just have the year month day (if that)
+                               $val = $res[1];
+                               if ( isset( $res[2] ) ) {
+                                       $val .= ':' . $res[2];
+                               }
+                               if ( isset( $res[3] ) ) {
+                                       $val .= ':' . $res[3];
+                               }
                                return;
                        }
-                       //if hour is set, so is minute or regex above will fail.
-                       //Extra check for empty string necessary due to TZ but no second case.
-                       $res[6] = isset( $res[6] ) && $res[6] != '' ? $res[6] : '00';
 
                        if ( !isset( $res[7] ) || $res[7] === 'Z' ) {
+                               //if hour is set, then minute must also be or regex above will fail.
                                $val = $res[1] . ':' . $res[2] . ':' . $res[3]
-                                       . ' ' . $res[4] . ':' . $res[5] . ':' . $res[6];
+                                       . ' ' . $res[4] . ':' . $res[5];
+                               if ( isset( $res[6] ) && $res[6] !== '' ) {
+                                       $val .= ':' . $res[6];
+                               }
                                return;
                        }
 
-                       //do timezone processing. We've already done the case that tz = Z.
+
+                       // Extra check for empty string necessary due to TZ but no second case.
+                       $stripSeconds = false;
+                       if ( !isset( $res[6] ) || $res[6] === '' ) {
+                               $res[6] = '00';
+                               $stripSeconds = true;
+                       }
+
+                       // Do timezone processing. We've already done the case that tz = Z.
+
+                       // We know that if we got to this step, year, month day hour and min must be set
+                       // by virtue of regex not failing.
 
                        $unix = wfTimestamp( TS_UNIX, $res[1] . $res[2] . $res[3] . $res[4] . $res[5] . $res[6] );
                        $offset = intval( substr( $res[7], 1, 2 ) ) * 60 * 60;
@@ -267,6 +293,11 @@ class XMPValidate {
                                $offset = -$offset;
                        }
                        $val = wfTimestamp( TS_EXIF, $unix + $offset );
+
+                       if ( $stripSeconds ) {
+                               // If seconds weren't specified, remove the trailing ':00'.
+                               $val = substr( $val, 0, -3 );
+                       }
                }
 
        }
diff --git a/tests/phpunit/includes/media/XMPValidateTest.php b/tests/phpunit/includes/media/XMPValidateTest.php
new file mode 100644 (file)
index 0000000..94ff1da
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+class XMPTest extends MediaWikiTestCase {
+
+       /**
+        * @dataProvider providerDate
+        */
+       function testValidateDate( $value, $expected ) {
+               // The method should modify $value.
+               XMPValidate::validateDate( array(), $value, true );
+               $this->assertEquals( $expected, $value );
+       }
+
+       function providerDate() {
+               /* For reference valid date formats are:
+                * YYYY
+                * YYYY-MM
+                * YYYY-MM-DD
+                * YYYY-MM-DDThh:mmTZD
+                * YYYY-MM-DDThh:mm:ssTZD
+                * YYYY-MM-DDThh:mm:ss.sTZD
+                * (Time zone is optional)
+                */
+               return array(
+                       array( '1992', '1992' ),
+                       array( '1992-04', '1992:04' ),
+                       array( '1992-02-01', '1992:02:01' ),
+                       array( '2011-09-29', '2011:09:29' ),
+                       array( '1982-12-15T20:12', '1982:12:15 20:12' ),
+                       array( '1982-12-15T20:12Z', '1982:12:15 20:12' ),
+                       array( '1982-12-15T20:12+02:30', '1982:12:15 22:42' ),
+                       array( '1982-12-15T01:12-02:30', '1982:12:14 22:42' ),
+                       array( '1982-12-15T20:12:11', '1982:12:15 20:12:11' ),
+                       array( '1982-12-15T20:12:11Z', '1982:12:15 20:12:11' ),
+                       array( '1982-12-15T20:12:11+01:10', '1982:12:15 21:22:11' ),
+                       array( '2045-12-15T20:12:11', '2045:12:15 20:12:11' ),
+                       array( '1867-06-01T15:00:00', '1867:06:01 15:00:00' ),
+                       /* some invalid ones */
+                       array( '2001--12', null ),
+                       array( '2001-5-12', null ),
+                       array( '2001-5-12TZ', null ),
+                       array( '2001-05-12T15', null ),
+                       array( '2001-12T15:13', null ),
+               );
+
+       }
+
+}