47
\$\begingroup\$

This challenge is quite simple. You will take an input which will be a year from 1801 to 2400, and output if it is a leap year or not.

Your input will have no newlines or trailing spaces:

1954

You will output in any way that you like that clearly tells the user if it is or isn't a leap year (I will accept y or n for yes/no)

You can get a list of leap years here: http://kalender-365.de/leap-years.php I would note that leap years are not ever four years always. 1896 is a leap year, but 1900 is not. The years that follow this "skip" are:

1900
2100
2200
2300

Test cases:

1936 ->  y
1805 ->  n
1900 ->  n
2272 ->  y
2400 ->  y 

EDIT: This is based on a standard Gregorian calendar: http://www.epochconverter.com/date-and-time/daynumbers-by-year.php

The Catalogue

The Stack Snippet at the bottom of this post generates the catalogue from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the snippet:

## [><>](https://esolangs.org/wiki/Fish), 121 bytes

/* Configuration */

var QUESTION_ID = 50798; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 8478; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];
  
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });
    else console.log(body);
  });
  
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;
    
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    lang = jQuery('<a>'+lang+'</a>').text();
    
    languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang, user: a.user, size: a.size, link: a.link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang_raw.toLowerCase() > b.lang_raw.toLowerCase()) return 1;
    if (a.lang_raw.toLowerCase() < b.lang_raw.toLowerCase()) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body {
  text-align: left !important;
  display: block !important;
}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 500px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/codegolf/all.css?v=ffb5d0584c5f">
<div id="language-list">
  <h2>Shortest Solution by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

\$\endgroup\$
5
  • 12
    \$\begingroup\$ You should be more clear: A given year is a leap year if and only if it is (divisible by 4)∧((divisible by 100)→(divisible by 400)). \$\endgroup\$ Commented May 26, 2015 at 11:34
  • \$\begingroup\$ Your input will have no newlines or trailing spaces. Dang it, that would have saved me 2 bytes... \$\endgroup\$
    – Dennis
    Commented May 26, 2015 at 17:10
  • 2
    \$\begingroup\$ You should extend the accepted input range to AD 1601 thru 2400. This covers two 400-year Gregorian cycles (which proleptically start on Monday). \$\endgroup\$ Commented May 26, 2015 at 18:17
  • 2
    \$\begingroup\$ Does falsy if leap year and truthy if not a leap year count as "clearly tells the user if it is or isn't"? \$\endgroup\$
    – lirtosiast
    Commented May 28, 2015 at 21:27
  • \$\begingroup\$ @lirtosiast I think so. A lot of user assume so. \$\endgroup\$
    – aloisdg
    Commented Jul 20, 2016 at 13:58

82 Answers 82

23
\$\begingroup\$

APL, 16 14 12 characters

Returns 0 for a leap year, 1 for a non-leap year.

≥/⌽×4 25 4⊤⎕

Try this solution on tryapl.org. Note that I have changed the solution to the dfn {≥/⌽×4 25 4⊤⍵} as tryapl.com does not support (take user input). Note that is an empty box, not a missing character.

The same solution in J:

4 25 4>:/@|.@:*@#:]

Explanation

Dyadic (encode) represents its right argument in the base specified by its left argument. I use base 4 25 4 in this solution. This represents the year y as a polynomial

y mod 400 = 100 a + 4 b + c where b < 100 and c < 4.

Let propositions α, β, and γ represent if a, b, and c are non-zero: Proposition γ is false if y is dividable by 4, βγ is false if y is dividable by 100 and αβγ is false if y is dividable by 400.

A truth table (* representing “don't care”) were proposition Δ represents if y is a leap-year obtains:

α β γ | Δ
0 0 0 | 1
1 0 0 | 0
* 1 0 | 1
* * 1 | 0

The following statement expresses Δ in α, β, and γ:

Δ = ¬((αβ) → γ)).

