-2

I need to convert this date : 2019-08-22 16:16:08 to this specific form: aammjjhhmmss (aa for 'année' or year; jj for 'jour' or day).

I'm working with C language. This is my code. I don't find it good because I need to call the function three times to get what I want:

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

void removeChar(char *s, int c){ 

    int j;
    int n = strlen(s); 
    for (int i=j=0; i<n; i++) 
       if (s[i] != c) 
          s[j++] = s[i]; 

    s[j] = '\0'; 
} 

int main() 
{ 
   char s[] = "2019-08-22 16:16:08"; 
   removeChar(s, '-'); 
   printf("test 1 without '-' %s \n",s); 
   removeChar(s, ':');
   printf("test 2 without ':' %s \n",s); 
   removeChar(s, ' ');
   printf("test 3 without ' ' %s \n",s); 
   return 0; 
} 

Results :

test 1 without '-' 20190822 16:16:08                                                                                                        
test 2 without ':' 20190822 161608                                                                                                          
test 3 without ' ' 20190822161608

And the format is: YYMMDDHHMMSS.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Alma
  • 31
  • 1
  • 10
  • 1
    Have you tried to write any code at all? What was it? Should the result you want people to write for you take the form of a function, and if so taking and returning what? Or should it be a self-contained program that takes input from stdin, or a user-specified file, or a hard-coded filename in a hard-coded directory, or, etc... – underscore_d Aug 22 '19 at 14:45
  • Create a string buffer with the necessary size (do not forget the trailing NUL character), then copy the desired characters one by one from source string to the string buffer. Seems pretty straightforward. What problems did you encounter? – Ruud Helderman Aug 22 '19 at 14:48
  • Your result shows YYYYMMDD (4 digits for the year); your request shows AA or YY (2 digits) for the year. Which is correct — because if you have 4 input and 4 output digits life is simpler than if you have 4 input and 2 output. You could write a single copy function which only copies digits, for example. – Jonathan Leffler Aug 22 '19 at 15:11

1 Answers1

2

You can treat this as an exercise in date/time manipulation (hard), or as an exercise in string manipulation (easier).

If you want to do date/time manipulation, then in a POSIX environment, strptime() and strftime() are your friends. (NB: strftime() is standard C; strptime() is part of POSIX.)

Your code treats it as an exercise in string manipulation. Your result shows YYYYMMDD (4 digits for the year); your request shows AA or YY (2 digits) for the year. I wonder which is correct? If you have 4 input and 4 output digits life is simpler than if you have 4 input and 2 output. Assuming that it should be 4 digits in, 4 digits out, then all you need to do is copy the digits.

There's a subtle bug in your code:

int j;
int n = strlen(s); 
for (int i=j=0; i<n; i++) 
   if (s[i] != c) 
      s[j++] = s[i]; 

s[j] = '\0'; 

You have two different variables j, and the j used in the last assignment is uninitialized. If you use GCC, you could use -Wshadow as a compilation option to get warnings about such variable shadowing. You should use:

int j = 0;
int n = strlen(s); 
for (int i = 0; i < n; i++) 
{
   if (s[i] != c) 
      s[j++] = s[i];
}
s[j] = '\0'; 

However, you legitimately worry about calling your function three times. You could write a variant that only needs to be called once, because it keeps only the digits in the input:

#include <ctype.h>

void keepDigits(char *s)
{
    int j = 0;
    int n = strlen(s);
    for (int i = 0; i < n; i++)
    {
        if (isdigit((unsigned char)s[i]))
            s[j++] = s[i];
    }
    s[j] = '\0';
}

Indeed, you could also avoid pre-scanning the string with strlen() by using:

void keepDigits(char *s)
{
    int j = 0;
    for (int i = 0; s[i] != '\0'; i++)
    {
        if (isdigit((unsigned char)s[i]))
            s[j++] = s[i];
    }
    s[j] = '\0';
}

Now you scan the string once instead of 6 times (3 calls to your 'remove' function which scans the entire string, and each of which calls strlen() which also scans the entire string).

Test code:

int main(void) 
{ 
   char s[] = "2019-08-22 16:16:08"; 
   printf("Before: [%s]\n", s);
   keepDigits(s); 
   printf("After:  [%s]\n", s);
   return 0; 
}

Output:

Before: [2019-08-22 16:16:08]
After:  [20190822161608]

If you only want 2 digits for the year, then you could use:

int main(void) 
{ 
   char s[] = "2019-08-22 16:16:08"; 
   char *p = &s[2];
   printf("Before: [%s]\n", p);
   keepDigits(p); 
   printf("After:  [%s]\n", p);
   return 0; 
}

Output:

Before: [19-08-22 16:16:08]
After:  [190822161608]

Note, however, that the leading two digits are still in s here.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • BIG thanks it works and you take time to explain what you did, again thank you :) – Alma Aug 22 '19 at 16:00
  • please could you explain why did you convert the isdigit parameter to unsigned char ? – Alma Sep 04 '19 at 09:57
  • The `isdigit()` function, and all the other `isXXXXX()` functions in [``](http://port70.net/~nsz/c/c11/n1570.html#7.4), expect an `int` argument — _In all cases the argument is an `int`, the value of which shall be representable as an `unsigned char` or shall equal the value of the macro `EOF`. If the argument has any other value, the behavior is undefined._ If your plain `char` type is signed (that's normally the case on x86-type machines), then passing a `char` with the sign bit set passes a value out of range. The `unsigned char` cast ensure the correct value is passed. – Jonathan Leffler Sep 04 '19 at 17:34