简体   繁体   中英

parsing date and time from a string in C

I am trying to parse the date and time from the following response I get from the modem. The response is present in the BG96_TmpBuffer buffer.

+CCLK: "21/03/29,16:17:13+52"

 OK

I have developed the following function for it.

uint8_t BG96_parseNetworkTime(uint8_t *year_out, uint8_t *month_out, uint8_t *day_out, uint8_t *hour_out,
                                uint8_t *min_out, uint8_t *sec_out, uint8_t *timezone_out){
        //Extract the date and time
        printf("Parsing: %s\r\n", BG96_TmpBuffer);
        
        uint8_t num = sscanf((char*)BG96_TmpBuffer,
        "%hhu %hhu %hhu %hhu %hhu %hhu %hhu",
        *year_out,
        *month_out,
        *day_out,
        *hour_out,
        *min_out,
        *sec_out,
        *timezone_out);
        
        //Check if it was successful
        if(num > 0){
            printf("Date: %u/%u/%hu\r\n", *day_out, *month_out, *year_out);
            printf("Time: %u:%u:%u\r\n", *hour_out, *min_out, *sec_out);
            return true;
        }
        
    return false;                           
}

When I tested the function, it does not work. sscanf always returns 0. I did the following to test the code.

        uint8_t year = 0, month = 0, day = 0, hour = 0, min = 0, secs = 0, timezone = 0;
        bool status = BG96_parseNetworkTime(&year, &month, &day, &hour, &min, &secs, &timezone);

Could someone advise on why the above is not working and what I am doing wrong?

Edit-1: On entering the function, the BG96_TmpBuffer is printed as shown below.

Parsing:
+CCLK: "21/03/30,10:48:30+52"

OK

Edit-2: Adding the whole API.

/****************************************************************
 * Function Name    : BG96_synchronizeTime
 * Description      : Set the RTC time via BG96
 * Returns          : 0 on in progress, 1 on OK, -1 on error
 * Params           None.
 ****************************************************************/
int8_t BG96_synchronizeTime(void){
    enum BG96_syncTimes_t {GET_CCLK, UPDATE_CCLK, REBOOT, REBOOT_WAIT, GET_TIME, SET_TIME, OK, ERROR};
    static enum BG96_syncTimes_t state = GET_CCLK;
    static bool timeSync = false;
    static int8_t syncStatus = false;
    
    syncStatus = false; //this will be updated later
    
    if(timeSync){//Already synchronized
        printf("[BG96 CLK], ### Already synchronized ###\r\n");
        return true;
    }
    
    switch(state){
        case GET_CCLK:{
            //Get the current clock time
            int8_t status = BG96_sendCommand((char*)"AT+CCLK?\r", strlen("AT+CCLK?\r"), sBG96_OK, NULL, NULL, NULL, 1000, 1);
            if(status == false) {
                //Operation in progress
            } else if(status == -1) {
                state = ERROR;
            } else if(status == true ){
                state = UPDATE_CCLK;        //valid ans1
            } else {
                //Should never arrive here
            }
        }
        break;
        
        case UPDATE_CCLK:{
            //Update the clock time to GMT via NITZ
            int8_t status = BG96_sendCommand((char*)"AT+CTZU=3\r", strlen("AT+CTZU=1\r"), sBG96_OK, NULL, NULL, NULL, 1000, 1);
            if(status == false) {
                //Operation in progress
            } else if(status == -1) {
                state = ERROR;
            } else if(status == true ){
                state = REBOOT;     //valid ans1
            } else {
                //Should never arrive here
            }
        }
        break;
        
        case REBOOT:{
            //Reset the ME, all the above will take effect after this reset
            int8_t status = BG96_sendCommand((char*)"AT+CFUN=1,1\r", strlen("AT+CFUN=1,1\r"), sBG96_OK, NULL, NULL, NULL, 5000, 1);
            if(status == false) {
                //Operation in progress
            } else if(status == -1) {
                 state = ERROR; //no answer or error
            } else if(status == true) {
                 _cfun_waitComplete = false;
                 EventTimerCreate(10000,    1,  BG96_cfunWaitCompleteCb);
                 state = REBOOT_WAIT; //valid ans1
            } else {
                  // Should never arrive here
            }
        }
        break;
        
        case REBOOT_WAIT:{
            //Wait for the ME to scan the bands
            if(_cfun_waitComplete == true) {
                state = GET_TIME;
            } else {
                //Wait here
            }
        }
        break;
        
        case GET_TIME:{
            //Get the current clock time
            int8_t status = BG96_sendCommand((char*)"AT+CCLK?\r", strlen("AT+CCLK?\r"), "+", NULL, NULL, NULL, 1000, 1);
            if(status == false) {
                //Operation in progress
            } else if(status == -1) {
                state = ERROR;
            } else if(status == true ){
                state = SET_TIME;       //valid ans1
            } else {
                //Should never arrive here
            }
        }
        break;
        
        case SET_TIME:{
            uint8_t year = 0, month = 0, day = 0, hour = 0, min = 0, secs = 0, timezone = 0;
            bool status = BG96_parseNetworkTime(&year, &month, &day, &hour, &min, &secs, &timezone);
            state = OK;
        }
        break;
        
        case OK:{
            BG96_resetTmpRxBuffer();
            state = GET_CCLK;
            timeSync = true;
            syncStatus = true;
        }
        break;
        
        case ERROR:{
            BG96_resetTmpRxBuffer();
            state = GET_CCLK;
            timeSync = false;
            syncStatus = -1;
        }
        break;
        
        default:
        break;
    }
    
    return syncStatus;
}

