17
\$\begingroup\$

This is inspired by one of Downgoat's questions in Sandbox, where I suggested that he include April 31 as Pi day for people who use day/month format, only for him to inform me that there is no April 31!

Given a date string in month/day format that might be invalid, output the correct date using rollover. (First rollover the month, then rollover the day).

Examples:

"15/43" - This reads as the 43rd day of the 15th month. First, we roll over the month to the next year, so we end up with 3 (March). Now, since March only has 31 days, we rollover the extra days to April, so we output the actual date as "4/12" (April 12th).

"3/16" - This is a valid date (March 16th). Return it as is.

"12/64" - Ah, so many fond memories from December 64th... December has 31 days, January has 31 days, so what I really mean is "2/2" (February 2nd).

"19/99" - First, the 19 becomes a 7 (July). July has 31 days, August has 31 days, September has 30 days, so the output is "10/7" (October 7th).

"1/99999" - A year has 365 days. 99999 (mod 365) = 354. The 354 day of the year is "12/20".

"9999999/10" - Apparently, 9999999 (mod 12) = 3, so this is "3/10" (March 10th).

Criteria:

Input month is an integer> 0. Input day is an integer> 0. Year never needs to be specified, as such there are no leap years to deal with.

Update:

As I think it would overly simplify the challenge, calendar functions, such as those in the Java Calendar class, are banned. Date parsing/formatting functions are still allowed though.

asked Dec 17, 2015 at 16:38
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Related. \$\endgroup\$ Commented Dec 17, 2015 at 16:40
  • 1
    \$\begingroup\$ Another important test case would be one with enough days to roll over more than 8 years, such that answers which use built-ins have to pay attention to those built-ins using leap years. \$\endgroup\$ Commented Dec 17, 2015 at 17:28
  • \$\begingroup\$ Oh, that answers that... I was just about to post a Mathematica answer which uses a built-in. :/ \$\endgroup\$ Commented Dec 17, 2015 at 17:28
  • \$\begingroup\$ @Martin Sorry about that ;). \$\endgroup\$ Commented Dec 17, 2015 at 17:29
  • \$\begingroup\$ For reference, the Mathematica solution was still 90 bytes long (although that was massively dominated by the string processing). If you want to add such a test case nevertheless, 1/99999 should yield 12/19 I think. \$\endgroup\$ Commented Dec 17, 2015 at 17:32

5 Answers 5

11
\$\begingroup\$

LabVIEW, 32 LabVIEW Primitives

answered Dec 17, 2015 at 16:47
\$\endgroup\$
3
  • \$\begingroup\$ That was quick. \$\endgroup\$ Commented Dec 17, 2015 at 16:53
  • \$\begingroup\$ Can you assure me there are no calendar functions used here? \$\endgroup\$ Commented Dec 18, 2015 at 18:18
  • \$\begingroup\$ The good thing about LabVIEW is that its basically what it looks to be. First thing scans numbers from a string 2 modulos, the box is a switch case structure that gives out 28,30 or 31 and then it gets put together as a string again. \$\endgroup\$ Commented Dec 19, 2015 at 8:28
4
\$\begingroup\$

C#, (削除) 269 (削除ここまで) 223

string v(string n){var x=new[]{31,28,31,30,31,30,31,31,30,31,30,31};var s=n.Split('/');Func<string,int> p=int.Parse;var m=p(s[0]);var d=p(s[1]);m=m>=12?m%12:m;while(d>x[m]){d-=x[m];m=++m>=12?m%12:m;}return(m==0?1:m)+"/"+d;}

Edit: Fixed to work for cases like 24/1, 36/1, etc. and golfed a little. Thanks for the comments, there are several places I saved a bit!

Ungolfed:

string v(string n)
{
 var x = new [] { 31 ,28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };
 var s = n.Split('/');
 Func<string,int> p = int.Parse;
 var m = p(s[0]);
 var d = p(s[1]);
 m = m >= 12 ? m % 12 : m;
 while (d > x[m])
 {
 d -= x[m];
 m = ++m >= 12 ? m % 12 : m;
 }
 return (m==0?1:m) + "/" + d;
}
answered Dec 17, 2015 at 20:10
\$\endgroup\$
3
  • \$\begingroup\$ First of all: Welcome to the community! I would guess you could save some Bytes by assigning the dictionary in a loop or using a switch function (no C# pro here though). Also directly printing ´m + "/" + d´ might help a little. And last (this might or might not work) using char* instead of string in the arguments. \$\endgroup\$ Commented Dec 17, 2015 at 21:41
  • \$\begingroup\$ This fails on certain test cases, e.g. 24/1. \$\endgroup\$ Commented Dec 17, 2015 at 23:58
  • \$\begingroup\$ @Eumel thanks! Directly printing uses Console.Write which is more than return, and in C# I would use char[] as a replacement for string, but it's the same amount of chars, and makes splitting on the / more problematic. But, your note on the Dictionary did lead me to a way better version! \$\endgroup\$ Commented Dec 18, 2015 at 17:53
4
\$\begingroup\$

R, (削除) 208 (削除ここまで) 182 bytes

m=c(31,28,31,30,31,30,31,31,30,31,30,31)
e=scan(sep="/");n=(e[1]/12-1)*12;if(!n%%12)n=12;if(n<0)n=e[1];j=e[2];while((j<-j-m[n])>0){n=n+1;if(n>12)n=1};j=m[n]+j;cat(n,j,sep="/")

Get the month by dividing by 12, then loop, removing the number of days of the current month until you get a negative number., inverse last step and print.

On multiple lines (need to use a file and source it):

m=c(31,28,31,30,31,30,31,31,30,31,30,31)
e=scan(sep="/")
n=(e[1]/12-1)*12
if(!n%%12)n=12
if(n<0)n=e[1]
j=e[2]
while((j<-j-m[n])>0){n=n+1;if(n>12)n=1}
j=m[n]+j;cat(n,j,sep="/")
answered Dec 18, 2015 at 16:17
\$\endgroup\$
9
  • \$\begingroup\$ This is the message I get when trying to run your program in R: pastebin.com/dPh1n64a \$\endgroup\$ Commented Dec 18, 2015 at 17:10
  • \$\begingroup\$ Strange I'll recheck later \$\endgroup\$ Commented Dec 18, 2015 at 17:13
  • \$\begingroup\$ I also got this message. Your program seems to have problems with some months. Otherwise it's running. pastebin.com/g3BCUDi8 \$\endgroup\$ Commented Dec 18, 2015 at 17:24
  • \$\begingroup\$ thanks for the feedback. I'm on road actually, I'll correct it \$\endgroup\$ Commented Dec 18, 2015 at 17:27
  • 1
    \$\begingroup\$ @Tensibai yes you're right, my bad (i should have remembered that the error message says that it expects "a real"). \$\endgroup\$ Commented Dec 30, 2015 at 9:11
2
\$\begingroup\$

JavaScript (ES6), 106 bytes

s=>eval('q="030101001010";p=s.split`/`;for(d=i=p[1],m=p[0]-1;i--;d>n&&(m++,d-=n))n=31-q[m%=12];m+1+"/"+d')

Explanation

s=>
 eval(` // use eval to enable for loop without needing to write {} or return
 q="030101001010"; // q = array of 31 - days in each month
 p=s.split\`/\`; // p = array of [ month, day ]
 for(
 d=i=p[1], // d = day
 m=p[0]-1; // m = month - 1
 i--; // loop for each day, this is more iterations than needed but extra
 // iterations do not affect the result and it's the shortest way
 // to guarantee all months have been subtracted from d, it also
 // ensures the loop runs at least once to get m % 12
 d>n&&(m++,d-=n) // if too many days, subtract the month's days and increment month
 )
 n=31-q[m%=12]; // n = number of days in month, get m % 12
 m+1+"/"+d // return the result
 `)

Test

var solution = s=>eval('q="030101001010";p=s.split`/`;for(d=i=p[1],m=p[0]-1;i--;d>n&&(m++,d-=n))n=31-q[m%=12];m+1+"/"+d')
<input type="text" id="input" value="19/99" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

answered Dec 17, 2015 at 23:02
\$\endgroup\$
2
\$\begingroup\$

PHP>= 5.5, 181 bytes

list($m,$d)=explode("/",$argv[1]);$m%=12;$d%=365;$i=0;while($d>100)$d-=[31,28,31,30,31,30,31,31,30,31,30,31][$i++];$m+=$i;echo date_create_from_format("m/d","$m/$d")->format("n/j");

PHP almost supports rollover with date parsing and formatting instructions alone. For example:

echo date_create_from_format("m/d","12/64")->format("n/j"); // Output: 2/2

However, once either number gets bigger than 100, PHP rejects parsing it and returns an error (probably for some arbitrary reason). So, the theory with this answer is to get it back down to where PHP will parse it, then submit it to date_create_from_format().

Ungolfed:

list($month, $day) = explode("/", $argv[1]);
$month = $month % 12;
$day = $day % 365;
$i = 0;
$days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
while($day > 31) $day -= $days[$i++];
$month += $i;
echo DateTime::createFromFormat("m/d", $month . "/" . $day)->format("n/j");

Try it online

answered Dec 17, 2015 at 21:50
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You need to give me a way to input the date string, or make it a function. \$\endgroup\$ Commented Dec 17, 2015 at 21:55
  • \$\begingroup\$ GET parameters are not acceptable as an input method in PHP. You will need to either make this a function and pass the input as function parameters, or get input from $argv or STDIN. \$\endgroup\$ Commented Dec 18, 2015 at 8:35
  • \$\begingroup\$ @Mego Jeeze, give me some time to update my answer since the OP didn't state any requirements for input - it's simple enough to change $t to $argv[1] and now it reads from command line input. \$\endgroup\$ Commented Dec 18, 2015 at 15:13
  • \$\begingroup\$ The OP stating requirements for input is irrelevant; we have a list of default acceptable I/O methods (which I linked) so that challenge authors don't have to specify them on every challenge. \$\endgroup\$ Commented Dec 18, 2015 at 15:44

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.