Coverage Report

Created: 2026-06-15 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/simpledateformat.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
#include <log4cxx/logstring.h>
18
#include <log4cxx/helpers/simpledateformat.h>
19
20
#include <apr_time.h>
21
#include <apr_strings.h>
22
#include <sstream>
23
#include <log4cxx/helpers/transcoder.h>
24
#include <log4cxx/helpers/stringhelper.h>
25
#include <assert.h>
26
#if !defined(LOG4CXX)
27
  #define LOG4CXX 1
28
#endif
29
#include <log4cxx/private/log4cxx_private.h>
30
#include <log4cxx/helpers/pool.h>
31
32
using namespace LOG4CXX_NS;
33
using namespace LOG4CXX_NS::helpers;
34
35
using namespace std;
36
37
#if LOG4CXX_HAS_STD_LOCALE
38
  #include <locale>
39
#endif
40
41
#if defined(_MSC_VER) && _MSC_VER < 1300
42
  #define HAS_FACET(locale, type) _HAS(locale, type)
43
  #define USE_FACET(locale, type) _USE(locale, type)
44
  #define PUT_FACET(facet, os, time, spec) facet.put(os, os, time, spec)
45
#else
46
  #if defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
47
    #define HAS_FACET(locale, type) std::has_facet(locale, (type*) 0)
48
    #define USE_FACET(locale, type) std::use_facet(locale, (type*) 0)
49
  #else
50
0
    #define HAS_FACET(locale, type) std::has_facet < type >(locale)
51
0
    #define USE_FACET(locale, type) std::use_facet < type >(locale)
52
  #endif
53
0
  #define PUT_FACET(facet, os, time, spec) facet.put(os, os, os.fill(), time, spec)
