// STEREOsecs.c // // Originated and maintained by // // Tycho von Rosenvinge // Laboratory for High Energy Astrophysics // NASA/Goddard Space Flight Center // Greenbelt, MD 20771 // // Tel. 301-286-6721 // e-mail tycho@milkyway.gsfc.nasa.gov // // See STEREOtime.h for a description of each function // STEREOsecs is a subset of STEREOtime // #define TEST__ // define to include main() at the end // of this file to test STEREOtime.c; // comment this out when linking to // user program #define SID 86400L // number of seconds in a day #define SECONDS_OFFSET -378691200L // 1958 Jan 1 00:00:00 relative to // 1970 Jan 1 00:00:00 #define DAYS_OFFSET -4383 // 1958 Jan 1 relative to 1970 Jan 1 #include #include #include #include // #include DOS only #include static char *Months[]={"Jan","Feb","Mar","Apr","May", "Jun","Jul","Aug","Sep","Oct", "Nov","Dec","???"}; static int maxday[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; char *pass_bl(char *str); // Pass blanks,/,tabs,FF,LF or \n in string char *pass_fld(char *str); // Pass next field in string // 24 hour clock // 1958 Jan 1=> DOY=1 (not 0!) void sec58_ymdhms(long sec58,int *piyear,int *pimon,int *piday,int *pihour,int *pimin,int *pisec); int ymd_doy58(int iyear,int imon,int iday); void doy58_ymd(int doy58,int *piyear,int *pimon,int *piday); // char *dayofwk(int iday,int imon,int iyear); long ts_sec58(char *str,char **end); // Scan date/time string to obtain seconds of 1958 // e.g. 1997 Nov 11 00:00:00 // returns pointer to end of string in case there is // another time to scan (e.g. when you have a start // and end date/time in one string); // Must supply proper char **end even if you aren't // going to use this feature because the routine // will set *end equal to a pointer value // int ds_doy58(char *ds); // date string -> doy58 // void doy58_ds(int doy58,char *ds); // doy58 -> date string void sec58_ts(long sec58,char *ts); // long sec58_sec70(long sec58); // changes seconds of 1958 to seconds of 1970 // int doy58_doyxx(int doy58,int yrxx ); // int doyxx_doy58(int doyxx, int yrxx); char *month(int imon); // void day_fraction_hms(double day_fraction,int *phour,int *pmin,int *psec); // void DDOY_ts(int year,double DDOY,char *ts); // Decimal DOY -> time string char *pass_bl(char *str) // Pass blanks,/,tabs,FF,LF or \n in string { while (*str && (isspace(*str) || *str=='/')) str++; // debug // printf("\npass_bl:"); // printf("\n str: .%s",str); // printf("\nCR to cont"); // getch(); return str; } char *pass_fld(char *str) // Pass next field in string { while (*str && (isspace(*str) || *str=='/')) str++; while (*str && !(isspace(*str) || *str=='/')) str++; // debug // printf("\npass_fld:"); // printf("\n str: .%s",str); // printf("\nCR to cont"); // getch(); return str; } void sec58_ymdhms(long sec58,int *piyear,int *pimon,int *piday,int *phour,int *pmin,int *psec) // Converts seconds of 1958 to iyear,imon,iday,... // time= 0 seconds at 00:00:00 on 1958 Jan 1 // Hour based on 24 hour clock { long d70,sec70; // 1970 Jan 1=> d70=0! (vs doy70=1) sec70=sec58 + SECONDS_OFFSET; d70=sec70/SID; sec70-=d70*SID; if(sec70<0) { sec70+=SID; d70--; } doy58_ymd(d70+1-DAYS_OFFSET,piyear,pimon,piday); *phour=(int)(sec70/3600L); *pmin=(int)((sec70-*phour*3600L)/60L); *psec=(int)(sec70-*phour*3600L-*pmin*60L); // Be careful: *phour*3600 can evaluate to a negative integer! return; } int ymd_doy58(int iyear,int imon,int iday) // function to convert date of Gregorian // calendar (iyear,imon,iday) to day of year 1958 // 1958 Jan 1 = doy58 #1 (not 0!); // iyear must be 4 digits-e.g. 1979, not 79 { long c; if(imon>2){ imon -=3; } else{ imon +=9; iyear -=1; } c=iyear/100; iyear=iyear-c*100; return (int)((long)(146097L*c)/4+(1461L*iyear)/4+(153*imon+2)/5+iday-719469L-DAYS_OFFSET+1L); } void doy58_ymd(int doy58,int *piyear,int *pimon,int *piday) // converts doy58 to iyear,imon,iday // 1958 Jan 1 = doy58 #1 (not 0!) { long d,m,y,j; j=(doy58+719469L+DAYS_OFFSET-1L)*4-1; y=j/146097; j=j-y*146097; d=(j/4)*4+3; j=d/1461; d=((d+4-j*1461)/4)*5-3; m=d/153; d=(d+5-153*m)/5; y=100*y+j; if(m<10) m+=3; else{ m-=9; y+=1; } *piday=d; *pimon=m; *piyear=y; } long ts_sec58(char *str,char **end) // Scan date/time string to obtain seconds of 1958; // string in [YY]YY Mon DD HH[:]MM[:][SS] format, // where [] imply optional parameters; // // [YY]YY/MM/DD HH[:]MM[:][SS] also works. // [YY]YY DOY HH[:]MM[:][SS] also works // [YY]YY DecimalDoy also works (e.g. 1998 33.5 = 1998 Feb 2 12:00) // // e.g.00 Nov 1 0410 is recognised as 2000 Nov 1 04:10:00 // // ts_sec58 returns pointer to the point after the time // scanned (a useful feature if there is another time // to scan e.g., when you have a start and end date/time // in one string); you must supply a proper char **end // argument even if you aren't going to use this feature // since the routine will set *end to equal a pointer // value { char *ptr; char buf[4],sZmon[4]; long sec58; int i,doy58,doy,year,mon,day,hour,mins,sec; double DDOY,frac; ptr=str; *end=ptr; // gets reset at end upon successful scan year=atoi(ptr); if(year>36 && year<100) year+=1900; else if (year<26) year+=2000; if(!(year>1936 && year<2026)) { printf("\n\007ERROR in ts_sec58:\n %s; CR to cont",str); getchar(); return 0L; } // debug // printf("\nts_sec58(): %s",ptr); // printf("\n year=%d",year); // printf("\nCR to cont "); // getch(); ptr=pass_fld(ptr); // skip ptr over year ptr=pass_bl(ptr); // skip to start of month or DOY // debug // printf("\nptr=%ld,strchr=%ld; CR to continue ",ptr,strchr(ptr,'.')); // getch(); if(strchr(ptr,'.') && strchr(ptr,'.')-ptr <5) { // Decimal DOY sscanf(ptr,"%lf",&DDOY); frac=DDOY-(int)DDOY; hour=(int)(frac*SID/3600.); mins=(int)((frac*SID-hour*3600.)/60.); // important to have '.' in hour*3600. sec=(int)(frac*SID-hour*3600.-mins*60.); // because hour*3600 can evaluate to a // negative integer! doy58=ymd_doy58(year,1,1)+(long)DDOY-1; // DDOY starts with 1 on Jan 1 instead of 0 doy58_ymd(doy58,&year,&mon,&day); // debug // printf("\nts_sec58() encountered a decimal doy:"); // printf("\n %s",ptr); // printf("\n %8.4lf: %d %d/%d %2d:%2d:%2d",DDOY,year,mon,day,hour,mins,sec); // printf("\nCR to cont "); // getch(); ptr=pass_fld(ptr); // unnecessary, but leaves ptr at same point as other formats } else { // (DOY or MM/DD or Mon DD) + HH[:]MM[:][SS] if(isdigit(ptr[0]) && (strchr(ptr,'/')==NULL || strchr(ptr,'/')-ptr>4)) { // DOY doy=atoi(ptr); doy58=ymd_doy58(year,1,1)+(long)doy-1; // DOY starts with 1 on Jan 1 instead of 0 doy58_ymd(doy58,&year,&mon,&day); ptr=pass_fld(ptr); ptr=pass_bl(ptr); // ptr at start of time } else if(isdigit(ptr[0]) && strchr(ptr,'/')!=NULL && (strchr(ptr,'/')-ptr)<3) { // MM/DD mon=atoi(ptr); if(mon<1 || mon>12) { printf("\n\007ERROR in ts_sec58:\n%s ??; CR to cont",ptr); getchar(); return 0L; } ptr=pass_fld(ptr); ptr=pass_bl(ptr); // skip to start of DD day=atoi(ptr); ptr=pass_fld(ptr); ptr=pass_bl(ptr); // ptr at start of time } else { // Mon DD sZmon[0]=toupper(ptr[0]); sZmon[1]=tolower(ptr[1]); sZmon[2]=tolower(ptr[2]); sZmon[3]='\0'; for(i=0;i<12;i++) if(!strcmp(sZmon,Months[i])) { mon=i+1; break; } if(i==12) { printf("\n\007ERROR in ts_sec58:\nmonth = %s ???; CR to cont",sZmon); getchar(); return 0L; } ptr=pass_fld(ptr); ptr=pass_bl(ptr); day=atoi(ptr); ptr=pass_fld(ptr); ptr=pass_bl(ptr); // ptr at start of time } if((year%4==0&&(year%100!=0))||(year%400==0)) maxday[2]=29; else maxday[2]=28; if(day<1||day>maxday[mon]) { printf("\n\007ERROR in ts_sec58:\nmonth = %s, day = %d ???; CR to cont",sZmon,day); getchar(); return 0L; } // note: 12:10 = 12:10:00 = 1210; need to be careful! buf[0]=*ptr++; if(*ptr==':') buf[1]='\0'; else { buf[1]=*ptr++; buf[2]='\0'; } hour=atoi(buf); // Hrs if(*ptr==':') ptr++; buf[0]=*ptr++; if(*ptr==':') buf[1]='\0'; else { buf[1]=*ptr++; buf[2]='\0'; } mins=atoi(buf); // Minutes ... lint didn't like min if(*ptr==':') ptr++; if(isdigit(*ptr)) { sec=atoi(ptr); // Secs ptr=pass_fld(ptr); } else sec=0; // debug // printf("\nts_sec58(): YY=%d,MM=%d,DD=%d,HH=%d, MM=%d, SS=%d", // year,mon,day,hour,mins,sec); } if(hour<0||hour>23) { if(hour==24 && mins==0 && sec==0) ; // 24:00:00 allowed else return 0L; } if(mins<0||mins>59) return 0L; if(sec<0||sec>59) return 0L; // debug // printf("\nts_sec58(): YY=%d,MM=%d,DD=%d,HH=%d, MM=%d, SS=%d", // year,mon,day,hour,mins,sec); sec58=(ymd_doy58(year,mon,day)-1)*SID+hour*3600L+mins*60L+sec; // Be careful: hour*3600 can evaluate to a negative integer! // debug // printf("\nts_sec58(): sec58 = %ld",sec58); *end=ptr; // debug // printf("\nLeaving ts_sec58():"); // printf("\nstr: %s",str); // printf("\nend: %s",*end); // printf("\nCR to cont"); // getch(); return sec58; } void sec58_ts(long sec58,char *ts) // builds time string ts as YYYY Mon DD HH:MM:SS // time string is 21 chars including \0 { int year,mon,day,hour,mins,sec; sec58_ymdhms(sec58,&year,&mon,&day,&hour,&mins,&sec); sprintf(ts,"%4d %s %2d %02d:%02d:%02d", year,month(mon),day,hour,mins,sec); } char *month(int imon) // returns pointer to abbreviated string for month { static char *Months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug", "Sep","Oct","Nov","Dec","???"}; if ( imon < 1 || imon > 12 ) return(Months[12]); else return(Months[imon-1]); } #ifdef TEST__ void main() { char tstring[80], buf[80], *end; long tsec58; int year,mon,day,hour,minutes,seconds; int doy58; double ddoy; // decimal day of year int ok; printf("\n\nCheck ymd_doy58(): 58 Jan 1= doy58 #%d", ymd_doy58(1958,1,1)); printf(" \n(expect 1)\n"); printf( "\n 59 Jan 1= doy58 #%d", ymd_doy58(1959,1,1)); printf(" \n(expect 366)\n"); strcpy(tstring,"1997 Dec 15 18:00"); printf("\n\nConvert %s to seconds of 1958 and back:", tstring); tsec58=ts_sec58(tstring,&end); // printf("\n%s (%ld seconds of 1958)",tstring,tsec58); sec58_ts(tsec58,buf); printf("\n %s",buf); sec58_ymdhms(tsec58,&year,&mon,&day,&hour,&minutes,&seconds); doy58=ymd_doy58(year,mon,day); printf("\ndoy58=%d (expect 715+4383+9496 =14594)\n\n",doy58); printf("\nCR to continue"); getchar(); doy58=ymd_doy58(2000,2,1); printf("\n\n\ndoy58 for 2000 Feb 1: %d (expect 1493+4383+9496=15372)",doy58); strcpy(tstring,"2000 250.75"); printf("\nDay 250 of year 2000 is Sep 6"); printf("\nConvert %s to seconds of 1958 and back:", tstring); tsec58=ts_sec58(tstring,&end); sec58_ts(tsec58,buf); printf("\n %s\n",buf); strcpy(tstring,"2000 250 1820"); printf("\nConvert %s to seconds of 1958 and back:", tstring); tsec58=ts_sec58(tstring,&end); sec58_ts(tsec58,buf); printf("\n %s\n",buf); strcpy(tstring,"2000/9/6 18:1:30"); printf("\nConvert %s to seconds of 1958 and back:", tstring); tsec58=ts_sec58(tstring,&end); sec58_ts(tsec58,buf); printf("\n %s\n\n",buf); ok=0; while(!ok) { printf("\nEnter any year as YYYY: "); scanf("%d",&year); if(year<1900 || year>2100) continue; printf("\nEnter any month number: "); scanf("%d",&mon); if(mon<1 || mon>12) continue; printf("\nEnter the day of month: "); scanf("%d",&day); if(day<1 || day>31) // crude check only continue; ok=1; } sprintf(tstring,"%d %s %d 00:00:00", year,month(mon),day); tsec58=ts_sec58(tstring,&end); printf("\ntsec58 at start of day =%ld",tsec58); ok=0; while(!ok) { printf("\nEnter any year as YYYY: "); scanf("%d",&year); if(year<1900 || year>2100) continue; printf("\nEnter any time as decimal DOY (Note: Noon on Jan 1 is 1.5): "); scanf("%lf",&ddoy); // if(ddoy<1.0 || ddoy>366.0) // crude check // continue; ok=1; } // long ts_sec58(char *str,char **end) sprintf(tstring,"%d %lf",year,ddoy); tsec58=ts_sec58(tstring,&end); printf("\ntsec58 =%ld",tsec58); sec58_ts(tsec58,buf); printf("\n %s\n",buf); } #endif #ifdef TEST__ #undef TEST__ #endif