1<?xml version="1.0" encoding="utf-8"?> 2<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" 3"../../../tools/boostbook/dtd/boostbook.dtd"> 4 5<!-- Copyright (c) 2005 CrystalClear Software, Inc. 6 Subject to the Boost Software License, Version 1.0. 7 (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 8--> 9 10<section id="date_time.io_tutorial" 11 xmlns:xi="http://www.w3.org/2001/XInclude"> 12 <title>Date Time IO Tutorial</title> 13 <bridgehead renderas="sect2">Date Time IO Tutorial</bridgehead> 14 15 <link linkend="basic_use">Basic Use</link> | 16 <link linkend="format_strings">Format Strings</link> | 17 <link linkend="content_strings">Content Strings</link> | 18 <link linkend="tut_sv">Special Values</link> | 19 <link linkend="tut_dper">Date/Time Periods</link> | 20 <link linkend="tut_dgen">Date Generators</link> 21 22 <anchor id="basic_use" /> 23 <bridgehead renderas="sect4">Basic Use</bridgehead> 24 <para>Facets are automatically imbued when operators '>>' and '<<' are called. The list of date_time objects that can be streamed are:</para> 25 <bridgehead renderas="sect5">Gregorian</bridgehead> 26 <para> 27 <code>date</code>, 28 <code>days</code>, 29 <code>date_period</code>, 30 <code>greg_month</code>, 31 <code>greg_weekday</code>, 32 <code>greg_year</code>, 33 <code>partial_date</code>, 34 <code>nth_day_of_the_week_in_month</code>, 35 <code>first_day_of_the_week_in_month</code>, 36 <code>last_day_of_the_week_in_month</code>, 37 <code>first_day_of_the_week_after</code>, 38 <code>first_day_of_the_week_before</code> 39 </para> 40 <bridgehead renderas="sect5">Posix_time</bridgehead> 41 <para> 42 <code>ptime</code>, 43 <code>time_period</code>, 44 <code>time_duration</code> 45 </para> 46 <bridgehead renderas="sect5">Local_time</bridgehead> 47 <para> 48 <code>local_date_time</code> 49 </para> 50 51 <para> 52 The following example is of the basic use of the new IO code, utilizing all the defaults. (this example can be found in the <code>libs/date_time/example/tutorial</code> directory) 53 </para> 54 <programlisting> 55 <![CDATA[ 56 date d(2004, Feb, 29); 57 time_duration td(12,34,56,789); 58 stringstream ss; 59 ss << d << ' ' << td; 60 ptime pt(not_a_date_time); 61 cout << pt << endl; // "not-a-date-time" 62 ss >> pt; 63 cout << pt << endl; // "2004-Feb-29 12:34:56.000789" 64 ss.str(""); 65 ss << pt << " EDT-05EDT,M4.1.0,M10.5.0"; 66 local_date_time ldt(not_a_date_time); 67 ss >> ldt; 68 cout << ldt << endl; // "2004-Feb-29 12:34:56.000789 EDT" 69 ]]> 70 </programlisting> 71 72 <para>This example used the default settings for the input and output facets. The default formats are such that interoperability like that shown in the example is possible. NOTE: Input streaming of local_date_time can only be done with a <link linkend="date_time.local_time.posix_time_zone">posix time zone string</link>. The default output format uses a time zone abbreviation. The format can be changed so out and in match (as we will see later in this tutorial).</para> 73 74 <anchor id="format_strings" /> 75 <bridgehead renderas="sect4">Format Strings</bridgehead> 76 <para>The format strings control the order, type, and style of the date/time elements used. The facets provide some predefined formats (iso_format_specifier, iso_format_extended_specifier, and default_date_format) but the user can easily create their own.</para> 77 (continued from previous example) 78 <programlisting> 79 <![CDATA[ 80 local_time_facet* output_facet = new local_time_facet(); 81 local_time_input_facet* input_facet = new local_time_input_facet(); 82 ss.imbue(locale(locale::classic(), output_facet)); 83 ss.imbue(locale(ss.getloc(), input_facet)); 84 85 output_facet->format("%a %b %d, %H:%M %z"); 86 ss.str(""); 87 ss << ldt; 88 cout << ss.str() << endl; // "Sun Feb 29, 12:34 EDT" 89 90 output_facet->format(local_time_facet::iso_time_format_specifier); 91 ss.str(""); 92 ss << ldt; 93 cout << ss.str() << endl; // "20040229T123456.000789-0500" 94 95 output_facet->format(local_time_facet::iso_time_format_extended_specifier); 96 ss.str(""); 97 ss << ldt; 98 cout << ss.str() << endl; // "2004-02-29 12:34:56.000789-05:00" 99 ]]> 100 </programlisting> 101 102 <para>Format strings are not limited to date/time elements. Extra verbiage can be placed in a format string. NOTE: When extra verbiage is present in an input format, the data being input must also contain the exact verbiage.</para> 103 (continued from previous example) 104 <programlisting> 105 <![CDATA[ 106 // extra words in format 107 string my_format("The extended ordinal time %Y-%jT%H:%M can also be \ 108 represented as %A %B %d, %Y"); 109 output_facet->format(my_format.c_str()); 110 input_facet->format(my_format.c_str()); 111 ss.str(""); 112 ss << ldt; 113 cout << ss.str() << endl; 114 115 // matching extra words in input 116 ss.str("The extended ordinal time 2005-128T12:15 can also be \ 117 represented as Sunday May 08, 2005"); 118 ss >> ldt; 119 cout << ldt << endl; 120 ]]> 121 </programlisting> 122 123 <anchor id="content_strings" /> 124 <bridgehead renderas="sect4">Content Strings</bridgehead> 125 <para>So far we've shown how a user can achieve a great deal of customization with very little effort by using formats. Further customization can be achieved through user defined elements (ie strings). The elements that can be customized are: Special value names, month names, month abbreviations, weekday names, weekday abbreviations, delimiters of the date/time periods, and the phrase elements of the date_generators.</para> 126 <para>The default values for these are as follows:</para> 127 <bridgehead renderas="sect5">Special values</bridgehead> 128 <para> 129 <code>not-a-date-time</code>, 130 <code>-infinity</code>, 131 <code>+infinity</code>, 132 <code>minimum-date-time</code>, 133 <code>maximum-date-time</code> 134 </para> 135 <bridgehead renderas="sect5">Months</bridgehead> 136 <para> 137 <code>English calendar and three letter abbreviations</code> 138 </para> 139 <bridgehead renderas="sect5">Weekdays</bridgehead> 140 <para> 141 <code>English calendar and three letter abbreviations</code> 142 </para> 143 <bridgehead renderas="sect5">Date generator phrase elements</bridgehead> 144 <para> 145 <code>first</code>, 146 <code>second</code>, 147 <code>third</code>, 148 <code>fourth</code>, 149 <code>fifth</code>, 150 <code>last</code>, 151 <code>before</code>, 152 <code>after</code>, 153 <code>of</code> 154 </para> 155 <para>NOTE: We've shown earlier that the components of a date/time representation can be re-ordered via the format string. This is not the case with date_generators. The elements themselves can be customized but their order cannot be changed.</para> 156 157 <bridgehead renderas="sect4">Content Strings</bridgehead> 158 <para>To illustrate the customization possibilities we will use custom strings for months and weekdays (we will only use long names, is all lowercase, for this example).</para> 159 (continued from previous example) 160 <programlisting> 161 <![CDATA[ 162 // set up the collections of custom strings. 163 // only the full names are altered for the sake of brevity 164 string month_names[12] = { "january", "february", "march", 165 "april", "may", "june", 166 "july", "august", "september", 167 "october", "november", "december" }; 168 vector<string> long_months(&month_names[0], &month_names[12]); 169 string day_names[7] = { "sunday", "monday", "tuesday", "wednesday", 170 "thursday", "friday", "saturday" }; 171 vector<string> long_days(&day_names[0], &day_names[7]); 172 173 // create date_facet and date_input_facet using all defaults 174 date_facet* date_output = new date_facet(); 175 date_input_facet* date_input = new date_input_facet(); 176 ss.imbue(locale(ss.getloc(), date_output)); 177 ss.imbue(locale(ss.getloc(), date_input)); 178 179 // replace names in the output facet 180 date_output->long_month_names(long_months); 181 date_output->long_weekday_names(long_days); 182 183 // replace names in the input facet 184 date_input->long_month_names(long_months); 185 date_input->long_weekday_names(long_days); 186 187 // customize month, weekday and date formats 188 date_output->format("%Y-%B-%d"); 189 date_input->format("%Y-%B-%d"); 190 date_output->month_format("%B"); // full name 191 date_input->month_format("%B"); // full name 192 date_output->weekday_format("%A"); // full name 193 date_input->weekday_format("%A"); // full name 194 195 ss.str(""); 196 ss << greg_month(3); 197 cout << ss.str() << endl; // "march" 198 ss.str(""); 199 ss << greg_weekday(3); 200 cout << ss.str() << endl; // "tuesday" 201 ss.str(""); 202 ss << date(2005,Jul,4); 203 cout << ss.str() << endl; // "2005-july-04" 204 ]]> 205 </programlisting> 206 207 208 <anchor id="tut_sv" /> 209 <bridgehead renderas="sect4">Special Values</bridgehead> 210 <para>Customizing the input and output of special values is best done by creating a new special_values_parser and special_values_formatter. The new strings can be set at construction time (as in the example below).</para> 211 (continued from previous example) 212 <programlisting> 213 <![CDATA[ 214 // reset the formats to defaults 215 output_facet->format(local_time_facet::default_time_format); 216 input_facet->format(local_time_input_facet::default_time_input_format); 217 218 // create custom special_values parser and formatter objects 219 // and add them to the facets 220 string sv[5] = {"nadt","neg_inf", "pos_inf", "min_dt", "max_dt" }; 221 vector<string> sv_names(&sv[0], &sv[5]); 222 special_values_parser sv_parser(sv_names.begin(), sv_names.end()); 223 special_values_formatter sv_formatter(sv_names.begin(), sv_names.end()); 224 output_facet->special_values_formatter(sv_formatter); 225 input_facet->special_values_parser(sv_parser); 226 227 ss.str(""); 228 ldt = local_date_time(not_a_date_time); 229 ss << ldt; 230 cout << ss.str() << endl; // "nadt" 231 232 ss.str("min_dt"); 233 ss >> ldt; 234 ss.str(""); 235 ss << ldt; 236 cout << ss.str() << endl; // "1400-Jan-01 00:00:00 UTC" 237 ]]> 238 </programlisting> 239 <para>NOTE: even though we sent in strings for min and max to the formatter, they are ignored because those special values construct to actual dates (as shown above).</para> 240 241 242 <anchor id="tut_dper" /> 243 <bridgehead renderas="sect4">Date/Time Periods</bridgehead> 244 <para>Customizing the input and output of periods is best done by creating a new period_parser and period_formatter. The new strings can be set at construction time (as in the example below).</para> 245 (continued from previous example) 246 <programlisting> 247 <![CDATA[ 248 // all formats set back to defaults (not shown for brevity) 249 250 // create our date_period 251 date_period dp(date(2005,Mar,1), days(31)); // month of march 252 253 // custom period formatter and parser 254 period_formatter per_formatter(period_formatter::AS_OPEN_RANGE, 255 " to ", "from ", " exclusive", " inclusive" ); 256 period_parser per_parser(period_parser::AS_OPEN_RANGE, 257 " to ", "from ", " exclusive" , "inclusive" ); 258 259 // default output 260 ss.str(""); 261 ss << dp; 262 cout << ss.str() << endl; // "[2005-Mar-01/2005-Mar-31]" 263 264 // add out custom parser and formatter to the facets 265 date_output->period_formatter(per_formatter); 266 date_input->period_parser(per_parser); 267 268 // custom output 269 ss.str(""); 270 ss << dp; 271 cout << ss.str() << endl; // "from 2005-Feb-01 to 2005-Apr-01 exclusive" 272 ]]> 273 </programlisting> 274 275 <anchor id="tut_dgen" /> 276 <bridgehead renderas="sect4">Date Generators</bridgehead> 277 <para>Customizing the input and output of date_generators is done by replacing the existing strings (in the facet) with new strings.</para> 278 <para>NOTE: We've shown earlier that the components of a date/time representation can be re-ordered via the format string. This is not the case with date_generators. The elements themselves can be customized but their order cannot be changed.</para> 279 (continued from previous example) 280 <programlisting> 281 <![CDATA[ 282 // custom date_generator phrases 283 string dg_phrases[9] = { "1st", "2nd", "3rd", "4th", "5th", 284 "final", "prior to", "following", "in" }; 285 vector<string> phrases(&dg_phrases[0], &dg_phrases[9]); 286 287 // create our date_generator 288 first_day_of_the_week_before d_gen(Monday); 289 290 // default output 291 ss.str(""); 292 ss << d_gen; 293 cout << ss.str() << endl; // "Mon before" 294 295 // add our custom strings to the date facets 296 date_output->date_gen_phrase_strings(phrases); 297 date_input->date_gen_element_strings(phrases); 298 299 // custom output 300 ss.str(""); 301 ss << d_gen; 302 cout << ss.str() << endl; // "Mon prior to" 303 ]]> 304 </programlisting> 305 306</section> 307