54
#endif
55
56
namespace LOG4CXX_NS
57
{
58
namespace helpers
59
{
60
namespace SimpleDateFormatImpl
61
{
62
typedef void (*incrementFunction)(tm& time, apr_time_exp_t& apr_time);
63
64
/**
65
 * Append \c names[index] only when \c index is within bounds.
66
 *
67
 * The day/month/AM-PM name tables have a fixed size, but the index comes
68
 * directly from an apr_time_exp_t field (tm_wday, tm_mon, tm_hour). APR's
69
 * time-explosion arithmetic can overflow and yield an out-of-range field for
70
 * extreme apr_time_t inputs, in which case the previous code performed an
71
 * out-of-bounds std::vector read (std::vector::operator[] is unchecked).
72
 */
73
static inline void appendName(LogString& s,
74
  const std::vector<LogString>& names, int index)
75
0
{
76
0
  if (0 <= index && static_cast<std::vector<LogString>::size_type>(index) < names.size())
77
0
  {
78
0
    s.append(names[index]);
79
0
  }
80
0
}
81
82
/**
83
 * Abstract inner class representing one format token
84
 * (one or more instances of a character).
85
 */
86
class PatternToken
87
{
88
  public:
89
    PatternToken()
90
0
    {
91
0
    }
92
93
    virtual ~PatternToken()
94
0
    {
95
0
    }
96
97
    /**
98
     * Sets the time zone.
99
     * @param zone new time zone.
100
     */
101
    virtual void setTimeZone(const TimeZonePtr& zone)
102
0
    {
103
0
    }
104
105
    /**
106
     * Appends the formatted content to the string.
107
     * @param s string to which format contribution is appended.
108
     * @param date exploded date/time.
109
     * @param p memory pool.
110
     */
111
    virtual void format(LogString& s,
112
      const apr_time_exp_t& date,
113
      LOG4CXX_NS::helpers::Pool& p) const = 0;
114
115
  protected:
116
117
    static void incrementMonth(tm& time, apr_time_exp_t& aprtime)
118
0
    {
119
0
      time.tm_mon++;
120
0
      aprtime.tm_mon++;
121
0
    }
122
123
    static void incrementDay(tm& time, apr_time_exp_t& aprtime)
124
0
    {
125
0
      time.tm_wday++;
126
0
      aprtime.tm_wday++;
127
0
    }
128
129
    static void incrementHalfDay(tm& time, apr_time_exp_t& aprtime)
130
0
    {
131
0
      time.tm_hour += 12;
132
0
      aprtime.tm_hour += 12;
133
0
    }
134
135
    static void renderFacet(const std::locale* locale,
136
      incrementFunction inc,
137
      char spec,
138
      unsigned int wspec,
139
      const char* aprspec,
140
      std::vector<LogString>& values)
141
0
    {
142
0
      std::vector<LogString>::iterator valueIter = values.begin();
143
0
      tm time;
144
0
      memset(&time, 0, sizeof(time));
145
0
      apr_time_exp_t aprtime;
146
0
      memset(&aprtime, 0, sizeof(aprtime));
147
0
#if LOG4CXX_HAS_STD_LOCALE
148
149
0
      if (locale != NULL)
150
0
      {
151
0
#if LOG4CXX_WCHAR_T_API
152
153
0
        if (HAS_FACET(*locale, std::time_put<wchar_t>))
154
0
        {
155
0
          const std::time_put<wchar_t>& facet = USE_FACET(*locale, std::time_put<wchar_t>);
156
0
          size_t start = 0;
157
0
          std::basic_ostringstream<wchar_t> os;
158
159
0
          for (; valueIter != values.end(); valueIter++)
160
0
          {
161
0
            PUT_FACET(facet, os, &time, (char)wspec);
162
0
            Transcoder::decode(os.str().substr(start), *valueIter);
163
0
            start = os.str().length();
164
0
            (*inc)(time, aprtime);
165
0
          }
166
0
        }
167
0
        else
168
0
#endif
169
0
          if (HAS_FACET(*locale,  std::time_put<char>))
170
0
          {
171
0
            const std::time_put<char>& facet = USE_FACET(*locale, std::time_put<char> );
172
0
            size_t start = 0;
173
0
            std::ostringstream os;
174
175
0
            for (; valueIter != values.end(); valueIter++)
176
0
            {
177
0
              PUT_FACET(facet, os, &time, spec);
178
0
              Transcoder::decode(os.str().substr(start), *valueIter);
179
0
              start = os.str().length();
180
0
              (*inc)(time, aprtime);
181
0
            }
182
0
          }
183
0
      }
184
185
0
#endif
186
0
      const size_t BUFSIZE = 256;
187
0
      char buf[BUFSIZE];
188
0
      memset(buf, 0, BUFSIZE);
189
0
      apr_size_t retsize = 0;
190
191
0
      for (; valueIter != values.end(); valueIter++)
192
0
      {
193
0
        apr_status_t stat = apr_strftime(buf, &retsize, BUFSIZE, aprspec, &aprtime);
194
0
        (*inc)(time, aprtime);
195
196
0
        if (stat == APR_SUCCESS)
197
0
        {
198
0
          Transcoder::decode(std::string(buf, retsize), *valueIter);
199
0
        }
200
0
        else
201
0
        {
202
0
          valueIter->append(1, (logchar) 0x3F);
203
0
        }
204
0
      }
205
0
    }
206
207
  private:
208
    /**
209
     * Private copy constructor.
210
     */
211
    PatternToken(const PatternToken&);
212
213
    /**
214
     * Private assignment operator.
215
     */
216
    PatternToken& operator=(const PatternToken&);
217
};
218
219
220
class LiteralToken : public PatternToken
221
{
222
  public:
223
0
    LiteralToken( logchar ch1, int count1 ) : ch( ch1 ), count( count1 )
224
0
    {
225
0
    }
226
227
    void format( LogString& s, const apr_time_exp_t&, Pool& /* p */ ) const
228
0
    {
229
0
      s.append( count, ch );
230
0
    }
231
232
  private:
233
    logchar ch;
234
    int count;
235
};
236
237
238
239
class EraToken : public PatternToken
240
{
241
  public:
242
    EraToken( int /* count */, const std::locale* /* locale */  )
243
0
    {
244
0
    }
245
246
    void format(LogString& s, const apr_time_exp_t& /* tm */, Pool& /* p */ ) const
247
0
    {
248
0
      s.append(1, (logchar) 0x41 /* 'A' */);
249
0
      s.append(1, (logchar) 0x44 /* 'D' */);
250
0
    }
251
};
252
253
254
255
class NumericToken : public PatternToken
256
{
257
  public:
258
0
    NumericToken( size_t width1 ) : width( width1 )
259
0
    {
260
0
    }
261
262
    virtual int getField( const apr_time_exp_t& tm ) const = 0;
263
264
    void format( LogString& s, const apr_time_exp_t& tm, Pool& p ) const
265
0
    {
266
0
      size_t initialLength = s.length();
267
268
0
      StringHelper::toString( getField( tm ), s );
269
0
      size_t finalLength = s.length();
270
271
0
      if ( initialLength + width > finalLength )
272
0
      {
273
0
        s.insert( initialLength, ( initialLength + width ) - finalLength, (logchar) 0x30 /* '0' */);
274
0
      }
275
0
    }
276
277
  private:
278
    size_t width;
279
};
280
281
282
283
class YearToken : public NumericToken
284
{
285
  public:
286
0
    YearToken( int width1 ) : NumericToken( width1 )
287
0
    {
288
0
    }
289
290
    int getField( const apr_time_exp_t& tm ) const
291
0
    {
292
0
      return 1900 + tm.tm_year;
293
0
    }
294
};
295
296
297
298
class MonthToken : public NumericToken
299
{
300
  public:
301
0
    MonthToken( int width1 ) : NumericToken( width1 )
302
0
    {
303
0
    }
304
305
    int getField( const apr_time_exp_t& tm ) const
306
0
    {
307
0
      return tm.tm_mon + 1;
308
0
    }
309
};
310
311
312
313
class AbbreviatedMonthNameToken : public PatternToken
314
{
315
  public:
316
0
    AbbreviatedMonthNameToken(int, const std::locale* locale) : names( 12 )
317
0
    {
318
0
      renderFacet(locale, PatternToken::incrementMonth, 'b', 0x62, "%b", names);
319
0
    }
320
321
    void format(LogString& s, const apr_time_exp_t& tm, Pool& /* p */ ) const
322
0
    {
323
0
      appendName( s, names, tm.tm_mon );
324
0
    }
325
326
  private:
327
    std::vector < LogString > names;
328
};
329
330
331
332
class FullMonthNameToken : public PatternToken
333
{
334
  public:
335
0
    FullMonthNameToken( int width, const std::locale* locale) : names( 12 )
336
0
    {
337
0
      renderFacet(locale, PatternToken::incrementMonth, 'B', 0x42, "%B", names);
338
0
    }
339
340
    void format( LogString& s, const apr_time_exp_t& tm, Pool& /* p */ ) const
341
0
    {
342
0
      appendName( s, names, tm.tm_mon );
343
0
    }
344
345
  private:
346
    std::vector < LogString > names;
347
};
348
349
350
351
class WeekInYearToken : public NumericToken
352
{
353
  public:
354
0
    WeekInYearToken( int width1 ) : NumericToken( width1 )
355
0
    {
356
0
    }
357
358
    int getField( const apr_time_exp_t& tm ) const
359
0
    {
360
0
      return tm.tm_yday / 7;
361
0
    }
362
};
363
364
365
366
class WeekInMonthToken : public NumericToken
367
{
368
  public:
369
0
    WeekInMonthToken( int width1 ) : NumericToken( width1 )
370
0
    {
371
0
    }
372
373
    int getField( const apr_time_exp_t& tm ) const
374
0
    {
375
0
      return tm.tm_mday / 7;
376
0
    }
377
};
378
379
380
381
class DayInMonthToken : public NumericToken
382
{
383
  public:
384
0
    DayInMonthToken( int width1 ) : NumericToken( width1 )
385
0
    {
386
0
    }
387
388
    int getField( const apr_time_exp_t& tm ) const
389
0
    {
390
0
      return tm.tm_mday;
391
0
    }
392
};
393
394
395
396
class DayInYearToken : public NumericToken
397
{
398
  public:
399
0
    DayInYearToken( int width1 ) : NumericToken( width1 )
400
0
    {
401
0
    }
402
403
    int getField( const apr_time_exp_t& tm ) const
404
0
    {
405
0
      return tm.tm_yday;
406
0
    }
407
};
408
409
410
411
class DayOfWeekInMonthToken : public NumericToken
412
{
413
  public:
414
0
    DayOfWeekInMonthToken( int width1 ) : NumericToken( width1 )
415
0
    {
416
0
    }
417
418
    int getField( const apr_time_exp_t& /* tm */ ) const
419
0
    {
420
0
      return -1;
421
0
    }
422
};
423
424
425
426
class AbbreviatedDayNameToken : public PatternToken
427
{
428
  public:
429
0
    AbbreviatedDayNameToken( int width, const std::locale* locale) : names( 7 )
430
0
    {
431
0
      renderFacet(locale, PatternToken::incrementDay, 'a', 0x61, "%a", names);
432
0
    }
433
434
    void format( LogString& s, const apr_time_exp_t& tm, Pool& /* p */ ) const
435
0
    {
436
0
      appendName( s, names, tm.tm_wday );
437
0
    }
438
439
  private:
440
    std::vector < LogString > names;
441
442
};
443
444
445
446
class FullDayNameToken : public PatternToken
447
{
448
  public:
449
0
    FullDayNameToken( int width, const std::locale* locale) : names( 7 )
450
0
    {
451
0
      renderFacet(locale, PatternToken::incrementDay, 'A', 0x41, "%A", names);
452
0
    }
453
454
    void format( LogString& s, const apr_time_exp_t& tm, Pool& /* p */ ) const
455
0
    {
456
0
      appendName( s, names, tm.tm_wday );
457
0
    }
458
459
  private:
460
    std::vector < LogString > names;
461
462
};
463
464
465
466
class MilitaryHourToken : public NumericToken
467
{
468
  public:
469
0
    MilitaryHourToken( int width1, int offset1 ) : NumericToken( width1 ), offset( offset1 )
470
0
    {
471
0
    }
472
473
    int getField( const apr_time_exp_t& tm ) const
474
0
    {
475
0
      return tm.tm_hour + offset;
476
0
    }
477
478
  private:
479
    int offset;
480
};
481
482
483
484
class HourToken : public NumericToken
485
{
486
  public:
487
0
    HourToken( int width1, int /* offset1 */ ) : NumericToken( width1 ), offset( 0 )
488
0
    {
489
0
    }
490
491
    int getField( const apr_time_exp_t& tm ) const
492
0
    {
493
0
      return ( ( tm.tm_hour + 12 - offset ) % 12 ) + offset;
494
0
    }
495
496
  private:
497
    int offset;
498
};
499
500
501
502
class MinuteToken : public NumericToken
503
{
504
  public:
505
0
    MinuteToken( int width1 ) : NumericToken( width1 )
506
0
    {
507
0
    }
508
509
    int getField( const apr_time_exp_t& tm ) const
510
0
    {
511
0
      return tm.tm_min;
512
0
    }
513
};
514
515
516
517
class SecondToken : public NumericToken
518
{
519
  public:
520
0
    SecondToken( int width1 ) : NumericToken( width1 )
521
0
    {
522
0
    }
523
524
    int getField( const apr_time_exp_t& tm ) const
525
0
    {
526
0
      return tm.tm_sec;
527
0
    }
528
};
529
530
531
532
class MillisecondToken : public NumericToken
533
{
534
  public:
535
0
    MillisecondToken( int width1 ) : NumericToken( width1 )
536
0
    {
537
0
    }
538
539
    int getField( const apr_time_exp_t& tm ) const
540
0
    {
541
0
      return tm.tm_usec / 1000;
542
0
    }
543
};
544
545
546
547
class MicrosecondToken : public NumericToken
548
{
549
  public:
550
0
    MicrosecondToken( int width1 ) : NumericToken( width1 )
551
0
    {
552
0
    }
553
554
    int getField( const apr_time_exp_t& tm ) const
555
0
    {
556
0
      return tm.tm_usec;
557
0
    }
558
};
559
560
561
562
class AMPMToken : public PatternToken
563
{
564
  public:
565
0
    AMPMToken( int width, const std::locale* locale) : names( 2 )
566
0
    {
567
0
      renderFacet(locale, PatternToken::incrementHalfDay, 'p', 0x70, "%p", names);
568
0
    }
569
570
    void format( LogString& s, const apr_time_exp_t& tm, Pool& /* p */ ) const
571
0
    {
572
0
      appendName( s, names, tm.tm_hour / 12 );
573
0
    }
574
575
  private:
576
    std::vector < LogString > names;
577
};
578
579
580
581
class GeneralTimeZoneToken : public PatternToken
582
{
583
  public:
584
    GeneralTimeZoneToken( int /* width */ )
585
0
    {
586
0
    }
587
588
    void format( LogString& s, const apr_time_exp_t&, Pool& /* p */ ) const
589
0
    {
590
0
      s.append(timeZone->getID());
591
0
    }
592
593
    void setTimeZone( const TimeZonePtr& zone )
594
0
    {
595
0
      timeZone = zone;
596
0
    }
597
598
  private:
599
    TimeZonePtr timeZone;
600
};
601
602
603
604
class RFC822TimeZoneToken : public PatternToken
605
{
606
  public:
607
    RFC822TimeZoneToken( int /* width */ )
608
0
    {
609
0
    }
610
611
    void format( LogString& s, const apr_time_exp_t& tm, Pool& p ) const
612
0
    {
613
0
      if ( tm.tm_gmtoff == 0 )
614
0
      {
615
0
        s.append( 1, (logchar) 0x5A /* 'Z'  */ );
616
0
      }
617
0
      else
618
0
      {
619
0
        apr_int32_t off = tm.tm_gmtoff;
620
0
        s.reserve(s.length() + 5);
621
622
0
        if ( off < 0 )
623
0
        {
624
0
          s.push_back( '-' );
625
0
          off = -off;
626
0
        }else{
627
0
          s.push_back( '+' );
628
0
        }
629
630
0
        LogString hours;
631
0
        StringHelper::toString( off / 3600, hours );
632
0
        if( hours.size() == 1 ){
633
0
          s.push_back( '0' );
634
0
        }
635
0
        s.append(hours);
636
637
0
        LogString min;
638
0
        StringHelper::toString( ( off % 3600 ) / 60, min );
639
0
        if( min.size() == 1 ){
640
0
          s.push_back( '0' );
641
0
        }
642
0
        s.append(min);
643
0
      }
644
0
    }
645
};
646
647
648
649
650
}
651
}
652
}
653
654
655
using namespace LOG4CXX_NS::helpers::SimpleDateFormatImpl;
656
657
void SimpleDateFormat::addToken(const logchar spec, const int repeat, const std::locale* locale,
658
  std::vector < PatternToken* >& pattern )