As stated in the comments by kaylum you have to match the format of the input string:

uint8_t BG96_parseNetworkTime(uint8_t *year_out, uint8_t *month_out, uint8_t *day_out, uint8_t *hour_out,
                                uint8_t *min_out, uint8_t *sec_out, uint8_t *timezone_out){
        //Extract the date and time // "21/03/29,16:17:13+52"
        printf("Parsing: %s\r\n", BG96_TmpBuffer);
        
        uint8_t num = sscanf((char*)BG96_TmpBuffer,
        "%hhu/%hhu/%hhu,%hhu:%hhu:%hhu+%hhu",
        year_out,
        month_out,
        day_out,
        hour_out,
        min_out,
        sec_out,
        timezone_out);
        
        //Check if it was successful
        if(num == 7){
            printf("Date: %u/%u/%hu\r\n", *day_out, *month_out, *year_out);
            printf("Time: %u:%u:%u\r\n", *hour_out, *min_out, *sec_out);
            return true;
        }
        
    return false;                           
}

NB: Note that the response could be a different format since Europeans would have the day and month reversed, if you are sure that your modem would be located it is fine. But honestly you would be better off with a long value of timestamp in seconds since epoch (and also for parsing).

I strongly suggest you use the strptime function, which is provided by the standard C library, for this exact purpose, unless you want to roll your own for educational purpose. Its prototype is char *strptime(const char *s, const char *format, struct tm *tm);

Take a look at its man page for more information. You can find it for example there http://manpagesfr.free.fr/man/man3/strptime.3.html

Below is a working function/solution.

uint8_t BG96_parseNetworkTime(int *year_out, int *month_out, int *day_out, int *hour_out,
                            int *min_out, int *sec_out, int *timezone_out){
    
    // Extract the date and time // "21/03/29,16:17:13+52"
    printf("date & time: %s\r\n", BG96_TmpBuffer);
    
    // Search first occurrence of "
    char *ptr = strstr((char*)BG96_TmpBuffer, "\"");
    if(ptr == NULL){
        printf("Error parsing the date & time\r\n");
        return false;
    }
    
    // Skip the " for parsing
    ptr++;
    printf("parsing: %s\r\n", ptr);
    uint8_t num = sscanf(ptr, "%d/%d/%d,%d:%d:%d+%d",
    year_out,
    month_out,
    day_out,
    hour_out,
    min_out,
    sec_out,
    timezone_out);
    
    // Convert year to 21st century
    *year_out = *year_out + 2000;
    
    //Check if it was successful
    if(num == 7){
        printf("Date: %d/%d/%d\r\n", *day_out, *month_out, *year_out);
        printf("Time: %d:%d:%d\r\n", *hour_out, *min_out, *sec_out);
        printf("Timezone: %d\r\n", *timezone_out);
        return true;
    }
    
    return false;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM