A historical mistake and how you can solve it TL;DR: Most languages fail to find the correct behavior for leap year calculation. Disclaimer: While I've tried my best to provide accurate insights across various programming languages, I acknowledge that I may not be an expert in everyone. If you spot an error or disagree with any points, please leave a respectful comment, and I'll promptly address it. The State of the Art Determining whether a year is a leap (or not) is a simple mathematical problem. Every student can solve it as their first programming assignment. To simplify the problem, let's assume a Year is when it is evenly divisible by 4, except if it's also divisible by 100, but it is a leap year if it's divisible by 400. leap The real world and cosmic mechanics are a bit more complicated, but that is beyond the scope of this article. Let's explore how several programming languages solve this problem: Horrible Approach PHP: <?php $yearNumber = 2024; $isLeap = date('L', mktime(0, 0, 0, 1, 1, $yearNumber)); SQL (PostgreSQL): SELECT (EXTRACT(year FROM TIMESTAMP '2024-02-29') IS NOT NULL) AS is_leap_year; These languages attempt to create a valid (or invalid) leap day and exploit . truthy values This hack violates the fail-fast principle and abuses the . billion-dollar mistake Trying to create an invalid date should throw an exception in serious languages since this happens in the . real world domain Performing other actions, like concealing errors beneath the surface, breaches the principle of least astonishment. Missing Behavior Ada: function Is_Leap_Year (Year : Integer) return Boolean is begin return (Year mod 4 = 0 and then Year mod 100 /= 0) or else (Year mod 400 = 0); end Is_Leap_Year; C/C++: bool isLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } Go: package main import ( "fmt" "time" ) func isLeapYear(year int) bool { return year%4 == 0 && (year%100 != 0 || year%400 == 0) } Haskell: import Data.Time.Calendar (isLeapYear) let year = 2024 let isLeap = isLeapYear year JavaScript/TypeScript: function isLeapYear(year) { return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0); } Julia: using Dates year = 2024 isleap(year) Lua: local year = 2024 local isLeap = (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0) MATLAB: year = 2024; isLeap = mod(year, 4) == 0 && (mod(year, 100) ~= 0 || mod(year, 400) == 0); Objective-C: int yearNumber = 2024; BOOL isLeap = (yearNumber % 4 == 0 && yearNumber % 100 != 0) || (yearNumber % 400 == 0); PowerShell: $yearNumber = 2024 $isLeap = ($yearNumber % 4 -eq 0 -and $yearNumber % 100 -ne 0) -or ($yearNumber % 400 -eq 0) Rust: fn is_leap_year(year: i32) -> bool { (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) } Smalltalk: | yearNumber | yearNumber := 2024. (yearNumber \\ 4 = 0) and: [(yearNumber \\ 100 ~= 0) or: [ yearNumber \\ 400 = 0 ]] The above languages do not provide native support. You need to define global functions or use . helpers Incorrect Global Approach PHP (Again): <?php $yearNumber = 2024; $isLeap = checkdate(2, 29, $yearNumber); R: leap_year(2024) Ruby: year = 2024 is_leap = Date.leap?(year) Swift: let yearNumber = 2024 let isLeap = Calendar.current.isDateInLeapYear( Date(timeIntervalSince1970: TimeInterval(yearNumber))) These languages use to check if a year is a leap. global functions These global methods mistakenly place responsibility in the wrong location (a global access point). utility Helpers Bad Approach C#: int yearNumber = 2024; bool isLeap = System.DateTime.IsLeapYear(yearNumber); Dart: import 'package:intl/intl.dart'; var year = 2024; var isLeap = DateTime(year).isLeapYear; Perl: use Time::Piece; my $yearNumber = 2024; my $isLeap = Time::Piece ->strptime("$yearNumber-01-01", "%Y-%m-%d")->leapyear; Python: import calendar leap = calendar.isleap(2024) Visual Basic .NET: Dim year As Integer = 2024 Dim isLeap As Boolean = DateTime.IsLeapYear(year) These languages use as libraries to check if a year is a leap. helpers The is not present in a real object but in a bag of . misplaced responsibly DateTime related functions The Year Approach Java: int yearNumber = 2024; boolean isLeap = java.time.Year.of(yearNumber).isLeap(); Kotlin: val yearNumber = 2024 val isLeap = java.time.Year.of(yearNumber).isLeap Scala: val year = 2024 val isLeap = java.time.Year.of(year).isLeap These languages rely on the to check if it is a leap. Year The protocol is closer to the real world in the bijection Notice they create objects and not objects since this would also break the . Year Integer bijection A has a different protocol than an integer, and modeling a Year as an integer would also be a smell and a symptom of mixing . Year premature optimization the what and the how A can tell if it is a leap (an integer shouldn't do it) and can tell you about its months (which are , not integers, 1-based integers, or strings). Year Months 0-based Conversely, an 's capabilities extend to arithmetic operations such as multiplication and exponentiation. Integer Time is not a joke Representing a point in time as a , , or any other data type comes with consequences. float integer You can break a point in time in the real world in tiny fractions (but not ) too small Using is not a valid option. floats is not 0.03, and this has terrible consequences points in time. 0.01 + 0.02 dealing with floating point The Challenge We've been talking about leap years. What are the needs to know if a year is a leap? The date and time mechanics you model need to know the February 28th, 2024 successor. But this is your problem. NOT Following the information hiding principle, you should leave the responsibility as a private protocol. Conclusion There is no . Silver Bullet Use your language wisely. Today is February 29th, a leap day to pause and reflect on the tools you use daily. See you in 4 years.