Пример #1
0
int day_number (int year, int month)

{
	int Yfirst,Mfirst,Dfirst;
	int y,m;
	y=m=0;

	for(Yfirst=1582;Yfirst<year;Yfirst++)
	{
		y=y+365+leap_year(Yfirst);
	}
	for(Mfirst=1;Mfirst<month;Mfirst++)
	{

		if(Mfirst==1)
		{
			m=m+31;
		}
		else if(Mfirst==2)
		{
			m=m+28+leap_year(year);
		}
		else if(Mfirst==3)
		{
			m=m+31;
		}
		else if(Mfirst==4)
		{
			m=m+30;
		}
		else if(Mfirst==5)
		{
			m=m+31;
		}
		else if(Mfirst==6)
		{
			m=m+30;
		}
		else if(Mfirst==7)
		{
			m=m+31;
		}
		else if(Mfirst==8)
		{
			m=m+31;
		}
		else if(Mfirst==9)
		{
			m=m+30;
		}
		else if(Mfirst==10)
		{
			m=m+31;
		}
		else if(Mfirst==11)
		{
			m=m+30;
		}
		else if(Mfirst==12)
		{
			m=m+31;
		}


	}
	return m+y;

}
Пример #2
0
/******************************************************************************
 * @brief   Calculate the day, month, year and seconds given a Fractional
 *          Julian Day.
 * @return  dmy stucture.
 * @note    if calendar="standard" or "gregorian" (default), Julian day follows
 *          Julian Calendar on and before 1582-10-5, Gregorian calendar after
 *          1582-10-15.
 *
 *          if calendar="proleptic_gregorian", Julian Day follows gregorian
 *          calendar.
 *
 *          if calendar="julian", Julian Day follows julian calendar.
 *
 *          Algorithm:
 *          Meeus, Jean (1998) Astronomical Algorithms (2nd Edition).
 *          Willmann-Bell, Virginia. p. 63
 *
 *          based on redate.py by David Finlayson.
 *****************************************************************************/
