<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.locale.date.datesandtimes">
    <title>Working with Dates and Times</title>

    <para>
        <classname>Zend_Locale_Format</classname> provides several methods for working with dates
        and times to help convert and normalize between different formats for different locales. Use
        <classname>Zend_Date</classname> for manipulating dates, and working with date strings that
        already conform to <link linkend="zend.date.constants">one of the many internationally
            recognized standard formats, or one of the localized date formats supported by
            <classname>Zend_Date</classname></link>. Using an existing, pre-defined format offers
        advantages, including the use of well-tested code, and the assurance of some degree of
        portability and interoperability (depending on the standard used). The examples below do not
        follow these recommendations, since using non-standard date formats would needlessly
        increase the difficulty of understanding these examples.
    </para>

    <sect2 id="zend.locale.date.normalize">
        <title>Normalizing Dates and Times</title>

        <para>
            The <methodname>getDate()</methodname> method parses strings containing dates in
            localized formats. The results are returned in a structured array, with well-defined
            keys for each part of the date. In addition, the array will contain a key 'date_format'
            showing the format string used to parse the input date string. Since a localized date
            string may not contain all parts of a date/time, the key-value pairs are optional. for
            example, if only the year, month, and day is given, then all time values are suppressed
            from the returned array, and vice-versa if only hour, minute, and second were given as
            input. If no date or time can be found within the given input, an exception will be
            thrown.
        </para>

        <para>
            If <methodname>setOption(array('fix_date' => true))</methodname> is set the
            <methodname>getDate()</methodname> method adds a key 'fixed' with a whole number value
            indicating if the input date string required "fixing" by rearranging the day, month, or
            year in the input to fit the format used.
        </para>

        <table id="zend.locale.date.normalize.table-1">
            <title>Key values for getDate() with option 'fix_date'</title>

            <tgroup cols='2'>
                <thead>
                    <row>
                        <entry>value</entry>
                        <entry>meaning</entry>
                    </row>
                </thead>

                <tbody>
                    <row>
                        <entry>0</entry>
                        <entry>nothing to fix</entry>
                    </row>

                    <row>
                        <entry>1</entry>
                        <entry>fixed false month</entry>
                    </row>

                    <row>
                        <entry>2</entry>
                        <entry>swapped day and year</entry>
                    </row>

                    <row>
                        <entry>3</entry>
                        <entry>swapped month and year</entry>
                    </row>

                    <row>
                        <entry>4</entry>
                        <entry>swapped month and day</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <para>
            For those needing to specify explicitly the format of the date string, the following
            format token specifiers are supported. If an invalid format specifier is used, such as
            the <acronym>PHP</acronym> 'i' specifier when in <acronym>ISO</acronym> format mode,
            then an error will be thrown by the methods in <classname>Zend_Locale_Format</classname>
            that support user-defined formats.
        </para>

        <para>
            These specifiers (below) are a small subset of the full "ISO" set supported by
            <classname>Zend_Date</classname>'s <methodname>toString()</methodname>. If you need to
            use <acronym>PHP</acronym> <methodname>date()</methodname> compatible format specifiers,
            then first call <methodname>setOptions(array('format_type' => 'php'))</methodname>. And
            if you want to convert only one special format string from <acronym>PHP</acronym>
            <methodname>date()</methodname> compatible format to "ISO" format use
            <methodname>convertPhpToIsoFormat()</methodname>. Currently, the only practical
            difference relates to the specifier for minutes ('m' using the <acronym>ISO</acronym>
            default, and 'i' using the <acronym>PHP</acronym> date format).
        </para>

        <table id="zend.locale.date.normalize.table-2">
            <title>Return values</title>

            <tgroup cols='5'>
                <thead>
                    <row>
                        <entry>getDate() format character</entry>
                        <entry>Array key</entry>
                        <entry>Returned value</entry>
                        <entry>Minimum</entry>
                        <entry>Maximum</entry>
                    </row>
                </thead>

                <tbody>
                    <row>
                        <entry>d</entry>
                        <entry>day</entry>
                        <entry>integer</entry>
                        <entry>1</entry>
                        <entry>31</entry>
                    </row>

                    <row>
                        <entry>M</entry>
                        <entry>month</entry>
                        <entry>integer</entry>
                        <entry>1</entry>
                        <entry>12</entry>
                    </row>

                    <row>
                        <entry>y</entry>
                        <entry>year</entry>
                        <entry>integer</entry>
                        <entry>no limit</entry>
                        <entry>PHP integer's maximum</entry>
                    </row>

                    <row>
                        <entry>h</entry>
                        <entry>hour</entry>
                        <entry>integer</entry>
                        <entry>0</entry>
                        <entry>PHP integer's maximum</entry>
                    </row>

                    <row>
                        <entry>m</entry>
                        <entry>minute</entry>
                        <entry>integer</entry>
                        <entry>0</entry>
                        <entry>PHP integer's maximum</entry>
                    </row>

                    <row>
                        <entry>s</entry>
                        <entry>second</entry>
                        <entry>integer</entry>
                        <entry>0</entry>
                        <entry>PHP integer's maximum</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <example id="zend.locale.date.normalize.example-1">
            <title>Normalizing a date</title>

            <programlisting language="php"><![CDATA[
$dateString = Zend_Locale_Format::getDate('13.04.2006',
                                          array('date_format' =>
                                                    'dd.MM.yyyy')
                                         );

// creates a Zend_Date object for this date
$dateObject = Zend_Date('13.04.2006',
                         array('date_format' => 'dd.MM.yyyy'));

print_r($dateString); // outputs:

Array
(
    [format] => dd.MM.yyyy
    [day] => 13
    [month] => 4
    [year] => 2006
)

// alternatively, some types of problems with input data can be
// automatically corrected
$date = Zend_Locale_Format::getDate('04.13.2006',
                                    array('date_format' => 'dd.MM.yyyy',
                                          'fix_date' => true)
                                   );

print_r($date); // outputs:

Array
(
    [format] => dd.MM.yyyy
    [day] => 13
    [month] => 4
    [year] => 2006
    [fixed] => 4
)
]]></programlisting>
        </example>

        <para>
            Since <methodname>getDate()</methodname> is "locale-aware", specifying the
            <varname>$locale</varname> is sufficient for date strings adhering to that locale's
            format. The option '<property>fix_date</property>' uses simple tests to determine if the
            day or month is not valid, and then applies heuristics to try and correct any detected
            problems. Note the use of '<constant>Zend_Locale_Format::STANDARD</constant>' as the
            value for '<property>date_format</property>' to prevent the use of a class-wide default
            date format set using <methodname>setOptions()</methodname>. This forces getDate to use
            the default date format for <varname>$locale</varname>.
        </para>

        <example id="zend.locale.date.normalize.example-2">
            <title>Normalizing a date by locale</title>

            <programlisting language="php"><![CDATA[
$locale = new Zend_Locale('de_AT');
$date = Zend_Locale_Format::getDate('13.04.2006',
                                    array('date_format' =>
                                              Zend_Locale_Format::STANDARD,
                                          'locale' => $locale)
                                   );

print_r ($date);
]]></programlisting>
        </example>

        <para>
            A complete date and time is returned when the input contains both a date and time in the
            expected format.
        </para>

        <example id="zend.locale.date.normalize.example-3">
            <title>Normalizing a date with time</title>

            <programlisting language="php"><![CDATA[
$locale = new Zend_Locale('de_AT');
$date = Zend_Locale_Format::getDate('13.04.2005 22:14:55',
                                    array('date_format' =>
                                                Zend_Locale_Format::STANDARD,
                                          'locale' => $locale)
                                    );

print_r ($date);
]]></programlisting>
        </example>

        <para>
            If a specific format is desired, specify the <varname>$format</varname> argument,
            without giving a <varname>$locale</varname>. Only single-letter codes
            (H, m, s, y, M, d), and MMMM and EEEE are supported in the <varname>$format</varname>.
        </para>

        <example id="zend.locale.date.normalize.example-4">
            <title>Normalizing a userdefined date</title>

            <programlisting language="php"><![CDATA[
$date = Zend_Locale_Format::getDate('13200504T551422',
                                    array('date_format' =>
                                              'ddyyyyMM ssmmHH')
                                   );

print_r ($date);
]]></programlisting>
        </example>

        <para>
            The format can include the following signs :
        </para>

        <table id="zend.locale.date.normalize.table-3">
            <title>Format definition</title>

            <tgroup cols='2'>
                <thead>
                    <row>
                        <entry>Format Letter</entry>
                        <entry>Description</entry>
                    </row>
                </thead>

                <tbody>
                    <row>
                        <entry>d or dd</entry>
                        <entry>1 or 2 digit day</entry>
                    </row>

                    <row>
                        <entry>M or MM</entry>
                        <entry>1 or 2 digit month</entry>
                    </row>

                    <row>
                        <entry>y or yy</entry>
                        <entry>1 or 2 digit year</entry>
                    </row>

                    <row>
                        <entry>yyyy</entry>
                        <entry>4 digit year</entry>
                    </row>

                    <row>
                        <entry>h</entry>
                        <entry>1 or 2 digit hour</entry>
                    </row>

                    <row>
                        <entry>m</entry>
                        <entry>1 or 2 digit minute</entry>
                    </row>

                    <row>
                        <entry>s</entry>
                        <entry>1 or 2 digit second</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <para>
            Examples for proper formats are
        </para>

        <table id="zend.locale.date.normalize.table-4">
            <title>Example formats</title>

            <tgroup cols='3'>
                <thead>
                    <row>
                        <entry>Formats</entry>
                        <entry>Input</entry>
                        <entry>Output</entry>
                    </row>
                </thead>

                <tbody>
                    <row>
                        <entry>dd.MM.yy</entry>
                        <entry>1.4.6</entry>
                        <entry>['day'] => 1, ['month'] => 4, ['year'] => 6</entry>
                    </row>

                    <row>
                        <entry>dd.MM.yy</entry>
                        <entry>01.04.2006</entry>
                        <entry>['day'] => 1, ['month'] => 4, ['year'] => 2006</entry>
                    </row>

                    <row>
                        <entry>yyyyMMdd</entry>
                        <entry>1.4.6</entry>
                        <entry>['day'] => 6, ['month'] => 4, ['year'] => 1</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <note>
            <title>Database date format</title>

            <para>
                To parse a database date value (f.e. MySql or MsSql), use
                <classname>Zend_Date</classname>'s ISO_8601 format instead of getDate().
            </para>
        </note>

        <para>
            The option '<property>fix_date</property>' uses simple tests to determine if the day or
            month is not valid, and then applies heuristics to try and correct any detected
            problems. <methodname>getDate()</methodname> automatically detects and corrects some
            kinds of problems with input, such as misplacing the year:
        </para>

        <example id="zend.locale.date.normalize.example-5">
            <title>Automatic correction of input dates</title>

            <programlisting language="php"><![CDATA[
$date = Zend_Locale_Format::getDate('41.10.20',
                                    array('date_format' => 'ddMMyy',
                                          'fix_date' => true)
                                   );

// instead of 41 for the day, the 41 will be returned as year value
print_r ($date);
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.locale.date.test">
        <title>Testing Dates</title>

        <para>
            Use <methodname>checkDateFormat($inputString, array('date_format' => $format,
                $locale))</methodname> to check if a given string contains all expected date parts.
            The <methodname>checkDateFormat()</methodname> method uses
            <methodname>getDate()</methodname>, but without the option
            '<property>fixdate</property>' to avoid returning <constant>TRUE</constant> when the
            input fails to conform to the date format. If errors are detected in the input, such as
            swapped values for months and days, the option '<property>fixdate</property>' method
            will apply heuristics to "correct" dates before determining their validity.
        </para>

        <example id="zend.locale.date.test.example-1">
            <title>Date testing</title>

            <programlisting language="php"><![CDATA[
$locale = new Zend_Locale('de_AT');
// using the default date format for 'de_AT', is this a valid date?
if (Zend_Locale_Format::checkDateFormat('13.Apr.2006',
                                        array('date_format' =>
                                                  Zend_Locale_Format::STANDARD,
                                              $locale)
                                       ) {
    print "date";
} else {
    print "not a date";
}
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.locale.time.normalizing">
        <title>Normalizing a Time</title>

        <para>
            Normally, a time will be returned with a date, if the input contains both. If the proper
            format is not known, but the locale relevant to the user input is known, then
            <methodname>getTime()</methodname> should be used, because it uses the default time
            format for the selected locale.
        </para>

        <example id="zend.locale.time.normalizing.example-1">
            <title>Normalize an unknown time</title>

            <programlisting language="php"><![CDATA[
$locale = new Zend_Locale('de_AT');
if (Zend_Locale_Format::getTime('13:44:42',
                                array('date_format' =>
                                          Zend_Locale_Format::STANDARD,
                                      'locale' => $locale)) {
    print "time";
} else {
    print "not a time";
}
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.locale.time.test">
        <title>Testing Times</title>

        <para>
            Use <methodname>checkDateFormat()</methodname> to check if a given string contains a
            proper time. The usage is exact the same as with checking Dates, only
            <property>date_format</property> should contain the parts which you expect to have.
        </para>

        <example id="zend.locale.time.test.example-1">
            <title>Testing a time</title>

            <programlisting language="php"><![CDATA[
$locale = new Zend_Locale('de_AT');
if (Zend_Locale_Format::checkDateFormat('13:44:42',
                                        array('date_format' => 'HH:mm:ss',
                                              'locale' => $locale)) {
    print "time";
} else {
    print "not a time";
}
]]></programlisting>
        </example>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
