5

I am wanting to get yesterday's date into a char in the format: YYYYMMDD (with no slashes dots etc.).

I am using this code to get today's date:

time_t now;

struct tm  *ts;  
char yearchar[80]; 

now = time(NULL);  
ts = localtime(&now);

strftime(yearchar, sizeof(yearchar), "%Y%m%d", ts);

How would I adapt this code so that it is generating yesterday's date instead of today's?

Many Thanks.

sbi
  • 219,715
  • 46
  • 258
  • 445
baxterma
  • 811
  • 1
  • 11
  • 22
  • You might want to convert your time to a tm struct, so that you have control over hours, mins, etc. explicitly. Often we want yesterday's midnight rather than 24 hours ago, etc. (example: http://www.cplusplus.com/reference/clibrary/ctime/localtime/) – john personna Jan 20 '11 at 15:39
  • 1
    @sbi: virtual -1 He wants no punctuation, so the correct answer is `20110119` :-) – JeremyP Jan 20 '11 at 18:00

7 Answers7

10

The mktime() function will normalise the struct tm that you pass it (ie. it will convert out-of-range dates like 2020/2/0 into the in-range equivalent 2020/1/31) - so all you need to do is this:

time_t now;
struct tm  *ts;  
char yearchar[80]; 

now = time(NULL);
ts = localtime(&now);
ts->tm_mday--;
mktime(ts); /* Normalise ts */
strftime(yearchar, sizeof(yearchar), "%Y%m%d", ts);
caf
  • 233,326
  • 40
  • 323
  • 462
  • I'm sorry I had to downvote you but this is very wrong. If you do this on the 1st day of the month, instead of going back to the last day of the previous month it sets the day to 0th eg, 2020-02-01 becomes 2020-02-00 instead of 2020-01-31 – mfloris Mar 21 '20 at 15:21
  • 2
    @mfloris: That is not true, because as noted in the answer the `mktime()` function will normalise the `struct tm` that you pass it - it will change a `struct tm` that represents `2020-02-00` into one that represents `2020-01-31`. That is why there is the call to `mktime(ts)` before the `strftime()`. – caf Mar 22 '20 at 01:28
  • [Thsi ideone example](https://ideone.com/Zx22Gi) shows it in action. – caf Mar 22 '20 at 06:00
  • my bad, you're right, it works. If you edit the answer I can upvote it again (I suggest you include the variable declarations so that it can be copypasted into a main() and it will compile straight away) – mfloris Mar 23 '20 at 07:23
  • 1
    @walkman: No, unless your C library is buggy, it will finish as 31/12/2019. [See this example](https://ideone.com/IX6eK8) – caf Jun 16 '20 at 13:10
6

how about adding

now = now - (60 * 60 * 24)

Might fail in some VERY rare corner cases (e.g. during leapseconds) but should do what you want 99.999999% of the time.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
Tyler Eaves
  • 12,879
  • 1
  • 32
  • 39
  • 2
    This would have broken horribly on January 1, 1970, but I don't see any reason why it would today :) – Tim Post Jan 20 '11 at 15:29
  • 1
    The time() function returns the value of time in seconds since 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time. If an error occurs, time() returns the value (time_t)-1. – Tyler Eaves Jan 20 '11 at 15:30
  • 2
    In the C standard, `time()` just returns the time in an unspecified encoding - it's POSIX that restricts it to the encoding you describe. – caf Jan 21 '11 at 02:01
  • @dan04 UTC doesn't care about them. DST changes the time zone applied to UTC. – glglgl Nov 14 '18 at 11:54
2

Please try this code

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
 
int main(void)
{
    char yestDt[9];
    time_t now = time(NULL);
    now = now - (24*60*60);
    struct tm *t = localtime(&now);
    sprintf(yestDt,"%04d%02d%02d", t->tm_year+1900, t->tm_mday,t->tm_mon+1);
    printf("Target String: \"%s\"", yestDt);
    return 0;
}
User97693321
  • 3,336
  • 7
  • 45
  • 69
2

Simply subtracting one day's worth of seconds from time(NULL); should do. Change this line:

now = time(NULL);

to this:

now = time(NULL) - (24 * 60 * 60);
orlp
  • 112,504
  • 36
  • 218
  • 315
0

You're pretty close on. First of all, Tyler's solution will almost work -- you need to use (24*60*60*1000) since time(3) returns milliseconds. But have a look at that struct tm. It has fields for all the components of a date.

Update: Damn, my mistake -- time(3) does return seconds. I was thinking of another call. But have a look at the contents of struct tm anyway.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
0

You can manipulate the contents of the ts struct before passing it to strftime. The day of the month is contained in the tm_mday member. Basic procedure:

/**
 * If today is the 1st, subtract 1 from the month
 * and set the day to the last day of the previous month
 */
if (ts->tm_mday == 1)
{
  /**
   * If today is Jan 1st, subtract 1 from the year and set
   * the month to Dec.
   */
  if (ts->tm_mon == 0)
  {
    ts->tm_year--;
    ts->tm_mon = 11;
  }
  else
  {
    ts->tm_mon--;
  }

  /**
   * Figure out the last day of the previous month.
   */
  if (ts->tm_mon == 1)
  {
    /**
     * If the previous month is Feb, then we need to check 
     * for leap year.
     */
    if (ts->tm_year % 4 == 0 && ts->tm_year % 400 == 0)
      ts->tm_mday = 29;
    else
      ts->tm_mday = 28;
  }
  else
  {
    /**
     * It's either the 30th or the 31st
     */
    switch(ts->tm_mon)
    {
       case 0: case 2: case 4: case 6: case 7: case 9: case 11:
         ts->tm_mday = 31;
         break;

       default:
         ts->tm_mday = 30;
    }
  }
}
else
{
  ts->tm_mday--;
}

Edit: Yes, days of the month are numbered from 1 whereas everything else (seconds, minutes, hours, weekdays, and days of the year) are numbered from 0.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 2
    This is unnecessary, because `mktime()` will normalise a `struct tm` for you. – caf Jan 21 '11 at 02:02
0
time_t now;
int day;

struct tm  *ts;  
char yearchar[80]; 

now = time(NULL);  
ts = localtime(&now);
day = ts->tm_mday;

now = now + 10 - 24 * 60 * 60;
ts = localtime(&now);
if (day == ts->tm_mday)
{
  now = now - 24 * 60 * 60;
  ts = localtime(&now);
}

strftime(yearchar, sizeof(yearchar), "%Y%m%d", ts);

Will work with leap seconds too.