41
\$\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\$
  • 9
    \$\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\$ – LegionMammal978 May 26 '15 at 11:34
  • \$\begingroup\$ Your input will have no newlines or trailing spaces. Dang it, that would have saved me 2 bytes... \$\endgroup\$ – Dennis May 26 '15 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\$ – David R Tribble May 26 '15 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 May 28 '15 at 21:27
  • \$\begingroup\$ @lirtosiast I think so. A lot of user assume so. \$\endgroup\$ – aloisdg moving to codidact.com Jul 20 '16 at 13:58

69 Answers 69

2
\$\begingroup\$

Mathematica, 15 bytes

LeapYearQ@*List

Mathematica has a built-in for everything. List is there to make the integer input into a compact DateList object. Returns True or False.

\$\endgroup\$
  • \$\begingroup\$ LeapYearQ@{#}& for 14 \$\endgroup\$ – attinat Aug 15 '19 at 6:39
2
\$\begingroup\$

PHP, 28 bytes

Why calculate when there´s a builtin?

<?=checkdate(2,29,$argv[1]);

prints 1 for leap year, empty string for no leap year.
Add + after <?= for 1/0.

\$\endgroup\$
2
\$\begingroup\$

SmileBASIC, 40 bytes

INPUT Y?0DTREAD STR$(Y)+"/02/29"OUT,,,?1

Prints 0 1 if it's a leap year, otherwise prints 0 and errors.

DTREAD parses a date string in the form of YYYY/MM/DD and gives the year, month, and day. It can also return the day of the week, and trying to get the day of the week of a day that doesn't exist (Feb. 29 of a non-leap year) will cause an error.

This is shorter than the obvious answer using mod, because SB uses MOD instead of %, which takes up 3-5 characters.

\$\endgroup\$
2
\$\begingroup\$

PHP, 34 30 bytes

echo+!($argn%($argn%25?4:16));

I'm using the + sign to convert false (which would normally be converted to an empty string) to 0, because that seems to comply closer to the "clearness" requirement (maybe not?). With standard truthy/falsy rules, 1 byte can be saved.

Note: I shamelessly implemented the divisibility by 25 trick from @David Hammen. Without his algorithm it would be 37 bytes:

<?=+!(($b=$argv[1])%400^$b%100^$b%4);

Run like this:

echo 1900 | php -nR 'echo+!($argn%($argn%25?4:16));';echo

Tweaks

  • Saved 4 bytes by using $argn
\$\endgroup\$
  • 1
    \$\begingroup\$ Save one more byte on standard truthy/falsy with <1 instead of !() \$\endgroup\$ – Titus Feb 2 '17 at 2:45
2
\$\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\$
2
\$\begingroup\$

Haskell, 43 41 39 bytes

l x=mod x(if mod x 25<1then 16else 4)<1

If x is divisible by 25, check if it is also divisible by 16, making it divisible by the least common multiple of 25 and 16, which is 400.
If x is not divisible by 25, check if it is divisible by 4.

Inspired by @David Hammen's answer in JavaScript.

\$\endgroup\$
  • \$\begingroup\$ I don't know Haskell, but can ==0 be <1? \$\endgroup\$ – lirtosiast May 28 '15 at 21:13
  • \$\begingroup\$ You are right, it can. \$\endgroup\$ – AplusKminus May 29 '15 at 9:04
  • 1
    \$\begingroup\$ You can drop the spaces before then and else. \$\endgroup\$ – dfeuer Mar 1 '19 at 7:38
  • 1
    \$\begingroup\$ The conditional can be equivalently expressed as (4+sum[12|mod x 25<1]) for a total of 33 bytes: Try it online! \$\endgroup\$ – Laikoni Mar 3 '19 at 9:24
2
\$\begingroup\$

Excel, 30 bytes

David Hammen's method (A1 serves as input):

=MOD(A1,IF(MOD(A1,25),4,16))=0

Built-in functions can get you down to 23 bytes. However, this approach doesn't work on 1900 because of bug compatibility with Lotus 1-2-3:

=MONTH(DATE(A1,2,29))=2

You could even save two more bytes by using Portugese locale:

=MÊS(DATA(A1;2;29))=2
\$\endgroup\$
2
\$\begingroup\$

x86 machine code, 14 bytes

00000000: adfd ad2d 3030 74fa 86c4 d50a a803       ...-00t.......

Unassembled

AD         LODSW           ; SI += 2 to start with last two digits
FD         STD             ; set direction for LODSW to decrement
AD         LODSW           ; load two ASCII digit chars into AX
2D 3030    SUB  AX, '00'   ; convert to decimal, test if year ends in 00?
74 FA      JZ   -6         ; if so, look at the first two digits instead
86 C4      XCHG AL, AH     ; endian convert
D5 0A      AAD             ; base convert from 10 to binary
A8 03      TEST AL, 3      ; mod 4 = 0?

Input string in SI, output is ZF if is a leap year.

Explanation

If the year does not end in 00, it is a leap year if last two digits mod 4 is 0. If it does end in 00, it will be a leap year if the first two digits mod 4 is 0. Example:

Leap year:

  • 1936: 36 mod 4 == 0
  • 2400: 24 mod 4 == 0

NOT leap year:

  • 1805: 05 mod 4 == 1
  • 1900: 19 mod 4 == 3

Test Program Output

LEAP.COM test output

Download and test LEAP.COM.

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

SpecBAS - 77

Not the shortest (but not the longest either).

1 INPUT y: PRINT y;"->";"ny"((y MOD 4=0 AND (y MOD 100<>0) OR y MOD 400=0)+1)

Uses the standard formula, then prints "n" or "y" based on return value (the final +1 at the end is due to strings being 1-based).

\$\endgroup\$
  • \$\begingroup\$ I don't know the language, but based the fact that there are no booleans, you may be able to save some characters by using something like y MOD (4+12*(y MOD 100=0))=0. \$\endgroup\$ – lirtosiast May 28 '15 at 22:49
1
\$\begingroup\$

Python, 37 bytes

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

Python, 50 48 bytes

import calendar as y
def a(b):print(y.isleap(b))
\$\endgroup\$
1
\$\begingroup\$

C#, 26 bytes

y=>DateTime.IsLeapYear(y);

C# lambda (Predicate) where the input is a int and the output is a bool. I use a builtin.

\$\endgroup\$
  • \$\begingroup\$ You don't really need the lambda here, and I would argue the answer is more valid without it. \$\endgroup\$ – VisualMelon Jan 13 '17 at 9:26
  • \$\begingroup\$ @VisualMelon In the meta section, they ask for a function. (If I remember) \$\endgroup\$ – aloisdg moving to codidact.com Jan 14 '17 at 15:24
  • 4
    \$\begingroup\$ Aye, but DateTime.IsLeapYear is a function ;) generally the rule is that it has to evaluate to a function if it isn't named, and strictly your current submission is meaningless (join the argument here!), while System.DateTime.IsLeapYear is fully typed (System.Func<int,bool>A=System.DateTime.IsLeapYear compiles fine) without demanding any user inference (or indeed the text in your answer which specifies the input and output types). \$\endgroup\$ – VisualMelon Jan 14 '17 at 17:22