Due to the structure of this statement, one can express ¬Δ as the reduction ≥/⌽α β γ where ≥ implements ←. This leads to the answer I am explaining right now.

\$\endgroup\$
0
17
\$\begingroup\$

Javascript (ES6), 21 characters

The standard rule is that y is a leap year if 4 divides y and if either 100 doesn't divide y or 400 does divide y. In code,

y%4 == 0 && (y%100 != 0 || y%400 == 0)

There's no need for that 100 and 400. Instead it suffices to check whether 16 or 4 divides y, with 16 chosen if 25 divides y, 4 otherwise. Golfed, this becomes

!(y%(y%25?4:16))

A javascript function that implements this is 21 characters long:

l=y=>!(y%(y%25?4:16))


Perl, 28 26 characters

Same idea, but in perl.

$_=$_%($_%25?4:16)?"n":"y"

Run using the -lp options. For example,

perl -lpe '$_=$_%($_%25?4:16)?"n":"y"'

With the test set as input, this produces

1936
y
1805
n
1900
n
2272
y
2400
y
\$\endgroup\$
5
  • \$\begingroup\$ I had used your suggestion in my answer, did not see yours. Now I have rolled back. Note: You should specify EcmaScript 6, or else someone will complain 'not working in Chrome' \$\endgroup\$
    – edc65
    Commented May 28, 2015 at 21:59
  • \$\begingroup\$ @edc65: Well, he should specify EcmaScript 6 because it is EcmaScript 6. Arrow function notation (y=>...) is an ES6 feature. \$\endgroup\$
    – Tim Čas
    Commented Sep 5, 2016 at 11:50
  • \$\begingroup\$ Shouldn't this be two answers? \$\endgroup\$
    – dfeuer
    Commented Mar 1, 2019 at 18:31
  • \$\begingroup\$ -1 byte: l=y=>y%(y%25?4:16)<1 \$\endgroup\$
    – user100690
    Commented Feb 15, 2021 at 17:19
  • \$\begingroup\$ Save 2 bytes for Perl: Try it online! \$\endgroup\$ Commented Aug 25, 2021 at 6:59
16
\$\begingroup\$

Pyth, 11 bytes

!%|F_jQ*TT4

This full program read from STDIN and prints True for leap years and False otherwise.

Thanks to @Jakube for suggesting Pyth and basically porting my CJam code.

Verify the test cases yourself in the Pyth Compiler/Executor.

How it works

     jQ*TT   Returns the evaluated input in base 10 × 10.
  |F_        Swaps the digit order and reduces using logical OR.
             So far, we've achieved 1954 -> [19, 54] -> 54 || 19.
!%        4  Returns the logical NOT of the result modulo 4.
             This prints True for multiples of 4 and False otherwise.
\$\endgroup\$
0
15
\$\begingroup\$

CJam, 12 bytes

rS+2m<~e|4%!

This full program read from STDIN and prints 1 for leap years and 0 otherwise.

Verify the test cases yourself in the CJam interpreter.

How it works

r   e# Read from STDIN.
S+  e# Append a space.
2m< e# Rotate two characters to the left.
~   e# Evaluate.
    e# So far, we achieved "1954" -> "54 19" -> 54 19.
e|  e# Logical OR; keep the leftmost non-zero integer.
4%! e# Logical NOT of the kept integer modulo 4.
    e# This pushes 1 for multiples of 4 and 0 otherwise.
