~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item_timefunc.cc

  • Committer: Andy Lester
  • Date: 2008-08-09 05:13:22 UTC
  • mto: (266.1.29 use-replace-funcs)
  • mto: This revision was merged to the branch mainline in revision 287.
  • Revision ID: andy@petdance.com-20080809051322-dzas70no2mv6c9i5
removed incorrect comment

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
{
54
54
  char *buff;
55
55
  const CHARSET_INFO * const cs= &my_charset_bin;
56
 
  uint32_t length= MAX_DATE_STRING_REP_LENGTH;
 
56
  uint length= MAX_DATE_STRING_REP_LENGTH;
57
57
 
58
58
  if (str->alloc(length))
59
59
    return 1;
121
121
 
122
122
  make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
123
123
                               str->ptr(), str->length(),
124
 
                               DRIZZLE_TIMESTAMP_TIME, NULL);
 
124
                               DRIZZLE_TIMESTAMP_TIME, NullS);
125
125
  return make_datetime(format, ltime, str);
126
126
}
127
127
 
148
148
  {
149
149
    make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
150
150
                                 str->ptr(), str->length(),
151
 
                                 DRIZZLE_TIMESTAMP_TIME, NULL);
 
151
                                 DRIZZLE_TIMESTAMP_TIME, NullS);
152
152
    make_time(format, l_time, str);
153
153
  }
154
154
 
178
178
  
179
179
static bool sec_to_time(int64_t seconds, bool unsigned_flag, DRIZZLE_TIME *ltime)
180
180
{
181
 
  uint32_t sec;
 
181
  uint sec;
182
182
 
183
183
  memset(ltime, 0, sizeof(*ltime));
184
184
  
185
185
  if (seconds < 0)
186
186
  {
 
187
    if (unsigned_flag)
 
188
      goto overflow;
187
189
    ltime->neg= 1;
188
190
    if (seconds < -3020399)
189
191
      goto overflow;
209
211
                 - buf);
210
212
  make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
211
213
                               buf, len, DRIZZLE_TIMESTAMP_TIME,
212
 
                               NULL);
 
214
                               NullS);
213
215
  
214
216
  return 1;
215
217
}
260
262
*/
261
263
 
262
264
static bool extract_date_time(DATE_TIME_FORMAT *format,
263
 
                              const char *val, uint32_t length, DRIZZLE_TIME *l_time,
264
 
                              enum enum_drizzle_timestamp_type cached_timestamp_type,
 
265
                              const char *val, uint length, DRIZZLE_TIME *l_time,
 
266
                              timestamp_type cached_timestamp_type,
265
267
                              const char **sub_pattern_end,
266
268
                              const char *date_time_type)
