How to detect a leap year?

Status
Not open for further replies.

alphacat

New Member
Hey,
What is a simple way to detect a leap year?
i mean in code.

I'm writing an application in C language and am not sure how to do it in a simple way.

Thanks.
 
Hey,
What is a simple way to detect a leap year?
i mean in code.

I'm writing an application in C language and am not sure how to do it in a simple way.

Thanks.
except in century years, like 2000, take the 4 digit year value and divide by 4, if no reminder, then a leap year
 
I use a similar method. In the comments below, when year & 3 == 0 it's a leap year...

Regards, Mike

Code:
;******************************************************************
;*                                                                *
;*  Day_of_Week, 2000-2099           Mike McLaren, K8LH, Aug '07  *
;*                                                                *
;*  preset: Month (1..12), Day (1..31), Year (0..99) vars'        *
;*  return: W = 0..6 (Sun..Sat)                                   *
;*                                                                *
;*  39 words, 1 local variable (14 bit core)                      *
;******************************************************************
        radix dec
;
;  char Month;                  // 1..12
;  char Day;                    // 1..31
;  char Year;                   // 0..99 (2000-2099)
;
;  char DayOfWeek()             // Mike McLaren, K8LH, Aug '07
;  {                            // returns 0..6 (Sun..Sat)
;    char Leap;
;    const rom char Base[] = { 5, 1, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3 };
;    Leap = (Year & 3) || (Month > 2);
;    return (Base[Month-1] + Day + Leap + Year + Year/4) % 7;
;  }
;
DayOfWeek
        clrf    Leap            ; Leap = 0                        |B0
        movf    Month,W         ; get Month (1..12)               |B0
        addlw   -3              ; C = 0 if Jan or Feb             |B0
        movf    Year,W          ; W = Year (0..99)                |B0
        andlw   b'00000011'     ; is this a leap year?            |B0
        skpz                    ; yes, skip, else                 |B0
        setc                    ; set C (force Leap = 1)          |B0
        rlf     Leap,F          ; Leap = 0 or 1                   |B0
;
;  an "in-line table" of DOW values minus 1 for the 1st of each
;  month in 2000, a leap year.  1st param is desired value, 2nd
;  param cancels out WREG, and 3rd param cancels out next table
;  entry.  an "in-line" table saves me 1 word and 1 stack level
;  but uses more cycles for lower table index values.  the "in-
;  line table" is 256-byte-boundary tolerant.
;
;  WREG = Y2000[Month-1]
;
        movlw   high (Y2000)    ;                                 |B0
        movwf   PCLATH          ;                                 |B0
        decf    Month,W         ;                                 |B0
        addlw   low (Y2000)     ;                                 |B0
        skpnc                   ;                                 |B0
        incf    PCLATH,F        ;                                 |B0
        movwf   PCL             ;                                 |B0
Y2000   xorlw   5^$^(1^$+1)     ; 6 (Jan 2000)                    |B0
        xorlw   1^$^(1^$+1)     ; 2 (Feb)                         |B0
        xorlw   1^$^(4^$+1)     ; 2 (Mar)                         |B0
        xorlw   4^$^(6^$+1)     ; 5 (Apr)                         |B0
        xorlw   6^$^(2^$+1)     ; 0 (May)                         |B0
        xorlw   2^$^(4^$+1)     ; 3 (Jun)                         |B0
        xorlw   4^$^(0^$+1)     ; 5 (Jul)                         |B0
        xorlw   0^$^(3^$+1)     ; 1 (Aug)                         |B0
        xorlw   3^$^(5^$+1)     ; 4 (Sep)                         |B0
        xorlw   5^$^(1^$+1)     ; 6 (Oct)                         |B0
        xorlw   1^$^(3^$+1)     ; 2 (Nov)                         |B0
        xorlw   3^$             ; 4 (Dec)                         |B0
;
;  WREG = (((Y2000[Month-1]+Day+Leap)*2 + Year/2)/2 + Year) % 7
;
        addwf   Day,W           ; add Day (1..31)                 |B0
        addwf   Leap,F          ; add Leap (0 or 1), C=0          |B0
        rlf     Leap,F          ; multiply by 2, C=0              |B0
        rrf     Year,W          ; divide year by 2                |B0
        addwf   Leap,F          ; add 'em together, C=0           |B0
        rrf     Leap,W          ; divide result by 2              |B0
        addwf   Year,W          ; add Year (0..99)                |B0
Mod7    addlw   -7              ; result % 7                      |B0
        bc      Mod7            ;                                 |B0
        addlw   7               ;                                 |B0
        return                  ; W = 0..6 (Sun..Sat)             |B0
;
 
Last edited:
Hi there,



Those code entries are probably valid enough, but you should know that there
are some years that are divisible by 4 but are not leap years. This is because
the leap year was introduced to make an approximation to the number of
days in a year over the span of 4 years, which is an error correction.
Another error correction needs to be applied for the years that do not require
this error correction.
From memory, i think it was every 100 years we do NOT have a leap year
unless that year is ALSO divisible by 400.
You should verify this number (400) on the web.

The code change would be simple similar to this:
Code:
if integer(year/4)=year/4 then
  if integer(year/100)!=year/100 then
    DoLeapYear()
  else
    if integer(year/400)=year/400 then
       DoLeapYear()
    end if
  end if
end if
For example:

The years 2000 and 2400 are leap years, but 2100, 2200, and 2300 are not.

Note there would have to be another correction after something like 2400 or 2800 years,
but i dont think anyone is worried about that.
 
Last edited:
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…