C: Output "tomorrow's date"

4

I'm a code golf novice, but I'm eager to give it a go.

My challenge is: Write the shortest program in C which takes in a date D as input and outputs the date D + 1 day

Rules:

  • program must compile only with gcc progname.c -o progname So no compiler/makefile tricks (if there are any) - compiler warnings don't matter
  • The input and output format must be day/month/year zero padding of single digit values does not matter: 1/3/1998 is equal to 01/03/1998
  • It doesn't matter how you give the the program it's input date, it can be a program argument, scanf whatever. Output must be to stdout however
  • February has 29 days when the year is divisible by 4
  • No date validation necessary, i.e. assume the input is always a valid date.
  • any integer year should be supported, i.e. INT_MIN -> INT_MAX

Shortest code length wins, and there are extra points for extra bastardised C.

My solution uses 126 123* 121 characters

Good luck

*s="%i/%i/%i",m,d;main(y){scanf(s,&d,&m,&y);printf(s,d,m,(d=d%((m>7^m&1)+27+(m-2?3:y%4?1:2))+1)-1?y:(m=m%12+1)-1?y:y+1);}

*because of an idea Gareth's code gave me

Griffin

Posted 2011-08-09T18:57:45.353

Reputation: 4 349

3February doesn't have 29 days when the year is divisible by 100 unless it is also divisible by 400. Or is your last rule there to simplify matters slightly? – Gareth – 2011-08-09T19:16:50.267

@Gareth I think so. – FUZxxl – 2011-08-09T19:20:14.703

@Gareth, yes it's a simplification. – Griffin – 2011-08-09T19:20:33.937

3Code golf is usually open for all languages, except if the problem can only be solved in one language. Please lift the restriction on using C only. – FUZxxl – 2011-08-09T19:21:12.050

@FUZxxl "Usually"... Not this time :) – Griffin – 2011-08-09T19:26:13.773

@Griffin Would you mind reading this?

– FUZxxl – 2011-08-09T19:49:05.150

@FUZxxl, I read it but I don't agree, if it's any language, then really it's to who knows the least verbose language for the problem. This way, everyone who wants to play, is on a level playing field, it's also a test of how much you can push the given language and the restraint should force more creativity. Anyway, as the code-golf tag states: "Code-golf is a competition to solve a particular problem in the fewest bytes of source code." - Doing it in C is part of the problem. No one is forcing you to play though :) – Griffin – 2011-08-09T19:58:31.393

To whomever voted me down, care to explain it? You either take part in the challenge or you don't. What possible objective reason was there for the down-vote? – Griffin – 2011-08-09T21:06:01.467

@Griffin The downvoter probably don't likes the idea of having a C-only competition. – FUZxxl – 2011-08-09T21:13:50.927

@FUZxxl, so what, I should be down-voted? Or should they just not take part instead? What a joke, thought this site was for a bit of fun. – Griffin – 2011-08-09T21:17:35.507

@Griffin I did not vote down. I accept the conditions you give, but suggest changes. I just want to explain what reasoning (s)he has. – FUZxxl – 2011-08-09T21:18:54.570

Further clarification needed: a) Should the input get checked for validity, b) what is the year range to handle (e.g should BC years get handled)? – Harry K. – 2011-08-09T21:49:34.143

@Harry, I've added that info, thanks for catching that. – Griffin – 2011-08-09T21:55:08.767

I downvoted later, but not for the language restriction, but for the idea of leap-years. @FUZxxl: You can't explain the reasons somebody else had, if you don't know them. – user unknown – 2011-08-09T23:05:33.487

On a 2nd thought, the problem doesn't make sense now! For example, how will the program respond on an input like this: -300/20000/-32768 – Harry K. – 2011-08-09T23:10:08.660

@Harry, That's not a valid date format, the range I have was for years. days can only be from 1 to 30 and months from 1-12, clearly there is no restriction on number of years - Just saw my edit mistake, sorry harry, I've fixed it now. – Griffin – 2011-08-09T23:11:49.420

@Griffin: Still, the best way I know to handle such tasks is to convert first a Gregorian date to a Julian Day Number, but there are several issues to consider for really early years, which I really doubt they fit in just 126 chars (before Gregorian year 400 for example) . – Harry K. – 2011-08-09T23:29:07.943