\$\endgroup\$
2
  • \$\begingroup\$ I've got a few more 12 byte alternatives. Maybe you can find something in them to bring it down to 11? r2/~~\e|i4%!, r2/~~\~e|4%!, r2/:~~\e|4%!, r2/S*~\e|4%! and the 13 byte r2/:~W%:e|4%! \$\endgroup\$ Commented May 26, 2015 at 18:40
  • \$\begingroup\$ @MartinBüttner: There's also r2/:i:\e|4%! (12) and r2/:i(fe|~4%! (13). I've even tried GolfScript (which doesn't require r), but or4 is interpreted as a single token. If only the input had a trailing newline... \$\endgroup\$
    – Dennis
    Commented May 26, 2015 at 19:00
11
\$\begingroup\$

TI-BASIC, 20 17 16 13

Because it is tokenized, TI-BASIC is often competitive at simple math challenges, but not this one since there is no "divisible" command. Maybe it is after all, but this is still longer than CJam and Pyth.

This uses David Hammond's method.

not(fPart(Ans/4/4^not(fPart(sub(Ans

Old code at 16 bytes:

not(fPart(Ans/16not(fPart(sub(Ansnot(fPart(Ans/4

Ungolfed:

not(fPart(Ans/16) and not(fPart(Ans/100) and not(fPart(Ans/4))))

fPart( is "fractional part"; exponentiation has higher precedence than division. In TI-BASIC, close-parens are optional.

I use undocumented behavior of the sub( command, usually used to get a substring: when its argument is a number instead of a string, it divides the number by 100. It will work on a TI-83 or 84 series calculator.

20 -> 17 by rearranging code to allow removal of close-parens; 17 -> 16 by replacing 400 with 16; 16 -> 13 by using David Hammond's idea.

\$\endgroup\$
11
\$\begingroup\$

Stackylogic, 226 bytes

Yes, that is right. I made a program in Stackylogic (non-TC), which was invented by Helka Homba, for the challenge found here.

Stackylogic has only binary input, so 10 (or more, any more digits will be ignored) bit binary must be used (least significant bit inputted first). Any dates outside the specified range might fail, as it simply checks what the inputted number is: it doesn't cover unnecessary dates

Not only is this my first challenge with stackylogic, but the first challenge with stackylogic at all.

Get ready for this mess:

1
0
1?
010
1?0
010
1?10
?1010
001010
?1010
?1010
?010
?10
?0
0
?
110
?10
11010
?010
11010
?1010
001010
?1010
?1010
?1010
?1010
?010
?0
110
?10
11010
?010
1010
01010
01010
?010
?0
110
?0
110
?0
110
1?0
?10
0?10
?10
?0
01
?
?<
0

This took me so long to make, because Stackylogic is the most confusing language I have encountered, and extremely unreadable: you have to know how the rest of the program has executed before you can read the current section being edited. I even had to add spaces for readability while creating it.

Meagre explanation

This is a simple explanation of what it does.

Stackylogic does not have any mathematical functions, so that made this harder. I had to hardcode most of it, to check if it was a specific number.

First, this program will do a NOR of the least significant bits, discarding them in the process. this means that if it is divisible by 4, it will proceed to the main part of the program, otherwise output 0.

Second, the pointer is carried over to the labyrinth of stackylogic, from here, if the next two bits are zero, it will instantly output 1 (as then it is divisible by 16, and so a leap year despite any other conditions), other wise it will check if it is not any of the numbers that is divisible by 4 but not a leap year, between 1801 and 2400.

To explain in detail, would involve making this post many times longer than it already is

\$\endgroup\$
10
\$\begingroup\$

Pyth, 19 15 14 bytes

xFm!%Q^d2[2TyT

Way too easy. Try it online: Demonstration or Test harness

edit: Missed, that you can print Truthy/Falsy values, instead of n/y. -4 byte

edit 2: Used the square root idea of Martin. -1 byte

Explanation

                 implicit: Q = input number
         [         generate a list with the numbers:
          2          2
           T         10
            yT       2*10 = 20
  m              map each number d to:
   !%Q^d2          not(Q mod d^2) // True if Q % d^2 == 0 otherwise False
xF               fold by xor
\$\endgroup\$
0
10
\$\begingroup\$

Regex, 83 62 38

Thanks to Toby for tips about combining both halves of the regex.

If we focus on 1801..2400 range only and assume input are integers:

(?!00)([02468][048]|[13579][26])(00)?$

Test in Ruby (^ = \A and $ = \Z because Ruby) for the desired range:

r = /(?!00)([02468][048]|[13579][26])(00)?\Z/
(1801..2401).each do |year|
  leap = year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))
  leap_regex = !year.to_s[r].nil?
  if leap != leap_regex
    print 'Assertion broken:', year, " ", leap, " ", leap_regex, "\n"
  end
end

(Bonus) for something that should work not only for 1801..2400, but for any non-negative year:

^\d*(0000|(?!00)([13579][26]|(^|[02468])[048])(00)?)$

Test in Ruby (^ = \A and $ = \Z because Ruby) for first 100000 years:

r = /\A\d*(0000|(?!00)([13579][26]|(\A|[02468])[048])(00)?)\Z/
100000.times do |year|
  leap = year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))
  leap_regex = !year.to_s[r].nil?
  if leap != leap_regex
    print 'Assertion broken:', year, " ", leap, " ", leap_regex, "\n"
  end
end
\$\endgroup\$
1
  • 1
    \$\begingroup\$ If you have (?!) you can combine the two halves: (?!00)([02468][048]|[13579][26])(00)?$ - for 38. That won't work for one-digit years, though. \$\endgroup\$ Commented May 27, 2015 at 16:45
10
\$\begingroup\$

Haskell, 19 bytes

f i=gcd 80i>gcd 50i

Try it online!

\$\endgroup\$
9
\$\begingroup\$

Pip, 13 bytes

This one was more interesting than it at first appeared. It took some finagling, but I was finally able to replace those lengthy references to 400 with 4 and the h variable (=100).

!(a%h?aa/h)%4

Outputs 1 for leap year, 0 for non-leap year. Explanation:

               a is command-line argument (implicit)
  a%h?aa/h     If a is divisible by 100, divide it by 100; otherwise, leave it alone
 (        )%4  The result mod 4 is 0 if it's a leap year, nonzero otherwise
!              Negate and (implicitly) print
\$\endgroup\$
9
\$\begingroup\$

JavaScript (ES6) 27

The rule: (y%4==0) && (y%100!=0 || y%400==0)

Golfed: !(y%100<1&&y%400||y%4) (mainly using De Morgans's law)

A function implementing the rule:

l=y=>!(y%100<1&&y%400||y%4)

A test (run in Firefox) just to be sure:

l=y=>!(y%100<1&&y%400||y%4)

for(o=[],i=0;i<700;i++)
  y=i+1800,
  x=l(y),
  o[i/100|0]=(o[i/100|0]||'')+y+(x?' <b>Y</b>':' <i>N</i>')+'\n'
    
R.innerHTML='<td>'+o.join('</td><td>')+'</td>'
console.log(o[1])
td { white-space: pre; font-family: monospace; padding: 8px}

b { color: red; }
i { color: blue; }
<table>
  <tr id=R></tr>
</table>

\$\endgroup\$
2
  • 3
    \$\begingroup\$ You can reduce this by six characters if you use !(y%(y%25?4:16)) instead of !(y%100<1&&y%400||y%4). For those bothered by the ternary operator, you could use !(y%(4<<2*!(y%25))) and still save three characters over !(y%100<1&&y%400||y%4). \$\endgroup\$ Commented May 28, 2015 at 20:48
  • 1
    \$\begingroup\$ David Hammen's suggestion is identical to his answer, so I think you should keep the length as 27. \$\endgroup\$
    – lirtosiast
    Commented May 28, 2015 at 21:52
8
\$\begingroup\$

IBM System Z assembler - 56 bytes.

(96 bytes of source. Previously 712 384 202 bytes of source, 168 byte executable).

Smaller version still. No longer saves caller's registers, changes to literal storage, changed addressing mode.

 l        CSECT      
         using l,15 
         l  5,y     
         n 5,f      
         bnz r      
         xr 4,4     
         l 5,y      
         d 4,c      
         ch 4,i     
         bne i      
         n 5,f      
         bnz r      
i        dc h'0'    
r        b  *       
y        dc f'2004' 
f        dc f'3'    
c        dc f'100'  
         end 

New version. This will ABEND with a S0C1 if it's a leap year, and loop if it isn't. Hopefully that fulfils the requirement of indicating the result.

l        CSECT             
         ASMDREG           
         SYSSTATE archlvl=2
         IEABRCX  DEFINE   
         save  (14,12)     
         larl  r9,s        
         using s,r9        
         st 13,w+4         
         la 13,w           
         st 13,w+8         
         la 5,2004         
         st 5,y            
         n 5,=f'3'         
         bnz r             
         xr r4,r4          
         l 5,y             
         d r4,=f'100'      
         ch r4,=h'0'       
         bne i             
         n 5,=f'3'         
         bnz r             
i        dc h'0'           
r        b  0              
s        dc 0d'0'          
y        ds f              
w        ds 18f            
         ltorg             
         end  

OK, so not the shortest (although it might be once we look at the actual executed code plus the interpreter size...)

leapyear CSECT                                                
         ASMDREG                                              
         SYSSTATE archlvl=2                                   
         IEABRCX  DEFINE                                      

         save  (14,12)                                        

         larl  r9,staticArea                                  
         using staticArea,r9                                  
         st r13,w_savea+4       .Save callers savearea        
         la r13,w_savea         .Address my savearea          
         st r13,w_savea+8         . and save it               

         open  (O,OUTPUT)             .open file              

         la r5,1936             .r5 = input year              
         st r5,years            .Save year                    

         cvd r5,double          .Convert year to p-decimal    
         mvc edarea,=xl8'4020202020202120' .Move in edit mask 
         ed edarea,double+4      .Make packed decimal year printable                              
         mvc outrec(4),edarea+4  .Move year string to output area                             
         bas r10,isitleap       .Call leap year routine       

         close (O)              .Close files            
         b return               .Branch to finish

isitleap ds 0h                                                      
         mvi outrec+5,c'N'      .Set default value                                   
         n r5,=f'3'             .Are last 2 bits 0 (Divisible by 4)?
         bnz notleap            .No - not leap                      
         xr r4,r4               .Clear R4                           
         l r5,years             .Reload r5 with year                
         d r4,=f'100'           .divide r4/r5 pair by 100           
         ch r4,=h'0'            .Remainder 0?                       
         bne isleap             .No - leap year                     
         n r5,=f'3'             .Quotient divisible by 4?           
         bnz notleap            .No - not leap                      

isleap   ds    0h                                                   
         mvi outrec+5,c'Y'      .Move in leap year indicator                                    

notleap  ds    0h                                                   
         put O,outrec           .Print output record                                    
         br r10                 .Return to caller                   

* Program termination                                               
return   ds 0h                                                      
         l r13,w_savea+4         .Restore callers savearea          
         return (14,12),,rc=0    .Restore registers and return    
* storage areas                                                     
staticarea  dc 0d'0'                                                
outrec      ds cl10                                                 
years       ds f                                                    
w_savea     ds 18f                save area                         
edarea      ds cl8                    .edit area                    
double      ds d                                                    
* Macros and literals                                               
         print nogen                                                
O        dcb   recfm=F,lrecl=6,dsorg=PS,ddname=O,macrf=PM           
         print gen                                                  
*                                                                   
         ltorg                         literal storage              
         end  

Output:

ABEND S0C1 for a leap year, S222 (when the CPU time has run out) if not.

1936 Y 1805 N 1900 N 2272 Y 2400 Y

(when run multiple times)

\$\endgroup\$
4
  • \$\begingroup\$ Down to 376 bytes by making storage areas minimum size (13 bytes), removing staging area 'leapflag' and only including a single year (rather than 5) in the program. \$\endgroup\$
    – Steve Ives
    Commented May 27, 2015 at 10:08
  • \$\begingroup\$ 384 bytes by providing a slightly formatted output: \$\endgroup\$
    – Steve Ives
    Commented May 27, 2015 at 10:29
  • 1
    \$\begingroup\$ +1 for interesting and educational choice of language. :-) \$\endgroup\$ Commented May 27, 2015 at 17:02
  • \$\begingroup\$ I could save a few bytes by abandoning convention and not bothering to save the callers registers at the start, seeing as the program never returns to the caller. This is Very Bad Form. \$\endgroup\$
    – Steve Ives
    Commented May 29, 2015 at 12:47
7
\$\begingroup\$

CJam, 18 16 bytes

q~[YAK]f{2#%!}:^

Gives 1 (truthy) for leap years and 0 (falsy) otherwise.

Run all test cases here.

Explanation

q~                 e# Read and eval input.
  [YAK]            e# Push an array containing 2, 10, 20 (the square roots of the
                   e# relevant divisors).
       f{    }     e# Map this block onto that array, also passing in the input year.
         2#        e# Square the divisor.
           %!      e# Modulo followed by logical negation. Gives 1 if the year is divisible
                   e# by the given divisor and 0 otherwise.
                   e# At this point we have one of the following arrays:
                   e#   [0 0 0] - not a leap year
                   e#   [1 0 0] - a leap year
                   e#   [1 1 0] - not a leap year
                   e#   [1 1 1] - a leap year
              :^   e# Reduce XOR onto this array, which gives 1 if there is an odd number
                   e# of 1s and 0 if there's an even number.
\$\endgroup\$
7
\$\begingroup\$

R, 29

!(Y=scan())%%4&Y%%100|!Y%%400

Test run

> !(Y=scan())%%4&Y%%100|!Y%%400
1: 1936
2: 1805
3: 1900
4: 2272
5: 2400
6: 2200
7: 
Read 6 items
[1]  TRUE FALSE FALSE  TRUE  TRUE FALSE
\$\endgroup\$
6
\$\begingroup\$

Mathematica, 40 27 bytes, 17 chars

#∣4∧(#∣100<U+F523>#∣400)

Uses 17 chars, but 27 bytes. Thanks to @alephalpha for the tip. Note that the vertical bars are actually U+2223 for divides. The <U+F523> should be replaced with the corresponding character.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ This is one of those puzzles where Mathematica offers a solution that feels kind of cheaty: LeapYearQ[#]& \$\endgroup\$
    – zeldredge
    Commented May 26, 2015 at 13:23
  • 1
    \$\begingroup\$ You can use to represent Divisible : #∣4&&(!#∣100||#∣400)&, 21 characters, 27 UTF-8 bytes. \$\endgroup\$
    – alephalpha
    Commented May 26, 2015 at 13:54
  • \$\begingroup\$ @zeldredge Still, that's not shorter than the APL solution. \$\endgroup\$
    – FUZxxl
    Commented May 26, 2015 at 14:10
  • \$\begingroup\$ @alephalpha Alternatively, you could use U+F523 (\[Implies]) to make it #∣4&&(#∣100<U+F523>#∣400)& for 19 chars (but still 27 bytes). \$\endgroup\$ Commented May 26, 2015 at 15:15
  • \$\begingroup\$ This is a standard loophole; you're using a function that does exactly the required functionality. This is verboten. \$\endgroup\$
    – FUZxxl
    Commented May 26, 2015 at 15:33
6
\$\begingroup\$

Python2 - 37 bytes

g=lambda x:(x%4or x%400and x%100<1)<1

Note that if a is a nonnegative integer, then a<1 is a short way of writing not bool(a). The last <1 thus effectively converts the expression in the parentheses to a boolean and negates the result.

Applying the function g to an integer n between 1801 and 2400 will return True if n is a leap year, and False otherwise.

\$\endgroup\$
5
\$\begingroup\$

sed, 55

s/00$//
y/0123456789/yNnNyNnNyN/
/N.$/y/ny/yn/
s/.\B//g
  • First line divides exact centuries by 100.
  • Second line gives 'N' to odd digits, 'y' to 4s, and 'n' to non-4s.
  • Third line swaps 'y' and 'n' if there's an odd penultimate digit (because 10 is 2 mod 4)
  • Final line deletes all but the last character

Note that non-leap years may be printed as n or N depending on whether they are even or odd. I consider this a creative interpretation of the rule which allows alternatives to 'yes' and 'no' without specifying that they have to be consistent.

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

Julia, 30 28 bytes

y->(y%4<1&&y%100>0)||y%400<1

This creates an unnamed function that accepts an integer argument and returns a boolean value. To call it, give it a name, e.g. f=y->....

Ungolfed:

function f(y)
    (y % 4 == 0 && y % 100 != 0) || y % 400 == 0
end

Example:

julia> for y in [1936, 1805, 1900, 2272, 2400] println(f(y)) end
true
false
false
true
true
true
\$\endgroup\$
5
\$\begingroup\$

C, 81

I can do shorter, but this one neatly sticks to 'char' types, without parsing the argument (e.g. with atoi):

main(c,v)char**v;{char*p=*v+9;p-=2*(96==*p+p[1]);putchar("ynnn"[(2**p^p[1])&3]);}

It must be invoked with a name 4 characters long, because it makes the standard assumption that arguments immediately follow the program name, separated by NULs. Furthermore, it assumes that the single argument is encoded in ASCII and has no leading space.

Explanation:

main(c,v)
char**v;
{
    char *p = *v+9;
    if (p[0] + p[1] == '0'+'0')
        p -= 2;
    putchar("ynnn"[((*p << 1) ^ p[1])&3]);
}

*v+9 is the position of the 'tens' digit in v[1]+2.

If the 'tens' and 'units' characters add to 96, we end in 00, so back up two characters, so that 'tens' and 'units' point to the century number.

Now xor 'units' with twice the 'tens', mod 4. This works because 10==±2 mod 4, so the lower bit of the 'tens' can just toggle bit 1 of the 'units'. We use the result as an index into our remainders table, printing y only if the modular result is zero.

\$\endgroup\$
5
\$\begingroup\$

Jelly, 7 bytes

ọ4,25>/

Try it online!

How it works

ọ4,25>/  Main link. Argument: n (1801 - 2400)

ọ4,25    Test how many times n is divisible by 4 and 25.
     >/  Verify that the order of 4 is higher than the order of 25.
\$\endgroup\$
4
\$\begingroup\$

Befunge-98, (41 bytes)

&:4%#v_:aa*%#v_28*%|
"y",;<;@,"n";>;  ;#[

Simplicity is awesome.

\$\endgroup\$
4
\$\begingroup\$

Python, 37 bytes

def c(s):return s%16*(s%25<1)<(s%4<1)
\$\endgroup\$
0
4
\$\begingroup\$

C#, 23 bytes

y=>y%25<1?y%16<1:y%4<1;

Try it online!

Full source, including test cases:

using System;

namespace CountingLeapYears
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int,bool>s=y=>y%25<1?y%16<1:y%4<1;
            Console.WriteLine(s(1936)); //y
            Console.WriteLine(s(1805)); //n
            Console.WriteLine(s(1900)); //n
            Console.WriteLine(s(2272)); //y
            Console.WriteLine(s(2400)); //y
        }
    }
}
\$\endgroup\$
4
\$\begingroup\$

C, 37 34 30 bytes

l(y){y=y%(y%25?4:16)?110:121;}

Wandbox

\$\endgroup\$
4
\$\begingroup\$

Java 8, 49 45 22 20 bytes

n->n%(n%25<1?16:4)<1

-2 bytes thanks to @OlivierGrégoire.

Try it online.

Some 22 bytes solutions:

n->n%25<1?n%16<1:n%4<1

Try it online.

n->(n%25<1?n%16:n%4)<1

Try it online.

java.time.Year::isLeap

Try it online.

Explanation:

n->                // Method with integer parameter and boolean return-type
   n%          <1  //  Return whether the integer is divisible by:
     (n%25<1?      //   If the input is divisible by 25:
             16    //    Check if its divisible by 16
            :      //   Else:
             4)    //    Check if its divisible by 4 instead
\$\endgroup\$
3
4
\$\begingroup\$

05AB1E, 9 7 6 bytes

тÖoooÖ

-1 byte porting @emanresuA's Vyxal answer, so make sure to upvote that answer as well!

Try it online or verify all test cases.

Original 9 7 bytes approach:

т‰0Kθ4Ö

Try it online or verify all test cases.

Explanation:

тÖ       # Check whether the (implicit) input is divisible by 100
         #  i.e. 1900 → 1
         #  i.e. 1936 → 0
         #  i.e. 1991 → 0
         #  i.e. 2000 → 1
  ooo    # Take 2 to the power that three times
         #  i.e. 1 → 2 → 4 → 16
         #  i.e. 0 → 1 → 2 → 4
     Ö   # Check whether the (implicit) input is divisible by that
         # (and output the result implicitly)
         #  i.e. 1900 and 16 → 0 (falsey)
         #  i.e. 1936 and 4 → 1 (truthy)
         #  i.e. 1991 and 4 → 0 (falsey)
         #  i.e. 2000 and 16 → 1 (truthy)
т‰       # Divmod the (implicit) input by 100
         #  i.e. 1900 → [19,00]
         #  i.e. 1936 → [19,36]
         #  i.e. 1991 → [19,91]
         #  i.e. 2000 → [20,00]
  0K     # Remove all 0s
         #  i.e. [19,00] → [19]
         #  i.e. [19,36] → [19,36]
         #  i.e. [19,91] → [19,91]
         #  i.e. [20,00] → [20]
    θ    # Pop and get the last item
         #  i.e. [19] → 19
         #  i.e. [19,36] → 36
         #  i.e. [19,91] → 91
         #  i.e. [20] → 20
     4Ö  # Check if it's divisible by 4
         # (and output the result implicitly)
         #  i.e. 19 → 0 (falsey)
         #  i.e. 36 → 1 (truthy)
         #  i.e. 91 → 0 (falsey)
         #  i.e. 20 → 1 (truthy)
\$\endgroup\$
3
\$\begingroup\$

KDB(Q), 27 bytes

{0=x mod(4 400)0=x mod 100}

Explanation

               0=x mod 100      / boolean of 100 divisibility
        (4 400)                 / 0b -> 4, 1b -> 400
 0=x mod                        / boolean of 4/400 divisibility
{                         }     / lambda

Test

q){0=x mod(4 400)0=x mod 100}1936 1805 1900 2272 2400
10011b
\$\endgroup\$
3
\$\begingroup\$

PHP - 45 bytes

$b=$argv[1]%400;echo !$b|!($b%4)&!!($b%100);

Nothing that special really, just abusing type-juggling.

\$\endgroup\$
3
\$\begingroup\$

T-SQL 37 22 bytes

Saved 15 bytes thanks to BradC's comment.

The usual hardcoded variable for lack of a stdin.

e.g.

DECLARE @ NVARCHAR(4) = '2016'

Then the solution is:

PRINT ISDATE(@+'0229')
\$\endgroup\$
1
  • 1
    \$\begingroup\$ If I'm reading the challenge right, I think you can save a bunch of bytes by just returning the 1 or 0 directly: PRINT ISDATE(@+'0229') \$\endgroup\$
    – BradC
    Commented Jan 8, 2019 at 14:40
2
\$\begingroup\$

Javascript ES6, 32, 29, 26

Any of following lines works:

f=y=>new Date(y,2,0).getDate()&1
g=y=>!(y&3)^!(y%100)>!(y%400)
h=y=>!(y&3|y%100<1&&y%400)
\$\endgroup\$

Your Answer

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