Ejemplo n.º 1
0
static int check_tm(struct TM *tm)
{
  /* Don't forget leap seconds */
  assert(tm->tm_sec >= 0);

  /* Allow for just one positive leap second, which is what the C99 standard says. */
  /* Two leap seconds in the same minute are not allowed (the C90 range 0..61 was a defect). */
  assert(tm->tm_sec <= 60);

  assert(tm->tm_min >= 0);
  assert(tm->tm_min <= 59);

  assert(tm->tm_hour >= 0);
  assert(tm->tm_hour <= 23);

  assert(tm->tm_mday >= 1);
  assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);

  assert(tm->tm_mon  >= 0);
  assert(tm->tm_mon  <= 11);

  assert(tm->tm_wday >= 0);
  assert(tm->tm_wday <= 6);

  assert(tm->tm_yday >= 0);
  assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);

#ifdef HAS_TM_TM_GMTOFF
  assert(tm->tm_gmtoff >= -24 * 60 * 60);
    assert(tm->tm_gmtoff <=  24 * 60 * 60);
#endif

  return 1;
}
Ejemplo n.º 2
0
static int check_tm(struct TM *tm)
{
    /* Don't forget leap seconds */
    assert(tm->tm_sec >= 0);
    assert(tm->tm_sec <= 61);

    assert(tm->tm_min >= 0);
    assert(tm->tm_min <= 59);

    assert(tm->tm_hour >= 0);
    assert(tm->tm_hour <= 23);

    assert(tm->tm_mday >= 1);
    assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);

    assert(tm->tm_mon  >= 0);
    assert(tm->tm_mon  <= 11);

    assert(tm->tm_wday >= 0);
    assert(tm->tm_wday <= 6);
   
    assert(tm->tm_yday >= 0);
    assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);

#ifdef HAS_TM_TM_GMTOFF
    assert(tm->tm_gmtoff >= -24 * 60 * 60);
    assert(tm->tm_gmtoff <=  24 * 60 * 60);
#endif

    return 1;
}
Ejemplo n.º 3
0
static Time64_T S_timegm64(struct TM *date) {
    int      days    = 0;
    Time64_T seconds = 0;
    Year     year;

    if( date->tm_year > 70 ) {
        year = 70;
        while( year < date->tm_year ) {
            days += length_of_year[IS_LEAP(year)];
            year++;
        }
    }
    else if ( date->tm_year < 70 ) {
        year = 69;
        do {
            days -= length_of_year[IS_LEAP(year)];
            year--;
        } while( year >= date->tm_year );
    }

    days += julian_days_by_month[IS_LEAP(date->tm_year)][date->tm_mon];
    days += date->tm_mday - 1;

    /* Avoid overflowing the days integer */
    seconds = days;
    seconds = seconds * 60 * 60 * 24;

    seconds += date->tm_hour * 60 * 60;
    seconds += date->tm_min * 60;
    seconds += date->tm_sec;

    return(seconds);
}
Ejemplo n.º 4
0
// isoweek_from_date -
//	Computes the ISO week number from the specified date.
static void  isoweek_from_date ( int  y, int  m, int  d, int *  iso_week, int *  iso_year )
   {
	int		y_leap			=  IS_LEAP ( y ), 
			y_previous_leap		=  IS_LEAP ( y - 1 ) ;
	int		doy			=  day_of_year ( y, m, d ) + 1 ;
	int		weekday, jan1_weekday ;

	//if  ( y_leap  &&  m  >  2 )
	//	doy ++ ;

	jan1_weekday	=  day_of_week ( y, 1, 1, 1 ) ;
	weekday		=  day_of_week ( y, m, d, 1 ) ;

	if  ( ! weekday )
		weekday		=  7 ;

	if  ( ! jan1_weekday )
		jan1_weekday	=  7 ;

	/* Find if Y M D falls in year Y-1, week# 52 or 53 */
	if  ( doy  <=  ( 8 - jan1_weekday )  &&  jan1_weekday  >  4 )
	   {
		* iso_year	=  y - 1 ;

		if  ( jan1_weekday  ==  5  ||  ( y_previous_leap  &&  jan1_weekday  ==  6 ) )
			* iso_week	=  53 ;
		else
			* iso_week	=  52 ;
	    }
	else
		* iso_year	=  y ;

	/* Find if Y M D falls in year Y+1, week# 1 */
	if  ( * iso_year  ==  y )
	   {
		int		i	=  ( y_leap ) ?  366 : 365 ;

		if  ( ( i - ( doy - y_leap ) )  <  4 - weekday )
		   {
			( * iso_year ) ++ ;
			* iso_week	=  1 ;

			return ;
		    }
	    }

	/* Find if Y M D falls in year Y, week# 1 through 53 */
	if  ( * iso_year  ==  y )
	   {
		int	j =  doy + ( 7 - weekday ) + ( jan1_weekday - 1 ) ;

		* iso_week	=  j / 7 ;

		if  ( jan1_weekday )
			( * iso_week ) -- ;
	    }
    }
