int ggmtime(struct tm *tm, double l_clock) { /* l_clock is relative to ZERO_YEAR, jan 1, 00:00:00,defined in plot.h */ int i, days; /* dodgy way of doing wday - i hope it works ! */ int wday = JAN_FIRST_WDAY; /* eg 6 for 2000 */ FPRINTF((stderr, "%g seconds = ", l_clock)); if (fabs(l_clock) > 1.e12) { /* Some time in the year 33688 */ int_warn(NO_CARET, "time value out of range"); return(-1); } tm->tm_year = ZERO_YEAR; tm->tm_mday = tm->tm_yday = tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0; if (l_clock < 0) { while (l_clock < 0) { int days_in_year = gdysize(--tm->tm_year); l_clock += days_in_year * DAY_SEC; /* 24*3600 */ /* adding 371 is noop in modulo 7 arithmetic, but keeps wday +ve */ wday += 371 - days_in_year; } } else { for (;;) { int days_in_year = gdysize(tm->tm_year); if (l_clock < days_in_year * DAY_SEC) break; l_clock -= days_in_year * DAY_SEC; tm->tm_year++; /* only interested in result modulo 7, but %7 is expensive */ wday += (days_in_year - 364); } } tm->tm_yday = (int) (l_clock / DAY_SEC); l_clock -= tm->tm_yday * DAY_SEC; tm->tm_hour = (int) l_clock / 3600; l_clock -= tm->tm_hour * 3600; tm->tm_min = (int) l_clock / 60; l_clock -= tm->tm_min * 60; tm->tm_sec = (int) l_clock; days = tm->tm_yday; /* wday%7 should be day of week of first day of year */ tm->tm_wday = (wday + days) % 7; while (days >= (i = mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365)))) { days -= i; tm->tm_mon++; } tm->tm_mday = days + 1; FPRINTF((stderr, "broken-down time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec)); return (0); }
/* time_t */ double gtimegm(struct tm *tm) { int i; /* returns sec from year ZERO_YEAR, defined in gp_time.h */ double dsec = 0.; if (tm->tm_year < ZERO_YEAR) { for (i = tm->tm_year; i < ZERO_YEAR; i++) { dsec -= (double) gdysize(i); } } else { for (i = ZERO_YEAR; i < tm->tm_year; i++) { dsec += (double) gdysize(i); } } if (tm->tm_mday > 0) { for (i = 0; i < tm->tm_mon; i++) { dsec += (double) mndday[i] + (i == 1 && (gdysize(tm->tm_year) > 365)); } dsec += (double) tm->tm_mday - 1; } else { dsec += (double) tm->tm_yday; } dsec *= (double) 24; dsec += tm->tm_hour; dsec *= 60.0; dsec += tm->tm_min; dsec *= 60.0; dsec += tm->tm_sec; FPRINTF((stderr, "broken-down time : %02d/%02d/%d:%02d:%02d:%02d = %g seconds\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec, dsec)); return (dsec); }
char * gstrptime(char *s, char *fmt, struct tm *tm, double *usec) { int yday = 0; TBOOLEAN sanity_check_date = FALSE; tm->tm_mday = 1; tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0; /* make relative times work (user-defined tic step) */ tm->tm_year = ZERO_YEAR; /* Fractional seconds will be returned separately, since * there is no slot for the fraction in struct tm. */ *usec = 0.0; /* we do not yet calculate wday or yday, so make them illegal * [but yday will be read by %j] */ tm->tm_yday = tm->tm_wday = -1; /* If the format requests explicit day, month, or year, then we will * do sanity checking to make sure the input makes sense. * For backward compatibility with gnuplot versions through 4.6.6 * hour, minute, seconds default to zero with no error return * if the corresponding field cannot be found or interpreted. */ if (strstr(fmt,"%d")) { tm->tm_mday = -1; sanity_check_date = TRUE; } if (strstr(fmt,"%y") || strstr(fmt,"%Y")) { tm->tm_year = -1; sanity_check_date = TRUE; } if (strstr(fmt,"%m") || strstr(fmt,"%B") || strstr(fmt,"%b")) { tm->tm_mon = -1; sanity_check_date = TRUE; } while (*fmt) { if (*fmt != '%') { if (*fmt == ' ') { /* space in format means zero or more spaces in input */ while (*s == ' ') ++s; ++fmt; continue; } else if (*fmt == *s) { ++s; ++fmt; continue; } else break; /* literal match has failed */ } /* we are processing a percent escape */ switch (*++fmt) { case 'b': /* abbreviated month name */ { int m; for (m = 0; m < 12; ++m) if (strncasecmp(s, abbrev_month_names[m], strlen(abbrev_month_names[m])) == 0) { s += strlen(abbrev_month_names[m]); goto found_abbrev_mon; } /* get here => not found */ int_warn(DATAFILE, "Bad abbreviated month name"); m = 0; found_abbrev_mon: tm->tm_mon = m; break; } case 'B': /* full month name */ { int m; for (m = 0; m < 12; ++m) if (strncasecmp(s, full_month_names[m], strlen(full_month_names[m])) == 0) { s += strlen(full_month_names[m]); goto found_full_mon; } /* get here => not found */ int_warn(DATAFILE, "Bad full month name"); m = 0; found_full_mon: tm->tm_mon = m; break; } case 'd': /* read a day of month */ s = read_int(s, 2, &tm->tm_mday); break; case 'm': /* month number */ s = read_int(s, 2, &tm->tm_mon); --tm->tm_mon; break; case 'y': /* year number */ s = read_int(s, 2, &tm->tm_year); /* In line with the current UNIX98 specification by * The Open Group and major Unix vendors, * two-digit years 69-99 refer to the 20th century, and * values in the range 00-68 refer to the 21st century. */ if (tm->tm_year <= 68) tm->tm_year += 100; tm->tm_year += 1900; break; case 'Y': s = read_int(s, 4, &tm->tm_year); break; case 'j': s = read_int(s, 3, &tm->tm_yday); tm->tm_yday--; sanity_check_date = TRUE; yday++; break; case 'H': s = read_int(s, 2, &tm->tm_hour); break; case 'M': s = read_int(s, 2, &tm->tm_min); break; case 'S': s = read_int(s, 2, &tm->tm_sec); if (*s == '.' || (decimalsign && *s == *decimalsign)) *usec = atof(s); break; case 's': /* read EPOCH data * EPOCH is the std. unix timeformat seconds since 01.01.1970 UTC */ { char *fraction = strchr(s, decimalsign ? *decimalsign : '.'); double ufraction = 0; double when = strtod (s, &s) - SEC_OFFS_SYS; ggmtime(tm, when); if (fraction && fraction < s) ufraction = atof(fraction); if (ufraction < 1.) /* Filter out e.g. 123.456e7 */ *usec = ufraction; break; } default: int_warn(DATAFILE, "Bad time format in string"); } fmt++; } FPRINTF((stderr, "read date-time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec)); /* now sanity check the date/time entered, normalising if necessary * read_int cannot read a -ve number, but can read %m=0 then decrement * it to -1 */ #define S (tm->tm_sec) #define M (tm->tm_min) #define H (tm->tm_hour) if (S >= 60) { M += S / 60; S %= 60; } if (M >= 60) { H += M / 60; M %= 60; } if (H >= 24) { if (yday) tm->tm_yday += H / 24; tm->tm_mday += H / 24; H %= 24; } #undef S #undef M #undef H FPRINTF((stderr, "normalised time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec)); if (sanity_check_date) { if (yday) { if (tm->tm_yday < 0) { // int_error(DATAFILE, "Illegal day of year"); return (NULL); } /* we just set month to jan, day to yday, and let the * normalising code do the work. */ tm->tm_mon = 0; /* yday is 0->365, day is 1->31 */ tm->tm_mday = tm->tm_yday + 1; } if (tm->tm_mon < 0) { // int_error(DATAFILE, "illegal month"); return (NULL); } if (tm->tm_mday < 1) { // int_error(DATAFILE, "illegal day of month"); return (NULL); } if (tm->tm_mon > 11) { tm->tm_year += tm->tm_mon / 12; tm->tm_mon %= 12; } { int days_in_month; while (tm->tm_mday > (days_in_month = (mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365))))) { if (++tm->tm_mon == 12) { ++tm->tm_year; tm->tm_mon = 0; } tm->tm_mday -= days_in_month; } } } return (s); }
char * gstrptime(char *s, char *fmt, struct tm *tm) { int yday, date; date = yday = 0; tm->tm_mday = 1; tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0; /* make relative times work (user-defined tic step) */ tm->tm_year = ZERO_YEAR; /* we do not yet calculate wday or yday, so make them illegal * [but yday will be read by %j] */ tm->tm_yday = tm->tm_wday = -1; while (*fmt) { if (*fmt != '%') { if (*fmt == ' ') { /* space in format means zero or more spaces in input */ while (*s == ' ') ++s; ++fmt; continue; } else if (*fmt == *s) { ++s; ++fmt; continue; } else break; /* literal match has failed */ } /* we are processing a percent escape */ switch (*++fmt) { case 'b': /* abbreviated month name */ { int m; for (m = 0; m < 12; ++m) if (strncasecmp(s, abbrev_month_names[m], strlen(abbrev_month_names[m])) == 0) { s += strlen(abbrev_month_names[m]); goto found_abbrev_mon; } /* get here => not found */ int_warn(DATAFILE, "Bad abbreviated month name"); m = 0; found_abbrev_mon: tm->tm_mon = m; break; } case 'B': /* full month name */ { int m; for (m = 0; m < 12; ++m) if (strncasecmp(s, full_month_names[m], strlen(full_month_names[m])) == 0) { s += strlen(full_month_names[m]); goto found_full_mon; } /* get here => not found */ int_warn(DATAFILE, "Bad full month name"); m = 0; found_full_mon: tm->tm_mon = m; break; } case 'd': /* read a day of month */ s = read_int(s, 2, &tm->tm_mday); date++; break; case 'm': /* month number */ s = read_int(s, 2, &tm->tm_mon); date++; --tm->tm_mon; break; case 'y': /* year number */ s = read_int(s, 2, &tm->tm_year); /* In line with the current UNIX98 specification by * The Open Group and major Unix vendors, * two-digit years 69-99 refer to the 20th century, and * values in the range 00-68 refer to the 21st century. */ if (tm->tm_year <= 68) tm->tm_year += 100; date++; tm->tm_year += 1900; break; case 'Y': s = read_int(s, 4, &tm->tm_year); date++; break; case 'j': s = read_int(s, 3, &tm->tm_yday); tm->tm_yday--; date++; yday++; break; case 'H': s = read_int(s, 2, &tm->tm_hour); break; case 'M': s = read_int(s, 2, &tm->tm_min); break; case 'S': s = read_int(s, 2, &tm->tm_sec); break; /* read EPOCH data * EPOCH is the std. unixtimeformat seconds since 01.01.1970 UTC * actualy i would need a read_long (or what time_t is else) * aktualy this is not my idea i got if from * AlunDa Penguin Jones (21.11.97) * but changed %t to %s because of strftime * and fixed the localtime() into gmtime() * maybe we should use ggmtime() ? but who choose double ???? * Walter Harms <*****@*****.**> 26 Mar 2000 */ case 's': #if 0 /* HBB 20040213: comment this out, but keep it around for now */ { /* time_t when; */ int when; struct tm *tmwhen; s = read_int(s, 10, &when); tmwhen = gmtime((time_t*)&when); tmwhen->tm_year += 1900; *tm = *tmwhen; break; } #else /* HBB 20040213: New version of this. 64-bit proof and * more in line with the rest of this module than the * original one. */ { double when; /* offset from UNIX epoch (1970) to gnuplot epoch */ static const long epoch_offset = (long)((ZERO_YEAR - 1970) * 365.25) * DAY_SEC; when = strtod (s, &s) - epoch_offset; ggmtime(tm, when); break; } #endif default: int_warn(DATAFILE, "Bad time format in string"); } fmt++; } FPRINTF((stderr, "read date-time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec)); /* now check the date/time entered, normalising if necessary * read_int cannot read a -ve number, but can read %m=0 then decrement * it to -1 */ #define S (tm->tm_sec) #define M (tm->tm_min) #define H (tm->tm_hour) if (S >= 60) { M += S / 60; S %= 60; } if (M >= 60) { H += M / 60; M %= 60; } if (H >= 24) { if (yday) tm->tm_yday += H / 24; tm->tm_mday += H / 24; H %= 24; } #undef S #undef M #undef H FPRINTF((stderr, "normalised time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec)); if (date) { if (yday) { if (tm->tm_yday < 0) int_error(DATAFILE, "Illegal day of year"); /* we just set month to jan, day to yday, and let the * normalising code do the work. */ tm->tm_mon = 0; /* yday is 0->365, day is 1->31 */ tm->tm_mday = tm->tm_yday + 1; } if (tm->tm_mon < 0) { int_error(DATAFILE, "illegal month"); return (NULL); } if (tm->tm_mday < 1) { int_error(DATAFILE, "illegal day of month"); return (NULL); } if (tm->tm_mon > 11) { tm->tm_year += tm->tm_mon / 12; tm->tm_mon %= 12; } { int days_in_month; while (tm->tm_mday > (days_in_month = (mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365))))) { if (++tm->tm_mon == 12) { ++tm->tm_year; tm->tm_mon = 0; } tm->tm_mday -= days_in_month; } } } return (s); }