void
dmy_julian_day(double             julian,
               unsigned short int calendar,
               dmy_struct        *dmy)
{
    double day, F, eps;
    int    second;
    int    Z, alpha;
    int    A, B, C, D, E;
    int    nday, dayofyr;
    int    year, month;
    bool   is_leap;

    if (julian < 0) {
        log_err("Julian Day must be positive");
    }

    // get the day (Z) and the fraction of the day (F)
    // add 0.000005 which is 452 ms in case of jd being after
    // second 23:59:59 of a day we want to round to the next day
    Z = (int) round(julian);
    F = (double) (julian + 0.5 - Z);
    if (calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN) {
        alpha = (int) ((((double) Z - 1867216.0) - 0.25) / 36524.25);
        A = Z + 1 + alpha - (int) (0.25 * (double) alpha);
        // check if dates before oct 5th 1582 are in the array
        if (julian < 2299160.5) {
            A = Z;
        }
    }
    else if (calendar == CALENDAR_PROLEPTIC_GREGORIAN) {
        alpha = (int) (((Z - 1867216.0) - 0.25) / 36524.25);
        A = Z + 1 + alpha - (int) (0.25 * alpha);
    }
    else if (calendar == CALENDAR_JULIAN) {
        A = Z;
    }
    else {
        log_err("unknown calendar, must be one of julian,standard,gregorian,"
                "proleptic_gregorian");
    }

    B = A + 1524;
    C = (int) (6680. +
               (((double) B - 2439870.) - 122.1) / (double) DAYS_PER_JYEAR);
    D = (int) (DAYS_PER_YEAR * C + (int) (0.25 * (double) C));
    E = (int) (((double) (B - D)) / 30.6001);

    // Convert to date
    day = floor(B - D - floor(30.6001 * (double) E) + F);
    if (day < 1) {
        day = 1;
    }
    nday = B - D - 123;
    dayofyr = nday - 305;
    if (nday <= 305) {
        dayofyr = nday + 60;
    }

    month = E - 1;
    if (month > MONTHS_PER_YEAR) {
        month -= MONTHS_PER_YEAR;
    }
    year = C - 4715;
    if (month > 2) {
        year -= 1;
    }
    if (year <= 0) {
        year -= 1;
    }

    // a leap year?
    is_leap = leap_year(year, calendar);

    if (is_leap && (month > 2)) {
        dayofyr += 1;
    }

    eps = max(DBL_EPSILON, DBL_EPSILON * julian);

    second = (int) round((double) F * (double) SEC_PER_DAY - eps);
    if (second < 0) {
        second = 0.;
    }

    dmy->day = (int) day;
    dmy->day_in_year = dayofyr;
    dmy->month = month;
    dmy->year = year;
    dmy->dayseconds = second;

    return;
}
Пример #3
0
/*--------------------------------------------------------------------------*/
IsotimeEpoch _convert2epoch(long year, long month, long day, 
                            long hh, long mm, long ss, double uuuuuu, 
                            long osign, long Hh, long Mm, long Ss) 
{ long days, base;
  IsotimeEpoch epoch;

  if (ISOTIME_debug>0) fprintf(stderr,"_convert2epoch BEGIN\n");

  epoch.offset = (long int) 0;
  epoch.fract  = (double) 0.0;
  epoch.sec    = (long int) 0;

  epoch.status = -1;

  days = year*365+leap_days(year) - DAYS_19700101;

  switch (month) {
    case  1: days+=day; break;
    case  2: days+=day+31; break;
    case  3: days+=day+59; break;
    case  4: days+=day+90; break;
    case  5: days+=day+120; break;
    case  6: days+=day+151; break;
    case  7: days+=day+181; break;
    case  8: days+=day+212; break;
    case  9: days+=day+243; break;
    case 10: days+=day+273; break;
    case 11: days+=day+304; break;
    case 12: days+=day+334; break;
    default : month=0; // invalid
  }

  if ( month ) {

    // correct march to december leap years
    if ( leap_year ( year ) ) {
      if (month>2) days+=1;
    }

    epoch.offset = osign*( (Hh*60+Mm)*60+Ss );

    base = floor(uuuuuu);
    epoch.fract = uuuuuu - (double) base;
    epoch.sec   = ((days*24+hh)*60+mm)*60+ss+base-epoch.offset;

    // normalize fract and sec
    base = floor(epoch.fract);
    epoch.fract -= (double) base;
    epoch.sec   += base;

    epoch.status = 0; // success
  } 

  if (ISOTIME_debug>2)
    fprintf(stderr,"  %ld (DAYS_%04ld%02ld%02ld) - %ld (DAYS_19700101) = %ld\n",
      days+DAYS_19700101,year,month,day,DAYS_19700101,days);

  if (ISOTIME_debug>0) fprintf(stderr,"_convert2epoch END\n");

  return ( epoch );

} // _convert2epoch
Пример #4
0
/*+++------------------------------------------------------------------------
NAME
  epoch2isotime --- convert IsotimeEpoch to isotime string

SYNOPSIS

  const char * epoch2isotime( char buffer[], size_t buflen, IsotimeEpoch epoch )

DESCRIPTION

  (not implemented)

RETURN VALUE

  pointer to isotime string in buffer

----------------------------------------------------------------------------*/
const char * epoch2isotime( char buffer[], size_t buflen, IsotimeEpoch epoch )
{ char epobuf[EPOLEN]; 
  char osign_c;
  long year=0, month=0, day=0;
  long hh=0, mm=0, ss=0;
  double fract=0.0;
  long Hh=0, Mm=0, Ss=0;

  long days, yd, ts, tz, leap;

  long base;

  if (ISOTIME_debug>0) fprintf(stderr,"epoch2isotime %s BEGIN\n",
     epoch2string( epobuf, EPOLEN, epoch ) );

  if ( (!buffer)||(buflen<ISOLEN) ) {
    if (ISOTIME_debug>0) fprintf(stderr,"epoch2isotime END\n");
    return ( ( const char *) NULL );
  }

  buffer[0] ='\0';

  if (!epoch.status) {
    // normalize fract and sec
    base = floor(epoch.fract);
    epoch.fract -= (double) base;
    epoch.sec   += base;

    // convert2time
    fract = epoch.fract;

    if (epoch.offset<0) osign_c='-'; else osign_c='+';
    tz    = epoch.offset; 
    Hh    = floor(tz/3600);
    tz   -= Hh*3600;
    Mm    = floor(tz/60);
    tz   -= Mm*60;
    Ss    = tz;

    Hh=labs(Hh); Mm=labs(Mm); Ss = labs(Ss);

    if (ISOTIME_debug>3)
      fprintf(stderr," osign=%c1, Hh=%ld, Mm=%ld, Ss=%ld\n",osign_c,Hh,Mm,Ss);

    ts    = epoch.sec + epoch.offset; // add time zone offset

    days  = floor( ts/3600/24 );

    ts   -= days*3600*24;

    if (ts<0) { days-=1; ts+=3600*24; }

    hh    = floor(ts/3600);
    ts   -= hh*3600;
    mm    = floor(ts/60);
    ts   -= mm*60;
    ss    = ts;

    days += DAYS_19700101; // == year*365+leap_days

    year  = floor( days/365 );
    yd    = days - year*365 - leap_days( year ); // day in the year

    if (ISOTIME_debug>3)
      fprintf(stderr," hh=%ld, hm=%ld, ss=%ld\n",hh,mm,ss);

    // days contains all leap_days => year is correct or too high 
    while ( yd <= 0 ) {
      year--;
      yd    = days - year*365 - leap_days( year ); // day in the year
    }

    if (ISOTIME_debug>3)
      fprintf(stderr," year=%ld, yd=%ld\n",year,yd);

    // get number of leap days in the year
    if ( leap_year ( year ) ) leap=1; else leap=0;

         if (yd<=31)       { month= 1; day=yd; }          // Jan
    else if (yd<=59+leap)  { month= 2; day=yd-31; }       // Feb 
    else if (yd<=90+leap)  { month= 3; day=yd-59-leap; }  // Mar
    else if (yd<=120+leap) { month= 4; day=yd-90-leap; }  // Apr
    else if (yd<=151+leap) { month= 5; day=yd-120-leap; } // May
    else if (yd<=181+leap) { month= 6; day=yd-151-leap; } // Jun
    else if (yd<=212+leap) { month= 7; day=yd-181-leap; } // Jul
    else if (yd<=243+leap) { month= 8; day=yd-212-leap; } // Aug
    else if (yd<=273+leap) { month= 9; day=yd-243-leap; } // Sep
    else if (yd<=304+leap) { month=10; day=yd-273-leap; } // Oct
    else if (yd<=334+leap) { month=11; day=yd-304-leap; } // Nov
    else                   { month=12; day=yd-334-leap; } // Dec

    // print
    switch (ISOTIME_mode) {
      case IsotimeModeSpace:
        sprintf(buffer,"%04ld-%02ld-%02ld %02ld:%02ld:%02ld.%06ld %c%02ld%02ld",
                year,month,day,hh,mm,ss,(long) floor(epoch.fract*1e6+0.5),
                osign_c,labs(Hh),labs(Mm) );
        break;
      default: // IsotimeModeNoSpace
        sprintf(buffer,"%04ld-%02ld-%02ldT%02ld:%02ld:%02ld.%06ld%c%02ld%02ld",
             year,month,day,hh,mm,ss,(long) floor(epoch.fract*1e6+0.5),
             osign_c,labs(Hh),labs(Mm) );
    }
  }

  if (ISOTIME_debug>0) fprintf(stderr,"epoch2isotime %s END\n",buffer);

  return( buffer );

} // epoch2isotime
Пример #5
0
int Date::current_dpm() const {
    if (leap_year() && mth == ly_month)
    return months[mth] + leap_days;
    return months[mth];
}
Пример #6
0
int
main(int argc, char **argv) {
	struct tm *local_time;
	time_t now;
	int ch, day, month, year, yflag;
	char *progname, *p;
	int num_months = NUM_MONTHS;

	progname = argv[0];
	if ((p = strrchr(progname, '/')) != NULL)
		progname = p+1;
	__progname = progname;

	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);