@Herry, man its just a simple, if you go into all of the intricacies of dates, you'll never finish defining the challenge. If you reach the last day of the month, you go to the next month, same with last day of the year, you go to the next year. Take into account my simplified leap year and thats it. – Griffin – 2011-08-09T23:41:52.453

@Griffin: Nah, I think I'll skip this one altogether, it's too (over)simplified and tailored for my taste after all. But no down-votes from me ;) Good luck to all who'll participate though! – Harry K. – 2011-08-09T23:48:47.740

i think more efficient count bite not characters. – None – 2014-07-07T12:59:21.333

@Harry, sorry to hear it doesn't interest you enough, but it's pretty hard to get it down to so little characters. – Griffin – 2011-08-11T20:41:32.317

You can still have the best C-language entry in a challenge that is open to other languages. I don't see the purpose of restricting it. – recursive – 2011-08-19T21:35:55.527

Answers

3

Okay, it's been a while since I wrote any C but I'll give it a go:

m,y,*q="%d/%d/%d";
main(d){
scanf(q,&d,&m,&y);
++d>30+(m+(m>7))%2-(m^2?0:2-!(y%4))?(m+=d=1)>12?y+=m=1:0:0;
printf(q,d,m,y);}

120 characters.
With a bit of formatting(not that it makes it any more readable any more...):

m,y,*q="%d/%d/%d";
main(d)
{
    scanf(q,&d,&m,&y);
    ++d>30+(m+(m>7))%2-(m^2?0:2-!(y%4))?(m+=d=1)>12?y+=m=1:0:0;
    printf(q,d,m,y);
}

The compiler throws out warnings like nobody's business, but it works.

I'm not sure I can get it any smaller than this now without stealing a couple of tricks from Griffin. With those tricks I can get to 116 characters:

m,y,*q="%d/%d/%d";
main(d){
scanf(q,&d,&m,&y);
printf(q,d,m,++d>30+(m>7^m&1)-(m^2?0:2-!(y%4))?(m+=d=1)>12?y+=m=1:y:y);}

Gareth

Posted 2011-08-09T18:57:45.353

Reputation: 11 678

Never say never - see my newly added answer. – ugoren – 2012-03-04T08:00:26.650

Looks good mate, I reckon you can replace those ifs for ternary operators, also there's some repetition there that you can take out. – Griffin – 2011-08-11T21:18:46.720

I'm not entirely sure how I'd use the ternary operator in this case. I've got no if else blocks. – Gareth – 2011-08-11T22:03:48.110

You can just put a 0 in the else part: if(x)b; becomes x?b:0; you save one character, might take some refactoring though – Griffin – 2011-08-11T22:50:57.153

@Griffin 125 characters. Do I get a prize? ;-) – Gareth – 2011-08-11T23:21:52.277

That's excellent! You get a upvote from me. Though you've given me an idea that got my code down to 123 characters. I'll post it up since I've stolen your idea of making the vars global so as to not define a type for them. – Griffin – 2011-08-11T23:41:34.687

I'm down to 123 now, and I think I've hit my limit for the night. Time for bed and nightmares about question marks, semicolons and braces. :-) – Gareth – 2011-08-11T23:45:19.627

Steal as many tricks as possible. 116 is amazing. – Griffin – 2011-08-12T12:36:41.157

Seeing as my I keep getting voted down for this question, I'm accepting your answer. I don't see 116 being beaten anyway. – Griffin – 2011-08-13T18:08:03.057

2

C, 112 chars

Many months late, but I just saw it and decided to improve it.
The leading * isn't needed for 32bit platforms (and some 64bit platforms), so it can perhaps be removed.

*s="%d/%d/%d";
main(y,m,d){
    scanf(s,&d,&m,&y);
    d++>29+(m-2?m+m/8&1:!(y%4)-2)?d=m++<12||(y+=m=1):0;
    printf(s,d,m,y);
}

Lots of similarity to Gareth's solution, but honestly - I didn't look.
The only thing I did borrow was saving the format string in a variable (which is kind of obvious, but I missed it).

I do fix a problem with Gareth's solution - it relies on the evaluation order of printf parameters.

