1 //  (C) Copyright Howard Hinnant
2 //  (C) Copyright 2010-2011 Vicente J. Botet Escriba
3 //  Use, modification and distribution are subject to the Boost Software License,
4 //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt).
6 
7 //===-------------------------- locale ------------------------------------===//
8 //
9 //                     The LLVM Compiler Infrastructure
10 //
11 // This file is dual licensed under the MIT and the University of Illinois Open
12 // Source Licenses. See LICENSE.TXT for details.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 // This code was adapted by Vicente from Howard Hinnant's experimental work
17 // on chrono i/o to Boost and some functions from libc++/locale to emulate the missing time_get::get()
18 
19 #ifndef BOOST_CHRONO_IO_TIME_POINT_IO_HPP
20 #define BOOST_CHRONO_IO_TIME_POINT_IO_HPP
21 
22 #include <boost/chrono/io/time_point_put.hpp>
23 #include <boost/chrono/io/time_point_get.hpp>
24 #include <boost/chrono/io/duration_io.hpp>
25 #include <boost/chrono/io/ios_base_state.hpp>
26 #include <boost/chrono/io/utility/manip_base.hpp>
27 #include <boost/chrono/time_point.hpp>
28 #include <boost/chrono/clock_string.hpp>
29 #include <boost/chrono/round.hpp>
30 #include <boost/chrono/detail/scan_keyword.hpp>
31 #include <boost/static_assert.hpp>
32 #include <boost/detail/no_exceptions_support.hpp>
33 #include <cstring>
34 #include <locale>
35 #include <ctime>
36 
37 #if  ( defined BOOST_WINDOWS && ! defined(__CYGWIN__) )  \
38   || (defined(sun) || defined(__sun)) \
39   || (defined __IBMCPP__) \
40   || defined __ANDROID__ \
41   || defined __QNXNTO__ \
42   || (defined(_AIX) && defined __GNUC__)
43 #define  BOOST_CHRONO_INTERNAL_TIMEGM
44 #endif
45 
46 #if (defined BOOST_WINDOWS && ! defined(__CYGWIN__)) \
47   || ( (defined(sun) || defined(__sun)) && defined __GNUC__) \
48   || (defined __IBMCPP__) \
49   || defined __ANDROID__ \
50   || (defined(_AIX) && defined __GNUC__)
51 #define  BOOST_CHRONO_INTERNAL_GMTIME
52 #endif
53 
54 #define  BOOST_CHRONO_USES_INTERNAL_TIME_GET
55 
56 namespace boost
57 {
58   namespace chrono
59   {
60     typedef double fractional_seconds;
61     namespace detail
62     {
63 
64 
65       template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> >
66       struct time_get
67       {
68         std::time_get<CharT> const &that_;
time_getboost::chrono::detail::time_get69         time_get(std::time_get<CharT> const& that) : that_(that) {}
70 
71         typedef std::time_get<CharT> facet;
72         typedef typename facet::iter_type iter_type;
73         typedef typename facet::char_type char_type;
74         typedef std::basic_string<char_type> string_type;
75 
76         static int
get_up_to_n_digitsboost::chrono::detail::time_get77         get_up_to_n_digits(
78             InputIterator& b, InputIterator e,
79             std::ios_base::iostate& err,
80             const std::ctype<CharT>& ct,
81             int n)
82         {
83             // Precondition:  n >= 1
84             if (b == e)
85             {
86                 err |= std::ios_base::eofbit | std::ios_base::failbit;
87                 return 0;
88             }
89             // get first digit
90             CharT c = *b;
91             if (!ct.is(std::ctype_base::digit, c))
92             {
93                 err |= std::ios_base::failbit;
94                 return 0;
95             }
96             int r = ct.narrow(c, 0) - '0';
97             for (++b, --n; b != e && n > 0; ++b, --n)
98             {
99                 // get next digit
100                 c = *b;
101                 if (!ct.is(std::ctype_base::digit, c))
102                     return r;
103                 r = r * 10 + ct.narrow(c, 0) - '0';
104             }
105             if (b == e)
106                 err |= std::ios_base::eofbit;
107             return r;
108         }
109 
110 
get_dayboost::chrono::detail::time_get111         void get_day(
112             int& d,
113             iter_type& b, iter_type e,
114             std::ios_base::iostate& err,
115             const std::ctype<char_type>& ct) const
116         {
117             int t = get_up_to_n_digits(b, e, err, ct, 2);
118             if (!(err & std::ios_base::failbit) && 1 <= t && t <= 31)
119                 d = t;
120             else
121                 err |= std::ios_base::failbit;
122         }
123 
get_monthboost::chrono::detail::time_get124         void get_month(
125             int& m,
126             iter_type& b, iter_type e,
127             std::ios_base::iostate& err,
128             const std::ctype<char_type>& ct) const
129         {
130             int t = get_up_to_n_digits(b, e, err, ct, 2);
131             if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12)
132                 m = --t;
133             else
134                 err |= std::ios_base::failbit;
135         }
136 
137 
get_year4boost::chrono::detail::time_get138         void get_year4(int& y,
139                                                       iter_type& b, iter_type e,
140                                                       std::ios_base::iostate& err,
141                                                       const std::ctype<char_type>& ct) const
142         {
143             int t = get_up_to_n_digits(b, e, err, ct, 4);
144             if (!(err & std::ios_base::failbit))
145                 y = t - 1900;
146         }
147 
148         void
get_hourboost::chrono::detail::time_get149         get_hour(int& h,
150                                                      iter_type& b, iter_type e,
151                                                      std::ios_base::iostate& err,
152                                                      const std::ctype<char_type>& ct) const
153         {
154             int t = get_up_to_n_digits(b, e, err, ct, 2);
155             if (!(err & std::ios_base::failbit) && t <= 23)
156                 h = t;
157             else
158                 err |= std::ios_base::failbit;
159         }
160 
161         void
get_minuteboost::chrono::detail::time_get162         get_minute(int& m,
163                                                        iter_type& b, iter_type e,
164                                                        std::ios_base::iostate& err,
165                                                        const std::ctype<char_type>& ct) const
166         {
167             int t = get_up_to_n_digits(b, e, err, ct, 2);
168             if (!(err & std::ios_base::failbit) && t <= 59)
169                 m = t;
170             else
171                 err |= std::ios_base::failbit;
172         }
173 
get_secondboost::chrono::detail::time_get174         void  get_second(int& s,
175                                                        iter_type& b, iter_type e,
176                                                        std::ios_base::iostate& err,
177                                                        const std::ctype<char_type>& ct) const
178         {
179             int t = get_up_to_n_digits(b, e, err, ct, 2);
180             if (!(err & std::ios_base::failbit) && t <= 60)
181                 s = t;
182             else
183                 err |= std::ios_base::failbit;
184         }
185 
get_white_spaceboost::chrono::detail::time_get186         void get_white_space(iter_type& b, iter_type e,
187                                                             std::ios_base::iostate& err,
188                                                             const std::ctype<char_type>& ct) const
189         {
190             for (; b != e && ct.is(std::ctype_base::space, *b); ++b)
191                 ;
192             if (b == e)
193                 err |= std::ios_base::eofbit;
194         }
195 
get_12_hourboost::chrono::detail::time_get196         void get_12_hour(int& h,
197                                                         iter_type& b, iter_type e,
198                                                         std::ios_base::iostate& err,
199                                                         const std::ctype<char_type>& ct) const
200         {
201             int t = get_up_to_n_digits(b, e, err, ct, 2);
202             if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12)
203                 h = t;
204             else
205                 err |= std::ios_base::failbit;
206         }
207 
get_percentboost::chrono::detail::time_get208         void get_percent(iter_type& b, iter_type e,
209                                                         std::ios_base::iostate& err,
210                                                         const std::ctype<char_type>& ct) const
211         {
212             if (b == e)
213             {
214                 err |= std::ios_base::eofbit | std::ios_base::failbit;
215                 return;
216             }
217             if (ct.narrow(*b, 0) != '%')
218                 err |= std::ios_base::failbit;
219             else if(++b == e)
220                 err |= std::ios_base::eofbit;
221         }
222 
get_day_year_numboost::chrono::detail::time_get223         void get_day_year_num(int& d,
224                                                              iter_type& b, iter_type e,
225                                                              std::ios_base::iostate& err,
226                                                              const std::ctype<char_type>& ct) const
227         {
228             int t = get_up_to_n_digits(b, e, err, ct, 3);
229             if (!(err & std::ios_base::failbit) && 1 <= t && t <= 366)
230                 d = --t;
231             else
232                 err |= std::ios_base::failbit;
233         }
234 
235         void
get_weekdayboost::chrono::detail::time_get236         get_weekday(int& w,
237                                                         iter_type& b, iter_type e,
238                                                         std::ios_base::iostate& err,
239                                                         const std::ctype<char_type>& ct) const
240         {
241             int t = get_up_to_n_digits(b, e, err, ct, 1);
242             if (!(err & std::ios_base::failbit) && t <= 6)
243                 w = t;
244             else
245                 err |= std::ios_base::failbit;
246         }
247 #if 0
248 
249         void
250         get_am_pm(int& h,
251                                                       iter_type& b, iter_type e,
252                                                       std::ios_base::iostate& err,
253                                                       const std::ctype<char_type>& ct) const
254         {
255             const string_type* ap = am_pm();
256             if (ap[0].size() + ap[1].size() == 0)
257             {
258                 err |= ios_base::failbit;
259                 return;
260             }
261             ptrdiff_t i = detail::scan_keyword(b, e, ap, ap+2, ct, err, false) - ap;
262             if (i == 0 && h == 12)
263                 h = 0;
264             else if (i == 1 && h < 12)
265                 h += 12;
266         }
267 
268 #endif
269 
getboost::chrono::detail::time_get270         InputIterator get(
271             iter_type b, iter_type e,
272             std::ios_base& iob,
273             std::ios_base::iostate& err,
274             std::tm* tm,
275             char fmt, char) const
276         {
277             err = std::ios_base::goodbit;
278             const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(iob.getloc());
279 
280             switch (fmt)
281             {
282             case 'a':
283             case 'A':
284               {
285                 std::tm tm2;
286                 std::memset(&tm2, 0, sizeof(std::tm));
287                 that_.get_weekday(b, e, iob, err, &tm2);
288                 //tm->tm_wday = tm2.tm_wday;
289               }
290               break;
291             case 'b':
292             case 'B':
293             case 'h':
294               {
295                 std::tm tm2;
296                 std::memset(&tm2, 0, sizeof(std::tm));
297                 that_.get_monthname(b, e, iob, err, &tm2);
298                 //tm->tm_mon = tm2.tm_mon;
299               }
300               break;
301 //            case 'c':
302 //              {
303 //                const string_type& fm = c();
304 //                b = get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size());
305 //              }
306 //              break;
307             case 'd':
308             case 'e':
309               get_day(tm->tm_mday, b, e, err, ct);
310               break;
311             case 'D':
312               {
313                 const char_type fm[] = {'%', 'm', '/', '%', 'd', '/', '%', 'y'};
314                 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0]));
315               }
316               break;
317             case 'F':
318               {
319                 const char_type fm[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd'};
320                 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0]));
321               }
322               break;
323             case 'H':
324               get_hour(tm->tm_hour, b, e, err, ct);
325               break;
326             case 'I':
327               get_12_hour(tm->tm_hour, b, e, err, ct);
328               break;
329             case 'j':
330               get_day_year_num(tm->tm_yday, b, e, err, ct);
331               break;
332             case 'm':
333               get_month(tm->tm_mon, b, e, err, ct);
334               break;
335             case 'M':
336               get_minute(tm->tm_min, b, e, err, ct);
337               break;
338             case 'n':
339             case 't':
340               get_white_space(b, e, err, ct);
341               break;
342 //            case 'p':
343 //              get_am_pm(tm->tm_hour, b, e, err, ct);
344 //              break;
345             case 'r':
346               {
347                 const char_type fm[] = {'%', 'I', ':', '%', 'M', ':', '%', 'S', ' ', '%', 'p'};
348                 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0]));
349               }
350               break;
351             case 'R':
352               {
353                 const char_type fm[] = {'%', 'H', ':', '%', 'M'};
354                 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0]));
355               }
356               break;
357             case 'S':
358               get_second(tm->tm_sec, b, e, err, ct);
359               break;
360             case 'T':
361               {
362                 const char_type fm[] = {'%', 'H', ':', '%', 'M', ':', '%', 'S'};
363                 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0]));
364               }
365               break;
366             case 'w':
367               {
368                 get_weekday(tm->tm_wday, b, e, err, ct);
369               }
370               break;
371             case 'x':
372               return that_.get_date(b, e, iob, err, tm);
373 //            case 'X':
374 //              return that_.get_time(b, e, iob, err, tm);
375 //              {
376 //                const string_type& fm = X();
377 //                b = that_.get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size());
378 //              }
379 //              break;
380 //            case 'y':
381 //              get_year(tm->tm_year, b, e, err, ct);
382                 break;
383             case 'Y':
384               get_year4(tm->tm_year, b, e, err, ct);
385               break;
386             case '%':
387               get_percent(b, e, err, ct);
388               break;
389             default:
390                 err |= std::ios_base::failbit;
391             }
392             return b;
393         }
394 
395 
getboost::chrono::detail::time_get396         InputIterator get(
397           iter_type b, iter_type e,
398           std::ios_base& iob,
399           std::ios_base::iostate& err, std::tm* tm,
400           const char_type* fmtb, const char_type* fmte) const
401         {
402           const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(iob.getloc());
403           err = std::ios_base::goodbit;
404           while (fmtb != fmte && err == std::ios_base::goodbit)
405           {
406               if (b == e)
407               {
408                   err = std::ios_base::failbit;
409                   break;
410               }
411               if (ct.narrow(*fmtb, 0) == '%')
412               {
413                   if (++fmtb == fmte)
414                   {
415                       err = std::ios_base::failbit;
416                       break;
417                   }
418                   char cmd = ct.narrow(*fmtb, 0);
419                   char opt = '\0';
420                   if (cmd == 'E' || cmd == '0')
421                   {
422                       if (++fmtb == fmte)
423                       {
424                           err = std::ios_base::failbit;
425                           break;
426                       }
427                       opt = cmd;
428                       cmd = ct.narrow(*fmtb, 0);
429                   }
430                   b = get(b, e, iob, err, tm, cmd, opt);
431                   ++fmtb;
432               }
433               else if (ct.is(std::ctype_base::space, *fmtb))
434               {
435                   for (++fmtb; fmtb != fmte && ct.is(std::ctype_base::space, *fmtb); ++fmtb)
436                       ;
437                   for (        ;    b != e    && ct.is(std::ctype_base::space, *b);    ++b)
438                       ;
439               }
440               else if (ct.toupper(*b) == ct.toupper(*fmtb))
441               {
442                   ++b;
443                   ++fmtb;
444               }
445               else
446                   err = std::ios_base::failbit;
447           }
448           if (b == e)
449               err |= std::ios_base::eofbit;
450           return b;
451         }
452 
453       };
454 
455 
456       template <class CharT>
457       class time_manip: public manip<time_manip<CharT> >
458       {
459         std::basic_string<CharT> fmt_;
460         timezone tz_;
461       public:
462 
time_manip(timezone tz,std::basic_string<CharT> fmt)463         time_manip(timezone tz, std::basic_string<CharT> fmt)
464         // todo move semantics
465         :
466           fmt_(fmt), tz_(tz)
467         {
468         }
469 
470         /**
471          * Change the timezone and time format ios state;
472          */
operator ()(std::ios_base & ios) const473         void operator()(std::ios_base &ios) const
474         {
475           set_time_fmt<CharT> (ios, fmt_);
476           set_timezone(ios, tz_);
477         }
478       };
479 
480       class time_man: public manip<time_man>
481       {
482         timezone tz_;
483       public:
484 
time_man(timezone tz)485         time_man(timezone tz)
486         // todo move semantics
487         :
488           tz_(tz)
489         {
490         }
491 
492         /**
493          * Change the timezone and time format ios state;
494          */
operator ()(std::ios_base & ios) const495         void operator()(std::ios_base &ios) const
496         {
497           //set_time_fmt<typename out_stream::char_type>(ios, "");
498           set_timezone(ios, tz_);
499         }
500       };
501 
502     }
503 
504     template <class CharT>
time_fmt(timezone tz,const CharT * fmt)505     inline detail::time_manip<CharT> time_fmt(timezone tz, const CharT* fmt)
506     {
507       return detail::time_manip<CharT>(tz, fmt);
508     }
509 
510     template <class CharT>
time_fmt(timezone tz,std::basic_string<CharT> fmt)511     inline detail::time_manip<CharT> time_fmt(timezone tz, std::basic_string<CharT> fmt)
512     {
513       // todo move semantics
514       return detail::time_manip<CharT>(tz, fmt);
515     }
516 
time_fmt(timezone f)517     inline detail::time_man time_fmt(timezone f)
518     {
519       return detail::time_man(f);
520     }
521 
522     /**
523      * time_fmt_io_saver i/o saver.
524      *
525      * See Boost.IO i/o state savers for a motivating compression.
526      */
527     template <typename CharT = char, typename Traits = std::char_traits<CharT> >
528     struct time_fmt_io_saver
529     {
530 
531       //! the type of the state to restore
532       //typedef std::basic_ostream<CharT, Traits> state_type;
533       typedef std::ios_base state_type;
534 
535       //! the type of aspect to save
536       typedef std::basic_string<CharT, Traits> aspect_type;
537 
538       /**
539        * Explicit construction from an i/o stream.
540        *
541        * Store a reference to the i/o stream and the value of the associated @c time format .
542        */
time_fmt_io_saverboost::chrono::time_fmt_io_saver543       explicit time_fmt_io_saver(state_type &s) :
544         s_save_(s), a_save_(get_time_fmt<CharT>(s_save_))
545       {
546       }
547 
548       /**
549        * Construction from an i/o stream and a @c time format  to restore.
550        *
551        * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter.
552        */
time_fmt_io_saverboost::chrono::time_fmt_io_saver553       time_fmt_io_saver(state_type &s, aspect_type new_value) :
554         s_save_(s), a_save_(get_time_fmt<CharT>(s_save_))
555       {
556         set_time_fmt(s_save_, new_value);
557       }
558 
559       /**
560        * Destructor.
561        *
562        * Restores the i/o stream with the format to be restored.
563        */
~time_fmt_io_saverboost::chrono::time_fmt_io_saver564       ~time_fmt_io_saver()
565       {
566         this->restore();
567       }
568 
569       /**
570        * Restores the i/o stream with the time format to be restored.
571        */
restoreboost::chrono::time_fmt_io_saver572       void restore()
573       {
574         set_time_fmt(s_save_, a_save_);
575       }
576     private:
577       state_type& s_save_;
578       aspect_type a_save_;
579     };
580 
581     /**
582      * timezone_io_saver i/o saver.
583      *
584      * See Boost.IO i/o state savers for a motivating compression.
585      */
586     struct timezone_io_saver
587     {
588 
589       //! the type of the state to restore
590       typedef std::ios_base state_type;
591       //! the type of aspect to save
592       typedef timezone aspect_type;
593 
594       /**
595        * Explicit construction from an i/o stream.
596        *
597        * Store a reference to the i/o stream and the value of the associated @c timezone.
598        */
timezone_io_saverboost::chrono::timezone_io_saver599       explicit timezone_io_saver(state_type &s) :
600         s_save_(s), a_save_(get_timezone(s_save_))
601       {
602       }
603 
604       /**
605        * Construction from an i/o stream and a @c timezone to restore.
606        *
607        * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter.
608        */
timezone_io_saverboost::chrono::timezone_io_saver609       timezone_io_saver(state_type &s, aspect_type new_value) :
610         s_save_(s), a_save_(get_timezone(s_save_))
611       {
612         set_timezone(s_save_, new_value);
613       }
614 
615       /**
616        * Destructor.
617        *
618        * Restores the i/o stream with the format to be restored.
619        */
~timezone_io_saverboost::chrono::timezone_io_saver620       ~timezone_io_saver()
621       {
622         this->restore();
623       }
624 
625       /**
626        * Restores the i/o stream with the timezone to be restored.
627        */
restoreboost::chrono::timezone_io_saver628       void restore()
629       {
630         set_timezone(s_save_, a_save_);
631       }
632     private:
633       timezone_io_saver& operator=(timezone_io_saver const& rhs) ;
634 
635       state_type& s_save_;
636       aspect_type a_save_;
637     };
638 
639     /**
640      *
641      * @param os
642      * @param tp
643      * @Effects Behaves as a formatted output function. After constructing a @c sentry object, if the @ sentry
644      * converts to true, calls to @c facet.put(os,os,os.fill(),tp) where @c facet is the @c time_point_put<CharT>
645      * facet associated to @c os or a new created instance of the default @c time_point_put<CharT> facet.
646      * @return @c os.
647      */
648     template <class CharT, class Traits, class Clock, class Duration>
649     std::basic_ostream<CharT, Traits>&
operator <<(std::basic_ostream<CharT,Traits> & os,const time_point<Clock,Duration> & tp)650     operator<<(std::basic_ostream<CharT, Traits>& os, const time_point<Clock, Duration>& tp)
651     {
652 
653       bool failed = false;
654       BOOST_TRY
655       {
656         std::ios_base::iostate err = std::ios_base::goodbit;
657         BOOST_TRY
658         {
659           typename std::basic_ostream<CharT, Traits>::sentry opfx(os);
660           if (bool(opfx))
661           {
662             if (!std::has_facet<time_point_put<CharT> >(os.getloc()))
663             {
664               if (time_point_put<CharT> ().put(os, os, os.fill(), tp) .failed())
665               {
666                 err = std::ios_base::badbit;
667               }
668             }
669             else
670             {
671               if (std::use_facet<time_point_put<CharT> >(os.getloc()) .put(os, os, os.fill(), tp).failed())
672               {
673                 err = std::ios_base::badbit;
674               }
675             }
676             os.width(0);
677           }
678         }
679         BOOST_CATCH (...)
680         {
681           bool flag = false;
682           BOOST_TRY
683           {
684             os.setstate(std::ios_base::failbit);
685           }
686           BOOST_CATCH (std::ios_base::failure )
687           {
688             flag = true;
689           }
690           BOOST_CATCH_END
691           if (flag) throw;
692         }
693         BOOST_CATCH_END
694         if (err) os.setstate(err);
695         return os;
696       }
697       BOOST_CATCH (...)
698       {
699         failed = true;
700       }
701       BOOST_CATCH_END
702       if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit);
703       return os;
704     }
705 
706     template <class CharT, class Traits, class Clock, class Duration>
707     std::basic_istream<CharT, Traits>&
operator >>(std::basic_istream<CharT,Traits> & is,time_point<Clock,Duration> & tp)708     operator>>(std::basic_istream<CharT, Traits>& is, time_point<Clock, Duration>& tp)
709     {
710       std::ios_base::iostate err = std::ios_base::goodbit;
711 
712       BOOST_TRY
713       {
714         typename std::basic_istream<CharT, Traits>::sentry ipfx(is);
715         if (bool(ipfx))
716         {
717           if (!std::has_facet<time_point_get<CharT> >(is.getloc()))
718           {
719             time_point_get<CharT> ().get(is, std::istreambuf_iterator<CharT, Traits>(), is, err, tp);
720           }
721           else
722           {
723             std::use_facet<time_point_get<CharT> >(is.getloc()).get(is, std::istreambuf_iterator<CharT, Traits>(), is,
724                 err, tp);
725           }
726         }
727       }
728       BOOST_CATCH (...)
729       {
730         bool flag = false;
731         BOOST_TRY
732         {
733           is.setstate(std::ios_base::failbit);
734         }
735         BOOST_CATCH (std::ios_base::failure )
736         {
737           flag = true;
738         }
739         BOOST_CATCH_END
740         if (flag) throw;
741       }
742       BOOST_CATCH_END
743       if (err) is.setstate(err);
744       return is;
745     }
746 
747 
748     namespace detail
749     {
750 
751 //#if defined BOOST_CHRONO_INTERNAL_TIMEGM
752 
is_leap(int32_t year)753     inline int32_t is_leap(int32_t year)
754     {
755       if(year % 400 == 0)
756       return 1;
757       if(year % 100 == 0)
758       return 0;
759       if(year % 4 == 0)
760       return 1;
761       return 0;
762     }
days_from_0(int32_t year)763     inline int32_t days_from_0(int32_t year)
764     {
765       year--;
766       return 365 * year + (year / 400) - (year/100) + (year / 4);
767     }
days_from_1970(int32_t year)768     inline int32_t days_from_1970(int32_t year)
769     {
770       static const int32_t days_from_0_to_1970 = days_from_0(1970);
771       return days_from_0(year) - days_from_0_to_1970;
772     }
days_from_1jan(int32_t year,int32_t month,int32_t day)773     inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day)
774     {
775       static const int32_t days[2][12] =
776       {
777         { 0,31,59,90,120,151,181,212,243,273,304,334},
778         { 0,31,60,91,121,152,182,213,244,274,305,335}
779       };
780 
781       return days[is_leap(year)][month-1] + day - 1;
782     }
783 
internal_timegm(std::tm const * t)784     inline time_t internal_timegm(std::tm const *t)
785     {
786       int year = t->tm_year + 1900;
787       int month = t->tm_mon;
788       if(month > 11)
789       {
790         year += month/12;
791         month %= 12;
792       }
793       else if(month < 0)
794       {
795         int years_diff = (-month + 11)/12;
796         year -= years_diff;
797         month+=12 * years_diff;
798       }
799       month++;
800       int day = t->tm_mday;
801       int day_of_year = days_from_1jan(year,month,day);
802       int days_since_epoch = days_from_1970(year) + day_of_year ;
803 
804       time_t seconds_in_day = 3600 * 24;
805       time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec;
806 
807       return result;
808     }
809 //#endif
810 
811     /**
812     * from_ymd could be made more efficient by using a table
813     * day_count_table indexed by the y%400.
814     * This table could contain the day_count
815     * by*365 + by/4 - by/100 + by/400
816     *
817     * from_ymd = (by/400)*days_by_400_years+day_count_table[by%400] +
818     * days_in_year_before[is_leap_table[by%400]][m-1] + d;
819     */
days_before_years(int32_t y)820     inline unsigned days_before_years(int32_t y)
821    {
822      return y * 365 + y / 4 - y / 100 + y / 400;
823    }
824 
825     // Returns year/month/day triple in civil calendar
826     // Preconditions:  z is number of days since 1970-01-01 and is in the range:
827     //                   [numeric_limits<Int>::min(), numeric_limits<Int>::max()-719468].
828     template <class Int>
829     //constexpr
830     void
civil_from_days(Int z,Int & y,unsigned & m,unsigned & d)831     inline civil_from_days(Int z, Int& y, unsigned& m, unsigned& d) BOOST_NOEXCEPT
832     {
833         BOOST_STATIC_ASSERT_MSG(std::numeric_limits<unsigned>::digits >= 18,
834                  "This algorithm has not been ported to a 16 bit unsigned integer");
835         BOOST_STATIC_ASSERT_MSG(std::numeric_limits<Int>::digits >= 20,
836                  "This algorithm has not been ported to a 16 bit signed integer");
837         z += 719468;
838         const Int era = (z >= 0 ? z : z - 146096) / 146097;
839         const unsigned doe = static_cast<unsigned>(z - era * 146097);          // [0, 146096]
840         const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;  // [0, 399]
841         y = static_cast<Int>(yoe) + era * 400;
842         const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);                // [0, 365]
843         const unsigned mp = (5*doy + 2)/153;                                   // [0, 11]
844         d = doy - (153*mp+2)/5 + 1;                             // [1, 31]
845         m = mp + (mp < 10 ? 3 : -9);                            // [1, 12]
846         y += (m <= 2);
847         --m;
848     }
internal_gmtime(std::time_t const * t,std::tm * tm)849    inline std::tm * internal_gmtime(std::time_t const* t, std::tm *tm)
850    {
851       if (t==0) return 0;
852       if (tm==0) return 0;
853 
854 #if 0
855       static  const unsigned char
856         day_of_year_month[2][366] =
857            {
858            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 },
859 
860            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
861 
862            } };
863 
864       static const int32_t days_in_year_before[2][13] =
865      {
866        { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
867        { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }
868      };
869 #endif
870 
871      const time_t seconds_in_day = 3600 * 24;
872      int32_t days_since_epoch = static_cast<int32_t>(*t / seconds_in_day);
873      int32_t hms = static_cast<int32_t>(*t - seconds_in_day*days_since_epoch);
874      if (hms < 0) {
875        days_since_epoch-=1;
876        hms = seconds_in_day+hms;
877      }
878 
879 #if 0
880      int32_t x = days_since_epoch;
881      int32_t y = static_cast<int32_t> (static_cast<long long> (x + 2) * 400
882            / 146097);
883        const int32_t ym1 = y - 1;
884        int32_t doy = x - days_before_years(y);
885        const int32_t doy1 = x - days_before_years(ym1);
886        const int32_t N = std::numeric_limits<int>::digits - 1;
887        const int32_t mask1 = doy >> N; // arithmetic rshift - not portable - but nearly universal
888        const int32_t mask0 = ~mask1;
889        doy = (doy & mask0) | (doy1 & mask1);
890        y = (y & mask0) | (ym1 & mask1);
891        //y -= 32767 + 2;
892        y += 70;
893        tm->tm_year=y;
894        const int32_t leap = is_leap(y);
895        tm->tm_mon = day_of_year_month[leap][doy]-1;
896        tm->tm_mday = doy - days_in_year_before[leap][tm->tm_mon] ;
897 #else
898        int32_t y;
899        unsigned m, d;
900        civil_from_days(days_since_epoch, y, m, d);
901        tm->tm_year=y-1900; tm->tm_mon=m; tm->tm_mday=d;
902 #endif
903 
904      tm->tm_hour = hms / 3600;
905      const int ms = hms % 3600;
906      tm->tm_min = ms / 60;
907      tm->tm_sec = ms % 60;
908 
909      tm->tm_isdst = -1;
910      (void)mktime(tm);
911      return tm;
912    }
913 
914     } // detail
915 #ifndef BOOST_CHRONO_NO_UTC_TIMEPOINT
916 
917 #if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT
918 
919     template <class CharT, class Traits, class Duration>
920     std::basic_ostream<CharT, Traits>&
operator <<(std::basic_ostream<CharT,Traits> & os,const time_point<system_clock,Duration> & tp)921     operator<<(std::basic_ostream<CharT, Traits>& os, const time_point<system_clock, Duration>& tp)
922     {
923       typename std::basic_ostream<CharT, Traits>::sentry ok(os);
924       if (bool(ok))
925       {
926         bool failed = false;
927         BOOST_TRY
928         {
929           const CharT* pb = 0; //nullptr;
930           const CharT* pe = pb;
931           std::basic_string<CharT> fmt = get_time_fmt<CharT> (os);
932           pb = fmt.data();
933           pe = pb + fmt.size();
934 
935           timezone tz = get_timezone(os);
936           std::locale loc = os.getloc();
937           time_t t = system_clock::to_time_t(time_point_cast<system_clock::duration>(tp));
938           std::tm tm;
939           std::memset(&tm, 0, sizeof(std::tm));
940           if (tz == timezone::local)
941           {
942 #if defined BOOST_WINDOWS && ! defined(__CYGWIN__)
943 #if BOOST_MSVC < 1400  // localtime_s doesn't exist in vc7.1
944             std::tm *tmp = 0;
945             if ((tmp=localtime(&t)) == 0)
946               failed = true;
947             else
948               tm =*tmp;
949 # else
950             if (localtime_s(&tm, &t) != 0) failed = true;
951 # endif
952 #else
953             if (localtime_r(&t, &tm) == 0) failed = true;
954 #endif
955           }
956           else
957           {
958 #if defined BOOST_CHRONO_INTERNAL_GMTIME
959             if (detail::internal_gmtime(&t, &tm) == 0) failed = true;
960 
961 #elif defined BOOST_WINDOWS && ! defined(__CYGWIN__)
962             std::tm *tmp = 0;
963             if((tmp = gmtime(&t)) == 0)
964               failed = true;
965             else
966               tm = *tmp;
967 #else
968             if (gmtime_r(&t, &tm) == 0) failed = true;
969             tm.tm_isdst = -1;
970             (void)mktime(&tm);
971 
972 #endif
973 
974           }
975           if (!failed)
976           {
977             const std::time_put<CharT>& tpf = std::use_facet<std::time_put<CharT> >(loc);
978             if (pb == pe)
979             {
980               CharT pattern[] =
981               { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' };
982               pb = pattern;
983               pe = pb + sizeof (pattern) / sizeof(CharT);
984               failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed();
985               if (!failed)
986               {
987                 duration<fractional_seconds> d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec);
988                 if (d.count() < 10) os << CharT('0');
989                 //if (! os.good()) {
990                 //  throw "exception";
991                 //}
992                 std::ios::fmtflags flgs = os.flags();
993                 os.setf(std::ios::fixed, std::ios::floatfield);
994                 //if (! os.good()) {
995                 //throw "exception";
996                 //}
997                 os.precision(9);
998                 os << d.count();
999                 //if (! os.good()) {
1000                 //throw "exception";
1001                 //}
1002                 os.flags(flgs);
1003                 if (tz == timezone::local)
1004                 {
1005                   CharT sub_pattern[] =
1006                   { ' ', '%', 'z' };
1007                   pb = sub_pattern;
1008                   pe = pb + +sizeof (sub_pattern) / sizeof(CharT);
1009                   failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed();
1010                 }
1011                 else
1012                 {
1013                   CharT sub_pattern[] =
1014                   { ' ', '+', '0', '0', '0', '0', 0 };
1015                   os << sub_pattern;
1016                 }
1017               }
1018             }
1019             else
1020             {
1021               failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed();
1022             }
1023           }
1024         }
1025         BOOST_CATCH (...)
1026         {
1027           failed = true;
1028         }
1029         BOOST_CATCH_END
1030         if (failed)
1031         {
1032           os.setstate(std::ios_base::failbit | std::ios_base::badbit);
1033         }
1034       }
1035       return os;
1036     }
1037 #endif
1038 
1039     namespace detail
1040     {
1041 
1042       template <class CharT, class InputIterator>
extract_z(InputIterator & b,InputIterator e,std::ios_base::iostate & err,const std::ctype<CharT> & ct)1043       minutes extract_z(InputIterator& b, InputIterator e, std::ios_base::iostate& err, const std::ctype<CharT>& ct)
1044       {
1045         int min = 0;
1046         if (b != e)
1047         {
1048           char cn = ct.narrow(*b, 0);
1049           if (cn != '+' && cn != '-')
1050           {
1051             err |= std::ios_base::failbit;
1052             return minutes(0);
1053           }
1054           int sn = cn == '-' ? -1 : 1;
1055           int hr = 0;
1056           for (int i = 0; i < 2; ++i)
1057           {
1058             if (++b == e)
1059             {
1060               err |= std::ios_base::eofbit | std::ios_base::failbit;
1061               return minutes(0);
1062             }
1063             cn = ct.narrow(*b, 0);
1064             if (! ('0' <= cn && cn <= '9'))
1065             {
1066               err |= std::ios_base::failbit;
1067               return minutes(0);
1068             }
1069             hr = hr * 10 + cn - '0';
1070           }
1071           for (int i = 0; i < 2; ++i)
1072           {
1073             if (++b == e)
1074             {
1075               err |= std::ios_base::eofbit | std::ios_base::failbit;
1076               return minutes(0);
1077             }
1078             cn = ct.narrow(*b, 0);
1079             if (! ('0' <= cn && cn <= '9'))
1080             {
1081               err |= std::ios_base::failbit;
1082               return minutes(0);
1083             }
1084             min = min * 10 + cn - '0';
1085           }
1086           if (++b == e) {
1087             err |= std::ios_base::eofbit;
1088           }
1089           min += hr * 60;
1090           min *= sn;
1091         }
1092         else
1093         {
1094           err |= std::ios_base::eofbit | std::ios_base::failbit;
1095         }
1096         return minutes(min);
1097       }
1098 
1099     } // detail
1100 
1101 #if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT
1102 
1103     template <class CharT, class Traits, class Duration>
1104     std::basic_istream<CharT, Traits>&
operator >>(std::basic_istream<CharT,Traits> & is,time_point<system_clock,Duration> & tp)1105     operator>>(std::basic_istream<CharT, Traits>& is, time_point<system_clock, Duration>& tp)
1106     {
1107       typename std::basic_istream<CharT, Traits>::sentry ok(is);
1108       if (bool(ok))
1109       {
1110         std::ios_base::iostate err = std::ios_base::goodbit;
1111         BOOST_TRY
1112         {
1113           const CharT* pb = 0; //nullptr;
1114           const CharT* pe = pb;
1115           std::basic_string<CharT> fmt = get_time_fmt<CharT> (is);
1116           pb = fmt.data();
1117           pe = pb + fmt.size();
1118 
1119           timezone tz = get_timezone(is);
1120           std::locale loc = is.getloc();
1121           const std::time_get<CharT>& tg = std::use_facet<std::time_get<CharT> >(loc);
1122           const std::ctype<CharT>& ct = std::use_facet<std::ctype<CharT> >(loc);
1123           tm tm; // {0}
1124           std::memset(&tm, 0, sizeof(std::tm));
1125 
1126           typedef std::istreambuf_iterator<CharT, Traits> It;
1127           if (pb == pe)
1128           {
1129             CharT pattern[] =
1130             { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' };
1131             pb = pattern;
1132             pe = pb + sizeof (pattern) / sizeof(CharT);
1133 
1134 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET
1135             const detail::time_get<CharT>& dtg(tg);
1136             dtg.get(is, 0, is, err, &tm, pb, pe);
1137 #else
1138             tg.get(is, 0, is, err, &tm, pb, pe);
1139 #endif
1140             if (err & std::ios_base::failbit) goto exit;
1141             fractional_seconds sec;
1142             CharT c = CharT();
1143             std::ios::fmtflags flgs = is.flags();
1144             is.setf(std::ios::fixed, std::ios::floatfield);
1145             is.precision(9);
1146             is >> sec;
1147             is.flags(flgs);
1148             if (is.fail())
1149             {
1150               err |= std::ios_base::failbit;
1151               goto exit;
1152             }
1153             It i(is);
1154             It eof;
1155             c = *i;
1156             if (++i == eof || c != ' ')
1157             {
1158               err |= std::ios_base::failbit;
1159               goto exit;
1160             }
1161             minutes min = detail::extract_z(i, eof, err, ct);
1162 
1163             if (err & std::ios_base::failbit) goto exit;
1164             time_t t;
1165 
1166 #if defined BOOST_CHRONO_INTERNAL_TIMEGM
1167             t = detail::internal_timegm(&tm);
1168 #else
1169             t = timegm(&tm);
1170 #endif
1171             tp = time_point_cast<Duration>(
1172                 system_clock::from_time_t(t) - min + round<system_clock::duration> (duration<fractional_seconds> (sec))
1173                 );
1174           }
1175           else
1176           {
1177             const CharT z[2] =
1178             { '%', 'z' };
1179             const CharT* fz = std::search(pb, pe, z, z + 2);
1180 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET
1181             const detail::time_get<CharT>& dtg(tg);
1182             dtg.get(is, 0, is, err, &tm, pb, fz);
1183 #else
1184             tg.get(is, 0, is, err, &tm, pb, fz);
1185 #endif
1186             minutes minu(0);
1187             if (fz != pe)
1188             {
1189               if (err != std::ios_base::goodbit)
1190               {
1191                 err |= std::ios_base::failbit;
1192                 goto exit;
1193               }
1194               It i(is);
1195               It eof;
1196               minu = detail::extract_z(i, eof, err, ct);
1197               if (err & std::ios_base::failbit) goto exit;
1198               if (fz + 2 != pe)
1199               {
1200                 if (err != std::ios_base::goodbit)
1201                 {
1202                   err |= std::ios_base::failbit;
1203                   goto exit;
1204                 }
1205 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET
1206                 const detail::time_get<CharT>& dtg(tg);
1207                 dtg.get(is, 0, is, err, &tm, fz + 2, pe);
1208 #else
1209                 tg.get(is, 0, is, err, &tm, fz + 2, pe);
1210 #endif
1211                 if (err & std::ios_base::failbit) goto exit;
1212               }
1213             }
1214             tm.tm_isdst = -1;
1215             time_t t;
1216             if (tz == timezone::utc || fz != pe)
1217             {
1218 #if defined BOOST_CHRONO_INTERNAL_TIMEGM
1219               t = detail::internal_timegm(&tm);
1220 #else
1221               t = timegm(&tm);
1222 #endif
1223             }
1224             else
1225             {
1226               t = mktime(&tm);
1227             }
1228             tp = time_point_cast<Duration>(
1229                 system_clock::from_time_t(t) - minu
1230                 );
1231           }
1232         }
1233         BOOST_CATCH (...)
1234         {
1235           err |= std::ios_base::badbit | std::ios_base::failbit;
1236         }
1237         BOOST_CATCH_END
1238         exit: is.setstate(err);
1239       }
1240       return is;
1241     }
1242 
1243 #endif
1244 #endif //UTC
1245   } // chrono
1246 
1247 }
1248 
1249 #endif  // header
1250