What is a quick way of working out if a year happens to be a leap year?

Here’s my first attempt


SQL> create or replace
  2  function f1(y number) return boolean is
  3    x date;
  4  begin
  5    x := to_date('2902'||y,'ddmmyyyy');
  6    return true;
  7  exception
  8    when others then return false;
  9  end;
 10  /

Function created.

However, whatever the context, relying on an exception handler to determine a result can often have performance consequences. Let’s give that routine a hammering


SQL> set timing on
SQL> declare
  2    l boolean;
  3  begin
  4   for i in 1 .. 1000 loop
  5     for j in 1600 .. 2300 loop
  6       l := f1(j);
  7     end loop;
  8   end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:11.28

If possible, avoiding the “break and jump to an exception” will be a more efficient way of doing things in PL/SQL. Here’s an alterative version taking advantage of the LAST_DAY function


SQL> create or replace
  2  function f2(y number) return boolean is
  3  begin
  4    return to_char(last_day(to_date('0102'||y,'ddmmyyyy')),'DD') = '29';
  5  end;
  6  /

Function created.

SQL> declare
  2    l boolean;
  3  begin
  4   for i in 1 .. 1000 loop
  5     for j in 1600 .. 2300 loop
  6       l := f2(j);
  7     end loop;
  8   end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.00

Then again, sometimes its best to use good old simple mathematics rather than date functions 😁


SQL>
SQL> create or replace
  2  function f3(y number) return boolean is
  3  begin
  4    return mod(y,4)=0 and ( mod(y,100) != 0 or mod(y,400) = 0 );
  5  end;
  6  /

Function created.

SQL> set timing on
SQL> declare
  2    l boolean;
  3  begin
  4   for i in 1 .. 1000 loop
  5     for j in 1600 .. 2300 loop
  6       l := f3(j);
  7     end loop;
  8   end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.17
SQL>

Moral of the story

1 – EXCEPTIONS are designed for exceptional cases, not the norm

2 – If you are calculating leap years 1000s of times per second, I need to ask what your business requirement is. 😁

Ho Ho Ho! Merry Christmas!

2 responses to “Kris Kringle the Database – Taking the LEAP”

  1. sqlmonster7621ed93a5 Avatar
    sqlmonster7621ed93a5

    Why don’t Oracle just provide a function for this?

  2. iudithd5bf8e4d8d Avatar
    iudithd5bf8e4d8d

    Hi Connor,

    Just for fun, a similar function to your F2, which seems to be just a tiny little bit faster (~ 30 milliseconds for your test):

    create or replace
    function f4 (y number) return boolean is
    begin
    return to_char(to_date(‘3112’||y,’ddmmyyyy’), ‘DDD’) = ‘366’;
    end;
    /

    Go figure …

    Cheers & Best Regards,
    Iudith
    |

Got some thoughts? Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Trending