Continue to Site

# 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)                      *
;******************************************************************
;
;  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
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, 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
;
rlf     Leap,F          ; multiply by 2, C=0              |B0
rrf     Year,W          ; divide year by 2                |B0
rrf     Leap,W          ; divide result by 2              |B0
Mod7    addlw   -7              ; result % 7                      |B0
bc      Mod7            ;                                 |B0
return                  ; W = 0..6 (Sun..Sat)             |B0
;

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.

Replies
33
Views
11K
Replies
7
Views
4K
Replies
15
Views
3K
Replies
10
Views
4K
Replies
15
Views
5K