Ejemplo n.º 5
0
/* timegm() is not in the C or POSIX spec, but it is such a useful
   extension I would be remiss in leaving it out.  Also I need it
   for localtime64()
*/
Time64_T timegm64(const struct TM *date) {
    Time64_T days    = 0;
    Time64_T seconds = 0;
    Year     year;
    Year     orig_year = (Year)date->tm_year;
    int      cycles  = 0;

    if( orig_year > 100 ) {
        cycles = (orig_year - 100) / 400;
        orig_year -= cycles * 400;
        days      += (Time64_T)cycles * days_in_gregorian_cycle;
    }
    else if( orig_year < -300 ) {
        cycles = (orig_year - 100) / 400;
        orig_year -= cycles * 400;
        days      += (Time64_T)cycles * days_in_gregorian_cycle;
    }
    TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);

    if( orig_year > 70 ) {
        year = 70;
        while( year < orig_year ) {
            days += length_of_year[IS_LEAP(year)];
            year++;
        }
    }
    else if ( orig_year < 70 ) {
        year = 69;
        do {
            days -= length_of_year[IS_LEAP(year)];
            year--;
        } while( year >= orig_year );
    }


    days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
    days += date->tm_mday - 1;

    seconds = days * 60 * 60 * 24;

    seconds += date->tm_hour * 60 * 60;
    seconds += date->tm_min * 60;
    seconds += date->tm_sec;

    return(seconds);
}
Ejemplo n.º 6
0
UINT32
SecondsElapsedFromBaseYear (
  IN UINT16             BaseYear,
  IN UINT16             Year,
  IN UINT8              Month,
  IN UINT8              Day,
  IN UINT8              Hour,
  IN UINT8              Minute,
  IN UINT8              Second
  )
{
  UINTN       Seconds;
  UINT32      LeapYear;
  INTN        Index;

  Seconds  = 0;
  for (Index = BaseYear; Index < Year; Index ++) {
    if (IS_LEAP(Index)) {
      Seconds += DAYS_PER_LYEAR * SECS_PER_DAY;
    } else {
      Seconds += DAYS_PER_NYEAR * SECS_PER_DAY;
    }
  }

  LeapYear = IS_LEAP(Year);
  for (Index = 0; Index < Month - 1; Index ++) {
    Seconds += MonthLengths[LeapYear][Index] * SECS_PER_DAY;
  }

  for (Index = 0; Index < Day - 1; Index ++) {
    Seconds += SECS_PER_DAY;
  }

  for (Index = 0; Index < Hour; Index ++) {
    Seconds += SECS_PER_HOUR;
  }

  for (Index = 0; Index < Minute; Index ++) {
    Seconds += SECS_PER_MIN;
  }

  return (UINT32) (Seconds + Second);
}
Ejemplo n.º 7
0
static bool dayvalid(EFI_TIME *Time)
{
	if (Time->Day < 1)
		return false;

	if (Time->Day > dayofmonth[Time->Month - 1])
		return false;

	/* check month 2 */
	if (Time->Month == 2 && (!IS_LEAP(Time->Year) && Time->Day > 28))
		return false;

	return true;
}
Ejemplo n.º 8
0
// day_of_week -
//	Returns the day of week.
//	Taken from PHP source code.
static int  day_of_week ( int  year, int  month, int  day, int  iso )
   {
	int	c1, y1, m1, dow ;

	c1	=  century_value ( year / 100 ) ;
	y1	=  positive_mod ( year, 100 ) ;
	m1	=  IS_LEAP ( year ) ?  leap_year_table [ month ] : nonleap_year_table [ month ] ;

	dow	=  positive_mod ( ( c1 + y1 + m1 + ( y1 / 4 ) + day ), 7) ;

	if  ( iso )
	   {
		if  ( ! dow )
			dow	=  7 ;
	    }

	return ( dow ) ;
    }
Ejemplo n.º 9
0
static PyObject*
_mktime_ymd(PyObject* self, PyObject* arg) {
	if (!PyUnicode_CheckExact(arg)) return NULL;

	Py_UNICODE *src = PyUnicode_AS_UNICODE(arg), *bPtr;
	size_t year = 0, month = 0, day = 0, timestamp = 0, multiplier, size = PyUnicode_GET_SIZE(arg);

	if (size >= 4) { ATOI(src, src + 4, year); }
	if (size >= 6) { ATOI(src + 4, src + 6, month); }
	if (size >= 8) { ATOI(src + 6, src + 8, day); }

	if (year < 1970 || year > 2038 || month > 13 || day > 32) {
		Py_RETURN_NONE;
	}

	timestamp = YEARS[year - 1970] + (IS_LEAP(year) ? MONTHS2[month] : MONTHS1[month]) + DAYS[day];

	return PyInt_FromSize_t(timestamp);
}
Ejemplo n.º 10
0
static PyObject*
_mktime_tuple(PyObject* self, PyObject* arg) {
	if (!PyTuple_CheckExact(arg)) return NULL;
	PyTupleObject* tuple = (PyTupleObject*) arg;
	size_t year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, size = tuple->ob_size, timestamp = 0;

	if (size > 0) year = PyInt_AsSsize_t(tuple->ob_item[0]);
	if (size > 1) month = PyInt_AsSsize_t(tuple->ob_item[1]);
	if (size > 2) day = PyInt_AsSsize_t(tuple->ob_item[2]);
	if (size > 3) hour = PyInt_AsSsize_t(tuple->ob_item[3]);
	if (size > 4) minute = PyInt_AsSsize_t(tuple->ob_item[4]);
	if (size > 5) second = PyInt_AsSsize_t(tuple->ob_item[5]);

	if (year < 1970 || year > 2038 || month > 13 || day > 32 || hour > 24 || minute > 60 || second > 60) {
		Py_RETURN_NONE;
	}

	timestamp = YEARS[year - 1970] + (IS_LEAP(year) ? MONTHS2[month] : MONTHS1[month]) +
		DAYS[day] + HOURS[hour] + MINUTES[minute] + second;

	return PyInt_FromSize_t(timestamp);
}
Ejemplo n.º 11
0
static Time64_T seconds_between_years(Year left_year, Year right_year) {
    int increment = (left_year > right_year) ? 1 : -1;
    Time64_T seconds = 0;
    int cycles;

    if( left_year > 2400 ) {
        cycles = (left_year - 2400) / 400;
        left_year -= cycles * 400;
        seconds   += cycles * seconds_in_gregorian_cycle;
    }
    else if( left_year < 1600 ) {
        cycles = (left_year - 1600) / 400;
        left_year += cycles * 400;
        seconds   += cycles * seconds_in_gregorian_cycle;
    }

    while( left_year != right_year ) {
        seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
        right_year += increment;
    }

    return seconds * increment;
}
Ejemplo n.º 12
0
static void addonehour(EFI_TIME *time)
{
	if (time->Hour != 23) {
		time->Hour += 1;
		return;
	}
	time->Hour = 0;

	if ((time->Day != dayofmonth[time->Month - 1]) &&
		(!(time->Month == 2 && (!IS_LEAP(time->Year)
		&& time->Day == 28)))) {
		time->Day += 1;
		return;
	}
	time->Day = 1;

	if (time->Month != 12) {
		time->Month += 1;
		return;
	}
	time->Month = 1;
	time->Year += 1;
	return;
}
Ejemplo n.º 13
0
static int  day_of_year ( int  y, int  m, int  d )
   {
	return ( ( ( IS_LEAP ( y ) ) ?  leap_day_count [m] : nonleap_day_count [m] ) + d - 1 ) ;
    }