659
0
{
660
0
  PatternToken* token = NULL;
661
662
0
  switch ( spec )
663
0
  {
664
0
    case 0x47: // 'G'
665
0
      token = ( new EraToken( repeat, locale ) );
666
0
      break;
667
668
0
    case 0x79: // 'y'
669
0
      token = ( new YearToken( repeat ) );
670
0
      break;
671
672
0
    case 0x4D: // 'M'
673
0
      if ( repeat <= 2 )
674
0
      {
675
0
        token = ( new MonthToken( repeat ) );
676
0
      }
677
0
      else if ( repeat <= 3 )
678
0
      {
679
0
        token = ( new AbbreviatedMonthNameToken( repeat, locale ) );
680
0
      }
681
0
      else
682
0
      {
683
0
        token = ( new FullMonthNameToken( repeat, locale ) );
684
0
      }
685
686
0
      break;
687
688
0
    case 0x77: // 'w'
689
0
      token = ( new WeekInYearToken( repeat ) );
690
0
      break;
691
692
0
    case 0x57: // 'W'
693
0
      token = ( new WeekInMonthToken( repeat ) );
694
0
      break;
695
696
0
    case 0x44: // 'D'
697
0
      token = ( new DayInYearToken( repeat ) );
698
0
      break;
699
700
0
    case 0x64: // 'd'
701
0
      token = ( new DayInMonthToken( repeat ) );
702
0
      break;
703
704
0
    case 0x46: // 'F'
705
0
      token = ( new DayOfWeekInMonthToken( repeat ) );
706
0
      break;
707
708
0
    case 0x45: // 'E'
709
0
      if ( repeat <= 3 )
710
0
      {
711
0
        token = ( new AbbreviatedDayNameToken( repeat, locale ) );
712
0
      }
713
0
      else
714
0
      {
715
0
        token = ( new FullDayNameToken( repeat, locale ) );
716
0
      }
717
718
0
      break;
719
720
0
    case 0x61: // 'a'
721
0
      token = ( new AMPMToken( repeat, locale ) );
722
0
      break;
723
724
0
    case 0x48: // 'H'
725
0
      token = ( new MilitaryHourToken( repeat, 0 ) );
726
0
      break;
727
728
0
    case 0x6B: // 'k'
729
0
      token = ( new MilitaryHourToken( repeat, 1 ) );
730
0
      break;
731
732
0
    case 0x4B: // 'K'
733
0
      token = ( new HourToken( repeat, 0 ) );
734
0
      break;
735
736
0
    case 0x68: // 'h'
737
0
      token = ( new HourToken( repeat, 1 ) );
738
0
      break;
739
740
0
    case 0x6D: // 'm'
741
0
      token = ( new MinuteToken( repeat ) );
742
0
      break;
743
744
0
    case 0x73: // 's'
745
0
      token = ( new SecondToken( repeat ) );
746
0
      break;
747
748
0
    case 0x53: // 'S'
749
0
      if ( repeat == 6 )
750
0
      {
751
0
        token = ( new MicrosecondToken( repeat ) );
752
0
      }
753
0
      else
754
0
      {
755
        // It would be nice to support patterns with arbitrary
756
        // subsecond precision (like "s.S" or "s.SSSS"), but we
757
        // don't; so this is a back-compatible default.
758
0
        token = ( new MillisecondToken( repeat ) );
759
0
      }
760
761
0
      break;
762
763
0
    case 0x7A: // 'z'
764
0
      token = ( new GeneralTimeZoneToken( repeat ) );
765
0
      break;
766
767
0
    case 0x5A: // 'Z'
768
0
      token = ( new RFC822TimeZoneToken( repeat ) );
769
0
      break;
770
771
0
    default:
772
0
      token = ( new LiteralToken( spec, repeat ) );
773
0
  }
774
775
0
  assert( token != NULL );
776
0
  pattern.push_back( token );
777
0
}
778
779
780
void SimpleDateFormat::parsePattern( const LogString& fmt, const std::locale* locale,
781
  std::vector < PatternToken* >& pattern )
