Legalize Reversed Date

17

Input:

A Date (containing dd, MM and yyyy). A date-object, or three separate integers are also valid as input.

Output:

Each part (dd, MM and yyyy) individually reverted and than rounded to the nearest valid date.

For example (in the format dd-MM-yyyy):
21-10-2016 becomes 12-01-6102

Challenge rules:

  • Only dd, MM, yyyy is valid, but the order and which separate-symbols you use is your own choice.
    So these are some valid format examples: dd-MM-yyyy; MM/dd/yyyy; yyyy MM dd; ddMMyyyy, etc.
    And these are some invalid format examples: dd MMM yyyy; dd-MM-'yy; etc.
  • You can also choose to just input a Date-object if your language supports it or three separate integer parameters, instead of the string representing a date.
  • Please state which date-format you've used! (And the input and output must be in the same format.) It is also allowed to output a Date-object, as long as it can handle all test cases and the challenge rule below.
  • The Julian to Gregorian Calendar transition is ignored for this challenge. So 1582 is just a valid reversed year for 2851.
    See Challenge info / tips for all valid years, months and days.
  • Since you cannot have February as reversed of any other month, you don't have to worry about leap years.

All reversed years, months and days:

  • The year can always be reversed without a problem, reaching from 0001 (reversed of 1000) to 9999 (remains 9999). (So 0000 isn't a valid input, and there are also no test cases for it.)
  • The only months you'll have reversed are: January (reversed from October / 10); October (reversed from January / 01); November (remains November / 11); and December (reversed from every other month / 02-09, 12).
  • The only days you'll have reversed are: 01 (reversed from 10), 02 (reversed from 20), 03 (reversed from 30), 10 (reversed from 01), 11 (remains 11), 12 (reversed from 21), 13 (reversed from 31), 20 (reversed from 02), 21 (reversed from 12), 22 (remains 22), 30 (reversed from 03 or the same as 31 for November!), 31 (reversed from 04-09 / 13-19 / 23-29).

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return statements/output, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if necessary.

Test cases (dd-MM-yyyy as format):

21-07-2016   ->   12-12-6102
12-11-1991   ->   21-11-1991
01-01-2000   ->   10-10-0002
27-08-1875   ->   31-12-5781
18-12-2010   ->   31-12-0102
13-01-1981   ->   31-10-1891
04-11-1671   ->   30-11-1761  // Semi-tricky case, since November has 30 days
28-11-2036   ->   30-11-6302  // Semi-tricky case, since November has 30 days
14-06-1855   ->   31-12-5581
30-10-9999   ->   03-01-9999
01-01-2851   ->   10-10-1582

Kevin Cruijssen

Posted 2016-07-27T11:17:39.023

Reputation: 67 575

@LegionMammal978 No, 21-07-2016 is reverted 12-70-6102 which is rounded to 12-12-6102. Not sure how you get the result ##-10-6107.. – Kevin Cruijssen – 2016-07-27T11:46:50.837

@KevinCruijssen Okay, I thought it was that the month 70 wrapped around, with the year incrementing. – LegionMammal978 – 2016-07-27T11:48:24.470

Is 10-10-2 valid output in the third case? – Luis Mendo – 2016-07-27T12:04:02.120

@LuisMendo Yeah sure. I've seen other people do it as well. The challenge is more about correctly reversing and rounding the dates than the in- or output format. – Kevin Cruijssen – 2016-07-27T18:23:47.843

Would it be acceptable to take three strings, and expect leading zeros? – None – 2016-07-27T22:35:55.503

Answers

3

Convex, 23 bytes

Byte count assumes CP-1252 encoding.

qS/Wf%_1=:=31^sCs¶.e<S*

I/O format is dd mm yyyy.

Try it online!

This is a direct port of my CJam answer. Convex is heavily based on CJam, and therefore the only difference is the use of Convex's operator which wraps the top two stack elements in a list, saving a byte over [...].

Martin Ender

Posted 2016-07-27T11:17:39.023

Reputation: 184 808

8

CJam, 24 bytes

qS/Wf%[_1=:=31^sCs].e<S*

I/O format is dd mm yyyy.

Try it online!

Same byte count, I/O format mm dd yyyy:

qS/Wf%_0=:=1231^s2/.e<S*

Try it online!

Explanation

qS/     e# Read input, split around spaces.
Wf%     e# Reverse each component.
[       e# Set marker for new list.
  _1=   e#   Duplicate reversed strings, extract reversed month.
  :=    e#   Check for equality of the characters. This gives 1 for
        e#   November (11) and 0 for everything else.
  31^   e#   XOR the result with 31, giving 30 for November and 31
        e#   for everything else.
  s     e#   Convert the result to a string, "30"/"31".
  Cs    e#   Push 12, convert to string, "12".
]       e# Wrap "30"/"31" and "12" in a list.
.e<     e# Element-wise minimum. This clamps the day and month to their
        e# respective maxima.
S*      e# Join the result with spaces.

The other version works similarly, except that we start from the integer 1230 or 1231 before converting it to ["12" "30"] or ["12" "31"].

Martin Ender

Posted 2016-07-27T11:17:39.023

Reputation: 184 808

2Languages with date built-in... – Leaky Nun – 2016-07-27T12:12:13.613

1@LeakyNun This doesn't use a date built-in and I don't see how it would help. – Martin Ender – 2016-07-27T12:12:37.497

Then how do you know that there are 30 days in November? – Leaky Nun – 2016-07-27T12:13:14.817

2@LeakyNun I'll add an explanation later, but 1= gets the reversed month, := checks whether its digits are equal and ^ xors the result into 31, giving 30 for month 11 and 31 for everything else. – Martin Ender – 2016-07-27T12:14:07.467

Oh, I didn't read the specs... – Leaky Nun – 2016-07-27T12:14:48.007

5

Pyth, 55 53 46 43 41 bytes

APJ_Mczd=HhS,12sH=GhS,sGC@."❤❤ó»î"H%"%02d %02d %s"[GHeJ
APJ_Mczd=hS,12sH=hS,sGC@."❤❤ó»î"H%"%02d %02d %s"[GHeJ
APJ_Mcz\-%"%02d %02d %s"[hS,sGx31q11sHhS,12sHeJ
APJ_Mczdjd[>2+\0hS,sGx31q11sH>2+\0hS,12sHeJ
APJ_Mczdjd.[L\02[`hS,sGx31q11sH`hS,12sHeJ

where ❤❤ were two unprintables, respectively U+001C and U+001F.

Test suite.

Leaky Nun

Posted 2016-07-27T11:17:39.023

Reputation: 45 011

2

Dyalog APL, 32 33 bytes

⍕¨{⍵-3↑31 11≡2↑⍵}31 12 1E4⌊⍎∊⍕⌽¨⎕

I/O is list of three strings ('dd' 'mm' 'yyyy').

TryAPL, but note that (prompt for input) has been replaced with and the entire line enclosed in {...} to enable online testing, and (execute expression) has been replaced with 2⊃⎕VFI (verify and fix input) because execution of arbitrary code is blocked.

Adám

Posted 2016-07-27T11:17:39.023

Reputation: 37 779

2

Python 3, 82 bytes

lambda x:[min(x[0][::-1],['31','30'][x[1]=='11']),min(x[1][::-1],'12'),x[2][::-1]]

An anonymous function that takes input, via argument, of the date as a list of strings of the form ['dd', 'mm', 'yyyy'] and returns the validated reversed date in the same format.

How it works

Python compares characters and strings by their Unicode code-points. This means that any comparison on two or more integers returns the same as that comparison on those integers as strings. Hence, calling min on two integers as strings returns the smallest integer as a string; by taking the reversed date-part as one argument and the maximum value as another, the day and month are clamped to the desired range. The date-parts are reversed by indexing with steps of -1 ([::-1]), and the maximum value for the month is changed from '31' to '30' if the month is November by indexing into a list with the Boolean result of a conditional.

Try it on Ideone

TheBikingViking

Posted 2016-07-27T11:17:39.023

Reputation: 3 674

2

C# 314 305 299 249 232 223 Bytes

using System.Linq;string f(int d,int m,int y){Func<int,string>r=i=>string.Concat((""+i).PadLeft(2,'0').Reverse());Func<string,int,string>x=(j,k)=>int.Parse(j)>k?""+k:j;return x(r(d),m==11?30:31)+"-"+x(r(m),12)+"-"+r(y);}

Thanks to @KevinCruijssen for pointing out that I could shorten my variable declaration, which also made aliasing string able to save some bytes.

Saved 50 bytes storing the reversing function for reuse and another 13 by doing the same for the rounding and removing the variable declarations.

Last update makes aliasing string no longer a byte saver.

Ungolfed Version:

using System.Linq;
    string dateReverse(int day, int month, int year)
{
    //setup a resuable function to reverse
    Func<int, string> reverse = intToReverse => string.Concat((""+intToReverse).PadLeft(2, '0').Reverse());

    //another function for rounding
    Func<string, int, string> round = (strToRound, maxVal) => int.Parse(strToRound) > maxVal ? "" + maxVal : strToRound;

    //Join the strings into the "dd-mm-yyyy" date format
    return 
        //Round down the day value, if november cap to 30 otherwise cap to 31
        round(reverse(day), month == 11 ? 30 : 31) + "-" +

        //Round the month down
        round(reverse(month), 12) + "-" +

        //we can use the reverse function here too and pad left just won't do anything
        reverse(year);
}

Test it here

user19547

Posted 2016-07-27T11:17:39.023

Reputation:

You can ignore the space between using System.Linq; and the function, so that's -1 byte. Also, var n=...;var e=...; can be golfed by 1 byte using this instead: string n=...,e=...; It's not much, but still -2 bytes. ;) – Kevin Cruijssen – 2016-07-27T20:20:45.973

Nice catch on that space, though it looks like my byte count actually didn't count it, so ill chock that up to a copy paste issue. Also I think using that variable declaration style Ill be able to win a few more bytes by aliasing string. – None – 2016-07-27T20:27:55.443

1

Javascript, 106 105 94 bytes

d=>d.split`,`.map((a,b,r)=>(e=[...a].reverse().join``,f=!b?r[1]==11^31:b<2&&12,f&&f<e?f:e))+''

Test suite (rev. 3)


Explanation

d=>d.split`,`                 // split into sections by `,`

.map((a,b,r)=>(               // map each section

e=[...a].reverse().join``,    // spread a date section into array and reverse and 
                              // join with `` to get string result

f=!b?r[1]==11^31              // if section being mapped is day (section 0), 
                              // then max (f) is 30 for November(month 11) or else 31

:b<2&&12,                     // if part being mapped is month (section 1), then max (f) is 12

f&&f<e?f:e))                  // if there is a max (f)
                              // and the max (f) is less than the reversed string (e),
                              // then return the max (f), 
                              // else return the reversed string (e)

+''                           // join all the sections back together with `,` 
                              // (concatenating [] with a string will do this)

Thanks @KevinCruijssen for saving 1 byte for b==1 to b<2. Thanks @Neil for saving 11 bytes by suggesting ES6 template literal and , separator.

CShark

Posted 2016-07-27T11:17:39.023

Reputation: 191

I'm pretty bad at JS, so correct me if I say something wrong, but can't b==1 be golfed down to b<2 to save a byte? It can't be 0 anymore, since you've already checked that at the !b? part of the code. It seems to work in your test suite when I change it. – Kevin Cruijssen – 2016-07-27T20:30:10.287

@KevinCruijssen yep, you're right, thanks! I just overlooked it. I haven't done golfing in javascript for very look so I miss things like that sometimes – CShark – 2016-07-27T20:55:40.200

*I meant 'for very long', not 'for very look' – CShark – 2016-07-27T21:03:18.787

2As you're targeting ES6, you can use template strings to shorten your code - join\`` instead of join('') for example - but you can save a little more by using , as your separator, which allows you to use +'' to join the three values together. – Neil – 2016-07-27T23:25:13.710

@Neil you mean , as the separator in the input? – CShark – 2016-07-28T14:16:48.570

My understanding is that you're allowed any separator, as long as you're consistent. Using a , allows you to stringify to join with commas on output, although obviously you still need to split\,`` on input. – Neil – 2016-07-28T17:02:31.427

Ok, I wasn't aware of that – CShark – 2016-07-28T19:41:43.690

1

Ruby, 92 84 + 1 (-p flag) = 93 85 bytes

Uses - as the seperator.

d,m,y=chomp.split(?-).map &:reverse
$_=[[d,m=="11"?"30":"31"].min,[m,"12"].min,y]*?-

Value Ink

Posted 2016-07-27T11:17:39.023

Reputation: 10 608

1

Pyke, 29 bytes

F_bw-o^tDI]SX(mhj_Xjth~%R@]Sh

Try it here!

I can definitely see this being golfable

Blue

Posted 2016-07-27T11:17:39.023

Reputation: 26 661

0

05AB1E, 24 bytes

#íÐÅsË31^12‚øεßт+¦}sθªðý

Port of @MartinEnder's CJam answer, so also inputs and outputs as a string in the format dd MM yyyy.

Try it online or verify all test cases.

Explanation:

#                         # Split the (implicit) input by spaces
                          #  i.e. "04 11 1671" → ["04","11","1671"]
                          #  i.e. "20 01 2000" → ["20","01","2000"]
 í                        # Reverse each string
                          #  i.e. ["04","11","1671"] → ["40","11","1761"]
                          #  i.e. ["20","01","2000"] → ["02","10","0002"]
  Ð                       # Triplicate this list
   Ås                     # Pop one of them, and push it's middle element (the months)
                          #  i.e. ["40","11","1761"] → "11"
                          #  i.e. ["02","10","0002"] → "10"
     Ë                    # Check if the digits are the same (1 for 11; 0 otherwise)
                          #  i.e. "11" → 1 (truthy)
                          #  i.e. "10" → 0 (falsey)
      31^                 # Bitwise-XOR with 31 (30 for November, 31 for other months)
                          #  i.e. 1 → 30
                          #  i.e. 0 → 31
         12‚              # Pair it with 12
                          #  i.e. 30 → [30,12]
                          #  i.e. 31 → [31,12]
            ø             # Zip/transpose; swapping rows and columns
                          # (implicitly removes year)
                          #  i.e. ["40","11","1761"] and [30,12] → [["40",30],["11",12]]
                          #  i.e. ["02","10","0002"] and [31,12] → [["02",31],["10",12]]
             ε    }       # Map each pair to:
              ß           # Get the minimum (implicitly converts to integer unfortunately)
                          #  i.e. [["40",30],["11",12]] → [30,11]
                          #  i.e. [["02",31],["10",12]] → [2,10]
               т+         # Add 100
                          #  i.e. [30,11] → [130,111]
                          #  i.e. [2,10] → [102,110]
                 ¦        # Remove the first character
                          #  i.e. [130,111] → ["30","11"]
                          #  i.e. [102,110] → ["02","10"]
                   s      # Swap so the triplicated list is at the top of the stack again
                    θ     # Pop and only leave it's last element (the year)
                          #  i.e. ["40","11","1761"] → "1761"
                          #  i.e. ["02","10","0002"] → "0002"
                     ª    # Append it to the list
                          #  i.e. ["30","11"] and "1761" → ["30","11","1761"]
                          #  i.e. ["02","10"] and "0002" → ["02","10","0002"]
                      ðý  # Join the list by spaces (and output implicitly)
                          #  i.e. ["30","11","1761"] → "30 11 1761"
                          #  i.e. ["02","10","0002"] → "02 10 0002"

Kevin Cruijssen

Posted 2016-07-27T11:17:39.023

Reputation: 67 575

0

Python 2, 154 bytes

z=input().split("-");r=[x[::-1]for x in z];z[1]=r[1]if r[1]<'12'else '12';z[0]=r[0]if r[0]<'31'else '30'if z[1]=='11'else '31';z[2]=r[2];print "-".join(z)

Takes the input as a string, so quotes need to be specified in the input, e.g. "11-04-2016".

Jeremy

Posted 2016-07-27T11:17:39.023

Reputation: 521

Just a basic improvement since I'm not a Python golfer: z=[x[::-1]for x in z];z[1]=min(z[1],'12');z[0]=min(z[0],['31','30'][z[1]=='11']);print"-".join(z). Basically, you don't need to use r at all, and min accomplishes a lot of the things you want to do. – Value Ink – 2016-07-27T20:20:45.220