Ejemplo n.º 14
0
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
{
    time_t safe_time;
    struct tm safe_date;
    struct TM gm_tm;
    Year orig_year;
    int month_diff;

    assert(local_tm != NULL);

    /* Use the system localtime() if time_t is small enough */
    if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
        safe_time = *time;

        TRACE1("Using system localtime for %lld\n", *time);

        LOCALTIME_R(&safe_time, &safe_date);

        copy_tm_to_TM(&safe_date, local_tm);
        assert(check_tm(local_tm));

        return local_tm;
    }

    if( gmtime64_r(time, &gm_tm) == NULL ) {
        TRACE1("gmtime64_r returned null for %lld\n", *time);
        return NULL;
    }

    orig_year = gm_tm.tm_year;

    if (gm_tm.tm_year > (2037 - 1900) ||
        gm_tm.tm_year < (1970 - 1900)
       )
    {
        TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
        gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
    }

    safe_time = timegm64(&gm_tm);
    if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
        TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
        return NULL;
    }

    copy_tm_to_TM(&safe_date, local_tm);

    local_tm->tm_year = orig_year;
    if( local_tm->tm_year != orig_year ) {
        TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
              (Year)local_tm->tm_year, (Year)orig_year);

#ifdef EOVERFLOW
        errno = EOVERFLOW;
#endif
        return NULL;
    }


    month_diff = local_tm->tm_mon - gm_tm.tm_mon;

    /*  When localtime is Dec 31st previous year and
        gmtime is Jan 1st next year.
    */
    if( month_diff == 11 ) {
        local_tm->tm_year--;
    }

    /*  When localtime is Jan 1st, next year and
        gmtime is Dec 31st, previous year.
    */
    if( month_diff == -11 ) {
        local_tm->tm_year++;
    }

    /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
       in a non-leap xx00.  There is one point in the cycle
       we can't account for which the safe xx00 year is a leap
       year.  So we need to correct for Dec 31st comming out as
       the 366th day of the year.
    */
    if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
        local_tm->tm_yday--;

    assert(check_tm(local_tm));

    return local_tm;
}
Ejemplo n.º 15
0
struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
{
    int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
    Time64_T v_tm_tday;
    int leap;
    Time64_T m;
    Time64_T time = *in_time;
    Year year = 70;
    int cycles = 0;

    assert(p != NULL);

    /* Use the system gmtime() if time_t is small enough */
    if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
        time_t safe_time = *in_time;
        struct tm safe_date;
        GMTIME_R(&safe_time, &safe_date);

        copy_tm_to_TM(&safe_date, p);
        assert(check_tm(p));

        return p;
    }

#ifdef HAS_TM_TM_GMTOFF
    p->tm_gmtoff = 0;
#endif
    p->tm_isdst  = 0;

#ifdef HAS_TM_TM_ZONE
    p->tm_zone   = "UTC";