267
269
{
300
302
      switch (*++ptr) {
301
303
        /* Year */
302
304
      case 'Y':
303
 
        tmp= (char*) val + cmin(4, val_len);
 
305
        tmp= (char*) val + min(4, val_len);
304
306
        l_time->year= (int) my_strtoll10(val, &tmp, &error);
305
307
        if ((int) (tmp-val) <= 2)
306
308
          l_time->year= year_2000_handling(l_time->year);
307
309
        val= tmp;
308
310
        break;
309
311
      case 'y':
310
 
        tmp= (char*) val + cmin(2, val_len);
 
312
        tmp= (char*) val + min(2, val_len);
311
313
        l_time->year= (int) my_strtoll10(val, &tmp, &error);
312
314
        val= tmp;
313
315
        l_time->year= year_2000_handling(l_time->year);
316
318
        /* Month */
317
319
      case 'm':
318
320
      case 'c':
319
 
        tmp= (char*) val + cmin(2, val_len);
 
321
        tmp= (char*) val + min(2, val_len);
320
322
        l_time->month= (int) my_strtoll10(val, &tmp, &error);
321
323
        val= tmp;
322
324
        break;
333
335
        /* Day */
334
336
      case 'd':
335
337
      case 'e':
336
 
        tmp= (char*) val + cmin(2, val_len);
 
338
        tmp= (char*) val + min(2, val_len);
337
339
        l_time->day= (int) my_strtoll10(val, &tmp, &error);
338
340
        val= tmp;
339
341
        break;
340
342
      case 'D':
341
 
        tmp= (char*) val + cmin(2, val_len);
 
343
        tmp= (char*) val + min(2, val_len);
342
344
        l_time->day= (int) my_strtoll10(val, &tmp, &error);
343
345
        /* Skip 'st, 'nd, 'th .. */
344
 
        val= tmp + cmin((int) (val_end-tmp), 2);
 
346
        val= tmp + min((int) (val_end-tmp), 2);
345
347
        break;
346
348
 
347
349
        /* Hour */
352
354
        /* fall through */
353
355
      case 'k':
354
356
      case 'H':
355
 
        tmp= (char*) val + cmin(2, val_len);
 
357
        tmp= (char*) val + min(2, val_len);
356
358
        l_time->hour= (int) my_strtoll10(val, &tmp, &error);
357
359
        val= tmp;
358
360
        break;
359
361
 
360
362
        /* Minute */
361
363
      case 'i':
362
 
        tmp= (char*) val + cmin(2, val_len);
 
364
        tmp= (char*) val + min(2, val_len);
363
365
        l_time->minute= (int) my_strtoll10(val, &tmp, &error);
364
366
        val= tmp;
365
367
        break;
367
369
        /* Second */
368
370
      case 's':
369
371
      case 'S':
370
 
        tmp= (char*) val + cmin(2, val_len);
 
372
        tmp= (char*) val + min(2, val_len);
371
373
        l_time->second= (int) my_strtoll10(val, &tmp, &error);
372
374
        val= tmp;
373
375
        break;
388
390
      case 'p':
389
391
        if (val_len < 2 || ! usa_time)
390
392
          goto err;
391
 
        if (!my_strnncoll(&my_charset_utf8_general_ci,
392
 
                          (const unsigned char *) val, 2, 
393
 
                          (const unsigned char *) "PM", 2))
 
393
        if (!my_strnncoll(&my_charset_latin1,
 
394
                          (const uchar *) val, 2, 
 
395
                          (const uchar *) "PM", 2))
394
396
          daypart= 12;
395
 
        else if (my_strnncoll(&my_charset_utf8_general_ci,
396
 
                              (const unsigned char *) val, 2, 
397
 
                              (const unsigned char *) "AM", 2))
 
397
        else if (my_strnncoll(&my_charset_latin1,
 
398
                              (const uchar *) val, 2, 
 
399
                              (const uchar *) "AM", 2))
398
400
          goto err;
399
401
        val+= 2;
400
402
        break;
419
421
        val= tmp;
420
422
        break;
421
423
      case 'j':
422
 
        tmp= (char*) val + cmin(val_len, 3);
 
424
        tmp= (char*) val + min(val_len, 3);
423
425
        yearday= (int) my_strtoll10(val, &tmp, &error);
424
426
        val= tmp;
425
427
        break;
431
433
      case 'u':
432
434
        sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V');
433
435
        strict_week_number= (*ptr=='V' || *ptr=='v');
434
 
        tmp= (char*) val + cmin(val_len, 2);
 
436
        tmp= (char*) val + min(val_len, 2);
435
437
        if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
436
438
            (strict_week_number && !week_number) ||
437
439
            week_number > 53)
443
445
      case 'X':
444
446
      case 'x':
445
447
        strict_week_number_year_type= (*ptr=='X');
446
 
        tmp= (char*) val + cmin(4, val_len);
 
448
        tmp= (char*) val + min(4, val_len);
447
449
        strict_week_number_year= (int) my_strtoll10(val, &tmp, &error);
448
450
        val= tmp;
449
451
        break;
513
515
 
514
516
  if (yearday > 0)
515
517
  {
516
 
    uint32_t days;
 
518
    uint days;
517
519
    days= calc_daynr(l_time->year,1,1) +  yearday - 1;
518
520
    if (days <= 0 || days > MAX_DAY_NUMBER)
519
521
      goto err;
523
525
  if (week_number >= 0 && weekday)
524
526
  {
525
527
    int days;
526
 
    uint32_t weekday_b;
 
528
    uint weekday_b;
527
529
 
528
530
    /*
529
531
      %V,%v require %X,%x resprectively,
573
575
  {
574
576
    do
575
577
    {
576
 
      if (!my_isspace(&my_charset_utf8_general_ci,*val))
 
578
      if (!my_isspace(&my_charset_latin1,*val))
577
579
      {
578
580
        make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
579
581
                                     val_begin, length,
580
 
                                     cached_timestamp_type, NULL);
 
582
                                     cached_timestamp_type, NullS);
581
583
        break;
582
584
      }
583
585
    } while (++val != val_end);
587
589
err:
588
590
  {
589
591
    char buff[128];
590
 
    strmake(buff, val_begin, cmin(length, (uint)sizeof(buff)-1));
 
592
    strmake(buff, val_begin, min(length, sizeof(buff)-1));
591
593
    push_warning_printf(current_thd, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
592
594
                        ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
593
595
                        date_time_type, buff, "str_to_date");
601
603
*/
602
604
 
603
605
bool make_date_time(DATE_TIME_FORMAT *format, DRIZZLE_TIME *l_time,
604
 
                    enum enum_drizzle_timestamp_type type, String *str)
 
606
                    timestamp_type type, String *str)
605
607
{
606
608
  char intbuff[15];
607
 
  uint32_t hours_i;
608
 
  uint32_t weekday;
 
609
  uint hours_i;
 
610
  uint weekday;
609
611
  ulong length;
610
612
  const char *ptr, *end;
611
613
  THD *thd= current_thd;
769
771
      case 'U':
770
772
      case 'u':
771
773
      {
772
 
        uint32_t year;
 
774
        uint year;
773
775
        if (type == DRIZZLE_TIMESTAMP_TIME)
774
776
          return 1;
775
777
        length= int10_to_str(calc_week(l_time,
783
785
      case 'v':
784
786
      case 'V':
785
787
      {
786
 
        uint32_t year;
 
788
        uint year;
787
789
        if (type == DRIZZLE_TIMESTAMP_TIME)
788
790
          return 1;
789
791
        length= int10_to_str(calc_week(l_time,
798
800
      case 'x':
799
801
      case 'X':
800
802
      {
801
 
        uint32_t year;
 
803
        uint year;
802
804
        if (type == DRIZZLE_TIMESTAMP_TIME)
803
805
          return 1;
804
806
        (void) calc_week(l_time,
848
850
                         For example, '1.1' -> '1.100000'
849
851
*/
850
852
 
851
 
static bool get_interval_info(const char *str,uint32_t length, const CHARSET_INFO * const cs,
852
 
                              uint32_t count, uint64_t *values,
 
853
static bool get_interval_info(const char *str,uint length, const CHARSET_INFO * const cs,
 
854
                              uint count, uint64_t *values,
853
855
                              bool transform_msec)
854
856
{
855
857
  const char *end=str+length;
856
 
  uint32_t i;
 
858
  uint i;
857
859
  while (str != end && !my_isdigit(cs,*str))
858
860
    str++;
859
861
 
862
864
    int64_t value;
863
865
    const char *start= str;
864
866
    for (value=0; str != end && my_isdigit(cs,*str) ; str++)
865
 
      value= value * 10L + (int64_t) (*str - '0');
 
867
      value= value * 10LL + (int64_t) (*str - '0');
866
868
    if (transform_msec && i == count - 1) // microseconds always last
867
869
    {
868
870
      long msec_length= 6 - (str - start);
876
878
    {
877
879
      i++;
878
880
      /* Change values[0...i-1] -> values[0...count-1] */
879
 
      bmove_upp((unsigned char*) (values+count), (unsigned char*) (values+i),
 
881
      bmove_upp((uchar*) (values+count), (uchar*) (values+i),
880
882
                sizeof(*values)*i);
881
883
      memset(values, 0, sizeof(*values)*(count-i));
882
884
      break;
1021
1023
{
1022
1024
  assert(fixed == 1);
1023
1025
  const char *month_name;
1024
 
  uint32_t   month= (uint) val_int();
 
1026
  uint   month= (uint) val_int();
1025
1027
  THD *thd= current_thd;
1026
1028
 
1027
1029
  if (null_value || !month)
1077
1079
}
1078
1080
 
1079
1081
 
1080
 
uint32_t week_mode(uint32_t mode)
 
1082
uint week_mode(uint mode)
1081
1083
{
1082
 
  uint32_t week_format= (mode & 7);
 
1084
  uint week_format= (mode & 7);
1083
1085
  if (!(week_format & WEEK_MONDAY_FIRST))
1084
1086
    week_format^= WEEK_FIRST_WEEKDAY;
1085
1087
  return week_format;
1119
1121
int64_t Item_func_week::val_int()
1120
1122
{
1121
1123
  assert(fixed == 1);
1122
 
  uint32_t year;
 
1124
  uint year;
1123
1125
  DRIZZLE_TIME ltime;
1124
1126
  if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
1125
1127
    return 0;
1132
1134
int64_t Item_func_yearweek::val_int()
1133
1135
{
1134
1136
  assert(fixed == 1);
1135
 
  uint32_t year,week;
 
1137
  uint year,week;
1136
1138
  DRIZZLE_TIME ltime;
1137
1139
  if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
1138
1140
    return 0;
1160
1162
String* Item_func_dayname::val_str(String* str)
1161
1163
{
1162
1164
  assert(fixed == 1);
1163
 
  uint32_t weekday=(uint) val_int();            // Always Item_func_daynr()
 
1165
  uint weekday=(uint) val_int();                // Always Item_func_daynr()
1164
1166
  const char *day_name;
1165
1167
  THD *thd= current_thd;
1166
1168
 
1461
1463
}
1462
1464
 
1463
1465
 
1464
 
bool Item_func_from_days::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date __attribute__((unused)))
 
1466
bool Item_func_from_days::get_date(DRIZZLE_TIME *ltime, uint fuzzy_date __attribute__((unused)))
1465
1467
{
1466
1468
  int64_t value=args[0]->val_int();
1467
1469
  if ((null_value=args[0]->null_value))
1528
1530
 
1529
1531
 
1530
1532
bool Item_func_curdate::get_date(DRIZZLE_TIME *res,
1531
 
                                 uint32_t fuzzy_date __attribute__((unused)))
 
1533
                                 uint fuzzy_date __attribute__((unused)))
1532
1534
{
1533
1535
  *res=ltime;
1534
1536
  return 0;
1634
1636
 
1635
1637
 
1636
1638
bool Item_func_now::get_date(DRIZZLE_TIME *res,
1637
 
                             uint32_t fuzzy_date __attribute__((unused)))
 
1639
                             uint fuzzy_date __attribute__((unused)))
1638
1640
{
1639
1641
  *res= ltime;
1640
1642
  return 0;
1695
1697
 
1696
1698
 
1697
1699
bool Item_func_sysdate_local::get_date(DRIZZLE_TIME *res,
1698
 
                                       uint32_t fuzzy_date __attribute__((unused)))
 
1700
                                       uint fuzzy_date __attribute__((unused)))
1699
1701
{
1700
1702
  store_now_in_TIME(&ltime);
1701
1703
  *res= ltime;
1772
1774
  else
1773
1775
  {
1774
1776
    fixed_length=0;
1775
 
    max_length=cmin(arg1->max_length,(uint32_t) MAX_BLOB_WIDTH) * 10 *
 
1777
    max_length=min(arg1->max_length, MAX_BLOB_WIDTH) * 10 *
1776
1778
                   collation.collation->mbmaxlen;
1777
1779
    set_if_smaller(max_length,MAX_BLOB_WIDTH);
1778
1780
  }
1805
1807
 
1806
1808
 
1807
1809
 
1808
 
uint32_t Item_func_date_format::format_length(const String *format)
 
1810
uint Item_func_date_format::format_length(const String *format)
1809
1811
{
1810
 
  uint32_t size=0;
 
1812
  uint size=0;
1811
1813
  const char *ptr=format->ptr();
1812
1814
  const char *end=ptr+format->length();
1813
1815
 
1882
1884
{
1883
1885
  String *format;
1884
1886
  DRIZZLE_TIME l_time;
1885
 
  uint32_t size;
 
1887
  uint size;
1886
1888
  assert(fixed == 1);
1887
1889
 
1888
1890
  if (!is_time_format)
1980
1982
}
1981
1983
 
1982
1984
bool Item_func_from_unixtime::get_date(DRIZZLE_TIME *ltime,
1983
 
                                       uint32_t fuzzy_date __attribute__((unused)))
 
1985
                                       uint fuzzy_date __attribute__((unused)))
1984
1986
{
1985
1987
  uint64_t tmp= (uint64_t)(args[0]->val_int());
1986
1988
  /*
2013
2015
    - If first arg is a DRIZZLE_TYPE_NEWDATE and the interval type uses hours,
2014
2016
      minutes or seconds then type is DRIZZLE_TYPE_DATETIME.
2015
2017
    - Otherwise the result is DRIZZLE_TYPE_VARCHAR
2016
 
      (This is because you can't know if the string contains a DATE, DRIZZLE_TIME or
 
2018
      (This is because you can't know if the string contains a DATE, MYSQL_TIME or
2017
2019
      DATETIME argument)
2018
2020
  */
2019
2021
  cached_field_type= DRIZZLE_TYPE_VARCHAR;
2033
2035
 
2034
2036
/* Here arg[1] is a Item_interval object */
2035
2037
 
2036
 
bool Item_date_add_interval::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date __attribute__((unused)))
 
2038
bool Item_date_add_interval::get_date(DRIZZLE_TIME *ltime, uint fuzzy_date __attribute__((unused)))
2037
2039
{
2038
2040
  INTERVAL interval;
2039
2041
 
2168
2170
{
2169
2171
  assert(fixed == 1);
2170
2172
  DRIZZLE_TIME ltime;
2171
 
  uint32_t year;
 
2173
  uint year;
2172
2174
  ulong week_format;
2173
2175
  long neg;
2174
2176
  if (date_value)
2320
2322
  else
2321
2323
  {
2322
2324
    // Convert character set if differ
2323
 
    uint32_t dummy_errors;
 
2325
    uint dummy_errors;
2324
2326
    if (!(res= args[0]->val_str(&tmp_value)) ||
2325
2327
        str->copy(res->ptr(), res->length(), from_cs,
2326
2328
        cast_cs, &dummy_errors))
2404
2406
  from_cs= (args[0]->result_type() == INT_RESULT || 
2405
2407
            args[0]->result_type() == DECIMAL_RESULT ||
2406
2408
            args[0]->result_type() == REAL_RESULT) ?
2407
 
           (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_utf8_general_ci) :
 
2409
           (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) :
2408
2410
           args[0]->collation.collation;
2409
2411
  charset_conversion= (cast_cs->mbmaxlen > 1) ||
2410
2412
                      (!my_charset_same(from_cs, cast_cs) && from_cs != &my_charset_bin && cast_cs != &my_charset_bin);
2484
2486
}
2485
2487
 
2486
2488
 
2487
 
bool Item_date_typecast::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date __attribute__((unused)))
 
2489
bool Item_date_typecast::get_date(DRIZZLE_TIME *ltime, uint fuzzy_date __attribute__((unused)))
2488
2490
{
2489
2491
  bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
2490
2492
  ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
2816
2818
 
2817
2819
  /* Check for integer overflows */
2818
2820
  if (hour < 0)
2819
 
    ltime.neg= 1;
2820
 
 
 
2821
  {
 
2822
    if (args[0]->unsigned_flag)
 
2823
      overflow= 1;
 
2824
    else
 
2825
      ltime.neg= 1;
 
2826
  }
2821
2827
  if (-hour > UINT_MAX || hour > UINT_MAX)
2822
2828
    overflow= 1;
2823
2829
 
2838
2844
      sprintf(ptr, ":%02u:%02u", (uint)minute, (uint)second);
2839
2845
    make_truncated_value_warning(current_thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
2840
2846
                                 buf, len, DRIZZLE_TIMESTAMP_TIME,
2841
 
                                 NULL);
 
2847
                                 NullS);
2842
2848
  }
2843
2849
  
2844
2850
  if (make_time_with_warn((DATE_TIME_FORMAT *) 0, &ltime, str))
2889
2895
      int_type == INTERVAL_QUARTER ||
2890
2896
      int_type == INTERVAL_MONTH)
2891
2897
  {
2892
 
    uint32_t year_beg, year_end, month_beg, month_end, day_beg, day_end;
2893
 
    uint32_t years= 0;
2894
 
    uint32_t second_beg, second_end, microsecond_beg, microsecond_end;
 
2898
    uint year_beg, year_end, month_beg, month_end, day_beg, day_end;
 
2899
    uint years= 0;
 
2900
    uint second_beg, second_end, microsecond_beg, microsecond_end;
2895
2901
 
2896
2902
    if (neg == -1)
2897
2903
    {
3010
3016
    break;
3011
3017
  }
3012
3018
 
3013
 
  for (uint32_t i=0 ; i < 2 ; i++)
 
3019
  for (uint i=0 ; i < 2 ; i++)
3014
3020
  {
3015
3021
    str->append(',');
3016
3022
    args[i]->print(str, query_type);
3035
3041
       (format_name= format->format_name);
3036
3042
       format++)
3037
3043
  {
3038
 
    uint32_t format_name_len;
 
3044
    uint format_name_len;
3039
3045
    format_name_len= strlen(format_name);
3040
3046
    if (val_len == format_name_len &&
3041
 
        !my_strnncoll(&my_charset_utf8_general_ci, 
3042
 
                      (const unsigned char *) val->ptr(), val_len, 
3043
 
                      (const unsigned char *) format_name, val_len))
 
3047
        !my_strnncoll(&my_charset_latin1, 
 
3048
                      (const uchar *) val->ptr(), val_len, 
 
3049
                      (const uchar *) format_name, val_len))
3044
3050
    {
3045
3051
      const char *format_str= get_date_time_format_str(format, type);
3046
3052
      str->set(format_str, strlen(format_str), &my_charset_bin);
3101
3107
*/
3102
3108
 
3103
3109
static date_time_format_types
3104
 
get_date_time_result_type(const char *format, uint32_t length)
 
3110
get_date_time_result_type(const char *format, uint length)
3105
3111
{
3106
3112
  const char *time_part_frms= "HISThiklrs";
3107
3113
  const char *date_part_frms= "MVUXYWabcjmvuxyw";
3183
3189
}
3184
3190
 
3185
3191
 
3186
 
bool Item_func_str_to_date::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date)
 
3192
bool Item_func_str_to_date::get_date(DRIZZLE_TIME *ltime, uint fuzzy_date)
3187
3193
{
3188
3194
  DATE_TIME_FORMAT date_time_format;
3189
3195
  char val_buff[64], format_buff[64];
3237
3243
}
3238
3244
 
3239
3245
 
3240
 
bool Item_func_last_day::get_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date)
 
3246
bool Item_func_last_day::get_date(DRIZZLE_TIME *ltime, uint fuzzy_date)
3241
3247
{
3242
3248
  if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
3243
3249
      (ltime->month == 0))
3246
3252
    return 1;
3247
3253
  }
3248
3254
  null_value= 0;
3249
 
  uint32_t month_idx= ltime->month-1;
 
3255
  uint month_idx= ltime->month-1;
3250
3256
  ltime->day= days_in_month[month_idx];
3251
3257
  if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
3252
3258
    ltime->day= 29;