ugoren

Posted 2011-08-09T18:57:45.353

Reputation: 16 527

1

C - 293

#define w(x) while(*(i++)!='/');x=atoi(i);
main(){char x[99];scanf("%s",x);f(x);}
f(char* i){
int a=atoi(i),b,c,m[]={0,1,0,1,0,1,0,1,1,0,1,0,1};
w(b);w(c);
if(b==2)if((a==28&&c%4)||a==29){a=1;b=3;}else a++;else if(a-m[b]-30==0)if(b==12){a=b=1;c++;}else{a=1;b++;}else a++;
printf("%d/%d/%d",a,b,c);}

I've never really tried to golf C (and I am by no means an expert in C), but I feel this is pretty good. Basically it goes like this: get input from scanf, convert days, shift pointer, convert months, shift pointer, convert years (latter two have a #define to help), do logic with calendar logic. year%4 was a cool trick, and I have a month hash table indicating if the month is 30 or 31 days (kinda big to declare, but I think it was worth it). Finally, print. I'm sure there is a neat way to refactor using ternary (?:), but again, I'm no expert.

EDIT: fixed some typos.

matt

Posted 2011-08-09T18:57:45.353

Reputation: 29

Brilliant, someone is having a go. Good start but your program does not work correctly. If you input any date with month != 1, your code outputs day+1/1/year e.g. input: 1/12/1999 -> output: 2/1/1999, input: 24/2/1999 -> output: 25/1/1999. I suspect you maybe have a couple of typos - also remove the #include<stdio.h> you can printf and scanf without it, you'll just get compiler warnings :) – Griffin – 2011-08-11T18:13:54.653

Oh whoops, the error in my program is because I had the mindset DD/MM/YYYY and then switched to MM/DD/YYYY halfway through and mixed it all up. I'm interested in seeing your solution. – matt – 2011-08-11T19:52:10.177

Hmmm, still not working: 23/06/20101 -> 1/7/20101 – Griffin – 2011-08-11T20:12:24.710

Ok try some test cases now. – matt – 2011-08-11T20:19:41.423

Looks good to me :) try and chop some characters off now. Try and get a few of those ternary operators in, also consider if taking input via scanf using the same format you printf in is better or worse than parsing the input with a macro. – Griffin – 2011-08-11T20:46:23.450

you can see my code now if you want ideas. – Griffin – 2011-08-11T23:45:22.217

Ah, very good stuff. C is much more golfable than I anticipated. – matt – 2011-08-12T12:20:50.787

0

C (in a way), 97 71

I will lose fifty rep for this but it was necessary.

The actual rule violation is that it doesn't quite do INT_MIN..INT_MAX; the range instead seems to be 0..1410065407 (on 64-bit Ubuntu 11... I'm saying nothing about portability :P).

main(){system("read a;date -d@$((`date -d$a +%s`+86400)) +%m/%d/%Y");}

(old version:)

d,e[9];main(){sprintf(e,"date -d@$((`date -d%s +%%s`+86400)) +%%m/%%d/%%Y",gets(&d))&system(e);}

marinus

Posted 2011-08-09T18:57:45.353

Reputation: 30 224

I think this solution will not meet the spec if the given date is 28/02/1900. The correct (real world) answer would be 01/03/1900 but the spec calls for the answer to be 29/02/1900. (And I don't see why you should lose any rep for this answer) – Gareth – 2012-03-04T12:54:55.013

0

106 100 characters

Another entry that breaks the year rule by supporting only the years 1 to 9999, and also implements correct leap year handling instead of following requirements. The code simply uses POSIX libraries while abusing the type system:

t[9],b[9],*f="%d/%m/%Y";main(){gets(b);strptime(b,f,t);t[3]++;mktime(t);strftime(b,99,f,t);puts(b);}

han

Posted 2011-08-09T18:57:45.353

Reputation: 1 226

You could save 7 characters by using gets instead of read and moving the gets call into strptime. – marinus – 2012-03-04T13:51:31.110

@marinus: Thanks, I had completely forgotten gets. I didn't move the call inside strptime, since treating the implicit int return value as a pointer is likely to crash on 64-bit systems. – han – 2012-03-04T17:00:38.673