#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW) || defined(HAVE_LIBTERMCAP)
	if ((term = getenv("TERM"))) {
		int ret;
		my_setupterm(term, 1, &ret);
		if (ret > 0) {
			Senter = my_tgetstr("so","smso");
			Sexit = my_tgetstr("se","rmso");
			Slen = strlen(Senter) + strlen(Sexit);
		}
	}
#endif

/*
 * The traditional Unix cal utility starts the week at Sunday,
 * while ISO 8601 starts at Monday. We read the start day from
 * the locale database, which can be overridden with the
 * -s (Sunday) or -m (Monday) options.
 */
#if HAVE_DECL__NL_TIME_WEEK_1STDAY
	/*
	 * You need to use 2 locale variables to get the first day of the week.
	 * This is needed to support first_weekday=2 and first_workday=1 for
	 * the rare case where working days span across 2 weeks.
	 * This shell script shows the combinations and calculations involved:

	 for LANG in en_US ru_RU fr_FR csb_PL POSIX; do
	   printf "%s:\t%s + %s -1 = " $LANG $(locale week-1stday first_weekday)
	   date -d"$(locale week-1stday) +$(($(locale first_weekday)-1))day" +%w
	 done

	 en_US:  19971130 + 1 -1 = 0  #0 = sunday
	 ru_RU:  19971130 + 2 -1 = 1
	 fr_FR:  19971201 + 1 -1 = 1
	 csb_PL: 19971201 + 2 -1 = 2
	 POSIX:  19971201 + 7 -1 = 0
	 */
	{
		int wfd;
		union { unsigned int word; char *string; } val;
		val.string = nl_langinfo(_NL_TIME_WEEK_1STDAY);

		wfd = val.word;
		wfd = day_in_week(wfd % 100, (wfd / 100) % 100, wfd / (100 * 100));
		weekstart = (wfd + *nl_langinfo(_NL_TIME_FIRST_WEEKDAY) - 1) % 7;
	}
