void CGldEditorView::LoadScheduleBlock(SCHEDULE *sch, unsigned int block) { CListCtrl &list = GetListCtrl(); int nColumns = list.GetHeaderCtrl()?list.GetHeaderCtrl()->GetItemCount():0; for (int i=0; i<nColumns; i++) list.DeleteColumn(0); CRect wr; list.GetClientRect(&wr); int nCol=0; int nWid=0; #define W(X) (nWid+=X,X) int Cal = list.InsertColumn(nCol++,"Month",LVCFMT_LEFT,W(150),nCol); int dowCol[8]; dowCol[0] = list.InsertColumn(nCol++,"Sun",LVCFMT_LEFT,W(50),nCol); dowCol[1] = list.InsertColumn(nCol++,"Mon",LVCFMT_LEFT,W(50),nCol); dowCol[2] = list.InsertColumn(nCol++,"Tue",LVCFMT_LEFT,W(50),nCol); dowCol[3] = list.InsertColumn(nCol++,"Wed",LVCFMT_LEFT,W(50),nCol); dowCol[4] = list.InsertColumn(nCol++,"Thu",LVCFMT_LEFT,W(50),nCol); dowCol[5] = list.InsertColumn(nCol++,"Fri",LVCFMT_LEFT,W(50),nCol); dowCol[6] = list.InsertColumn(nCol++,"Sat",LVCFMT_LEFT,W(50),nCol); dowCol[7] = list.InsertColumn(nCol++,"Hol",LVCFMT_LEFT,W(50),nCol); #undef W char *months[] = {"January","February","March","April","May","June","July","August","September","October","November","December"}; int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; int year=2000; for (int month=1; month<=12; month++) { char buffer[64]; sprintf(buffer,"%s",months[month-1]); int nItem = list.InsertItem(list.GetItemCount(),buffer); int hItem[24]; for (int hour=0; hour<24; hour++) { char buffer[64]; sprintf(buffer," %d:00",hour); hItem[hour] = list.InsertItem(list.GetItemCount(),buffer); } for (int day=0; day<7; day++) { for (int hour=0; hour<24; hour++) { DATETIME dt = {year,month,day+1,hour,0,0}; TIMESTAMP ts = mkdatetime(&dt); local_datetime(ts,&dt); SCHEDULEINDEX ref = schedule_index(sch,ts); double value = schedule_value(sch,ref); char buffer[64]; sprintf(buffer,"%g%c",value,schedule_dtnext(sch,ref)<60?'*':' '); list.SetItemText(hItem[hour],dowCol[dt.weekday],buffer); } } } }
void CGldEditorView::LoadSchedule(SCHEDULE *sch) { CListCtrl &list = GetListCtrl(); int nColumns = list.GetHeaderCtrl()?list.GetHeaderCtrl()->GetItemCount():0; for (int i=0; i<nColumns; i++) list.DeleteColumn(0); CRect wr; list.GetClientRect(&wr); int nCol=0; int nWid=0; #define W(X) (nWid+=X,X) int year = list.InsertColumn(nCol++,"Year",LVCFMT_LEFT,W(45),nCol); int month = list.InsertColumn(nCol++,"Month",LVCFMT_LEFT,W(50),nCol); int weekday = list.InsertColumn(nCol++,"Weekday",LVCFMT_LEFT,W(60),nCol); int day = list.InsertColumn(nCol++,"Day",LVCFMT_RIGHT,W(35),nCol); int hour = list.InsertColumn(nCol++,"Time",LVCFMT_RIGHT,W(50),nCol); int value = list.InsertColumn(nCol++,"Value",LVCFMT_RIGHT,W(50),nCol); #undef W TIMESTAMP tstart = global_clock; // TODO: this should be global_starttime but it's already been set to wall clock by this time TIMESTAMP tstop = global_stoptime; if (tstart==0) { time_t now = time(NULL); struct tm* ts = localtime(&now); DATETIME dt = {ts->tm_year,1,1,0,0,0,0,0}; tstart = mkdatetime(&dt); } if (tstop==TS_NEVER || tstop<tstart) { DATETIME dt; local_datetime(tstart,&dt); dt.year++; tstop = mkdatetime(&dt); } TIMESTAMP t = tstart; DATETIME last = {0,0,0,-1,0,0}; // -1 forces first time to be displayed even when it's midnight int max = 100; double lastvalue=-1; // -1 forces first time to be displayed even when it's zero value while (t<tstop )// && max-->0) { SCHEDULEINDEX ndx = schedule_index(sch,t); DATETIME next; local_datetime(t,&next); double nextvalue = schedule_value(sch,ndx); if (nextvalue!=lastvalue) { int hItem = list.InsertItem(list.GetItemCount(),""); CString buf; if (last.year!=next.year) { buf.Format("%d",next.year); list.SetItemText(hItem,year,buf); last.year = next.year; } if (last.month!=next.month) { char *mon[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; list.SetItemText(hItem,month,mon[next.month-1]); last.month = next.month; } if (last.day!=next.day) { buf.Format("%d",next.day); list.SetItemText(hItem,day,buf); last.day = next.day; char *wd[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; list.SetItemText(hItem,weekday,wd[next.weekday]); } if (last.hour!=next.hour || last.minute!=next.minute) { buf.Format("%d:%02d",next.hour,next.minute); list.SetItemText(hItem,hour,buf); last.hour = next.hour; last.minute = next.minute; } buf.Format("%g", nextvalue); list.SetItemText(hItem,value,buf); lastvalue = nextvalue; } t+=schedule_dtnext(sch,ndx)*60; // TODO increment by dtnext } }
/** Convert from a string to a timestamp -- delta compatibility **/ TIMESTAMP convert_to_timestamp_delta(const char *value, unsigned int *nanoseconds, double *dbl_time_value) { /* Declarations - inline ones make angry (since we're technically in C) */ DATETIME dt; double seconds_w_nano, t; char *p; char tz[5]=""; TIMESTAMP output_value; if (*value=='\'' || *value=='"') value++; /* By default, nanoseconds is set to 0 */ *nanoseconds = 0; /* Init double value */ *dbl_time_value = 0.0; /* Zero the DATETIME structure */ dt.year = 0; dt.month = 0; dt.day = 0; dt.hour = 0; dt.minute = 0; dt.second = 0; dt.nanosecond = 0; dt.is_dst = 0; dt.tz[0] = '\0'; dt.tzoffset = 0; dt.timestamp = 0; /* Default to TS_NEVER */ output_value = TS_NEVER; /* scan ISO format date/time -- nanosecond inclusive */ if (sscanf(value,"%d-%d-%d %d:%d:%lf %[-+:A-Za-z0-9]",&dt.year,&dt.month,&dt.day,&dt.hour,&dt.minute,&seconds_w_nano,tz)>=3) { dt.second = (unsigned int)seconds_w_nano; dt.nanosecond = (unsigned int)(1e9*(seconds_w_nano-(double)dt.second)+0.5); dt.is_dst = (strcmp(tz,tzdst)==0) ? 1 : 0; *nanoseconds = dt.nanosecond; strncpy(dt.tz,tz,sizeof(dt.tz)); output_value = mkdatetime(&dt); } /* scan ISO format date/time -- nanosecond inclusive */ else if (global_dateformat==DF_ISO && sscanf(value,"%d/%d/%d %d:%d:%lf %[-+:A-Za-z0-9]",&dt.year,&dt.month,&dt.day,&dt.hour,&dt.minute,&seconds_w_nano,tz)>=3) { dt.second = (unsigned int)seconds_w_nano; dt.nanosecond = (unsigned int)(1e9*(seconds_w_nano-(double)dt.second)+0.5); dt.is_dst = (strcmp(tz,tzdst)==0) ? 1 : 0; *nanoseconds = dt.nanosecond; strncpy(dt.tz,tz,sizeof(dt.tz)); output_value = mkdatetime(&dt); } /* scan US format date/time -- nanosecond inclusive */ else if (global_dateformat==DF_US && sscanf(value,"%d/%d/%d %d:%d:%lf %[-+:A-Za-z0-9]",&dt.month,&dt.day,&dt.year,&dt.hour,&dt.minute,&seconds_w_nano,tz)>=3) { dt.second = (unsigned int)seconds_w_nano; dt.nanosecond = (unsigned int)(1e9*(seconds_w_nano-(double)dt.second)+0.5); dt.is_dst = (strcmp(tz,tzdst)==0) ? 1 : 0; *nanoseconds = dt.nanosecond; strncpy(dt.tz,tz,sizeof(dt.tz)); output_value = mkdatetime(&dt); } /* scan EURO format date/time -- nanosecond inclusive */ else if (global_dateformat==DF_EURO && sscanf(value,"%d/%d/%d %d:%d:%lf %[-+:A-Za-z0-9]",&dt.day,&dt.month,&dt.year,&dt.hour,&dt.minute,&seconds_w_nano,tz)>=3) { dt.second = (unsigned int)seconds_w_nano; dt.nanosecond = (unsigned int)(1e9*(seconds_w_nano-(double)dt.second)+0.5); dt.is_dst = (strcmp(tz,tzdst)==0) ? 1 : 0; *nanoseconds = dt.nanosecond; strncpy(dt.tz,tz,sizeof(dt.tz)); output_value = mkdatetime(&dt); } /* @todo support European format date/time using some kind of global flag */ else if (strcmp(value,"INIT")==0) output_value = 0; else if (strcmp(value, "NEVER")==0) output_value = TS_NEVER; else if (strcmp(value, "NOW") == 0) output_value = global_clock; else if (isdigit(value[0])) { /* timestamp format */ t = atof(value); p=value; while (isdigit(*p) || *p=='.') p++; switch (*p) { case 's': case 'S': t *= SECOND; break; case 'm': case 'M': t *= MINUTE; break; case 'h': case 'H': t *= HOUR; break; case 'd': case 'D': t *= DAY; break; default: return TS_NEVER; break; } output_value = (TIMESTAMP)(t+0.5); } else output_value = TS_NEVER; /* Perform double conversion */ *dbl_time_value = (double)(output_value) + ((double)(dt.nanosecond)/1000000000.0); return output_value; }
/** Test the daylight saving time calculations @return the number of test the failed **/ int timestamp_test(void) { #define NYEARS 50 int year; static DATETIME last_t; TIMESTAMP step = SECOND; TIMESTAMP ts; char buf1[64], buf2[64]; char steptxt[32]; TIMESTAMP *event[]={dststart,dstend}; int failed=0, succeeded=0; output_test("BEGIN: daylight saving time event test for TZ=%s...", current_tzname); convert_from_timestamp(step,steptxt,sizeof(steptxt)); for (year=0; year<NYEARS; year++) { int test; for (test=0; test<2; test++) { for (ts=(event[test])[year]-2*step; ts<(event[test])[year]+2*step;ts+=step) { DATETIME t; if (local_datetime(ts,&t)) { if (last_t.is_dst!=t.is_dst) output_test("%s + %s = %s", strdatetime(&last_t,buf1,sizeof(buf1))?buf1:"(invalid)", steptxt, strdatetime(&t,buf2,sizeof(buf2))?buf2:"(invalid)"); last_t = t; succeeded++; } else { output_test("FAILED: unable to convert ts=%"FMT_INT64"d to local time", ts); failed++; } } } } output_test("END: daylight saving time event test"); step=HOUR; convert_from_timestamp(step,steptxt,sizeof(steptxt)); output_test("BEGIN: round robin test at %s timesteps",steptxt); for (ts=DAY+tzoffset; ts<DAY*365*NYEARS; ts+=step) { DATETIME t; if (local_datetime(ts,&t)) { TIMESTAMP tt = mkdatetime(&t); convert_from_timestamp(ts,buf1,sizeof(buf1)); convert_from_timestamp(tt,buf2,sizeof(buf2)); if (tt==TS_INVALID) { output_test("FAILED: unable to extract %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d)", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday); failed++; } else if (tt!=ts) { output_test("FAILED: unable to match %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d)\n from=%s, to=%s", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday,buf1,buf2); failed++; } else if (convert_to_timestamp(buf1)!=ts) { output_test("FAILED: unable to convert %04d-%02d-%02d %02d:%02d:%02d %s (dow=%s, doy=%d) back to a timestamp\n from=%s, to=%s", t.year,t.month,t.day,t.hour,t.minute,t.second,t.tz,dow[t.weekday],t.yearday,buf1,buf2); output_test(" expected %" FMT_INT64 "d but got %" FMT_INT64 "d", ts, convert_to_timestamp(buf1)); failed++; } else succeeded++; } else { output_test("FAILED: timestamp_test: unable to convert ts=%"FMT_INT64"d to local time", ts); failed++; } } output_test("END: round robin test",steptxt); output_test("END: daylight saving time tests for %d to %d", YEAR0, YEAR0+NYEARS); output_verbose("daylight saving time tests: %d succeeded, %d failed (see '%s' for details)", succeeded, failed, global_testoutputfile); return failed; }
/** Convert from a string to a timestamp **/ TIMESTAMP convert_to_timestamp(const char *value) { /* try date-time format */ int Y=0,m=0,d=0,H=0,M=0,S=0; char tz[5]=""; if (*value=='\'' || *value=='"') value++; /* scan ISO format date/time */ if (sscanf(value,"%d-%d-%d %d:%d:%d %[-+:A-Za-z0-9]",&Y,&m,&d,&H,&M,&S,tz)>=3) { int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0; DATETIME dt = {Y,m,d,H,M,S,0,isdst}; /* use GMT if tz is omitted */ strncpy(dt.tz,tz,sizeof(dt.tz)); return mkdatetime(&dt); } /* scan ISO format date/time */ else if (global_dateformat==DF_ISO && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&Y,&m,&d,&H,&M,&S,tz)>=3) { int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0; DATETIME dt = {Y,m,d,H,M,S,0,isdst}; /* use locale TZ if tz is omitted */ strncpy(dt.tz,tz,sizeof(dt.tz)); return mkdatetime(&dt); } /* scan US format date/time */ else if (global_dateformat==DF_US && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&m,&d,&Y,&H,&M,&S,tz)>=3) { int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0; DATETIME dt = {Y,m,d,H,M,S,0,isdst}; /* use locale TZ if tz is omitted */ strncpy(dt.tz,tz,sizeof(dt.tz)); return mkdatetime(&dt); } /* scan EURO format date/time */ else if (global_dateformat==DF_EURO && sscanf(value,"%d/%d/%d %d:%d:%d %[-+:A-Za-z0-9]",&d,&m,&Y,&H,&M,&S,tz)>=3) { int isdst = (strcmp(tz,tzdst)==0) ? 1 : 0; DATETIME dt = {Y,m,d,H,M,S,0,isdst}; /* use locale TZ if tz is omitted */ strncpy(dt.tz,tz,sizeof(dt.tz)); return mkdatetime(&dt); } /* @todo support European format date/time using some kind of global flag */ else if (strcmp(value,"INIT")==0) return 0; else if (strcmp(value, "NEVER")==0) return TS_NEVER; else if (strcmp(value, "NOW") == 0) return global_clock; else if (isdigit(value[0])) { /* timestamp format */ double t = atof(value); char *p=value; while (isdigit(*p) || *p=='.') p++; switch (*p) { case 's': case 'S': t *= SECOND; break; case 'm': case 'M': t *= MINUTE; break; case 'h': case 'H': t *= HOUR; break; case 'd': case 'D': t *= DAY; break; default: return TS_NEVER; break; } return (TIMESTAMP)(t+0.5); } else return TS_NEVER; }