parsing a date string in YYYYMMDDHH format using sscanf in c programing

Viewed 64

I have a date string in format YYYYMMDDHH that I am trying to split into year YYYY month MM day DD, and hour HH.

Below is my code in which I am attempting to do this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

int main()
{
    char datetime[10];
    char year;
    char month;
    char day;
    char hour;

    sprintf(datetime,"2022092300");
    sscanf(datetime,"%4s%2s%2s%2s",year,month,day,hour);
    printf("year is %s month is %s\n",year,month);

}

Unfortunately this code is not giving me a value for year and month and I doubt it would for day and hour. How do I tweak this code to get the desired results parsing the string into YYYYMMDDHH into YYYY, MM, DD, HH?

4 Answers

When reading strings, you must pass the address of a string as argument.

Also, strings must be terminated with a null (zero) character value. So if you expect a string to hold 10 characters, it must be 11 characters long to include the null terminator.

#include <stdio.h>

int main(void)
{
    char datetime[11];
    char year[5];
    char month[3];
    char day[3];
    char hour[3];

    sprintf(datetime,"2022092300");
    sscanf(datetime,"%4s%2s%2s%2s",year,month,day,hour);
    printf("year is %s month is %s\n",year,month);
}

EDIT

I meant to mention this, but forgot. You should turn your compiler warnings up to at least -Wall -Wextra -pedantic-errors if using GCC or Clang or /W3 if using MSVC. If you are using an IDE you will need to use Google to find how to adjust the compiler error/warning level for that IDE.

You need to use strings for each of the fields so your types are wrong, also you need to ensure space for the '\0' terminator. Introducing constants to ensure your types matches your format format string.

#include <stdio.h>

#define YEAR_LEN 4
#define MONTH_LEN 2
#define DAY_LEN 2
#define HOUR_LEN 2

#define str(s) str2(s)
#define str2(s) #s

int main() {
    char datetime[10+1];
    char year[YEAR_LEN+1];
    char month[MONTH_LEN+1];
    char day[DAY_LEN+1];
    char hour[HOUR_LEN+1];
    sprintf(datetime, "2022092300");
    sscanf(datetime, "%" str(YEAR_LEN) "s%" str(MONTH_LEN) "s%" str(DAY_LEN) "s%" str(HOUR_LEN) "s",year,month,day,hour);
    printf("year is %s month is %s\n",year,month);
}

Into datetime[ 10 ], the code is attempting to put the 11 bytes of the null terminated source string . This should be an obvious problem.
The other char variables are single bytes, not the string arrays you seem to want.

The family of scanf() functions lay at the heart of a large proportion of SO questions. It would be better, imo, to learn other techniques and avoid relying on scanf() & Co. as the Swiss Army Knife of input and/or string manipulation.

Here is an amended version copying substrings from the original string.

#include <stdio.h>

int main() {
    const char dt[] = "2022092321";

    // Use substrings directly, if that is all that is needed
    printf( "World - %.2s/%.2s/%.4s @ %.2shrs\n\n", dt+6, dt+4, dt+0, dt+8 );
    // Task may be accomplished, or...

    char yr[ 4 + 1 ]; // notation shows awareness of trailing '\0'
    char mn[ 2 + 1 ];
    char dy[ 2 + 1 ];
    char hr[ 2 + 1 ];

    // Use facilities of sprintf to copy sub-strings to null terminated buffers.
    // "compile time" compounding of offsets clearly shows intent.
    sprintf( yr, "%.4s", &dt[0] );
    sprintf( mn, "%.2s", &dt[0 + 4 ] );
    sprintf( dy, "%.2s", &dt[0 + 4 + 2 ] );
    sprintf( hr, "%.2s", &dt[0 + 4 + 2 + 2 ] );

    printf( "World - %s/%s/%s @ %shrs\n", dy, mn, yr, hr );
    printf( "  USA - %s/%s/%s @ %shrs\n", mn, dy, yr, hr );

    return 0;
}

Output

World - 23/09/2022 @ 21hrs

World - 23/09/2022 @ 21hrs
  USA - 09/23/2022 @ 21hrs

As other answers have explained, if you want to use formats like %4s and %2s to read strings, the corresponding argument must be an array of characters big enough to hold the string that is read. Single-character variables can't hold strings.

But it seems likely you'd rather have those year, month, day, and hour numbers as integers, not strings. You can do that like this:

int year;
int month;
int day;
int hour;

sscanf(datetime, "%4d%2d%2d%2d",&year, &month, &day, &hour);
printf("year is %d month is %d\n", year, month);

Also, there's a problem in your line

sprintf(datetime, "2022092300");

You've declared datetime as an array of 10 characters. But "2022092300" is a 10-character string, so you need eleven characters to store it, including the null terminator. (If you haven't heard the term "null terminator" yet, keep reading: it's bound to be described in the chapter in your textbook introducing strings.)

Also, sprintf is a strange way to copy strings; in this case you could just use

strcpy(datetime, "2022092300");

But you don't really need to copy a string at all here, either using strcpy or sprintf. A simpler way is just to initialize the array (in which case, the compiler will take care of making sure it's big enough):

char datetime[] = "2022092300";
Related