#endif

	yflag = 0;
	while ((ch = getopt(argc, argv, "13mjsyV")) != -1)
		switch(ch) {
		case '1':
			num_months = 1;		/* default */
			break;
		case '3':
			num_months = 3;
			break;
		case 's':
			weekstart = 0;		/* default */
			break;
		case 'm':
			weekstart = 1;
			break;
		case 'j':
			julian = 1;
			break;
		case 'y':
			yflag = 1;
			break;
		case 'V':
			printf(_("%s from %s\n"),
			       progname, PACKAGE_STRING);
			return 0;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	time(&now);
	local_time = localtime(&now);

	day = month = year = 0;
	switch(argc) {
	case 3:
		if ((day = atoi(*argv++)) < 1 || day > 31)
			errx(1, _("illegal day value: use 1-%d"), 31);
		/* FALLTHROUGH */
	case 2:
		if ((month = atoi(*argv++)) < 1 || month > 12)
			errx(1, _("illegal month value: use 1-12"));
		/* FALLTHROUGH */
	case 1:
		if ((year = atoi(*argv)) < 1 || year > 9999)
			errx(1, _("illegal year value: use 1-9999"));
		if (day) {
			int dm = days_in_month[leap_year(year)][month];
			if (day > dm)
				errx(1, _("illegal day value: use 1-%d"), dm);
			day = day_in_year(day, month, year);
		} else if ((local_time->tm_year + 1900) == year) {
			day = local_time->tm_yday + 1;
		}
		if (!month)
			yflag=1;
		break;
	case 0:
		day = local_time->tm_yday + 1;
		year = local_time->tm_year + 1900;
		month = local_time->tm_mon + 1;
		break;
	default:
		usage();
	}
	headers_init();

	if (!isatty(1))
		day = 0; /* don't highlight */

	if (yflag && julian)
		j_yearly(day, year);
	else if (yflag)
		yearly(day, year);
	else if (num_months == 1)
		monthly(day, month, year);
	else if (num_months == 3)
		monthly3(day, month, year);
	exit(0);
}
Пример #7
0
long
conv_str_date (
    const char *string,
    int  flags,
    int  format,
    int  order)
{
    static
        char *month_name [] =
          {
            "jan", "feb", "mar", "apr", "may", "jun",
            "jul", "aug", "sep", "oct", "nov", "dec"
          };

    static byte
        month_days [] =
          {
            31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
          },
        order_ptr [][3] =               /*  Year, Month, Day pointers        */
          {                             /*    for various orders & formats   */
          /*  YY MM DD   YYYY MM DD     YY MM       YYYY MM            MM DD */
            { 0, 2, 4 }, { 0, 4, 6 }, { 0, 2, 99 }, { 0, 4, 99 }, { 99, 0, 2 },
            { 4, 2, 0 }, { 4, 2, 0 }, { 2, 0, 99 }, { 2, 0, 99 }, { 99, 2, 0 },
            { 4, 0, 2 }, { 4, 0, 2 }, { 2, 0, 99 }, { 2, 0, 99 }, { 99, 0, 2 },
          };

    char
        date_digits   [9],              /*  8 digits of date                 */
        month_letters [4] = "???",      /*  3 characters of month            */
        ch;                             /*  Next character in date           */
    long
        feedback;                       /*  Returned date; -1 = error        */
    int
        digits,                         /*  Number of digits in string       */
        delimiters,                     /*  Number of delimiters in date     */
        digitseq,                       /*  Number of digits in sequence     */
        count,                          /*  Number of month letters          */
        year,                           /*  Date year value                  */
        month,                          /*  Date month value                 */
        day,                            /*  Date day value                   */
        order_index,                    /*  Index into order table           */
        y_ptr,                          /*  Where is year in date?           */
        m_ptr,                          /*  Where is month in date?          */
        d_ptr,                          /*  Where is day in date?            */
        date_order = order;             /*  Actual date order                */
    Bool
        had_month;                      /*  Did we already get a month?      */

    ASSERT (format >= DATE_FORMAT_FIRST && format <= DATE_FORMAT_LAST);
    ASSERT (order  >= DATE_ORDER_FIRST  && order  <= DATE_ORDER_LAST);

    conv_reason = 0;                    /*  No conversion errors so far      */
    if (flags & FLAG_D_ORDER_YMD)
        date_order = DATE_ORDER_YMD;
    else
    if (flags & FLAG_D_ORDER_DMY)
        date_order = DATE_ORDER_DMY;
    else
    if (flags & FLAG_D_ORDER_MDY)
        date_order = DATE_ORDER_MDY;

    /*  Collect date digits                                                  */
    digits     = 0;                     /*  Nothing collected so far         */
    digitseq   = 0;                     /*  No digits in sequence            */
    feedback   = 0;                     /*  No errors so far                 */
    delimiters = 0;                     /*  We allow up to 2 delimiters      */
    had_month  = FALSE;                 /*  True after 3-letter month seen   */

    do
      {
        ch = *string++;
        if (isdigit (ch))
          {
            if (digits < 8)
              {
                digitseq++;
                date_digits [digits++] = ch;
              }
            else
              {
                conv_reason = CONV_ERR_DATE_SIZE;
                feedback = -1;          /*  Too many digits                  */
              }
          }
        else
          {
            /*  Fill-up to even number of digits                             */
            if (digits > (digits / 2) * 2)
              {
                date_digits [digits] = date_digits [digits - 1];
                date_digits [digits - 1] = '0';
                digits++;
              }
            /*  3 or 5 in a row is not allowed                               */
            if (digitseq == 3 || digitseq == 5)
              {
                conv_reason = CONV_ERR_REJECT_3_5;
                feedback = -1;
              }
            digitseq = 0;

            /*  If a letter, try to match against a month                    */
            if (isalpha (ch))
              {
                if (had_month)
                  {
                    conv_reason = CONV_ERR_MULTIPLE_MONTH;
                    feedback = -1;
                  }
                else
                  {
                    for (count = 0; isalpha (ch); )
                      {
                        if (count < 3)
                            month_letters [count++] = (char) tolower (ch);
                        ch = *string++;
                      }
                    string--;           /*  Move back to char after month    */
                    if (count < 3)
                      {
                        conv_reason = CONV_ERR_BAD_MONTH;
                        feedback = -1;  /*  Too few letters                  */
                      }
                    month_letters [3] = 0;
                    for (count = 0; count < 12; count++)
                        if (streq (month_letters, month_name [count]))
                          {
                            count++;
                            date_digits [digits++] = (char) (count / 10 + '0');
                            date_digits [digits++] = (char) (count % 10 + '0');
                            had_month = TRUE;
                            break;
                          }
                    if (!had_month)
                      {
                        conv_reason = CONV_ERR_BAD_MONTH;
                        feedback = -1;  /*  Month not found                  */
                      }
                  }
              }
            else
            if (ispunct (ch))           /*  Skip any delimiter               */
                if ((++delimiters > 2)
                ||  (format > DATE_YMD_LAST && delimiters > 1))
                  {
                    conv_reason = CONV_ERR_MULTIPLE_DELIM;
                    feedback = -1;      /*  Multiple delimiters              */
                  }
          }
      }
    until (ch == 0);

    /*  Return zero date if empty                                            */
    if (digits == 0)
        return (feedback);

    /*  Calculate offset in date_digits for various date order & formats     */
    order_index = (date_order - 1) * 5; /*  Each row has 5 items             */

    if (format <= DATE_YMD_LAST)
      {
        if (digits == 6)
            ;   /* nothing */
        else
        if (digits == 8)
            order_index += 1;
      }
    else
    if (format <= DATE_YM_LAST)
      {
        date_digits [digits++] = '0';
        date_digits [digits++] = '0';
        if (digits == 6)
            order_index += 2;
        else
        if (digits == 8)
            order_index += 3;
        else
          {
            conv_reason = CONV_ERR_DATE_SIZE;
            return (-1);                /*  Error - bad date size            */
          }
      }
    else
    if (format <= DATE_MD_LAST)
      {
        date_digits [digits++] = '0';
        date_digits [digits++] = '0';
        if (digits == 6)
            order_index += 4;
        else
          {
            conv_reason = CONV_ERR_DATE_SIZE;
            return (-1);                /*  Error - bad date size            */
          }
      }

    /*  Decode order to pick-up offset of day/month/year in date_digits      */
    y_ptr = order_ptr [order_index][0];
    m_ptr = order_ptr [order_index][1];
    d_ptr = order_ptr [order_index][2];

#   define DIGIT(x) (date_digits [(x)] - '0')
    if (y_ptr != 99)
      {
        year = DIGIT (y_ptr) * 10 + DIGIT (y_ptr + 1);
        if (digits == 8)
            year = DIGIT (y_ptr + 2) * 10 + DIGIT (y_ptr + 3) + year * 100;

        if (year < 50)
            year += 2000;
        else
        if (year < 100)
            year += 1900;
      }
    else
        year = 0;

    if (m_ptr != 99)
      {
        month = DIGIT (m_ptr) * 10 + DIGIT (m_ptr + 1);
        if (month == 0 || month > 12)
          {
            conv_reason = CONV_ERR_OUT_OF_RANGE;
            feedback = -1;
          }
      }
    else
        month = 0;

    if (d_ptr != 99)
      {
        day = DIGIT (d_ptr) * 10 + DIGIT (d_ptr + 1);
        if ((day == 0 || day > (int) month_days [month - 1])
        ||  (month == 2 && day == 29 && !leap_year (year)))
          {
            conv_reason = CONV_ERR_OUT_OF_RANGE;
            feedback = -1;
          }
      }
    else
        day = 0;

    if (feedback == 0)
        feedback = year * 10000L + month * 100 + day;

    return (feedback);
}
Пример #8
0
struct tm64* localtime64_r(const time64_t* time64, struct tm64* tm64) {
  if(*time64 >= LONG_MIN && *time64 <= LONG_MAX) {
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    time_t time = (time_t) *time64;

    if(localtime_r(&time, &tm)) {
      tm_to_tm64(&tm, tm64);
#ifndef HAVE_TM_ZONE
#if HAVE_TZNAME && HAVE_DAYLIGHT
      tm64->tm_zone = tzname[daylight && tm64->tm_isdst];
#else
      tm64->tm_zone = NULL;
#endif
#endif
      return tm64;
    }
  }

  /*
   * First determine the (approximate) year that this timestamp
   * is in using the gmtime64_r function. We then use this so
   * we are able to map this to a year that should be compatible
   * with the system localtime_r
   */

  struct tm64 gm;
  gmtime64_r(time64, &gm);

  int64_t gm_year = gm.tm_year;

  if(gm_year < 1902) {
    /* For years below the 32 bit size time_t value we need to use
    * the lower comparable years */
    int day = day_of_week(gm_year, gm.tm_mon, gm.tm_mday);
    if(gm.tm_mon == 2 && leap_year(gm_year)) {
      gm.tm_year = lower_leap_month_table[day];
    } else {
      gm.tm_year = lower_common_month_table[gm.tm_mon][day];
    }
  } else if(gm_year > 2037) {
    /* For years above the 32 bit size time_t value we need to use
     * the lower comparable years */
    int day = day_of_week(gm_year, gm.tm_mon, gm.tm_mday);
    if(gm.tm_mon == 2 && leap_year(gm_year)) {
      gm.tm_year = higher_leap_month_table[day];
    } else {
      gm.tm_year = higher_common_month_table[gm.tm_mon][day];
    }
  }

  /*
   * Get the timestamp for the safe date that we mapped the
   * large date to.
   */
  time_t time = (time_t)timegm64(&gm);
  struct tm tm;
  memset(&tm, 0, sizeof(tm));