782
0
{
783
0
  if ( !fmt.empty() )
784
0
  {
785
0
    LogString::const_iterator iter = fmt.begin();
786
0
    int repeat = 1;
787
0
    logchar prevChar = * iter;
788
789
0
    for ( iter++; iter != fmt.end(); iter++ )
790
0
    {
791
0
      if ( * iter == prevChar )
792
0
      {
793
0
        repeat++;
794
0
      }
795
0
      else
796
0
      {
797
0
        addToken( prevChar, repeat, locale, pattern );
798
0
        prevChar = * iter;
799
0
        repeat = 1;
800
0
      }
801
0
    }
802
803
0
    addToken( prevChar, repeat, locale, pattern );
804
0
  }
805
0
}
806
807
808
struct SimpleDateFormat::SimpleDateFormatPrivate{
809
  SimpleDateFormatPrivate() :
810
0
    timeZone(TimeZone::getDefault())
811
0
  {}
812
813
  /**
814
   * Time zone.
815
   */
816
  TimeZonePtr timeZone;
817
818
  /**
819
   * List of tokens.
820
   */
821
  PatternTokenList pattern;
822
};
823
824
0
SimpleDateFormat::SimpleDateFormat( const LogString& fmt ) : m_priv(std::make_unique<SimpleDateFormatPrivate>())
825
0
{
826
0
#if LOG4CXX_HAS_STD_LOCALE
827
0
  std::locale defaultLocale;
828
0
  parsePattern( fmt, & defaultLocale, m_priv->pattern );
829
#else
830
  parsePattern( fmt, NULL, m_priv->pattern );
831
#endif
832
833
0
  for (auto const& item : m_priv->pattern)
834
0
  {
835
0
    item->setTimeZone( m_priv->timeZone );
836
0
  }
837
0
}
838
839
0
SimpleDateFormat::SimpleDateFormat( const LogString& fmt, const std::locale* locale ) : m_priv(std::make_unique<SimpleDateFormatPrivate>())
840
0
{
841
0
  parsePattern( fmt, locale, m_priv->pattern );
842
843
0
  for (auto const& item : m_priv->pattern)
844
0
  {
845
0
    item->setTimeZone( m_priv->timeZone );
846
0
  }
847
0
}
848
849
850
SimpleDateFormat::~SimpleDateFormat()
851
0
{
852
0
  for (auto item : m_priv->pattern)
853
0
  {
854
0
    delete item;
855
0
  }
856
0
}
857
858
859
void SimpleDateFormat::format( LOG4CXX_FORMAT_TIME_FORMAL_PARAMETERS ) const
860
0
{
861
0
  helpers::Pool tempPool;
862
0
  apr_time_exp_t exploded;
863
0
  apr_status_t stat = m_priv->timeZone->explode( & exploded, tm );
864
865
0
  if ( stat == APR_SUCCESS )
866
0
  {
867
0
    for ( PatternTokenList::const_iterator iter = m_priv->pattern.begin(); iter != m_priv->pattern.end(); iter++ )
868
0
    {
869
0
      ( * iter )->format( toAppendTo, exploded, tempPool );
870
0
    }
871
0
  }
872
0
}
873
874
void SimpleDateFormat::setTimeZone( const TimeZonePtr& zone )
875
0
{
876
0
  m_priv->timeZone = zone;
877
0
}