1
\$\begingroup\$

Java 8, 17 bytes

y->y%4<1&y%100>0;

It almost looks like a golfing language lol

\$\endgroup\$
  • \$\begingroup\$ Fails for input 2400... \$\endgroup\$ – Olivier Grégoire Jan 10 '19 at 9:39
  • \$\begingroup\$ The last 3 years of my life has been a lie \$\endgroup\$ – Shaun Wild Jan 11 '19 at 12:10
1
\$\begingroup\$

BASH, 68 bytes

((!(y % 4) && ( y % 100 || !(y % 400)))) &&  echo "leap" || echo "no"
\$\endgroup\$
1
\$\begingroup\$

Retina, 24 bytes

[^04]00$

.+
$*
....

^$

Try it online!

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

PHP, 45 bytes

<?=date_create($argv[1].'-1-1')->format('L');

Not the shortest, but using built in functions. Totally not code-golf.

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

Jelly, 8 bytes

ȷ2*ḍ¥×4ḍ

Try it online!

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

Bash, 14 bytes

date -d$1/2/29

Try it online!

Outputs via exit code, 0 for leap year and 1 otherwise.

date -d STRING will display the date indicated by STRING. $1/2/29 represents February 29th of $1, the argument. If STRING is not valid, i.e. Feb 29 does not exist, then date errors out.

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

Ruby, 22 bytes

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

Try it online!

The challenge is quite old, but I noticed there was no valid Ruby answer yet. Nothing particularly original, anyway.

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

D, 43 42 bytes

T l(T)(T y){return!(y%4)&&y%100+!(y%400);}

Try it online!

Another port of @HatsuPointerKun's C++ answer.

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

C++, 50 43 bytes

-7 bytes thanks to Zacharý

int l(int y){return!(y%4)&&y%100+!(y%400);}

And the test code is :

auto t = {
    1936,1805,1900,2272,2400
};

for (auto&a : t) {
    std::cout << "Year : " << a << " is " << (l(a) ? "" : "NOT") << " a leap year\n";
}
\$\endgroup\$
  • \$\begingroup\$ You can make it int l(int y){return(y%4==0&&y%100)+(y%400==0);} to save a few bytes \$\endgroup\$ – Zacharý Mar 29 '18 at 13:49
  • \$\begingroup\$ I think making +(y%400==0) +!(y%400) might work as well. \$\endgroup\$ – Zacharý Apr 1 '18 at 18:54
  • \$\begingroup\$ int l(int y){return!(y%4)&&y%100+!(y%400);} \$\endgroup\$ – Zacharý Nov 10 '18 at 20:21