  localtime_r(&time, &tm);
  tm_to_tm64(&tm, tm64);
  tm64->tm_year = gm_year;

  /*
   * We need to correct here for the case where the timezone difference
   * results in the dates occuring in two different years.
   */
  int month_diff = tm64->tm_mon - gm.tm_mon;
  if(month_diff == 11) {
    tm64->tm_year--;
  } else if(month_diff == -11) {
    tm64->tm_year++;
  }

  /* If the gm year is a leap year, but the local isn't and we're on
   * December 31st in the local year, this is marked as day 365 because
   * the gm year is a leap year. Therefore we need to substract 1.
   */
  if(!leap_year(tm64->tm_year) && tm64->tm_yday == 365 ) {
    tm64->tm_yday--;
  }

#ifndef HAVE_TM_ZONE
#if HAVE_TZNAME && HAVE_DAYLIGHT
  tm64->tm_zone = tzname[daylight && tm64->tm_isdst];
#else
  tm64->tm_zone = NULL;
#endif
#endif

  return tm64;
}
Пример #9
0
struct tm64* gmtime64_r(const time64_t* time64, struct tm64* tm64) {

  if(*time64 >= LONG_MIN && *time64 <= LONG_MAX) {
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    time_t time = (time_t) *time64;

    if(gmtime_r(&time, &tm)) {
      tm_to_tm64(&tm, tm64);
      return tm64;
    }
  }

