<?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 '<code>fix_date</code>' 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
            '<code>date_format</code>' 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 '<code>fix_date</code>' 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 <code>'fixdate'</code> to avoid returning true 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 <code>'fixdate'</code> 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 <code>date_format</code>
            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:
-->