1
\$\begingroup\$

Kotlin, 30 bytes

{it%4<1&&(it%100>0||it%400>0)}

Try it online!

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

Common Lisp, 46 bytes

(=(mod(setq x(read))(if(>(mod x 25)0)4 16))0)

Try it online!

Based on the David Hammen’s method.

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

MathGolf, 9 bytes

4♀`*]÷~≤*

Try it online!

Explanation

4         Push 4
 ♀        Push 100
  `*      Duplicate top two elements of stack and multiply (400)
    ]     Wrap stack in array ([4, 100, 400])
     ÷    Check input for divisibility with all array items
      ~   Dump array onto stack
       ≤  Check if divisibility by 100 is <= than divisibility with 400
        * Multiply with the divisibility bool for 4, works like logical and

The trick is that ensures that if a number is divisible by 100, it must also be divisible by 400, but if it's not divisible by 100, anything goes.

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

Clam, 33 31 bytes

=a*rp|e%a*"400"0&%a*"100"e%a*40

Try it online!

-2 bytes thanks to ASCII-only

Outputs true for leap years. Outputs false for other years

Explanation

=a*rp|e%a*"400"0&%a*"100"e%a*40
=a*r                             read input and store in a*
    p                            Print..
       %a*"400"                    a* % 400
      e                            ==
               0                   0
     |                             OR
                 %a*"100"            a* % 100
                &                    AND
                          %a*4       a* % 4
                         e           ==
                              0      0

Very awkward explanation, but basically what it does is this:

print(year % 400 == 0 || (year % 100 && year % 4 == 0))

Clam follows JS rules for truthy and falsey values, meaning year % 100 is true if it does not equal 0 (and it's shorter than adding an e before it and an 0 after it)

Resulting JS:

myVar = read();
console.log(year % 400 == 0 || (year % 100 && year % 4 == 0));
\$\endgroup\$
  • \$\begingroup\$ ew 8552. use something nicer like 4545 pls \$\endgroup\$ – ASCII-only Jan 8 '19 at 6:18
  • \$\begingroup\$ jk, 31 \$\endgroup\$ – ASCII-only Jan 8 '19 at 6:19
  • \$\begingroup\$ also pls fix your indentation in the explanation :| \$\endgroup\$ – ASCII-only Jan 8 '19 at 6:27
  • \$\begingroup\$ fixed that year % 100 thing \$\endgroup\$ – ASCII-only Jan 8 '19 at 6:42
1
\$\begingroup\$

Japt -!, 8 5 bytes

Locale dependent.

ÐUT k

Try it

\$\endgroup\$
  • \$\begingroup\$ You can do ÐUT91 Îv to output 1 for leap year and 0 for non-leap year. \$\endgroup\$ – Oliver Jan 8 '19 at 17:56
  • \$\begingroup\$ @Oliver, yeah, I suppose it would be clearer if I reversed the output. Updated. I came up with a few other similar alternatives, all relying on new Date rolling over. \$\endgroup\$ – Shaggy Jan 8 '19 at 18:05
  • \$\begingroup\$ @Oliver, found a shorter way. \$\endgroup\$ – Shaggy Jan 8 '19 at 18:31
  • 1
    \$\begingroup\$ Every test case is returning false for me. \$\endgroup\$ – Oliver Jan 8 '19 at 19:35
  • 1
    \$\begingroup\$ Why would a leap year be locale dependent? \$\endgroup\$ – Oliver Jan 8 '19 at 19:41
1
\$\begingroup\$

Japt -h!, 8 bytes

Input is taken as a string.

k0 ò o%4

Try it online!

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

Haskell, 35 bytes

l x|x!25<1=x!16<1
l x=x!4<1
(!)=mod

Try it online!

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

PHP, 35 34 bytes

-1 byte thanks to 640KB

<?=date(L,strtotime($argv[1].-1));

Try it online!

Came across the L option in the PHP date formatter, which returns if the year of the date is a leap year. After that, it was just a matter of trying to get the timestamp of the year in the shortest way (though I'm not too confident this is the shortest)

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

Reg, 14 bytes

1¿:%[4|]%[;]

Try it online!

How it works (because it contains unprintable characters)

\$\endgroup\$
  • \$\begingroup\$ Maybe leave a note as to why you've spelt it Reg when the link goes to Keg, so people like me don't think you've just made a typo. \$\endgroup\$ – Jo King Aug 15 '19 at 7:20
  • \$\begingroup\$ Okay. We have decided to rename "Unofficial Keg" as "Reg." \$\endgroup\$ – a'_' Aug 15 '19 at 7:33

Your Answer

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