  tm64->tm_isdst = 0;
  tm64->tm_gmtoff = 0;
  tm64->tm_zone = (char *)"UTC";

  /*
   * Fallback because out of range of time_t or gmtime_r failed
   */
  int64_t year = 1970;
  int leap = 0;

  time64_t days = *time64;
  tm64->tm_sec = (int)(days % 60);
  days /= 60;
  tm64->tm_min = (int)(days % 60);
  days /= 60;
  tm64->tm_hour = (int)(days % 24);
  days /= 24;

  WRAP (tm64->tm_sec, tm64->tm_min, 60);
  WRAP (tm64->tm_min, tm64->tm_hour, 60);
  WRAP (tm64->tm_hour, days, 24);

  /*
   * days now contains the number of days that have passed.
   * Week day is easy since we know the day that the epoch occured
   */
  tm64->tm_wday = (int)((days + 4) % 7);
  if (tm64->tm_wday < 0) {
    tm64->tm_wday += 7;
  }

  if (days >= 0) {
    /* Gregorian cycles */
    int64_t cycles = days / DAYS_IN_GREGORIAN_CYCLE;
    if(cycles) {
      days -= cycles * DAYS_IN_GREGORIAN_CYCLE;
      year += cycles * 400;
    }

    leap = leap_year(year);
    while (days >= length_of_year[leap]) {
      days -= length_of_year[leap];
      ++year;
      leap = leap_year(year);
    }

    tm64->tm_mon = 0;
    while (days >= days_in_month[leap][tm64->tm_mon]) {
      days -= days_in_month[leap][tm64->tm_mon];
      tm64->tm_mon++;
    }
  } else {
    --year;

    int64_t cycles = days / DAYS_IN_GREGORIAN_CYCLE + 1;
    if(cycles) {
      days -= cycles * DAYS_IN_GREGORIAN_CYCLE;
      year += cycles * 400;
    }

    leap = leap_year(year);
    while (days < -length_of_year[leap]) {
      days += length_of_year[leap];
      year--;
      leap = leap_year(year);
    }

    /* Months */
    tm64->tm_mon = 11;
    while (days < -days_in_month[leap][tm64->tm_mon]) {
      days += days_in_month[leap][tm64->tm_mon];
      tm64->tm_mon--;
    }
    days += days_in_month[leap][tm64->tm_mon];
  }

  tm64->tm_year = year;
  /* Remaining days are the day of the month, +1 since we don't
   * count with offset 0 for days */
  tm64->tm_mday = (int) days + 1;
  tm64->tm_yday = julian_days_by_month[leap][tm64->tm_mon] + (int)days;

  return tm64;
}