#endif

    v_tm_sec =  (int)(time % 60);
    time /= 60;
    v_tm_min =  (int)(time % 60);
    time /= 60;
    v_tm_hour = (int)(time % 24);
    time /= 24;
    v_tm_tday = time;

    WRAP (v_tm_sec, v_tm_min, 60);
    WRAP (v_tm_min, v_tm_hour, 60);
    WRAP (v_tm_hour, v_tm_tday, 24);

    v_tm_wday = (int)((v_tm_tday + 4) % 7);
    if (v_tm_wday < 0)
        v_tm_wday += 7;
    m = v_tm_tday;

    if (m >= CHEAT_DAYS) {
        year = CHEAT_YEARS;
        m -= CHEAT_DAYS;
    }

    if (m >= 0) {
        /* Gregorian cycles, this is huge optimization for distant times */
        cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
        if( cycles ) {
            m -= (cycles * (Time64_T) days_in_gregorian_cycle);
            year += (cycles * years_in_gregorian_cycle);
        }

        /* Years */
        leap = IS_LEAP (year);
        while (m >= (Time64_T) length_of_year[leap]) {
            m -= (Time64_T) length_of_year[leap];
            year++;
            leap = IS_LEAP (year);
        }

        /* Months */
        v_tm_mon = 0;
        while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
            m -= (Time64_T) days_in_month[leap][v_tm_mon];
            v_tm_mon++;
        }
    } else {
        year--;

        /* Gregorian cycles */
        cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
        if( cycles ) {
            m -= (cycles * (Time64_T) days_in_gregorian_cycle);
            year += (cycles * years_in_gregorian_cycle);
        }

        /* Years */
        leap = IS_LEAP (year);
        while (m < (Time64_T) -length_of_year[leap]) {
            m += (Time64_T) length_of_year[leap];
            year--;
            leap = IS_LEAP (year);
        }

        /* Months */
        v_tm_mon = 11;
        while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
            m += (Time64_T) days_in_month[leap][v_tm_mon];
            v_tm_mon--;
        }
        m += (Time64_T) days_in_month[leap][v_tm_mon];
    }

    p->tm_year = year;
    if( p->tm_year != year ) {
#ifdef EOVERFLOW
        errno = EOVERFLOW;
#endif
        return NULL;
    }

    /* At this point m is less than a year so casting to an int is safe */
    p->tm_mday = (int) m + 1;
    p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
    p->tm_sec  = v_tm_sec;
    p->tm_min  = v_tm_min;
    p->tm_hour = v_tm_hour;
    p->tm_mon  = v_tm_mon;
    p->tm_wday = v_tm_wday;

    assert(check_tm(p));

    return p;
}
Ejemplo n.º 16
0
SEXP make_d(SEXP year, SEXP month, SEXP day) {

  if(!isInteger(year)) error("year must be integer");
  if(!isInteger(month)) error("month must be integer");
  if(!isInteger(day)) error("day must be integer");

  R_len_t n = LENGTH(year);
  if(n != LENGTH(month)) error("length of 'month' vector is not the same as that of 'year'");
  if(n != LENGTH(day)) error("length of 'day' vector is not the same as that of 'year'");

  int* pyear = INTEGER(year);
  int* pmonth = INTEGER(month);
  int* pday = INTEGER(day);

  SEXP res = allocVector(REALSXP, n);
  double *data = REAL(res);

  for(int i = 0; i < n; i++) {

	// main accumulator
    double SECS = 0.0;

	int y = pyear[i];
	int m = pmonth[i];
	int d = pday[i];

	if(y == NA_INTEGER || m == NA_INTEGER || d == NA_INTEGER) {

	  data[i] = NA_REAL;

	} else {

	  if ( 0 < m && m < 13 )
		SECS += sm[m];
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  if ( 0 < d && d < 32 )
		SECS += (d - 1) * 86400;
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  int is_leap = IS_LEAP(y);

	  if(check_ymd(y, m, d, is_leap)){

		SECS += d30;
		y -= 2000;
		SECS += y * yearlen;
		SECS += adjust_leap_years(y, m, is_leap);
		data[i] = SECS;

	  } else {

		data[i] = NA_REAL;

	  }
	}
  }

  return res;
}
Ejemplo n.º 17
0
SEXP make_dt(SEXP year, SEXP month, SEXP day, SEXP hour, SEXP minute, SEXP second) {

  if(!isInteger(year)) error("year must be integer");
  if(!isInteger(month)) error("month must be integer");
  if(!isInteger(day)) error("day must be integer");
  if(!isInteger(hour)) error("hour must be integer");
  if(!isInteger(minute)) error("minute must be integer");
  if(!isNumeric(second)) error("second must be numeric");

  R_len_t n = LENGTH(year);

  if(n != LENGTH(month)) error("length of 'month' vector is not the same as that of 'year'");
  if(n != LENGTH(day)) error("length of 'day' vector is not the same as that of 'year'");
  if(n != LENGTH(hour)) error("length of 'hour' vector is not the same as that of 'year'");
  if(n != LENGTH(minute)) error("length of 'minute' vector is not the same as that of 'year'");
  if(n != LENGTH(second)) error("length of 'second' vector is not the same as that of 'year'");

  int* pyear = INTEGER(year);
  int* pmonth = INTEGER(month);
  int* pday = INTEGER(day);
  int* phour = INTEGER(hour);
  int* pminute = INTEGER(minute);

  int int_second = TYPEOF(second) == INTSXP;

  SEXP res = allocVector(REALSXP, n);
  double *data = REAL(res);

  for(int i = 0; i < n; i++) {

	// main accumulator
    double SECS = 0.0;

	int y = pyear[i];
	int m = pmonth[i];
	int d = pday[i];
	int H = phour[i];
	int M = pminute[i];
	int naS;
	double S;

	if(int_second){
	  S = (double) INTEGER(second)[i];
	  naS = INTEGER(second)[i] == NA_INTEGER;
	} else {
	  S = REAL(second)[i];
	  naS = ISNA(S);
	}

	if(naS || y == NA_INTEGER || m == NA_INTEGER || d == NA_INTEGER || H == NA_INTEGER || M == NA_INTEGER) {

	  data[i] = NA_REAL;

	} else {

	  if ( 0 < m && m < 13 )
		SECS += sm[m];
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  if ( 0 < d && d < 32 )
		SECS += (d - 1) * 86400;
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  if( H < 25 )
		SECS += H * 3600;
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  if ( M < 61 )
		SECS += M * 60;
	  else{
		data[i] = NA_REAL;
		continue;
	  }

	  // allow leap seconds
	  if ( S < 62 ) {
		SECS += S;
	  } else {
		data[i] = NA_REAL;
		continue;
	  }

	  int is_leap = IS_LEAP(y);

	  if(check_ymd(y, m, d, is_leap)){

		SECS += d30;
		y -= 2000;
		SECS += y * yearlen;
		SECS += adjust_leap_years(y, m, is_leap);

		data[i] = SECS;

	  } else {
		data[i] = NA_REAL;
	  }
	}
  }

  return res;
}
Ejemplo n.º 18
0
/*==============================================================================================================
 *
 *   NAME
 *	wake_builtin_date - Formats a date.
 *
 *   PROTOTYPE
 *	$(<date> [ format [, time] ] )
 *	$(<gmdate> [ format [, time] ] )
 *
 *   DESCRIPTION
 *	Formats a time value.
 *
 *   PARAMETERS
 *	format -
 *		A format string, that accepts the same specifiers than the PHP date() function.
 *		If not specified, the default format is 'Y-m-d H:i:s'.
 * 
 *	time -
 *		A time value. If not specified, the current Unix time is used.
 *
 *==============================================================================================================*/
