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.

\$\endgroup\$
  • 1
    \$\begingroup\$ Related. \$\endgroup\$ – cat Dec 17 '15 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\$ – Martin Ender Dec 17 '15 at 17:28
  • \$\begingroup\$ Oh, that answers that... I was just about to post a Mathematica answer which uses a built-in. :/ \$\endgroup\$ – Martin Ender Dec 17 '15 at 17:28
  • \$\begingroup\$ @Martin Sorry about that ;). \$\endgroup\$ – geokavel Dec 17 '15 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\$ – Martin Ender Dec 17 '15 at 17:32
11
\$\begingroup\$

LabVIEW, 32 LabVIEW Primitives

\$\endgroup\$
  • \$\begingroup\$ That was quick. \$\endgroup\$ – Addison Crump Dec 17 '15 at 16:53
  • \$\begingroup\$ Can you assure me there are no calendar functions used here? \$\endgroup\$ – geokavel Dec 18 '15 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\$ – Eumel Dec 19 '15 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;
}
\$\endgroup\$
  • \$\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\$ – Eumel Dec 17 '15 at 21:41
  • \$\begingroup\$ This fails on certain test cases, e.g. 24/1. \$\endgroup\$ – LegionMammal978 Dec 17 '15 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\$ – DrewJordan Dec 18 '15 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="/")
\$\endgroup\$
  • \$\begingroup\$ This is the message I get when trying to run your program in R: pastebin.com/dPh1n64a \$\endgroup\$ – geokavel Dec 18 '15 at 17:10
  • \$\begingroup\$ Strange I'll recheck later \$\endgroup\$ – Tensibai Dec 18 '15 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\$ – geokavel Dec 18 '15 at 17:24
  • \$\begingroup\$ thanks for the feedback. I'm on road actually, I'll correct it \$\endgroup\$ – Tensibai Dec 18 '15 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\$ – plannapus Dec 30 '15 at 9:11
3
\$\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

\$\endgroup\$
  • 1
    \$\begingroup\$ You need to give me a way to input the date string, or make it a function. \$\endgroup\$ – geokavel Dec 17 '15 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\$ – Mego Dec 18 '15 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\$ – nickb Dec 18 '15 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\$ – Mego Dec 18 '15 at 15:44
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>

\$\endgroup\$
1
\$\begingroup\$

Non-competing answer - Bash + coreutils, 55

date -d1-$[(${1%/*}-1)%12+1]-1+$[${1#*/}-1]day +%-m/%-d

"Date parsing/formatting functions are still allowed though" - I assume this means the date utility is allowed.

Input is read from command line, e.g.:

$ ./rollovercal.sh 15/43
4/12
$ 

This is non-competing because the date command expands to something like this which is adding a number of days:

date -d1-3-1+42day +%-m/%-d
\$\endgroup\$
  • \$\begingroup\$ It's allowed as long as it isn't doing anything like date.add(875) to increment the date by 875 days. That's mostly what I was going after. \$\endgroup\$ – geokavel Dec 17 '15 at 18:06
  • \$\begingroup\$ @geokavel oh, I see. The fully expanded date command here is date -d1-3-1+42day +%-m/%-d, so its doing exactly that. I guess this is a non-competing answer then :( \$\endgroup\$ – Digital Trauma Dec 17 '15 at 18:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.