/*----------------------------------------------------------------------*\ | Utility routines to convert FIPS dates to and from struct tm | | | | Routines that write date as string to address given by argument: | | tm_to_yd from struct tm, generate FIPS date in YYDDD form | | tm_to_yyd from struct tm, generate FIPS date in YYYYDDD form | | tm_to_ymd from struct tm, generate FIPS date in YYMMDD form | | tm_to_yymd from struct tm, generate FIPS date in YYYYMMDD form | | | | Routines that dynamically allocate struct tm and return its address: | | ymd_to_tm from FIPS date as YYMMDD or YYYYMMDD, make struct tm | | yd_to_tm from FIPS date as YYDDD or YYYYDDD, make struct tm | | get_tm from FIPS date and time (HHMM), make struct tm | | | | Routines that modify the time data passed by reference | | next_day modify struct tm by adding one day | | increment_yd modify FIPS date in YYDDD form by adding one day | | | | Peter N. Schweitzer (U.S. Geological Survey, Reston, VA 22092) | \*----------------------------------------------------------------------*/ #include #include #include #include #include "dw.h" static char msg [128]; /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ static int year_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static int leap_days[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static char *month_name[] = { "January","February","March","April","May","June","July","August", "September","October","November","December" }; size_t tm_to_yd (char *dst, const struct tm *tm) { return (strftime (dst,6,"%y%j",tm)); } size_t tm_to_yyd (char *dst,const struct tm *tm) { return (strftime (dst,8,"%Y%j",tm)); } size_t tm_to_ymd (char *dst, const struct tm *tm) { return (strftime (dst,7,"%y%m%d",tm)); } size_t tm_to_yymd (char *dst, const struct tm *tm) { return (strftime (dst,9,"%Y%m%d",tm)); } struct tm *ymd_to_tm (const char *ymd) { int y,m,d; const char *s; struct tm *tm; int *day_count; for (s=ymd; *s; s++) if (!isdigit (*s)) return (NULL); s = ymd; if (strlen (ymd) == 8) { y = *s++ - '0'; y *= 10; y += *s++ - '0'; if (y < 19) { sprintf (msg,"Error: year must be later than 1899 in \"%s\"",ymd); dw_error (msg); return (NULL); } y -= 19; } else y = 0; y *= 10; y += *s++ - '0'; y *= 10; y += *s++ - '0'; m = *s++ - '0'; m *= 10; m += *s++ - '0'; m--; if (m > 11) { sprintf (msg,"Error: invalid month %d in \"%s\"",m,ymd); dw_error (msg); return (NULL); } d = *s++ - '0'; d *= 10; d += *s++ - '0'; if (y & 3) day_count = year_days; else day_count = leap_days; if (d > day_count [m]) { sprintf (msg,"Error: %s of %d has only %d days, not %d",month_name[m],1900+y,day_count[m],d); dw_error (msg); return (NULL); } if (tm = (struct tm *) malloc (sizeof(struct tm))) { tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = d; tm->tm_mon = m; tm->tm_year = y; tm->tm_wday = 0; tm->tm_yday = 0; tm->tm_isdst = -1; if (mktime (tm) == (time_t) -1) { free (tm); tm = NULL; } } return (tm); } struct tm *yd_to_tm (const char *yd) { int y,m,d; const char *s; struct tm *tm; int *day_count; for (s=yd; *s; s++) if (!isdigit (*s)) { dw_error ("Error: date must consist entirely of numbers"); return (NULL); } s = yd; if (strlen (yd) == 7) { y = *s++ - '0'; y *= 10; y += *s++ - '0'; if (y < 19) { sprintf (msg,"Error: year must be later than 1899 in \"%s\"",yd); dw_error (msg); return (NULL); } y -= 19; } else y = 0; y *= 10; y += *s++ - '0'; y *= 10; y += *s++ - '0'; if (y & 3) day_count = year_days; else day_count = leap_days; d = *s++ - '0'; d *= 10; d += *s++ - '0'; d *= 10; d += *s++ - '0'; m = 0; while (d > day_count[m]) d -= day_count[m++]; if (m > 11) { sprintf (msg,"Error: invalid day count in \"%s\"",yd); dw_error (msg); return (NULL); } if (tm = (struct tm *) malloc (sizeof(struct tm))) { tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = d; tm->tm_mon = m; tm->tm_year = y; tm->tm_wday = 0; tm->tm_yday = 0; tm->tm_isdst = -1; if (mktime (tm) == (time_t) -1) { free (tm); tm = NULL; } } return (tm); } struct tm *get_tm (char *ds, char *ts) { int j,h,m; char *s; struct tm *tm = NULL; j = strlen (ds); if (j == 7 || j == 5) tm = yd_to_tm (ds); else if (j == 8 || j == 6) tm = ymd_to_tm (ds); else dw_error ("Error: expected date like YYMMDD or YYDDD"); if (tm) { s = ts; if (!isdigit(s[0]) || !isdigit(s[1]) || !isdigit(s[2]) || !isdigit(s[3])) dw_error ("Error: expected time like HHMM"); h = *s++ - '0'; h *= 10; h += *s++ - '0'; m = *s++ - '0'; m *= 10; m += *s++ - '0'; tm->tm_hour = h; tm->tm_min = m; } return (tm); } void next_day (struct tm *tm) { int *day_count; if (tm->tm_year & 3) day_count = year_days; else day_count = leap_days; tm->tm_yday++; tm->tm_mday++; if (tm->tm_mday > day_count[tm->tm_mon]) { tm->tm_mday -= day_count[tm->tm_mon]; tm->tm_mon++; if (tm->tm_mon > 11) { tm->tm_mon = 0; tm->tm_year++; tm->tm_yday = 0; } } } /*----------------------------------------------------------------------*\ | increment_yd modifies a FIPS date in the form YYDDD by adding one | | day and, if necessary, adjusting the year accordingly. Note that it | | modifies the string pointed to by the argument. | \*----------------------------------------------------------------------*/ void increment_yd (char *yyddd) { int y,d; char *s = yyddd; y = *s++ - '0'; y *= 10; y += *s++ - '0'; d = *s++ - '0'; d *= 10; d += *s++ - '0'; d *= 10; d += *s++ - '0'; d++; if (d > 365) if (y & 3) { /* not a leap year */ y++; s = yyddd; *s++ = '0' + (y / 10); *s++ = '0' + (y % 10); d -= 365; } else /* leap year */ if (d > 366) { y++; s = yyddd; *s++ = '0' + (y / 10); *s++ = '0' + (y % 10); d -= 366; } s = yyddd + 2; *s++ = '0' + d/100; *s++ = '0' + (d % 100)/10; *s = '0' + (d % 10); } /*----------------------------------------------------------------------*\ \*----------------------------------------------------------------------*/