static char *	__wake_builtin_date ( char *  output, char * format, time_t  time_value, int  is_localtime )
   {
	struct tm *	tm		=  ( is_localtime ) ?  localtime ( & time_value ) : gmtime ( & time_value ) ;
	char *		p		=  format ;
	int		ap_hour ;
	char		buffer [128] ;
	char *		buffer_p ;
	int		iso_year, iso_week ;
	int		iso_values_set	=  0,
			tz_set		=  0 ;


	tm -> tm_year		+=  1900 ;
	ap_hour			 =  ( tm -> tm_hour  %  12 ) ?  tm -> tm_hour % 12 : 12 ; 

	while  ( * p )
	   {
		buffer_p	=  NULL ;
		* buffer	=  0 ;

		switch ( * p )
		   {
			// 'a' : lowercase "am" or "pm"
			case	'a' :
				buffer_p	=  ( tm -> tm_hour  >=  12 ) ?  "pm" : "am" ;
				break ;

			// 'A' : uppercase "AM" or "PM"
			case	'A' :
				buffer_p	=  ( tm -> tm_hour  >=  12 ) ?  "PM" : "AM" ;
				break ;

			// 'B' : internet Swatch hour
			case	'B' :
			   {
				int	result		=
				   (
				      (
					 (
					    time_value -
						( time_value - 
						   (
						     ( time_value % 86400 ) + 3600
						    )
						 )
					  ) * 10
				       ) / 864
				    ) ;

				while  ( result  <  0 )
					result	+=  1000 ;

				result	%=  1000 ;
				sprintf ( buffer, "%03d", result ) ;
				break ;
			    }

			// 'c' : Full date, in ISO8601 format
			case	'c' :
				sprintf ( buffer, "%04d-%02d-%02dT%02d:%02d:%02d%s",
						tm -> tm_year, tm -> tm_mon + 1, tm -> tm_mday,
						tm -> tm_hour, tm -> tm_min, tm -> tm_sec,
						gmtoffset ( is_localtime, tm -> tm_gmtoff, 1 ) 
					 ) ;
				break ;

			// 'd' : day of month, as a two-digits number
			case	'd' : 
				sprintf ( buffer, "%02d", tm -> tm_mday ) ;
				break ;
			
			// 'D' : short day name
			case	'D' :
				buffer_p	=  short_day_names [ tm -> tm_wday ] ;
				break ;

			// 'e' : Timezone name
			case	'e' :
				if  ( ! tz_set )
					tzset ( ) ;

				buffer_p	=  tzname [0] ;
				break ;

			// 'F' : Long month name
			case	'F' :
				buffer_p	=  long_month_names [ tm -> tm_mon ] ;
				break ;

			// 'g' : Hour without leading zero (1..12)
			case	'g' :
				sprintf ( buffer, "%d", ap_hour ) ;
				break ;

			// 'G' : Hour without leading zero (0..23)
			case	'G' :
				sprintf ( buffer, "%d", tm -> tm_hour ) ;
				break ;
			
			// 'h' : Hour with leading zero (01..12)
			case	'h' :
				sprintf ( buffer, "%02d", ap_hour ) ;
				break ;

			// 'H' : Hour with leading zero (00..23)
			case	'H' :
				sprintf ( buffer, "%02d", tm -> tm_hour ) ;
				break ;
			
			// 'i' : Minute, with leading zero (00..59)
			case	'i' :
				sprintf ( buffer, "%02d", tm -> tm_min ) ;
				break ;

			// 'I' : 1 if daylight savings time is active, 0 otherwise
			case	'I' :
				sprintf ( buffer, "%d", tm -> tm_isdst ) ;
				break ;

			// 'j' : day of month, without the leading zero
			case	'j' : 
				sprintf ( buffer, "%d", tm -> tm_mday ) ;
				break ;

			// 'l' : Long day name
			case	'l' :
				buffer_p	=  long_day_names [ tm -> tm_wday ] ;
				break ;

			// 'L' : 1 is the year is leap, 0 otherwise
			case	'L' :
				sprintf ( buffer, "%d", IS_LEAP ( tm -> tm_year ) ) ;
				break ;

			// 'M' : short month name 
			case	'M' :
				buffer_p	=  short_month_names [ tm -> tm_mon ] ;
				break ;

			// 'm' : month of year, as a two-digits number
			case	'm' :
				sprintf ( buffer, "%02d", tm -> tm_mon + 1 ) ;
				break ;
			
			// 'n' : month of year, without the leading zero
			case	'n' :
				sprintf ( buffer, "%d", tm -> tm_mon + 1 ) ;
				break ;
			
			// 'N' : day of week, from 1 (monday) to 7 (sunday)
			case	'N' :
				sprintf ( buffer, "%d", ( tm -> tm_wday ) ?  tm -> tm_wday : 7 ) ;
				break ;

			// 'o' : ISO8601 year
			case	'o' :
				if  ( ! iso_values_set )
				   {
					isoweek_from_date ( tm -> tm_year, tm -> tm_mon, tm -> tm_mday, & iso_week, & iso_year ) ;
					iso_values_set	=  1 ;
				    }

				sprintf ( buffer, "%d", iso_year ) ;
				break ;

			// 'O' : GMT offset in ISO8601 format (+0200)
			case	'O' :
				buffer_p	=  gmtoffset ( is_localtime, tm -> tm_gmtoff, 0 ) ;
				break ;

			// 'P' : GMT offset in RFC822 format (+02:00)
			case	'P' :
				buffer_p	=  gmtoffset ( is_localtime, tm -> tm_gmtoff, 1 ) ;
				break ;

			// 'r' : RFC822 date
			case	'r' :
				sprintf ( buffer, "%3s %02d %3s %04d %02d:%02d:%02d %s", 
						short_day_names [ tm -> tm_wday ],
						tm -> tm_mday,
						short_month_names [ tm -> tm_mon ],
						tm -> tm_year,
						tm -> tm_hour, tm -> tm_min, tm -> tm_sec,
						gmtoffset ( is_localtime, tm -> tm_gmtoff, 0 ) 
					 ) ;
				break ;

			// 's' : Seconds, with leading zero (00..59)
			case	's' :
				sprintf ( buffer, "%02d", tm -> tm_sec ) ;
				break ;

			// 'S' : 2-letters english suffix for a day of month
			case	'S' :
				buffer_p	=  english_suffix ( tm -> tm_mday ) ;
				break ;

			// 't' : month length
			case	't' :
				sprintf ( buffer, "%d", MONTH_LENGTH ( tm -> tm_year, tm -> tm_mon ) ) ;
				break ;

			// 'T' : Timezone abbreviation
			case	'T' :
				if  ( ! tz_set )
					tzset ( ) ;

				buffer_p	=  tzname [1] ;
				break ;

			// 'u' : microsecond time. Always return '000000' since we accept an integer value as time
			case	'u' :
				buffer_p	=  "000000" ;
				break ;

			// 'U' : Unix time
			case	'U' :
				sprintf ( buffer, "%d", ( int ) time_value ) ;
				break ;

			// 'w' : day of week, from 0 (sunday) to 6 (saturday)
			case	'w' :
				sprintf ( buffer, "%d", tm -> tm_wday ) ;
				break ;

			// 'W' : ISO8601 week number (were weeks start on monday)
			case	'W' :
				if  ( ! iso_values_set )
				   {
					isoweek_from_date ( tm -> tm_year, tm -> tm_mon, tm -> tm_mday, & iso_week, & iso_year ) ;
					iso_values_set	=  1 ;
				    }

				sprintf ( buffer, "%d", iso_week ) ;
				break ;

			// 'y' : 2-digits year
			case	'y' :
				sprintf ( buffer, "%02d", ( tm -> tm_year % 100 ) ) ;
				break ;

			// 'Y' : 4-digits year
			case	'Y' :
				sprintf ( buffer, "%04d", tm -> tm_year ) ;
				break ;

			// 'z' : day of year, from 0 to 365
			case	'z' :
				sprintf ( buffer, "%d", tm -> tm_yday ) ;
				break ;

			// 'Z' : GMT offset in seconds
			case	'Z' :
				sprintf ( buffer, "%d", ( int ) tm -> tm_gmtoff ) ;
				break ;

			// Escape character : copy the next one without interpretation unless this is the last one
			case	'\\' :
				if  ( * ( p + 1 ) )
					p ++ ;
				/* Intentionally fall through the default case */

			// Other characters : copy as is
			default :
				buffer [0]	=  * p ;
				buffer [1]	=  0 ;
				break ;
		    }

		if  ( buffer_p  ==  NULL )
			buffer_p	=  buffer ;

		output	=  variable_buffer_output ( output, buffer_p, strlen ( buffer_p ) ) ;
		p ++ ;	
	    }	

	return ( output ) ;
    }
Ejemplo n.º 19
0
SEXP parse_dt(SEXP str, SEXP ord, SEXP formats, SEXP lt) {
  // STR: character vector of date-times.
  // ORD: formats (as in strptime) or orders (as in parse_date_time)
  // FORMATS: TRUE if ord is a string of formats (as in strptime)
  // LT: TRUE - return POSIXlt type list, FALSE - return POSIXct seconds

  if ( !isString(str) ) error("Date-time must be a character vector");
  if ( !isString(ord) || (LENGTH(ord) > 1))
    error("Format argument must be a character vector of length 1");

  R_len_t n = LENGTH(str);
  int is_fmt = *LOGICAL(formats);
  int out_lt = *LOGICAL(lt);

  SEXP oYEAR, oMONTH, oDAY, oHOUR, oMIN, oSEC;

  if(out_lt){
    oYEAR  = PROTECT(allocVector(INTSXP, n));
    oMONTH = PROTECT(allocVector(INTSXP, n));
    oDAY   = PROTECT(allocVector(INTSXP, n));
    oHOUR  = PROTECT(allocVector(INTSXP, n));
    oMIN   = PROTECT(allocVector(INTSXP, n));
    oSEC   = PROTECT(allocVector(REALSXP, n));
  } else {
    oSEC = PROTECT(allocVector(REALSXP, n));
  }

  const char *O = CHAR(STRING_ELT(ord, 0));

  for (int i = 0; i < n; i++) {

    const char *c = CHAR(STRING_ELT(str, i));
    const char *o = O;

    double secs = 0.0; // only accumulator for POSIXct case
    int y = 0, q = 0, m = 0, d = 0, H = 0, M = 0 , S = 0;
    int succeed = 1, O_format = 0, pm = 0, am = 0; // control logical

    // read order/format character by character
    while( *o && succeed ) {

      if( is_fmt && (*o != '%')) {
        // with fmt: non formatting characters should match exactly
        if ( *c == *o ) { c++; o++; } else succeed = 0;

      } else {

        if ( is_fmt ){
          o++; // skip %
        } else if ( *o != 'O' && *o != 'z' && *o != 'p' && *o != 'm' && *o != 'b' && *o != 'B') {
          // skip non-digits
          // O, z, p formats are treated specially below
          while (*c && !DIGIT(*c)) c++;
		}

        if ( *o == 'O' ) {
          // Special two letter orders/formats:
		  // Ou (Z), Oz (-0800), OO (-08:00) and Oo (-08)
          O_format = 1;
          o++;
        } else {
		  O_format = 0;
		}

        if (!(DIGIT(*c) || O_format || *o == 'z' || *o == 'p' || *o == 'm' || *o == 'b' || *o == 'B')) {
          succeed = 0;
        } else {

          /* Rprintf("c=%c o=%c\n", *c, *o); */

          switch( *o ) {
          case 'Y': // year in yyyy format
            y = parse_int(&c, 4, TRUE);
            if (y < 0)
              succeed = 0;
            break;
          case 'y': // year in yy format
            y = parse_int(&c, 2, FALSE);
            if (y < 0)
              succeed = 0;
			else if (y <= 68)
			  y += 2000;
			else
			  y += 1900;
            break;
          case 'q': // quarter
            q = parse_int(&c, 2, FALSE);
            if (!(0 < q && q < 5)) succeed = 0;
            break;
          case 'm': // month (allowing all months formats - m, b and B)
            SKIP_NON_ALPHANUMS(c);
            m = parse_int(&c, 2, FALSE);
            if (m == -1) { // failed
              m = parse_alpha_month(&c);
              if (m == 0) { // failed
                SKIP_NON_DIGITS(c);
                m = parse_int(&c, 2, FALSE);
              }
            }
            if (!(0 < m && m < 13))
              succeed = 0;
            break;
          case 'b': // alpha English months (both abbreviated and long versions)
          case 'B':
            /* SKIP_NON_ALPHANUMS(c); */
            m = parse_alpha_month(&c);
            succeed = m;
            /* Rprintf("succ=%d c=%c\n", succeed, *c); */
            break;
          case 'd': // day
            d = parse_int(&c, 2, FALSE);
            if (!(0 < d && d < 32)) succeed = 0;
            break;
          case 'H': // hour 24
            H = parse_int(&c, 2, FALSE);
            if (H > 24) succeed = 0;
            break;
          case 'I': // hour 12
            H = parse_int(&c, 2, FALSE);
            if (H > 12) succeed = 0;
            break;
          case 'M': // minute
            M = parse_int(&c, 2, FALSE);
            if (M > 59) succeed = 0;
            break;
          case 'S': // second
            if( O_format && !is_fmt ){
              while (*c && !DIGIT(*c)) c++;
              if (!*c) {
                succeed = 0;
                break;
              }
            }
            S = parse_int(&c, 2, FALSE);
            if (S < 62){ // allow leap seconds
              secs += S;
              if (O_format){
                // Parse milliseconds; both . and , as decimal separator are allowed
                if( *c == '.' || *c == ','){
                  double ms = 0.0, msfact = 0.1;
                  c++;
                  while (DIGIT(*c)) { ms = ms + (*c - '0')*msfact; msfact *= 0.1; c++; }
                  secs += ms;
                }
              }
            } else succeed = 0;
            break;
          case 'p': // AM/PM Both standard 'p' and lubridate 'Op' format
            SKIP_NON_ALPHANUMS(c);
            if (O_format) {
              // with Op format, p is optional (for order parsimony reasons)
              if (!(*c == 'P' || *c == 'p' || *c == 'A' || *c == 'a'))
                break;
            }
            if (*c == 'P' || *c == 'p') {
              pm = 1;
              c++;
            } else if (*c == 'A' ||  *c == 'a'){
              am = 1;
              c++;
            } else {
              succeed = 0;
            }
            if (succeed && !(*c && (*c == 'M' || *c == 'm'))){
              succeed = 0;
            }
            if (succeed) c++;
            break;
		  case 'u':
			// %Ou: "2013-04-16T04:59:59Z"
            if( O_format )
              if( *c == 'Z' || *c == 'z') c++;
              else succeed = 0;
            else succeed  = 0;
            break;
          case 'z':
            // for %z: "+O100" or "+O1" or "+01:00"
            if( !O_format ) {
              if( !is_fmt ) {
                while (*c && *c != '+' && *c != '-' && *c != 'Z') c++; // skip non + -
                if( !*c ) { succeed = 0; break; };
              }
              int Z = 0, sig;
              if( *c == 'Z') {c++; break;}
              else if ( *c == '+' ) sig = -1;
              else if ( *c == '-') sig = 1;
              else {succeed = 0; break;}
              c++;
              Z = parse_int(&c, 2, FALSE);
              if (Z < 0) {succeed = 0; break;}
              secs += sig*Z*3600;
              if( *c == ':' ){
                c++;
                if ( !DIGIT(*c) ) {succeed = 0; break;}
              }
              if( DIGIT(*c) ){
                Z = 0;
                Z = parse_int(&c, 2, FALSE);
                secs += sig*Z*60;
              }
              break;
            }
            // else O_format %Oz: "+0100"; pass through
          case 'O':
            // %OO: "+01:00"
          case 'o':
            // %Oo: "+01"
            if( O_format ){
              while (*c && *c != '+' && *c != '-' ) c++; // skip non + -
              int Z = 0, sig;
              if ( *c == '+' ) sig = -1;
              else if ( *c == '-') sig = 1;
              else { succeed = 0; break; }
              c++;
              Z = parse_int(&c, 2, FALSE);
              if (Z < 0) {succeed = 0; break;}
              secs += sig*Z*3600;
              if( *o == 'O'){
                if ( *c == ':') c++;
				else { succeed = 0; break; }
			  }
              if ( *o != 'o' ){ // z or O
                Z = parse_int(&c, 2, FALSE);
                if (Z < 0) {succeed = 0; break;}
                secs += sig*Z*60;
              }
            } else error("Unrecognized format '%c' supplied", *o);
            break;
          default:
            error("Unrecognized format %c supplied", *o);
          }

          o++;
        }
      }
    }

    // skip all remaining non digits
    if( !is_fmt )
      while (*c && !DIGIT(*c)) c++;

    // If at least one subparser hasn't finished it's a failure.
    if ( *c || *o ) succeed = 0;

    int is_leap;

    // adjust months for quarter
    if (q > 1)
      m += (q - 1) * 3 + 1;

    if (succeed) {
      // leap year every 400 years; no leap every 100 years
      is_leap = IS_LEAP(y);

      // check month
      if (m == 2){
		// no check for d > 0 because we allow missing days in parsing
        if (is_leap)
          succeed = d < 30;
        else
          succeed = d < 29;
      } else {
		succeed = d <= mdays[m];
      }
    }

    // allow missing months and days
    if (m == 0) m = 1;
    if (d == 0) d = 1;

    if(pm){
      if(H > 12)
        succeed = 0;
      else if (H < 12)
        H += 12;
    }

    if (am){
      if (H > 12)
        succeed = 0;
      else if (H == 12)
        H = 0;
    }

    if (succeed) {
      if(out_lt){

        INTEGER(oYEAR)[i] = y - 1900;
        INTEGER(oMONTH)[i] = m - 1;
        INTEGER(oDAY)[i] = d;
        INTEGER(oHOUR)[i] = H;
        INTEGER(oMIN)[i] = M;
        REAL(oSEC)[i] = secs;

      } else {

        secs += sm[m];
        secs += (d - 1) * 86400;
        secs += H * 3600;
        secs += M * 60;
        // process leap years
        y -= 2000;
        secs += y * yearlen;
        secs += adjust_leap_years(y, m, is_leap);

        REAL(oSEC)[i] = secs + d30;
      }

    } else {
      if(out_lt){
        INTEGER(oYEAR)[i] = NA_INTEGER;
        INTEGER(oMONTH)[i] = NA_INTEGER;
        INTEGER(oDAY)[i] = NA_INTEGER;
        INTEGER(oHOUR)[i] = NA_INTEGER;
        INTEGER(oMIN)[i] = NA_INTEGER;
        REAL(oSEC)[i] = NA_REAL;
      } else {
        REAL(oSEC)[i] = NA_REAL;
      }
    }
  }

  if (out_lt){
    SEXP names, out;
    PROTECT(names = allocVector(STRSXP, 6));
    for(int i = 0; i < 6; i++)
      SET_STRING_ELT(names, i, mkChar(ltnames[i]));
    PROTECT(out = allocVector(VECSXP, 6));
    SET_VECTOR_ELT(out, 0, oSEC);
    SET_VECTOR_ELT(out, 1, oMIN);
    SET_VECTOR_ELT(out, 2, oHOUR);
    SET_VECTOR_ELT(out, 3, oDAY);
    SET_VECTOR_ELT(out, 4, oMONTH);
    SET_VECTOR_ELT(out, 5, oYEAR);
    setAttrib(out, R_NamesSymbol, names);
    UNPROTECT(8);
    return out;
  } else {
    UNPROTECT(1);
    return oSEC;
  }

}