Chinese zodiac

From Rosetta Code
Task
Chinese zodiac
You are encouraged to solve this task according to the task description, using any language you may know.
Determine the Chinese zodiac sign and related associations for a given year.

Traditionally, the Chinese have counted years using two lists of labels, one of length 10 (the "celestial stems") and one of length 12 (the "terrestrial branches"). The labels do not really have any meaning outside their positions in the two lists; they're simply a traditional enumeration device, used much as Westerners use letters and numbers. They were historically used for months and days as well as years, and the stems are still sometimes used for school grades.

Years cycle through both lists concurrently, so that both stem and branch advance each year; if we used Roman letters for the stems and numbers for the branches, consecutive years would be labeled A1, B2, C3, etc. Since the two lists are different lengths, they cycle back to their beginning at different points: after J10 we get A11, and then after B12 we get C1. The result is a repeating 60-year pattern within which each pair of names occurs only once.

Mapping the branches to twelve traditional animal deities results in the well-known "Chinese zodiac", assigning each year to a given animal. For example, Sunday, January 22, 2023 CE (in the common Gregorian calendar) began the lunisolar Year of the Rabbit.

The celestial stems do not have a one-to-one mapping like that of the branches to animals; however, the five pairs of consecutive stems are each associated with one of the five traditional Chinese elements (Wood, Fire, Earth, Metal, and Water). Further, one of the two years within each element is assigned to yin, the other to yang.

Thus, the Chinese year beginning in 2023 CE is also the yin year of Water. Since 12 is an even number, the association between animals and yin/yang doesn't change; consecutive Years of the Rabbit will cycle through the five elements, but will always be yin.

Task
Create a subroutine or program that will return or output the animal, yin/yang association, and element for the lunisolar year that begins in a given CE year.

You may optionally provide more information in the form of the year's numerical position within the 60-year cycle and/or its actual Chinese stem-branch name (in Han characters or Pinyin transliteration).

Requisite information
  • The animal cycle runs in this order: Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, Monkey, Rooster, Dog, Pig.
  • The element cycle runs in this order: Wood, Fire, Earth, Metal, Water.
  • Each element gets two consecutive years; a yang followed by a yin.
  • The current 60-year cycle began in 1984; any multiple of 60 years from that point may be used to reckon from.

Thus, year 1 of a cycle is the year of the Wood Rat (yang), year 2 the Wood Ox (yin), and year 3 the Fire Tiger (yang). The year 2023 - which, as already noted, is the year of the Water Rabbit (yin) - is the 40th year of the current cycle.

Information for optional task
  • The ten celestial stems are jiă, , bĭng, dīng, , , gēng, xīn, rén, and gŭi. With the ASCII version of Pinyin tones, the names are written "jia3", "yi3", "bing3", "ding1", "wu4", "ji3", "geng1", "xin1", "ren2", and "gui3".
  • The twelve terrestrial branches are , chŏu, yín, măo, chén, , , wèi, shēn, yŏu, , hài. In ASCII Pinyin, those are "zi3", "chou3", "yin2", "mao3", "chen2", "si4", "wu3", "wei4", "shen1", "you3", "xu1", and "hai4".

Therefore 1984 was 甲子 (jiă-zĭ, or jia3-zi3). 2023 is 癸卯 (gŭi-măo or gui3-mao3).

11l

Translation of: C++
V animals = [‘Rat’, ‘Ox’, ‘Tiger’, ‘Rabbit’, ‘Dragon’, ‘Snake’, ‘Horse’, ‘Goat’, ‘Monkey’, ‘Rooster’, ‘Dog’, ‘Pig’]
V elements = [‘Wood’, ‘Fire’, ‘Earth’, ‘Metal’, ‘Water’]

F getElement(year)
   R :elements[(year - 4) % 10 I/ 2]

F getAnimal(year)
   R :animals[(year - 4) % 12]

F getYY(year)
   I year % 2 == 0
      R ‘yang’
   E
      R ‘yin’

L(year) [1935, 1938, 1968, 1972, 1976, 2017]
   print(year‘ is the year of the ’getElement(year)‘ ’getAnimal(year)‘ (’getYY(year)‘).’)
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
2017 is the year of the Fire Rooster (yin).

360 Assembly

Translation of: VBScript
*        Chinese zodiac            10/03/2019
CHINEZOD CSECT
         USING  CHINEZOD,R13       base register
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         SAVE   (14,12)            save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,=A(NY))   do i=1 to hbound(years)
         LR     R1,R6                i
         SLA    R1,2                 *4
         L      R2,YEARS-4(R1)       ~
         ST     R2,YEAR              year=years(i)
         SH     R2,=H'4'             -4
         LR     R7,R2                year-4
         SRDA   R2,32                ~
         D      R2,=F'10'            /10
         SRA    R2,1                 /2
         MH     R2,=H'6'             *6
         LA     R1,ELEMENTS(R2)      ~
         MVC    ELEMENT,0(R1)      element=elements(mod(year-4,10)/2+1)
         LR     R2,R7                year-4
         SRDA   R2,32                ~
         D      R2,=F'12'            /12
         SLA    R2,3                 *8
         LA     R1,ANIMALS(R2)       ~
         MVC    ANIMAL,0(R1)         animal=animals(mod(year-4,12)+1)
         L      R2,YEAR              year
         SRDA   R2,32                ~
         D      R2,=F'2'             /2
         SLA    R2,2                 *4
         LA     R1,YINYANGS(R2)      ~
         MVC    YINYANG,0(R1)        yinyang=yinyangs(mod(year,2)+1)
         LR     R2,R7                year-4
         SRDA   R2,32                ~
         D      R2,=F'60'            /60
         LA     R2,1(R2)             nn=mod(year-4,60)+1
         L      R1,YEAR              year
         XDECO  R1,XDEC              edit year
         MVC    PG+00(4),XDEC+8      output year
         MVC    PG+24(6),ELEMENT     output element
         MVC    PG+31(8),ANIMAL      output animal
         MVC    PG+41(4),YINYANG     output yinyang
         XDECO  R2,XDEC              edit nn
         MVC    PG+49(2),XDEC+10     output nn
         XPRNT  PG,L'PG              print buffer
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       restore previous savearea pointer
         RETURN (14,12),RC=0       restore registers from calling sav
NY       EQU    (ANIMAL-YEARS)/4
ANIMALS  DC     CL8'Rat',CL8'Ox',CL8'Tiger',CL8'Rabbit'
         DC     CL8'Dragon',CL8'Snake',CL8'Horse',CL8'Goat'
         DC     CL8'Monkey',CL8'Rooster',CL8'Dog',CL8'Pig'
ELEMENTS DC     CL6'Wood',CL6'Fire',CL6'Earth',CL6'Metal',CL6'Water'
YINYANGS DC     CL4'Yang',CL4'Yin'
YEARS    DC     F'1935',F'1938',F'1968',F'1972',F'1976',F'1984',F'2017'
ANIMAL   DS     CL8
ELEMENT  DS     CL6
YINYANG  DS     CL4
YEAR     DS     F
PG    DC   CL80':::: is the year of the :::::: :::::::: (::::).  ::/60'
XDEC     DS     CL12               temp for xdeco
         REGEQU
         END    CHINEZOD
Output:
1935 is the year of the Wood   Pig      (Yin ).  12/60
1938 is the year of the Earth  Tiger    (Yang).  15/60
1968 is the year of the Earth  Monkey   (Yang).  45/60
1972 is the year of the Water  Rat      (Yang).  49/60
1976 is the year of the Fire   Dragon   (Yang).  53/60
1984 is the year of the Wood   Rat      (Yang).   1/60
2017 is the year of the Fire   Rooster  (Yin ).  34/60

Action!

DEFINE PTR="CARD"

PTR ARRAY animals(12),elements(5),stems(10),branches(12),yinYangs(2)

PROC Init()
  animals(0)="Rat"    animals(1)="Ox"
  animals(2)="Tiger"  animals(3)="Rabbit"
  animals(4)="Dragon" animals(5)="Snake"
  animals(6)="Horse"  animals(7)="Goat"
  animals(8)="Monkey" animals(9)="Rooster"
  animals(10)="Dog"   animals(11)="Pig"
  elements(0)="Wood"  elements(1)="Fire"
  elements(2)="Earth" elements(3)="Metal"
  elements(4)="Water"
  stems(0)="jia"      stems(1)="yi"
  stems(2)="bing"     stems(3)="ding"
  stems(4)="wu"       stems(5)="ji"
  stems(6)="geng"     stems(7)="xin"
  stems(8)="ren"      stems(9)="gui"
  branches(0)="zi"    branches(1)="chou"
  branches(2)="yin"   branches(3)="mao"
  branches(4)="chen"  branches(5)="si"
  branches(6)="wu"    branches(7)="wei"
  branches(8)="shen"  branches(9)="you"
  branches(10)="xu"   branches(11)="hai"
  yinYangs(0)="Yang"  yinYangs(1)="Yin"
RETURN

PTR FUNC GetAnimal(INT y)
RETURN (animals((y-4) MOD 12))

PTR FUNC GetElement(INT y)
RETURN (elements(((y-4) MOD 10)/2))

PTR FUNC GetStem(INT y)
RETURN (stems((y-4) MOD 10))

PTR FUNC GetBranch(INT y)
RETURN (branches((y-4) MOD 12))

PTR FUNC GetYinYang(INT y)
RETURN (yinYangs(y MOD 2))

BYTE FUNC GetCycle(INT y)
RETURN ((y-4) MOD 60+1)

PROC Main()
  INT ARRAY years=[1935 1938 1968 1972 1976 1984 2017 2021]
  CHAR ARRAY s
  BYTE i,c
  INT y

  Init()
  FOR i=0 TO 7
  DO
    y=years(i)
    PrintI(y) Print(" ")
    s=GetStem(y) Print(s) Print("-")
    s=GetBranch(y) Print(s) Print(" ")
    s=GetElement(y) Print(s) Print(" ")
    s=GetAnimal(y) Print(s) Print(" ")
    s=GetYinYang(y) Print(s) Print(" ")
    c=GetCycle(y) PrintB(c) Print("/60") PutE()
  OD
RETURN
Output:

Screenshot from Atari 8-bit computer

1935 yi-hai Wood Pig Yin 12/60
1938 wu-yin Earth Tiger Yang 15/60
1968 wu-shen Earth Monkey Yang 45/60
1972 ren-zi Water Rat Yang 49/60
1976 bing-chen Fire Dragon Yang 53/60
1984 jia-zi Wood Rat Yang 1/60
2017 ding-you Fire Rooster Yin 34/60
2021 xin-chou Metal Ox Yin 38/60

Ada

Works with: GNAT version 8.3.0
with Ada.Text_IO; 	    use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is

	type Element_Index is mod 5;
	type Animal_Index  is mod 12;
	type Stem_Index    is mod 10;
	
	type Animal_Array  is array(Animal_Index  range <>) of Unbounded_String;
	type Element_Array is array(Element_Index range <>) of Unbounded_String;
	type Stem_Array    is array(Stem_Index    range <>) of Unbounded_String;

	
	Ani_Arr : 	Animal_Array 	:= 	(To_Unbounded_String ("Rat"),
						 To_Unbounded_String ("Ox"),
						 To_Unbounded_String ("Tiger"),
						 To_Unbounded_String ("Rabbit"),
						 To_Unbounded_String ("Dragon"),
						 To_Unbounded_String ("Snake"),
						 To_Unbounded_String ("Horse"),
						 To_Unbounded_String ("Sheep"),
						 To_Unbounded_String ("Monkey"),
						 To_Unbounded_String ("Rooster"),
						 To_Unbounded_String ("Dog"),
						 To_Unbounded_String ("Pig"));
								 
	Bra_Arr :	Animal_Array	:=      (To_Unbounded_String ("子"),
					         To_Unbounded_String ("丑"),
					         To_Unbounded_String ("寅"),
				                 To_Unbounded_String ("卯"),
					         To_Unbounded_String ("辰"),
					         To_Unbounded_String ("巳"),
					         To_Unbounded_String ("午"),
					         To_Unbounded_String ("未"),
					         To_Unbounded_String ("申"),
					         To_Unbounded_String ("酉"),
					         To_Unbounded_String ("戌"),
					         To_Unbounded_String ("亥"));
	
	Ele_Arr : 	Element_Array 	:= 	(To_Unbounded_String ("Wood"),
						 To_Unbounded_String ("Fire"),
						 To_Unbounded_String ("Earth"),
						 To_Unbounded_String ("Metal"),
						 To_Unbounded_String ("Water"));
							 
	Ste_Arr :	Stem_Array	:= 	(To_Unbounded_String ("甲"),
						 To_Unbounded_String ("乙"),
						 To_Unbounded_String ("丙"),
						 To_Unbounded_String ("丁"),
						 To_Unbounded_String ("戊"),
						 To_Unbounded_String ("己"),
						 To_Unbounded_String ("庚"),
						 To_Unbounded_String ("辛"),
						 To_Unbounded_String ("壬"),
						 To_Unbounded_String ("癸"));
									  
	procedure Sexagenary (Year : Positive) is
		Base_Year : Positive := 1984;
		Temp      : Natural  := abs (Base_Year - Year);
		Temp_Float: Float    := 0.0;
		
		Ele_Idx   : Element_Index    := Element_Index'First;
		Ani_Idx   : Animal_Index     := Animal_Index'First;
		Ste_Idx   : Stem_Index       := Stem_Index'First;
		Result    : Unbounded_String := Null_Unbounded_String;
		begin
			Result := Result & Year'Image & " is the year of ";
			
			if Year >= Base_Year then
				Temp_Float := Float'Floor (Float (Temp) / Float (2));
				Ele_Idx    := Element_Index (Natural (Temp_Float) mod 5);
				Result     := Result & Ele_Arr (Ele_Idx) & " ";
				
				Ani_Idx := Animal_Index (Temp mod 12);
				Result  := Result & Ani_Arr (Ani_Idx) & " ";
			elsif Year < Base_Year then
				Temp_Float := Float'Ceiling (Float (Temp) / Float (2));
				Ele_Idx    := Ele_Idx - Element_Index (Natural (Temp_Float) mod 5);
				Result     := Result & Ele_Arr (Ele_Idx) & " ";
				
				Ani_Idx := Ani_Idx - Animal_Index (Temp mod 12);
				Result  := Result & Ani_Arr (Ani_Idx) & " ";
			end if;
			
			if Year mod 2 = 0 then
				Result := Result & "(yang). ";
			else
				Result := Result & "(yin). ";
			end if;
            
			Ani_Idx := Animal_Index'First;

			if Year >= Base_Year then
				Ste_Idx := Stem_Index (Temp mod 10);
				Result  := Result & Ste_Arr (Ste_Idx);
				
				Ani_Idx := Animal_Index (Temp mod 12);
				Result  := Result & Bra_Arr (Ani_Idx);			
			elsif Year < Base_Year then
				Ste_Idx := Ste_Idx - Stem_Index (Temp mod 10);
				Result  := Result & Ste_Arr (Ste_Idx);			
			
				Ani_Idx := Ani_Idx - Animal_Index (Temp mod 12);
				Result  := Result & Bra_Arr (Ani_Idx);
			end if;
			
			Put (To_String (Result));
	end Sexagenary;
	
    arr : array(Positive range <>) of Positive := (1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017);
begin
    for I of arr loop
        Sexagenary (I);
        New_Line;
    end loop;
end Main;
Output:
 1935 is the year of Wood Pig (yin). 乙亥
 1938 is the year of Earth Tiger (yang). 戊寅
 1968 is the year of Earth Monkey (yang). 戊申
 1972 is the year of Water Rat (yang). 壬子
 1976 is the year of Fire Dragon (yang). 丙辰
 1984 is the year of Wood Rat (yang). 甲子
 1985 is the year of Wood Ox (yin). 乙丑
 2017 is the year of Fire Rooster (yin). 丁酉

ALGOL 68

Translation of: AWK
BEGIN # Chinese Zodiac #
    # returns s right-padded with blanks to w characters, or s if s is already at least w characters long #
    PRIO PAD = 1;
    OP   PAD = ( STRING s, INT w )STRING:
         BEGIN
            STRING result := s;
            WHILE ( ( UPB result + 1 ) - LWB s ) < w DO result +:= " " OD;
            result
         END # PAD # ;
    []STRING animal name  = ( "Rat",   "Ox",   "Tiger",  "Rabbit",  "Dragon", "Snake"
                            , "Horse", "Goat", "Monkey", "Rooster", "Dog",    "Pig"
                            );
    []STRING element name = ( "Wood",  "Fire", "Earth",  "Metal",   "Water" );
    []INT    test year    = ( 1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017 );
    print( ( "year element animal  aspect", newline ) );
    FOR i FROM LWB test year TO UPB test year DO
        INT    year    = test year[ i ];
        STRING element = element name[ ( ( year - 4 ) MOD 10 OVER 2 ) + 1 ];
        STRING animal  = animal name[    ( year - 4 ) MOD 12          + 1 ];
        STRING yy      = IF ODD year THEN "Yin" ELSE "Yang" FI;
        print( ( whole( year, -4 ), " ", element PAD 7, " ", animal PAD 7, " ", yy, newline ) )
    OD
END
Output:
year element animal  aspect
1935 Wood    Pig     Yin
1938 Earth   Tiger   Yang
1968 Earth   Monkey  Yang
1972 Water   Rat     Yang
1976 Fire    Dragon  Yang
1984 Wood    Rat     Yang
1985 Wood    Ox      Yin
2017 Fire    Rooster Yin

AppleScript

Translation of: JavaScript
Translation of: Haskell
on run
    
    -- TRADITIONAL STRINGS ---------------------------------------------------
    
    -- ts :: Array Int (String, String)            -- 天干 tiangan – 10 heavenly stems
    set ts to zip(chars("甲乙丙丁戊己庚辛壬癸"), ¬
        |words|("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi"))
    
    -- ds :: Array Int (String, String)            -- 地支 dizhi – 12 terrestrial branches
    set ds to zip(chars("子丑寅卯辰巳午未申酉戌亥"), ¬
        |words|("zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài"))
    
    -- ws :: Array Int (String, String, String)    -- 五行 wuxing – 5 elements
    set ws to zip3(chars("木火土金水"), ¬
        |words|("mù huǒ tǔ jīn shuǐ"), ¬
        |words|("wood fire earth metal water"))
    
    -- xs :: Array Int (String, String, String)    -- 十二生肖 shengxiao – 12 symbolic animals
    set xs to zip3(chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬"), ¬
        |words|("shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū"), ¬
        |words|("rat ox tiger rabbit dragon snake horse goat monkey rooster dog pig"))
    
    -- ys :: Array Int (String, String)            -- 阴阳 yinyang
    set ys to zip(chars("阳阴"), |words|("yáng yīn"))
    
    
    -- TRADITIONAL CYCLES ----------------------------------------------------
    
    script cycles
        on |λ|(y)
            set iYear to y - 4
            set iStem to iYear mod 10
            set iBranch to iYear mod 12
            set {hStem, pStem} to item (iStem + 1) of ts
            set {hBranch, pBranch} to item (iBranch + 1) of ds
            set {hElem, pElem, eElem} to item ((iStem div 2) + 1) of ws
            set {hAnimal, pAnimal, eAnimal} to item (iBranch + 1) of xs
            set {hYinyang, pYinyang} to item ((iYear mod 2) + 1) of ys
            
            {{show(y), hStem & hBranch, hElem, hAnimal, hYinyang}, ¬
                {"", pStem & pBranch, pElem, pAnimal, pYinyang}, ¬
                {"", show((iYear mod 60) + 1) & "/60", eElem, eAnimal, ""}}
        end |λ|
    end script
    
    -- FORMATTING ------------------------------------------------------------
    
    -- fieldWidths :: [[Int]]
    set fieldWidths to {{6, 10, 7, 8, 3}, {6, 11, 8, 8, 4}, {6, 11, 8, 8, 4}}
    
    script showYear
        script widthStringPairs
            on |λ|(nscs)
                set {ns, cs} to nscs
                zip(ns, cs)
            end |λ|
        end script
        
        script justifiedRow
            on |λ|(row)
                script
                    on |λ|(ns)
                        set {n, s} to ns
                        justifyLeft(n, space, s)
                    end |λ|
                end script
                
                concat(map(result, row))
            end |λ|
        end script
        
        on |λ|(y)
            unlines(map(justifiedRow, ¬
                map(widthStringPairs, ¬
                    zip(fieldWidths, |λ|(y) of cycles))))
        end |λ|
    end script
    
    -- TEST OUTPUT -----------------------------------------------------------
    intercalate("\n\n", map(showYear, {1935, 1938, 1968, 1972, 1976, 1984, 2017}))
end run


-- GENERIC FUNCTIONS ---------------------------------------------------------

-- chars :: String -> [String]
on chars(s)
    characters of s
end chars

-- concat :: [[a]] -> [a] | [String] -> String
on concat(xs)
    if length of xs > 0 and class of (item 1 of xs) is string then
        set acc to ""
    else
        set acc to {}
    end if
    repeat with i from 1 to length of xs
        set acc to acc & item i of xs
    end repeat
    acc
end concat

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
    set {dlm, my text item delimiters} to {my text item delimiters, strText}
    set strJoined to lstText as text
    set my text item delimiters to dlm
    return strJoined
end intercalate

-- justifyLeft :: Int -> Char -> Text -> Text
on justifyLeft(n, cFiller, strText)
    if n > length of strText then
        text 1 thru n of (strText & replicate(n, cFiller))
    else
        strText
    end if
end justifyLeft

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min

-- minimum :: [a] -> a 
on minimum(xs)
    script min
        on |λ|(a, x)
            if x < a or a is missing value then
                x
            else
                a
            end if
        end |λ|
    end script
    
    foldl(min, missing value, xs)
end minimum

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary 
-- assembly of a target length

-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}
    
    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate

-- show :: a -> String
on show(e)
    set c to class of e
    if c = list then
        script serialized
            on |λ|(v)
                show(v)
            end |λ|
        end script
        
        "[" & intercalate(", ", map(serialized, e)) & "]"
    else if c = record then
        script showField
            on |λ|(kv)
                set {k, ev} to kv
                "\"" & k & "\":" & show(ev)
            end |λ|
        end script
        
        "{" & intercalate(", ", ¬
            map(showField, zip(allKeys(e), allValues(e)))) & "}"
    else if c = date then
        "\"" & iso8601Z(e) & "\""
    else if c = text then
        "\"" & e & "\""
    else if (c = integer or c = real) then
        e as text
    else if c = class then
        "null"
    else
        try
            e as text
        on error
            ("«" & c as text) & "»"
        end try
    end if
end show

-- unlines :: [String] -> String
on unlines(xs)
    intercalate(linefeed, xs)
end unlines

-- words :: String -> [String]
on |words|(s)
    words of s
end |words|

-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
    set lng to min(length of xs, length of ys)
    set lst to {}
    repeat with i from 1 to lng
        set end of lst to {item i of xs, item i of ys}
    end repeat
    return lst
end zip

-- zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
on zip3(xs, ys, zs)
    script
        on |λ|(x, i)
            [x, item i of ys, item i of zs]
        end |λ|
    end script
    
    map(result, items 1 thru ¬
        minimum({length of xs, length of ys, length of zs}) of xs)
end zip3
Output:
1935  乙亥        木      豬       阴  
      yĭhài      mù      zhū     yīn 
      12/60      wood    pig         

1938  戊寅        土      虎       阳  
      wùyín      tǔ      hǔ      yáng
      15/60      earth   tiger       

1968  戊申        土      猴       阳  
      wùshēn     tǔ      hóu     yáng
      45/60      earth   monkey      

1972  壬子        水      鼠       阳  
      rénzĭ      shuǐ    shǔ     yáng
      49/60      water   rat         

1976  丙辰        火      龍       阳  
      bĭngchén   huǒ     lóng    yáng
      53/60      fire    dragon      

1984  甲子        木      鼠       阳  
      jiăzĭ      mù      shǔ     yáng
      1/60       wood    rat         

2017  丁酉        火      鸡       阴  
      dīngyŏu    huǒ     jī      yīn 
      34/60      fire    rooster     

AutoHotkey

Chinese Animal/Element/Yin/Yang Characters Copied From "AppleScript"

Chinese_zodiac(year){
	Animal		:= StrSplit("Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig", ",")
	AnimalCh	:= StrSplit("鼠牛虎兔龍蛇馬羊猴鸡狗豬")
	AnimalName	:= StrSplit("shǔ,niú,hǔ,tù,lóng,shé,mǎ,yáng,hóu,jī,gǒu,zhū", ",")	
	Element		:= StrSplit("Wood,Fire,Earth,Metal,Water", ",")
	ElementCh	:= StrSplit("木火土金水")
	ElementName	:= StrSplit("mù,huǒ,tǔ,jīn,shuǐ", ",")	
	StemCh		:= StrSplit("甲乙丙丁戊己庚辛壬癸")
	StemName	:= StrSplit("jiă,yĭ,bĭng,dīng,wù,jĭ,gēng,xīn,rén,gŭi", ",")
	BranchCh	:= StrSplit("子丑寅卯辰巳午未申酉戌亥")
	BranchName	:= StrSplit("zĭ,chŏu,yín,măo,chén,sì,wŭ,wèi,shēn,yŏu,xū,hài", ",")
	Mod10	:= Mod(year-4, 10)+1
	Mod12	:= Mod(year-4, 12)+1
	A	:= Animal[Mod12], 
	Ac	:= AnimalCh[Mod12]
	An	:= AnimalName[Mod12]
	E	:= Element[Floor(Mod(year-4, 10)/2+1)]
	Ec	:= ElementCh[Floor(Mod(year-4, 10)/2+1)]
	En	:= ElementName[Floor(Mod(year-4, 10)/2+1)]
	YY	:= Mod(year-4, 2)=1 ? "yīn 阴" : "yáng 阳"
	Yr	:= Mod(year-4, 60)+1 "/60"
	S	:= StemCh[Mod10]
	Sn	:= StemName[Mod10]
	B	:= BranchCh[Mod12]
	Bn	:= BranchName[Mod12]
	return year "`t" S B " " Sn "-" Bn " `t" E " " Ec " " En "`t" A " " Ac " " An "`t" YY " " Yr
}
Examples:
loop 12
{
	n := 1983+A_Index
	output .= Chinese_zodiac(n) "`n"
}
MsgBox % output "`n" Chinese_zodiac(2017)
return
Output:
1984	甲子 jiă-zĭ 	Wood 木 mù	Rat 鼠 shǔ	yáng 阳 1/60
1985	乙丑 yĭ-chŏu 	Wood 木 mù	Ox 牛 niú	yīn 阴 2/60
1986	丙寅 bĭng-yín 	Fire 火 huǒ	Tiger 虎 hǔ	yáng 阳 3/60
1987	丁卯 dīng-măo 	Fire 火 huǒ	Rabbit 兔 tù	yīn 阴 4/60
1988	戊辰 wù-chén 	Earth 土 tǔ	Dragon 龍 lóng	yáng 阳 5/60
1989	己巳 jĭ-sì 	Earth 土 tǔ	Snake 蛇 shé	yīn 阴 6/60
1990	庚午 gēng-wŭ 	Metal 金 jīn	Horse 馬 mǎ	yáng 阳 7/60
1991	辛未 xīn-wèi 	Metal 金 jīn	Goat 羊 yáng	yīn 阴 8/60
1992	壬申 rén-shēn 	Water 水 shuǐ	Monkey 猴 hóu	yáng 阳 9/60
1993	癸酉 gŭi-yŏu 	Water 水 shuǐ	Rooster 鸡 jī	yīn 阴 10/60
1994	甲戌 jiă-xū 	Wood 木 mù	Dog 狗 gǒu	yáng 阳 11/60
1995	乙亥 yĭ-hài 	Wood 木 mù	Pig 豬 zhū	yīn 阴 12/60

2017	丁酉 dīng-yŏu 	Fire 火 huǒ	Rooster 鸡 jī	yīn 阴 34/60

AWK

# syntax: GAWK -f CHINESE_ZODIAC.AWK
BEGIN {
    print("year element animal  aspect")
    split("Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig",animal_arr,",")
    split("Wood,Fire,Earth,Metal,Water",element_arr,",")
    n = split("1935,1938,1968,1972,1976,1984,1985,2017",year_arr,",")
    for (i=1; i<=n; i++) {
      year = year_arr[i]
      element = element_arr[int((year-4)%10/2)+1]
      animal = animal_arr[(year-4)%12+1]
      yy = (year%2 == 0) ? "Yang" : "Yin"
      printf("%4d %-7s %-7s %s\n",year,element,animal,yy)
    }
    exit(0)
}
Output:
year element animal  aspect
1935 Wood    Pig     Yin
1938 Earth   Tiger   Yang
1968 Earth   Monkey  Yang
1972 Water   Rat     Yang
1976 Fire    Dragon  Yang
1984 Wood    Rat     Yang
1985 Wood    Ox      Yin
2017 Fire    Rooster Yin

BASIC

BASIC256

# Chinese zodiac

elementos = {"Wood", "Fire", "Earth", "Metal", "Water"}
animales = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
aspectos = {"Yang","Yin"}
tallo_celestial = {'甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'}
rama_terrestre = {'子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'}
tallos_pinyin = {"jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"}
ramas_pinyin = {"zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"}
years = {1935, 1938, 1968, 1972, 1976, 1984, 2017}

For i = 0 To years[?]-1
	xYear    = years[i]
	yElemento = elementos[((xYear - 4) % 10) \ 2]
	yAnimal   = animales[  (xYear - 4) % 12     ]
	yAspectos = aspectos[   xYear      %  2     ]
	ytallo_celestial  = tallo_celestial[((xYear - 4) % 10)]
	yrama_terrestre   = rama_terrestre[  (xYear - 4) % 12 ]
	ytallos_pinyin    = tallos_pinyin[  ((xYear - 4) % 10)]
	yramas_pinyin     = ramas_pinyin[    (xYear - 4) % 12 ]
	ciclo = ((xYear - 4) % 60) + 1
	Print xYear & ": " & ytallo_celestial & yrama_terrestre & " (" & ytallos_pinyin & "-" & yramas_pinyin & ", " & yElemento & " " &  yAnimal & "; " &  yAspectos & " - ciclo " &ciclo & "/60)"
Next i
End
Output:
1935: 乙亥 (yĭ-hài, Wood Pig; Yin - ciclo 12/60)
1938: 戊寅 (wù-yín, Earth Tiger; Yang - ciclo 15/60)
1968: 戊申 (wù-shēn, Earth Monkey; Yang - ciclo 45/60)
1972: 壬子 (rén-zĭ, Water Rat; Yang - ciclo 49/60)
1976: 丙辰 (bĭng-chén, Fire Dragon; Yang - ciclo 53/60)
1984: 甲子 (jiă-zĭ, Wood Rat; Yang - ciclo 1/60)
2017: 丁酉 (dīng-yŏu, Fire Rooster; Yin - ciclo 34/60)

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
100 rem Chinese zodiac
110 cls
120 dim animals$(12)
130 for i = 0 to ubound(animals$)-1 : read animals$(i) : next i
140 dim elements$(5)
150 for i = 0 to ubound(elements$)-1 : read elements$(i) : next i
160 dim yinyang$(2)
170 yinyang$(0) = "Yang" : yinyang$(1) = "Yin"
180 dim years(7)
190 for i = 0 to ubound(years)-1 : read years(i) : next i
200 for i = 0 to ubound(years)-1
210 xyear = years(i)
220 yelement$ = elements$(((xyear-4) mod 10)/2)
230 yanimal$ = animals$((xyear-4) mod 12)
240 yyinyang$ = yinyang$(xyear mod 2)
250 nn = ((xyear-4) mod 60)+1
260 print xyear "is the year of the " yelement$ " " yanimal$ " (" yyinyang$ ")."
270 next i
280 end
290 data "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
300 data "Wood","Fire","Earth","Metal","Water"
310 data 1935,1938,1968,1972,1976,1984,2017
Output:
Same as Yabasic entry.

GW-BASIC

The MSX BASIC solution works without any changes.

MSX Basic

Works with: Chipmunk Basic
Works with: GW-BASIC
Works with: PC-BASIC
Works with: QBasic
100 REM Chinese zodiac
110 CLS
120 PRINT " ****       Chinese zodiac       ****"
130 DIM animals$(12)
140 FOR i = 0 TO 11
150 READ animals$(i)
160 NEXT i
170 DIM elements$(5)
180 FOR i = 0 TO 4
190 READ elements$(i)
200 NEXT i
210 DIM yinyang$(2)
220 yinyang$(0) = "Yang"
230 yinyang$(1) = "Yin"
240 DIM years(7)
250 FOR i = 0 TO 6
260 READ years(i)
270 NEXT i
280 FOR i = 0 TO 6
290 xyear = years(i)
300 yelement$ = elements$(((xyear-4) MOD 10)/2)
310 yanimal$ = animals$((xyear-4) MOD 12)
320 yyinyang$ = yinyang$(xyear MOD 2)
330 nn = ((xyear-4) MOD 60)+1
340 PRINT xyear; "is the year of the "; yelement$; " "; yanimal$; " ("; yyinyang$; ")."
350 NEXT i
360 END
370 DATA "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
380 DATA "Wood","Fire","Earth","Metal","Water"
390 DATA 1935,1938,1968,1972,1976,1984,2017
Output:

https://www.dropbox.com/s/ckhu3u5pbwq7p5n/Chinese_zodiac%20%28MSX%29.png?dl=0

IS-BASIC

100 PROGRAM "Zodiac.bas"
110 STRING ANIMALS$(0 TO 11)*7,ELEMENTS$(0 TO 4)*5,YINYANG$(0 TO 1)*4
120 FOR I=0 TO 11
130   READ ANIMALS$(I)
140 NEXT 
150 FOR I=0 TO 4
160   READ ELEMENTS$(I)
170 NEXT 
180 LET YINYANG$(0)="Yang":LET YINYANG$(1)="Yin"
190 CALL ZODIAC(1935):CALL ZODIAC(1938)
200 CALL ZODIAC(1968):CALL ZODIAC(1972)
210 CALL ZODIAC(1976):CALL ZODIAC(2017)
220 DEF ZODIAC(YEAR)
230   LET YELEMENT$=ELEMENTS$(MOD((YEAR-4),10)/2)
240   LET YANIMAL$=ANIMALS$(MOD((YEAR-4),12))
250   LET YYINYANG$=YINYANG$(MOD(YEAR,2))
260   PRINT YEAR;"is the year of the ";YELEMENT$;" ";YANIMAL$;" (";YYINYANG$;")."
270 END DEF 
280 DATA Rat,Ox,Tiger,Rabbit,Dragon,Snake, Horse,Goat,Monkey,Rooster,Dog,Pig
290 DATA Wood,Fire,Earth,Metal,Water

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
Works with: Chipmunk Basic
Works with: GW-BASIC
Works with: MSX_BASIC
Works with: PC-BASIC
10 REM Chinese zodiac
20 CLS
30 DIM animals$(12)
40 DIM elements$(5)
50 DIM yinyang$(2)
70 FOR i = 0 TO 11
80 READ animals$(i)
90 NEXT i
110 FOR i = 0 TO 4
120 READ elements$(i)
130 NEXT i
140 yinyang$(0) = "Yang": yinyang$(1) = "Yin"
150 DIM years(7)
170 FOR i = 0 TO 6
180 READ years(i)
190 NEXT i
200 FOR i = 0 TO 6
210 xyear = years(i)
220 yelement$ = elements$(((xyear - 4) MOD 10) / 2)
230 yanimal$ = animals$((xyear - 4) MOD 12)
240 yyinyang$ = yinyang$(xyear MOD 2)
250 nn = ((xyear - 4) MOD 60) + 1
260 PRINT xyear; "is the year of the "; yelement$; " "; yanimal$; " ("; yyinyang$; ")."
270 NEXT i
280 END
290 DATA "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
300 DATA "Wood","Fire","Earth","Metal","Water"
310 DATA 1935,1938,1968,1972,1976,1984,2017
Output:
Same as Yabasic entry.

Befunge

0"    :raeY">:#,_55+"< /8"&>+:66+%00p:55+v
v"Aspect:  "0++88*5%2\0\+1%"<":p01++66/2%<
>00g5g7-0"  :laminA"10g5g"<"+0" :tnemelE"v
v!:,+55$_v#!-*84,:g+5/<  >:#,_$.,,.,@ >0#<
_>>:#,_$>>1+::"("%\"("^  ^"Cycle:   " <<<<
 $'-4;AGLS[_ %*06yang yin Rat Ox Tiger R |
abbit Dragon Snake Horse Goat Monkey Roo |
ster Dog Pig Wood Fire Earth Metal Water |
Output:
Year:    2018
Element: Earth
Animal:  Dog
Aspect:  yang
Cycle:   35 / 60

C

Translation of: C++
#include <math.h>
#include <stdio.h>

const char* animals[] = { "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig" };
const char* elements[] = { "Wood","Fire","Earth","Metal","Water" };

const char* getElement(int year) {
    int element = (int)floor((year - 4) % 10 / 2);
    return elements[element];
}

const char* getAnimal(int year) {
    return animals[(year - 4) % 12];
}

const char* getYY(int year) {
    if (year % 2 == 0) {
        return "yang";
    } else {
        return "yin";
    }
}

int main() {
    int years[] = { 1935, 1938, 1968, 1972, 1976, 2017 };
    int i;

    //the zodiac cycle didnt start until 4 CE, so years <4 shouldnt be valid
    for (i = 0; i < 6; ++i) {
        int year = years[i];
        printf("%d is the year of the %s %s (%s).\n", year, getElement(year), getAnimal(year), getYY(year));
    }

    return 0;
}
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
2017 is the year of the Fire Rooster (yin).

C#

Translation of: Java
using System;

namespace ChineseZodiac {
    class Program {
        static string[] animals = { "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig" };
        static string[] elements = { "Wood", "Fire", "Earth", "Metal", "Water" };
        static string[] animalChars = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
        static string[,] elementChars = { { "甲", "丙", "戊", "庚", "壬" }, { "乙", "丁", "己", "辛", "癸" } };

        static string getYY(int year) {
            if (year % 2 == 0) {
                return "yang";
            }
            return "yin";
        }

        static void Main(string[] args) {
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            int[] years = { 1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017 };
            for (int i = 0; i < years.Length; i++) {
                int ei = (int)Math.Floor((years[i] - 4.0) % 10 / 2);
                int ai = (years[i] - 4) % 12;
                Console.WriteLine("{0} is the year of the {1} {2} ({3}). {4}{5}", years[i], elements[ei], animals[ai], getYY(years[i]), elementChars[years[i] % 2, ei], animalChars[(years[i] - 4) % 12]);
            }
        }
    }
}
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

C++

#include <iostream>
#include <cmath>

using namespace std;

const string animals[]={"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};
const string elements[]={"Wood","Fire","Earth","Metal","Water"};

string getElement(int year)
{
    int element = floor((year-4)%10/2);
    return elements[element];
}

string getAnimal(int year)
{
    return animals[(year-4)%12];
}

string getYY(int year)
{
    if(year%2==0)
    {
        return "yang";
    }
    else
    {
        return "yin";
    }
}

int main()
{
    int years[]={1935,1938,1968,1972,1976,2017};
    //the zodiac cycle didnt start until 4 CE, so years <4 shouldnt be valid
    for(int i=0;i<6;i++)
    {
        cout << years[i] << " is the year of the " << getElement(years[i]) << " " << getAnimal(years[i]) << " (" << getYY(years[i]) << ")." << endl;
    }
    return 0;
}
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
2017 is the year of the Fire Rooster (yin).

Clojure

(def base-year 4)
(def celestial-stems ["甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"])
(def terrestrial-branches ["子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"])
(def zodiac-animals ["Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"])
(def elements ["Wood" "Fire" "Earth" "Metal" "Water"])
(def aspects ["yang" "yin"])
(def pinyin (zipmap (concat celestial-stems terrestrial-branches)
                 '("jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
                   "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))

(defn chinese-zodiac [year]
  (let [cycle-year (- year base-year)
        cycle-position (inc (mod cycle-year 60))
        stem-number (mod cycle-year 10)
        stem-han (nth celestial-stems stem-number)
        stem-pinyin (get pinyin stem-han)
        element-number (int (Math/floor (/ stem-number 2)))
        element (nth elements element-number)
        branch-number (mod cycle-year 12)
        branch-han (nth terrestrial-branches branch-number)
        branch-pinyin (get pinyin branch-han)
        zodiac-animal (nth zodiac-animals branch-number)
        aspect-number (mod cycle-year 2)
        aspect (nth aspects aspect-number)]
    (println (format "%s: %s%s (%s-%s, %s %s; %s - cycle %s/60)"
                     year stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect cycle-position))))

(defn -main [& args]
  (doseq [years (map read-string args)]
    (chinese-zodiac years)))
Output:
$ lein run 1935 1938 1968 1972 1976 1984 2017
1935: 乙亥 (yĭ-hài, Wood Pig; yin - cycle 12/60)
1938: 戊寅 (wù-yín, Earth Tiger; yang - cycle 15/60)
1968: 戊申 (wù-shēn, Earth Monkey; yang - cycle 45/60)
1972: 壬子 (rén-zĭ, Water Rat; yang - cycle 49/60)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang - cycle 53/60)
1984: 甲子 (jiă-zĭ, Wood Rat; yang - cycle 1/60)
2017: 丁酉 (dīng-yŏu, Fire Rooster; yin - cycle 34/60)

Commodore BASIC

Works with: Commodore 64/128
1000 rem display the chinese zodiac for a given year
1010 poke 53281,7: rem yellow background
1020 poke 53280,2: rem red border
1030 poke 646,2: rem red text
1040 h1$="chinese zodiac":gosub 2000 set-heading
1050 gosub 3000 initialize-data
1060 print
1070 print "enter year (return to quit):";
1080 get k$:if k$="" then 1080
1090 if k$=chr$(13) then end
1100 poke 631,asc(k$):poke 198,1:rem ungetc(k$)
1110 open 1,0: input#1, y$: close 1:print
1120 if val(y$)=0 and y$<>"0" then print chr$(145):goto 1060
1130 y=val(y$)-4
1140 sy=fnym(60): rem year of the sexagesimal cycle
1150 cs=fnym(10): rem celestial stem
1160 tb=fnym(12): rem terrestrial branch
1170 el=int(cs/2): rem element
1180 za=tb: rem zodiac animal
1190 as=fnym(2): rem aspect
1200 print
1210 print "the chinese year beginning in ce "y$
1220 print "is "cs$(cs)"-"tb$(tb)", year"(sy+1)"of 60,"
1230 print "the year of the "el$(el)" "za$(za)" ("as$(as)")."
1260 goto 1060
1270 end
2000 print chr$(147);chr$(18);"****";
2010 sp=32-len(h1$)
2020 for i=1 to int(sp/2)
2030 : print " ";
2040 next i
2050 print h1$;
2060 for i=i to sp
2070 : print " ";
2080 next i
2090 print "****";
2100 return
3000 dim cs$(9): rem ten celestial stems
3010 dim tb$(11): rem twelve terrestrial branches
3020 dim za$(11): rem twelve "zodiac" animals
3030 dim el$(4): rem five elements
3040 dim as$(1): rem two aspects
3050 for i=0 to 9
3060 : read cs$(i)
3070 next i
3080 data jia3, yi3, bing3, ding1, wu4
3090 data ji3, geng1, xin1, ren2, gui3
3100 for i=0 to 11
3110 : read tb$(i)
3120 next i
3130 data zi3, chou3, yin2, mao3
3140 data chen2, si4, wu3, wei4
3150 data shen2, you3, xu1, hai4
3160 for i=0 to 11
3170 : read za$(i)
3180 next i
3190 data rat, ox, tiger, rabbit
3200 data dragon, snake, horse, goat
3210 data monkey, rooster, dog, pig
3220 for i=0 to 4
3230 : read el$(i)
3240 next i
3250 data wood, fire, earth
3260 data metal, water
3270 for i=0 to 1
3280 : read as$(i)
3290 next i
3300 data yang, yin
3310 rem year-mod function
3320 def fnym(d) = y - int(y/d)*d
3330 return
Output:

https://i.imgur.com/f3Fo1xm.png

Common Lisp

Translation of: Ruby
; Any CE Year that was the first of a 60-year cycle
(defconstant base-year 1984)

(defconstant celestial-stems
  '("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))

(defconstant terrestrial-branches
  '("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))

(defconstant zodiac-animals
  '("Rat"   "Ox"   "Tiger"  "Rabbit"  "Dragon" "Snake"
    "Horse" "Goat" "Monkey" "Rooster" "Dog"    "Pig"))

(defconstant elements '("Wood" "Fire" "Earth" "Metal" "Water"))

(defconstant aspects '("yang" "yin"))

(defconstant pinyin
  (pairlis (append celestial-stems terrestrial-branches)
    '("jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
      "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))

(defun this-year () (nth 5 (multiple-value-list (get-decoded-time))))

(defun pinyin-for (han) (cdr (assoc han pinyin :test #'string=)))

(defun chinese-zodiac (&rest years)
 (loop for ce-year in (if (null years) (list (this-year)) years) collecting
   (let* ((cycle-year (- ce-year base-year))
          (stem-number (mod cycle-year 10))
          (stem-han    (nth stem-number celestial-stems))
          (stem-pinyin (pinyin-for stem-han))

          (element-number (floor stem-number 2))
          (element        (nth element-number elements))

          (branch-number (mod cycle-year 12))
          (branch-han    (nth branch-number terrestrial-branches))
          (branch-pinyin (pinyin-for branch-han))
          (zodiac-animal (nth branch-number zodiac-animals))

          (aspect-number (mod cycle-year 2))
          (aspect        (nth aspect-number aspects)))
          (cons ce-year (list stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect)))))

(defun get-args ()
  (or
   #+CLISP *args*
   #+SBCL (cdr *posix-argv*)
   #+LISPWORKS system:*line-arguments-list*
   #+CMU extensions:*command-line-words*
   nil))

(loop for cz in (apply #'chinese-zodiac (mapcar #'read-from-string (get-args)))
 doing
  (format t "~{~a: ~a~a (~a-~a, ~a ~a; ~a)~%~}" cz))
Output:
$ sbcl --script cz.cl
2017: 丁酉 (dīng-yŏu, Fire Rooster; yin)
$ clisp cz.cl  193{5,8} 194{1,7} 1968 197{2,6}
1935: 乙亥 (yĭ-hài, Wood Pig; yin)
1938: 戊寅 (wù-yín, Earth Tiger; yang)
1941: 辛巳 (xīn-sì, Metal Snake; yin)
1947: 丁亥 (dīng-hài, Fire Pig; yin)
1968: 戊申 (wù-shēn, Earth Monkey; yang)
1972: 壬子 (rén-zĭ, Water Rat; yang)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang)

D

Translation of: haskell
import std.stdio;

// 10 heavenly stems
immutable tiangan=[
    ["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"],
    ["jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"]
];

// 12 terrestrial branches
immutable dizhi=[
    ["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"],
    ["zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"]
];

// 5 elements
immutable wuxing=[
    ["木","火","土","金","水"],
    ["mù","huǒ","tǔ","jīn","shuǐ"],
    ["wood","fire","earth","metal","water"]
];

// 12 symbolic animals
immutable shengxiao=[
    ["鼠","牛","虎","兔","龍","蛇","馬","羊","猴","鸡","狗","豬"],
    ["shǔ","niú","hǔ","tù","lóng","shé","mǎ","yáng","hóu","jī","gǒu","zhū"],
    ["rat","ox","tiger","rabbit","dragon","snake","horse","goat","monkey","rooster","dog","pig"]
];

// yin yang
immutable yinyang=[
    ["阳","阴"],
    ["yáng","yīn"]
];

void main(string[] args) {
    process(args[1..$]);
}

void process(string[] years) {
    import std.conv;
    foreach(yearStr; years) {
        try {
            auto year = to!int(yearStr);

            auto cy = year - 4;
            auto stem = cy % 10;
            auto branch = cy % 12;

            writefln("%4s  %-11s  %-7s  %-10s%s", year,tiangan[0][stem]~dizhi[0][branch], wuxing[0][stem/2], shengxiao[0][branch], yinyang[0][year%2]);
            writefln("      %-12s%-8s%-10s%s",      tiangan[1][stem]~dizhi[1][branch],    wuxing[1][stem/2], shengxiao[1][branch], yinyang[1][year%2]);
            writefln("      %2s/60     %-7s%s", cy%60+1,                                  wuxing[2][stem/2], shengxiao[2][branch]);
            writeln;
        } catch (ConvException e) {
            stderr.writeln("Not a valid year: ", yearStr);
        }
    }
}
Output:
1935  乙亥        木      豬       阴  
      yĭhài      mù      zhū     yīn 
      12/60      wood    pig         

1938  戊寅        土      虎       阳  
      wùyín      tǔ      hǔ      yáng
      15/60      earth   tiger       

1968  戊申        土      猴       阳  
      wùshēn     tǔ      hóu     yáng
      45/60      earth   monkey      

1972  壬子        水      鼠       阳  
      rénzĭ      shuǐ    shǔ     yáng
      49/60      water   rat         

1976  丙辰        火      龍       阳  
      bĭngchén   huǒ     lóng    yáng
      53/60      fire    dragon      

1984  甲子        木      鼠       阳  
      jiăzĭ      mù      shǔ     yáng
      1/60       wood    rat         

2017  丁酉        火      鸡       阴  
      dīngyŏu    huǒ     jī      yīn 
      34/60      fire    rooster     

Dart

Set animals = {'Rat','Ox','Tiger','Rabbit','Dragon','Snake','Horse','Goat','Monkey','Rooster','Dog','Pig'};
Set elements = {'Wood', 'Fire', 'Earth', 'Metal', 'Water'};

String getElement(num year) {
  num element = ((year - 4) % 10 / 2);
  return elements.elementAt(element.floor());
}

String getAnimal(int year) {
  return animals.elementAt((year - 4) % 12);
}

String getYY(int year) {
  return (year % 2 == 0) ? 'Yang' : 'Yin';
}

void main() {
  Set years = {1935, 1938, 1968, 1972, 1976, 2017};
  //the zodiac cycle didnt start until 4 CE, so years <4 shouldnt be valid
  for (int i = 0; i < 6; i++) {
    int indice = years.elementAt(i);
    print('$indice is the year of the ${getElement(indice)} ${getAnimal(indice)} (${getYY(indice)}).');
  }
}
Output:
Same as Yabasic entry.

Delphi

Library: System.Math
Translation of: C#
program Chinese_zodiac;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,
  System.SysUtils,
  System.Math;

type
  TElements = array of array of char;

  TChineseZodiac = record
    Year: Integer;
    Yyear: string;
    Animal: string;
    Element: string;
    AnimalChar: char;
    ElementChar: char;
    procedure Assign(aYear: Integer);
    function ToString: string;
  end;

const
  animals: TArray<string> = ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake',
    'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'];
  elements: TArray<string> = ['Wood', 'Fire', 'Earth', 'Metal', 'Water'];
  animalChars: TArray<char> = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉',
    '戌', '亥'];
  elementChars: TElements = [['甲', '丙', '戊', '庚', '壬'], ['乙', '丁', '己', '辛', '癸']];


function getYY(year: Integer): string;
begin
  if (year mod 2) = 0 then
  begin
    Exit('yang');
  end;
  Exit('yin');
end;

{ TChineseZodiac }

procedure TChineseZodiac.Assign(aYear: Integer);
var
  ei, ai: Integer;
begin
  ei := Trunc(Floor((Trunc(aYear - 4.0) mod 10) / 2));
  ai := (aYear - 4) mod 12;
  year := aYear;
  Element := elements[ei];
  Animal := animals[ai];
  ElementChar := elementChars[aYear mod 2, ei];
  AnimalChar := animalChars[(aYear - 4) mod 12];
  Yyear := getYY(aYear);
end;

var
  z: TChineseZodiac;
  years: TArray<Integer> = [1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017];
  year: integer;

function TChineseZodiac.ToString: string;
begin
  Result := Format('%d is the year of the %s %s (%s). %s%s', [year, Element,
    Animal, Yyear, ElementChar, AnimalChar]);
end;

var
  Outfile: TextFile;
  Written: Cardinal;

begin
  SetConsoleOutputCP(CP_UTF8);

  AssignFile(Outfile, 'Output.txt', CP_UTF8);
  Rewrite(Outfile);

  for year in years do
  begin
    z.Assign(year);
    Writeln(Outfile, z.ToString);
    Writeln(z.ToString);
  end;

  CloseFile(Outfile);
  Readln;
end.
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

EasyLang

animal$[] = [ "Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig" ]
element$[] = [ "Wood" "Fire" "Earth" "Metal" "Water" ]
yingyang$[] = [ "Yang" "Yin" ]
animal_ch$[] = strchars "子丑寅卯辰巳午未申酉戌亥"
stem_ch$[] = strchars "甲乙丙丁戊己庚辛壬癸"
# 
proc get year . el$ an$ yy$ anch$ stch$ .
   idx = (year - 4) mod 10
   el$ = element$[idx div 2 + 1]
   stch$ = stem_ch$[idx + 1]
   idx = (year - 4) mod 12
   an$ = animal$[idx + 1]
   anch$ = animal_ch$[idx + 1]
   yy$ = yingyang$[year mod 2 + 1]
.
proc zodiac year . .
   get year el$ an$ yy$ anch$ stch$
   print year
   cycle = (year - 1983) mod1 60
   print "      " & el$ & " " & an$ & " " & yy$ & " " & cycle & "/60"
   print "      " & stch$ & anch$
   print ""
.
zodiac 1935
zodiac 1938
zodiac 1968
zodiac 1972
zodiac 1976
zodiac 1984
zodiac 2017


Excel

LAMBDA

Binding the name to the following lambda expressions in the Name Manager of the Excel WorkBook:

(See LAMBDA: The ultimate Excel worksheet function)

CNZODIAC
=LAMBDA(y,
    APPENDCOLS(
        APPENDCOLS(
            APPENDCOLS(
                CNYEARNAME(y)
            )(
                CNYEARELEMENT(y)
            )
        )(
            CNYEARANIMAL(y)
        )
    )(
        CNYEARYINYANG(y)
    )
)


CNYEARANIMAL
=LAMBDA(y,
    LET(
        shengxiao, {
         "鼠","shǔ","rat";
         "牛","niú","ox";
         "虎","hǔ","tiger";
         "兔","tù","rabbit";
         "龍","lóng","dragon";
         "蛇","shé","snake";
         "馬","mǎ","horse";
         "羊","yáng","goat";
         "猴","hóu","monkey";
         "鸡","jī","rooster";
         "狗","gǒu","dog";
         "豬","zhū","pig"
         },
         
        iYear, y - 4,
        iBranch, 1 + MOD(iYear, 12),
         
        TRANSPOSE(
            INDEX(shengxiao, iBranch)
        )
    )
)


CNYEARELEMENT
=LAMBDA(y,
    LET(
        wuxing, {
         "木","mù","wood";
         "火","huǒ","fire";
         "土","tǔ","earth";
         "金","jīn","metal";
         "水","shuǐ","water"
         },
        
        iYear, y - 4,
        iStem, MOD(iYear, 10),

        TRANSPOSE(
            INDEX(
                wuxing, 
                1 + QUOTIENT(
                    iStem, 
                    2
                )
            )
        )
    )
)


CNYEARNAME
=LAMBDA(y,
    LET(
        tiangan, {
         "甲","jiă";
         "乙","yĭ";
         "丙","bĭng";
         "丁","dīng";
         "戊","wù";
         "己","jĭ";
         "庚","gēng";
         "辛","xīn";
         "壬","rén";
         "癸","gŭi"
         },
    
         dizhi, {
         "子","zĭ";
         "丑","chŏu";
         "寅","yín";
         "卯","măo";
         "辰","chén";
         "巳","sì";
         "午","wŭ";
         "未","wèi";
         "申","shēn";
         "酉","yŏu";
         "戌","xū";
         "亥","hài"
         },
         

        iYear, y - 4,
        iStem, 1 + MOD(iYear, 10),
        iBranch, 1 + MOD(iYear, 12),
        iIndex, 1 + MOD(iYear, 60),
         
        stem, INDEX(tiangan, iStem),
        branch, INDEX(dizhi, iBranch),
         
        APPENDROWS(
            APPENDROWS(
                CONCAT(INDEX(stem, 1), INDEX(branch, 1))
            )(
                CONCAT(INDEX(stem, 2), INDEX(branch, 2))
            )
        )(iIndex & "/60")
    )
)


CNYEARYINYANG
=LAMBDA(y,
    LET(
        yinyang, {
         "阳","yáng", "bright";
         "阴","yīn", "dark"
         },
         
        TRANSPOSE(
            INDEX(
                yinyang,
                1 + MOD(y - 4, 2)
            )
        )
    )
)

and also assuming the following generic bindings in the Name Manager for the WorkBook:

APPENDCOLS
=LAMBDA(xs,
    LAMBDA(ys,
        LET(
            nx, COLUMNS(xs),
            colIndexes, SEQUENCE(1, nx + COLUMNS(ys)),
            rowIndexes, SEQUENCE(MAX(ROWS(xs), ROWS(ys))),

            IFERROR(
                IF(nx < colIndexes,
                    INDEX(ys, rowIndexes, colIndexes - nx),
                    INDEX(xs, rowIndexes, colIndexes)
                ),
                NA()
            )
        )
    )
)


APPENDROWS
=LAMBDA(xs,
    LAMBDA(ys,
        LET(
            nx, ROWS(xs),
            rowIndexes, SEQUENCE(nx + ROWS(ys)),
            colIndexes, SEQUENCE(
                1,
                MAX(COLUMNS(xs), COLUMNS(ys))
            ),

            IFERROR(
                IF(rowIndexes <= nx,
                    INDEX(xs, rowIndexes, colIndexes),
                    INDEX(ys, rowIndexes - nx, colIndexes)
                ),
                NA()
            )
        )
    )
)
Output:

The formula in cell B2 defines a dynamic array, populating the grid B2:E4

fx =CNZODIAC(A2)
A B C D E
1 Year Name Element Animal Yinyang
2 1935 乙亥
3 yĭhài zhū yīn
4 12/60 wood pig dark
5 1938 戊寅
6 wùyín yáng
7 15/60 earth tiger bright
8 1968 戊申
9 wùshēn hóu yáng
10 45/60 earth monkey bright
11 1972 壬子
12 rénzĭ shuǐ shǔ yáng
13 49/60 water rat bright
14 1976 丙辰
15 bĭngchén huǒ lóng yáng
16 53/60 fire dragon bright
17 1984 甲子
18 jiăzĭ shǔ yáng
19 1/60 wood rat bright
20 2017 丁酉
21 dīngyŏu huǒ yīn
22 34/60 fire rooster dark
23 2021 辛丑
24 xīnchŏu jīn niú yīn
25 38/60 metal ox dark
26 2022 壬寅
27 rényín shuǐ yáng
28 39/60 water tiger bright

F#

open System

let animals = ["Rat";"Ox";"Tiger";"Rabbit";"Dragon";"Snake";"Horse";"Goat";"Monkey";"Rooster";"Dog";"Pig"]
let elements = ["Wood";"Fire";"Earth";"Metal";"Water"]
let years = [1935;1938;1968;1972;1976;1984;1985;2017]

let getZodiac(year: int) = 
    let animal = animals.Item((year-4)%12)
    let element = elements.Item(((year-4)%10)/2)
    let yy = if year%2 = 0 then "(Yang)" else "(Yin)"
    
    String.Format("{0} is the year of the {1} {2} {3}", year, element, animal, yy)

[<EntryPoint>]
let main argv =
    let mutable string = ""
    for i in years do 
        string <- getZodiac(i)
        printf "%s" string
        Console.ReadLine() |> ignore
    0 // return an integer exit code
Output:
1935 is the year of the Wood Pig (Yin)
1938 is the year of the Earth Tiger (Yang)
1968 is the year of the Earth Monkey (Yang)
1972 is the year of the Water Rat (Yang)
1976 is the year of the Fire dragon (Yang)
1984 is the year of the Wood Rat (Yang)
1985 is the year of the Wood Ox (Yin)
2017 is the year of the Fire Rooster (Yin)

Factor

USING: circular formatting io kernel math qw sequences
sequences.repeating ;
IN: rosetta-code.zodiac

<PRIVATE

! Offset start index by -4 because first cycle started on 4 CE.
: circularize ( seq -- obj )
    [ -4 ] dip <circular> [ change-circular-start ] keep ;

: animals ( -- obj )
    qw{
        Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey
        Rooster Dog Pig
    } circularize ;

: elements ( -- obj )
    qw{ Wood Fire Earth Metal Water } 2 <repeats> circularize ;

PRIVATE>

: zodiac ( n -- str )
    dup [ elements nth ] [ animals nth ]
    [ even? "yang" "yin" ? ] tri
    "%d is the year of the %s %s (%s)." sprintf ;

: zodiac-demo ( -- )
    { 1935 1938 1968 1972 1976 1984 1985 2017 }
    [ zodiac print ] each ;

MAIN: zodiac-demo
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
1984 is the year of the Wood Rat (yang).
1985 is the year of the Wood Ox (yin).
2017 is the year of the Fire Rooster (yin).

Forth

Works with: gforth version 0.7.3
: position ( n -- n ) 4 - 60 mod ;

s" Rat    Ox     Tiger  Rabbit Dragon Snake  Horse  Goat   Monkey RoosterDog    Pig    "
drop constant animals
: animal ( n -- a u ) 12 mod  7 * animals +  7 -trailing ;

s" Wood Fire EarthMetalWater" drop constant elements
: element ( n -- a u ) 2/ 5 mod  5 * elements +  5 -trailing ;

s" yangyin " drop constant aspects
: aspect ( n -- a u ) 2 mod  4 * aspects +  4 -trailing ;

next-arg s>number? drop d>s position
 dup element type space
 dup animal  type space
     aspect  '(' emit type ')' emit cr
bye
Output:
; for (x in 1935 1938 1968 1972 1976 1984 2017) {printf '%s ' $x; gforth zodiac.f $x}
1935 Wood Pig (yin)
1938 Earth Tiger (yang)
1968 Earth Monkey (yang)
1972 Water Rat (yang)
1976 Fire Dragon (yang)
1984 Wood Rat (yang)
2017 Fire Rooster (yin)

FreeBASIC

dim as string yy(0 to 1) = {"yang", "yin"}
dim as string elements(0 to 4) = {"Wood", "Fire", "Earth", "Metal", "Water"}
dim as string animals(0 to 11) = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",_
                                  "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}

dim as uinteger yr, y, e, a, i, tests(0 to 5) = {1801, 1861, 1984, 2020, 2186, 76543}
dim as string outstr

for i = 0 to 5
   yr = tests(i)
   y = yr mod 2
   e = (yr - 4) mod 5
   a = (yr - 4) mod 12
   outstr = str(yr)+" is the year of the "
   outstr += elements(e)+" " + animals(a) + " (" + yy(y) + ")." 
   
   print outstr
next i
Output:
1801 is the year of the Earth Rooster (yin).
1861 is the year of the Earth Rooster (yin).
1984 is the year of the Wood Rat (yang).
2020 is the year of the Fire Rat (yang).
2186 is the year of the Earth Dog (yang).
76543 is the year of the Water Rabbit (yin).

Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

Test case

Go

package main

import "fmt"

var (
    animalString = []string{"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
    stemYYString  = []string{"Yang", "Yin"}
    elementString = []string{"Wood", "Fire", "Earth", "Metal", "Water"}
    stemCh        = []rune("甲乙丙丁戊己庚辛壬癸")
    branchCh      = []rune("子丑寅卯辰巳午未申酉戌亥")
)

func cz(yr int) (animal, yinYang, element, stemBranch string, cycleYear int) {
    yr -= 4
    stem := yr % 10
    branch := yr % 12
    return animalString[branch],
        stemYYString[stem%2],
        elementString[stem/2],
        string([]rune{stemCh[stem], branchCh[branch]}),
        yr%60 + 1
}

func main() {
    for _, yr := range []int{1935, 1938, 1968, 1972, 1976} {
        a, yy, e, sb, cy := cz(yr)
        fmt.Printf("%d: %s %s, %s, Cycle year %d %s\n",
            yr, e, a, yy, cy, sb)
    }
}
Output:
1935: Wood Pig, Yin, Cycle year 12 乙亥
1938: Earth Tiger, Yang, Cycle year 15 戊寅
1968: Earth Monkey, Yang, Cycle year 45 戊申
1972: Water Rat, Yang, Cycle year 49 壬子
1976: Fire Dragon, Yang, Cycle year 53 丙辰

Groovy

Translation of: Java
class Zodiac {
    final static String[] animals = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    final static String[] elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
    final static String[] animalChars = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
    static String[][] elementChars = [["甲", "丙", "戊", "庚", "壬"], ["乙", "丁", "己", "辛", "癸"]]

    static String getYY(int year) {
        if (year % 2 == 0) {
            return "yang"
        } else {
            return "yin"
        }
    }

    static void main(String[] args) {
        int[] years = [1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017]
        for (int i = 0; i < years.length; i++) {
            println(years[i] + " is the year of the " + elements[(int) Math.floor((years[i] - 4) % 10 / 2)] + " " + animals[(years[i] - 4) % 12] + " (" + getYY(years[i]) + "). " + elementChars[years[i] % 2][(int) Math.floor((years[i] - 4) % 10 / 2)] + animalChars[(years[i] - 4) % 12])
        }
    }
}
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

Haskell

(We can use Chinese characters in Haskell names, as long as the first character is lower-case alphabetic)

import Data.Array (Array, listArray, (!))

------------------- TRADITIONAL STRINGS ------------------
ats :: Array Int (Char, String)
ats =
  listArray (0, 9) $
    zip
      -- 天干 tiangan – 10 heavenly stems
      "甲乙丙丁戊己庚辛壬癸"
      (words "jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")

ads :: Array Int (String, String)
ads =
  listArray (0, 11) $
    zip
      -- 地支 dizhi – 12 terrestrial branches
      (chars "子丑寅卯辰巳午未申酉戌亥")
      ( words $
          "zĭ chŏu yín măo chén sì "
            <> "wŭ wèi shēn yŏu xū hài"
      )

aws :: Array Int (String, String, String)
aws =
  listArray (0, 4) $
    zip3
      -- 五行 wuxing – 5 elements
      (chars "木火土金水")
      (words "mù huǒ tǔ jīn shuǐ")
      (words "wood fire earth metal water")

axs :: Array Int (String, String, String)
axs =
  listArray (0, 11) $
    zip3
      -- 十二生肖 shengxiao – 12 symbolic animals
      (chars "鼠牛虎兔龍蛇馬羊猴鸡狗豬")
      ( words $
          "shǔ niú hǔ tù lóng shé "
            <> "mǎ yáng hóu jī gǒu zhū"
      )
      ( words $
          "rat ox tiger rabbit dragon snake "
            <> "horse goat monkey rooster dog pig"
      )

ays :: Array Int (String, String)
-- 阴阳 yinyang
ays =
  listArray (0, 1) $
    zip (chars "阳阴") (words "yáng yīn")

chars :: String -> [String]
chars = (flip (:) [] <$>)

-------------------- TRADITIONAL CYCLES ------------------
f生肖五行年份 y =
  let i年份 = y - 4
      i天干 = rem i年份 10
      i地支 = rem i年份 12
      (h天干, p天干) = ats ! i天干
      (h地支, p地支) = ads ! i地支
      (h五行, p五行, e五行) = aws ! quot i天干 2
      (h生肖, p生肖, e生肖) = axs ! i地支
      (h阴阳, p阴阳) = ays ! rem i年份 2
   in -- 汉子 Chinese characters
      [ [show y, h天干 : h地支, h五行, h生肖, h阴阳],
        -- Pinyin roman transcription
        [[], p天干 <> p地支, p五行, p生肖, p阴阳],
        -- English
        [ [],
          show (rem i年份 60 + 1) <> "/60",
          e五行,
          e生肖,
          []
        ]
      ]

--------------------------- TEST -------------------------
main :: IO ()
main =
  mapM_ putStrLn $
    showYear
      <$> [1935, 1938, 1968, 1972, 1976, 1984, 2017]

------------------------ FORMATTING ----------------------
fieldWidths :: [[Int]]
fieldWidths =
  [ [6, 10, 7, 8, 3],
    [6, 11, 8, 8, 4],
    [6, 11, 8, 8, 4]
  ]

showYear :: Int -> String
showYear y =
  unlines $
    ( \(ns, xs) ->
        concat $
          uncurry (`justifyLeft` ' ')
            <$> zip ns xs
    )
      <$> zip fieldWidths (f生肖五行年份 y)
  where
    justifyLeft n c s = take n (s <> replicate n c)
Output:
1935  乙亥        木      豬       阴  
      yĭhài      mù      zhū     yīn 
      12/60      wood    pig         

1938  戊寅        土      虎       阳  
      wùyín      tǔ      hǔ      yáng
      15/60      earth   tiger       

1968  戊申        土      猴       阳  
      wùshēn     tǔ      hóu     yáng
      45/60      earth   monkey      

1972  壬子        水      鼠       阳  
      rénzĭ      shuǐ    shǔ     yáng
      49/60      water   rat         

1976  丙辰        火      龍       阳  
      bĭngchén   huǒ     lóng    yáng
      53/60      fire    dragon      

1984  甲子        木      鼠       阳  
      jiăzĭ      mù      shǔ     yáng
      1/60       wood    rat         

2017  丁酉        火      鸡       阴  
      dīngyŏu    huǒ     jī      yīn 
      34/60      fire    rooster   

J

   ELEMENTS=: _4 |. 2 # ;:'Wood Fire Earth Metal Water'
   YEARS=: 1935 1938 1968 1972 1976 2017

   ANIMALS=: _4 |. ;:'Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig'
   YINYANG=: ;:'yang yin'

   cz=: (|~ #)~ { [

   ANIMALS cz YEARS
┌───┬─────┬──────┬───┬──────┬───────┐
PigTigerMonkeyRatDragonRooster
└───┴─────┴──────┴───┴──────┴───────┘

   YINYANG cz YEARS
┌───┬────┬────┬────┬────┬───┐
yinyangyangyangyangyin
└───┴────┴────┴────┴────┴───┘

   chinese_zodiac =: 3 : ';:inv(<":y),(ELEMENTS cz y),(ANIMALS cz y),(<''(''),(YINYANG cz y),(<'')'')'

   chinese_zodiac&>YEARS
1935 Wood Pig ( yin )     
1938 Earth Tiger ( yang ) 
1968 Earth Monkey ( yang )
1972 Water Rat ( yang )   
1976 Fire Dragon ( yang ) 
2017 Fire Rooster ( yin )


   'CELESTIAL TERRESTRIAL'=:7&u:&.>{&a.&.> 16be7 16b94 16bb2 16be4 16bb9 16b99 16be4 16bb8 16b99 16be4 16bb8 16b81 16be6 16b88 16b8a 16be5 16bb7 16bb1 16be5 16bba 16b9a 16be8 16bbe 16b9b 16be5 16ba3 16bac 16be7 16b99 16bb8; 16be5 16bad 16b90 16be4 16bb8 16b91 16be5 16baf 16b85 16be5 16b8d 16baf 16be8 16bbe 16bb0 16be5 16bb7 16bb3 16be5 16b8d 16b88 16be6 16b9c 16baa 16be7 16b94 16bb3 16be9 16b85 16b89 16be6 16b88 16b8c 16be4 16bba 16ba5

   ANIMALS=: ;/ _4 |. TERRESTRIAL
   ELEMENTS=: ;/ _4 |. CELESTIAL

   chinese_zodiac&>YEARS
1935   ( yin ) 
1938   ( yang )
1968   ( yang )
1972   ( yang )
1976   ( yang )
2017   ( yin )

Java

public class Zodiac {

	final static String animals[]={"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};
	final static String elements[]={"Wood","Fire","Earth","Metal","Water"};
	final static String animalChars[]={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
	static String elementChars[][]={{"甲","丙","戊","庚","壬"},{"乙","丁","己","辛","癸"}};

	static String getYY(int year)
	{
	    if(year%2==0)
	    {
	        return "yang";
	    }
	    else
	    {
	        return "yin";
	    }
	}

	public static void main(String[] args)
	{
		int years[]={1935,1938,1968,1972,1976,1984,1985,2017};
		for(int i=0;i<years.length;i++)
		{
			System.out.println(years[i]+" is the year of the "+elements[(int) Math.floor((years[i]-4)%10/2)]+" "+animals[(years[i]-4)%12]+" ("+getYY(years[i])+"). "+elementChars[years[i]%2][(int) Math.floor((years[i]-4)%10/2)]+animalChars[(years[i]-4)%12]);
		}
	}
}
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

JavaScript

ES6

Translation of: Haskell
(() => {
    "use strict";

    // ---------- TRADITIONAL CALENDAR STRINGS -----------

    // ats :: Array Int (String, String)
    const ats = () =>
        // 天干 tiangan – 10 heavenly stems
        zip(
            chars("甲乙丙丁戊己庚辛壬癸")
        )(
            words("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")
        );


    // ads :: Array Int (String, String)
    const ads = () =>
        // 地支 dizhi – 12 terrestrial branches
        zip(
            chars("子丑寅卯辰巳午未申酉戌亥")
        )(
            words(
                "zĭ chŏu yín măo chén sì " + (
                    "wŭ wèi shēn yŏu xū hài"
                )
            )
        );


    // aws :: Array Int (String, String, String)
    const aws = () =>
        // 五行 wuxing – 5 elements
        zip3(
            chars("木火土金水")
        )(
            words("mù huǒ tǔ jīn shuǐ")
        )(
            words("wood fire earth metal water")
        );


    // axs :: Array Int (String, String, String)
    const axs = () =>
        // 十二生肖 shengxiao – 12 symbolic animals
        zip3(
            chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬")
        )(
            words(
                "shǔ niú hǔ tù lóng shé " + (
                    "mǎ yáng hóu jī gǒu zhū"
                )
            )
        )(
            words(
                "rat ox tiger rabbit dragon snake " + (
                    "horse goat monkey rooster dog pig"
                )
            )
        );


    // ays :: Array Int (String, String)
    const ays = () =>
        // 阴阳 yinyang
        zip(
            chars("阳阴")
        )(
            words("yáng yīn")
        );


    // --------------- TRADITIONAL CYCLES ----------------
    const zodiac = y => {
        const
            iYear = y - 4,
            iStem = iYear % 10,
            iBranch = iYear % 12,
            [hStem, pStem] = ats()[iStem],
            [hBranch, pBranch] = ads()[iBranch],
            [hElem, pElem, eElem] = aws()[quot(iStem)(2)],
            [hAnimal, pAnimal, eAnimal] = axs()[iBranch],
            [hYinyang, pYinyang] = ays()[iYear % 2];

        return [
            [
                show(y), hStem + hBranch, hElem,
                hAnimal, hYinyang
            ],
            ["", pStem + pBranch, pElem, pAnimal, pYinyang],
            [
                "", `${show((iYear % 60) + 1)}/60`,
                eElem, eAnimal, ""
            ]
        ];
    };


    // ---------------------- TEST -----------------------
    const main = () => [
            1935, 1938, 1968, 1972, 1976, 1984,
            new Date().getFullYear()
        ]
        .map(showYear)
        .join("\n\n");


    // ------------------- FORMATTING --------------------
    // fieldWidths :: [[Int]]
    const fieldWidths = [
        [6, 10, 7, 8, 3],
        [6, 11, 8, 8, 4],
        [6, 11, 8, 8, 4]
    ];


    // showYear :: Int -> String
    const showYear = y =>
        zipWith(zip)(fieldWidths)(zodiac(y))
        .map(
            row => row.map(
                ([n, s]) => s.padEnd(n, " ")
            )
            .join("")
        )
        .join("\n");


    // ---------------- GENERIC FUNCTIONS ----------------

    // chars :: String -> [Char]
    const chars = s => [...s];


    // quot :: Integral a => a -> a -> a
    const quot = n =>
        m => Math.trunc(n / m);


    // show :: Int -> a -> Indented String
    // show :: a -> String
    const show = (...x) =>
        JSON.stringify.apply(
            null, x.length > 1 ? [
                x[1], null, x[0]
            ] : x
        );


    // words :: String -> [String]
    const words = s =>
        // List of space-delimited sub-strings.
        s.split(/\s+/u);


    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs =>
        // The paired members of xs and ys, up to
        // the length of the shorter of the two lists.
        ys => Array.from({
            length: Math.min(xs.length, ys.length)
        }, (_, i) => [xs[i], ys[i]]);


    // zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
    const zip3 = xs =>
        ys => zs => xs.slice(
            0,
            Math.min(...[xs, ys, zs].map(x => x.length))
        )
        .map((x, i) => [x, ys[i], zs[i]]);


    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f =>
        // A list constructed by zipping with a
        // custom function, rather than with the
        // default tuple constructor.
        xs => ys => xs.map(
            (x, i) => f(x)(ys[i])
        ).slice(
            0, Math.min(xs.length, ys.length)
        );


    // MAIN ---
    return main();
})();
Output:
1935  乙亥        木      豬       阴  
      yĭhài      mù      zhū     yīn 
      12/60      wood    pig         

1938  戊寅        土      虎       阳  
      wùyín      tǔ      hǔ      yáng
      15/60      earth   tiger       

1968  戊申        土      猴       阳  
      wùshēn     tǔ      hóu     yáng
      45/60      earth   monkey      

1972  壬子        水      鼠       阳  
      rénzĭ      shuǐ    shǔ     yáng
      49/60      water   rat         

1976  丙辰        火      龍       阳  
      bĭngchén   huǒ     lóng    yáng
      53/60      fire    dragon      

1984  甲子        木      鼠       阳  
      jiăzĭ      mù      shǔ     yáng
      1/60       wood    rat         

2022  壬寅        水      虎       阳  
      rényín     shuǐ    hǔ      yáng
      39/60      water   tiger  

jq

Works with jq and gojq, that is, the C and Go implementations of jq.

Adapted from Wren

def ChineseZodiac: {
  animals  : ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
              "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
  aspects  : ["Yang","Yin"],
  elements : ["Wood", "Fire", "Earth", "Metal", "Water"],
  stems    : ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"],
  branches : ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"],
  sNames   : ["jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi"],
  bNames   : ["zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu",  "xū", "hài"]
};

def ChineseZodiac($year):
  ($year - 4) as $y
  | ($y % 10) as $s
  | ($y % 12) as $b
  | ChineseZodiac
  | {   year    : $year,
        stem    : .stems[$s],
        branch  : .branches[$b],
        sName   : .sNames[$s],
        bName   : .bNames[$b],
        element : .elements[($s/2)|floor],
        animal  : .animals[$b],
        aspect  : .aspects[$s % 2],
        cycle   : ($y % 60 + 1)
    };

def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;

# Input: ChineseZodiac($year)
def toString:
  (.sName + "-" + .bName | lpad(9)) as $name
  | (.element|lpad(7)) as $elem
  | (.animal|lpad(7)) as $anim
  | (.aspect|lpad(6)) as $aspt
  | ((.cycle|lpad(2)) + "/60") as $cycl
  | "\(.year)    \(.stem)\(.branch)   \($name)  \($elem)  \($anim)   \($aspt)  \($cycl)" ;


"Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle",
"----  -------  ---------  -------  -------  ------  -----",
(ChineseZodiac(1935, 1938, 1968, 1972, 1976, 1984, 2017, 2020) | toString)
Output:
Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle
----  -------  ---------  -------  -------  ------  -----
1935    乙亥      yĭ-hài     Wood      Pig      Yin  12/60
1938    戊寅      wù-yín    Earth    Tiger     Yang  15/60
1968    戊申     wù-shēn    Earth   Monkey     Yang  45/60
1972    壬子      rén-zĭ    Water      Rat     Yang  49/60
1976    丙辰   bĭng-chén     Fire   Dragon     Yang  53/60
1984    甲子      jiă-zĭ     Wood      Rat     Yang   1/60
2017    丁酉    dīng-yŏu     Fire  Rooster      Yin  34/60
2020    庚子     gēng-zĭ    Metal      Rat     Yang  37/60

Julia

Works with: Julia version 0.6
Translation of: Python
function chinese(year::Int)
    pinyin = Dict(
        "甲" => "jiă",
        "乙" => "yĭ",
        "丙" => "bĭng",
        "丁" => "dīng",
        "戊" => "wù",
        "己" => "jĭ",
        "庚" => "gēng",
        "辛" => "xīn",
        "壬" => "rén",
        "癸" => "gŭi",
        "子" => "zĭ",
        "丑" => "chŏu",
        "寅" => "yín",
        "卯" => "măo",
        "辰" => "chén",
        "巳" => "sì",
        "午" => "wŭ",
        "未" => "wèi",
        "申" => "shēn",
        "酉" => "yŏu",
        "戌" => "xū",
        "亥" => "hài",
    )
    elements    = ["Wood", "Fire", "Earth", "Metal", "Water"]
    animals     = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
                   "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    celestial   = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
    terrestrial = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
    aspects     = ["yang", "yin"]
    base = 4

    cycleyear = year - base

    stemnumber = cycleyear % 10 + 1
    stemhan    = celestial[stemnumber]
    stempinyin = pinyin[stemhan]

    elementnumber = div(stemnumber, 2) + 1
    element       = elements[elementnumber]

    branchnumber = cycleyear % 12 + 1
    branchhan    = terrestrial[branchnumber]
    branchpinyin = pinyin[branchhan]
    animal       = animals[branchnumber]

    aspectnumber = cycleyear % 2 + 1
    aspect       = aspects[aspectnumber]

    index = cycleyear % 60 + 1

    return "$year: $stemhan$branchhan ($stempinyin-$branchpinyin, $element $animal; $aspect - year $index of the cycle)"
end

curryr = Dates.year(now())
yrs = [1935, 1938, 1968, 1972, 1976, curryr]
foreach(println, map(chinese, yrs))
Output:
1935: 乙亥 (yĭ-hài, Fire Pig; yin - year 12 of the cycle)
1938: 戊寅 (wù-yín, Earth Tiger; yang - year 15 of the cycle)
1968: 戊申 (wù-shēn, Earth Monkey; yang - year 45 of the cycle)
1972: 壬子 (rén-zĭ, Water Rat; yang - year 49 of the cycle)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang - year 53 of the cycle)
2018: 戊戌 (wù-xū, Earth Dog; yang - year 35 of the cycle)

Kotlin

// version 1.1.2

class ChineseZodiac(val year: Int) {
    val stem   : Char
    val branch : Char
    val sName  : String
    val bName  : String
    val element: String
    val animal : String
    val aspect : String
    val cycle  : Int
               
    private companion object {
        val animals  = listOf("Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
                              "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig")
        val aspects  = listOf("Yang","Yin")
        val elements = listOf("Wood", "Fire", "Earth", "Metal", "Water")
        val stems    = listOf('甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸')
        val branches = listOf('子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥')
        val sNames   = listOf("jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi")
        val bNames   = listOf("zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu",  "xū", "hài")
        val fmt      = "%d    %c%c   %-9s  %-7s  %-7s   %-6s %02d/60"
    } 

    init {
        val y = year - 4
        val s = y % 10
        val b = y % 12
        stem    = stems[s]
        branch  = branches[b]
        sName   = sNames[s]
        bName   = bNames[b]
        element = elements[s / 2]
        animal  = animals[b]
        aspect  = aspects[s % 2]
        cycle   = y % 60 + 1 
    }

    override fun toString() = 
        fmt.format(year, stem, branch, sName + "-" + bName, element, animal, aspect, cycle)
}

fun main(args: Array<String>) {
    val years = intArrayOf(1935, 1938, 1968, 1972, 1976, 1984, 2017)
    println("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle")
    println("----  -------  ---------  -------  -------  ------  -----") 
    for (year in years) println(ChineseZodiac(year))
}
Output:
Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle
----  -------  ---------  -------  -------  ------  -----
1935    乙亥   yĭ-hài     Wood     Pig       Yin    12/60
1938    戊寅   wù-yín     Earth    Tiger     Yang   15/60
1968    戊申   wù-shēn    Earth    Monkey    Yang   45/60
1972    壬子   rén-zĭ     Water    Rat       Yang   49/60
1976    丙辰   bĭng-chén  Fire     Dragon    Yang   53/60
1984    甲子   jiă-zĭ     Wood     Rat       Yang   01/60
2017    丁酉   dīng-yŏu   Fire     Rooster   Yin    34/60

Lua

Translation of: C
local ANIMALS = {"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"}
local ELEMENTS = {"Wood","Fire","Earth","Metal","Water"}

function element(year)
    local idx = math.floor(((year - 4) % 10) / 2)
    return ELEMENTS[idx + 1]
end

function animal(year)
    local idx = (year - 4) % 12
    return ANIMALS[idx + 1]
end

function yy(year)
    if year % 2 == 0 then
        return "yang"
    else
        return "yin"
    end
end

function zodiac(year)
    local e = element(year)
    local a = animal(year)
    local y = yy(year)
    print(year.." is the year of the "..e.." "..a.." ("..y..")")
end

zodiac(1935)
zodiac(1938)
zodiac(1968)
zodiac(1972)
zodiac(1976)
zodiac(2017)
Output:
1935 is the year of the Wood Pig (yin)
1938 is the year of the Earth Tiger (yang)
1968 is the year of the Earth Monkey (yang)
1972 is the year of the Water Rat (yang)
1976 is the year of the Fire Dragon (yang)
2017 is the year of the Fire Rooster (yin)

Maple

zodiac:=proc(year::integer)
	local year60,yinyang,animal,element;
	year60:= (year-3) mod 60;								 
	yinyang:=["Yin","Yang"];
	animal:=["Pig","Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog"];
	element:=["Water","Wood","Wood","Fire","Fire","Earth","Earth","Metal","Metal","Water"];										 
	return sprintf("%a",cat(year," is the year of the ",element[(year60 mod 10)+1]," ",animal[(year60 mod 12)+1]," (",yinyang[(year60 mod 2)+1],")"));
end proc:

Mathematica / Wolfram Language

pinyin = <|"甲" -> "jiă", "乙" -> "yĭ", "丙" -> "bĭng", "丁" -> "dīng", 
   "戊" -> "wù", "己" -> "jĭ", "庚" -> "gēng", "辛" -> "xīn", 
   "壬" -> "rén", "癸" -> "gŭi", "子" -> "zĭ", "丑" -> "chŏu", 
   "寅" -> "yín", "卯" -> "măo", "辰" -> "chén", "巳" -> "sì", 
   "午" -> "wŭ", "未" -> "wèi", "申" -> "shēn", "酉" -> "yŏu", 
   "戌" -> "xū", "亥" -> "hài"|>;
animals = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse",
    "Goat", "Monkey", "Rooster", "Dog", "Pig"};
elements = {"Wood", "Fire", "Earth", "Metal", "Water"};
celestial = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
terrestrial = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", 
   "亥"};
aspects = {"yang", "yin"};
ClearAll[calculate]
calculate[year_] := Module[{BASE, cycleyear, stemnumber, stempinyin, element, 
   elementnumber, branchnumber, branchhan, branchpinyin, animal, 
   aspectnumber, aspect, stemhan},
  BASE = 4;
  cycleyear = year - BASE;
  stemnumber = Mod[cycleyear + 1, 10, 1];
  stemhan = celestial[[stemnumber]];
  stempinyin = pinyin[[stemhan]];
  elementnumber = Floor[stemnumber/2 + 1/2];
  element = elements[[elementnumber]];
  branchnumber = Mod[cycleyear + 1, 12, 1];
  branchhan = terrestrial[[branchnumber]];
  branchpinyin = pinyin[[branchhan]];
  animal = animals[[branchnumber]];
  aspectnumber = Mod[cycleyear + 1, 2, 1];
  aspect = aspects[[aspectnumber]];
  Row@{year, ": ", stemhan, branchhan, " (", stempinyin, "-", branchpinyin, ", ", element, " ", animal, "; ", aspect, ")"}
  ]
calculate[1935]
calculate[1938]
calculate[1941]
calculate[1947]
calculate[1968]
calculate[1972]
calculate[1976]
Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin)
1938: 戊寅 (wù-yín, Earth Tiger; yang)
1941: 辛巳 (xīn-sì, Metal Snake; yin)
1947: 丁亥 (dīng-hài, Fire Pig; yin)
1968: 戊申 (wù-shēn, Earth Monkey; yang)
1972: 壬子 (rén-zĭ, Water Rat; yang)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang)

Modula-2

Translation of: C++
MODULE ChineseZodiac;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,ReadChar;

TYPE Str = ARRAY[0..7] OF CHAR;

TYPE AA = ARRAY[0..11] OF Str;
CONST ANIMALS = AA{"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};

TYPE EA = ARRAY[0..4] OF Str;
CONST ELEMENTS = EA{"Wood","Fire","Earth","Metal","Water"};

PROCEDURE element(year : INTEGER) : Str;
VAR idx : CARDINAL;
BEGIN
    idx := ((year - 4) MOD 10) / 2;
    RETURN ELEMENTS[idx];
END element;

PROCEDURE animal(year : INTEGER) : Str;
VAR idx : CARDINAL;
BEGIN
    idx := (year - 4) MOD 12;
    RETURN ANIMALS[idx];
END animal;

PROCEDURE yy(year : INTEGER) : Str;
BEGIN
    IF year MOD 2 = 0 THEN
        RETURN "yang"
    ELSE
        RETURN "yin"
    END
END yy;

PROCEDURE print(year : INTEGER);
VAR buf : ARRAY[0..63] OF CHAR;
BEGIN
    FormatString("%i is the year of the %s %s (%s)\n", buf, year, element(year), animal(year), yy(year));
    WriteString(buf);
END print;

(* main *)
BEGIN
    print(1935);
    print(1938);
    print(1968);
    print(1972);
    print(1976);
    print(2017);

    ReadChar
END ChineseZodiac.

Nim

Translation of: Rust
import strformat

const ANIMALS: array[12, string] = ["Rat",    "Ox", 
                                    "Tiger",  "Rabbit", 
                                    "Dragon", "Snake", 
                                    "Horse",  "Goat", 
                                    "Monkey", "Rooster", 
                                    "Dog",    "Pig"]

const ASPECTS: array[2, string] = ["Yang",   "Yin"]

const ELEMENTS: array[5, string] = ["Wood",  "Fire",
                                    "Earth", "Metal",
                                    "Water"]

const STEMS: array[10, string] = ["甲", "乙", "丙", "丁", "戊", 
                                  "己", "庚", "辛", "壬", "癸"]

const BRANCHES: array[12, string] = ["子", "丑", "寅", "卯", "辰", "巳", 
                                     "午", "未", "申", "酉", "戌", "亥"]

const S_NAMES: array[10, string] = ["jiă", "yĭ", "bĭng", "dīng", "wù", 
                                    "jĭ", "gēng", "xīn", "rén", "gŭi"]

const B_NAMES: array[12, string] = ["zĭ", "chŏu", "yín", "măo", "chén", "sì",
                                    "wŭ", "wèi", "shēn", "yŏu", "xū", "hài"]

proc chineseZodiac(year: int): string =
  let y = year - 4
  let s = y mod 10
  let b = y mod 12
  let stem = STEMS[s]
  let branch = BRANCHES[b]
  let name = S_NAMES[s] & "-" & B_NAMES[b]
  let element = ELEMENTS[s div 2]
  let animal = ANIMALS[b]
  let aspect = ASPECTS[s mod 2]
  let cycle = y mod 60 + 1
  &"{year}   {stem}{branch}     {name:9}  {element:7}  {animal:7}  {aspect:6}  {cycle:02}/60"

let years = [1935, 1938, 1968, 1972, 1976, 1984, 2017, 2020]
echo "Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle"
echo "----  -------  ------     -------  ------   ------  -----"
for year in years:
  echo &"{chineseZodiac(year)}"
Output:
Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle
----  -------  ------     -------  ------   ------  -----
1935   乙亥     yĭ-hài     Wood     Pig      Yin     12/60
1938   戊寅     wù-yín     Earth    Tiger    Yang    15/60
1968   戊申     wù-shēn    Earth    Monkey   Yang    45/60
1972   壬子     rén-zĭ     Water    Rat      Yang    49/60
1976   丙辰     bĭng-chén  Fire     Dragon   Yang    53/60
1984   甲子     jiă-zĭ     Wood     Rat      Yang    01/60
2017   丁酉     dīng-yŏu   Fire     Rooster  Yin     34/60
2020   庚子     gēng-zĭ    Metal    Rat      Yang    37/60

Pascal

Works with: Extended Pascal

The built-in functions pred and succ accepting a second (optional) parameter is an Extended Pascal (ISO 10206) extension, as well as the possibility of specifying record literals.

type
	animalCycle = (rat, ox, tiger, rabbit, dragon, snake,
		horse, goat, monkey, rooster, dog, pig);
	elementCycle = (wood, fire, earth, metal, water);
	aspectCycle = (yang, yin);
		
	zodiac = record
			animal: animalCycle;
			element: elementCycle;
			aspect: aspectCycle;
		end;

function getZodiac(year: integer): zodiac;
begin
	year := pred(year, 4);
	getZodiac := zodiac[
			animal: succ(rat, year mod 12);
			element: succ(wood, year mod 10 div 2);
			aspect: succ(yang, year mod 2);
		]
end;

Perl

sub zodiac {
  my $year = shift;
  my @animals = qw/Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig/;
  my @elements = qw/Wood Fire Earth Metal Water/;
  my @terrestrial_han = qw/子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥/;
  my @terrestrial_pinyin = qw/zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài/;
  my @celestial_han = qw/甲 乙 丙 丁 戊 己 庚 辛 壬 癸/;
  my @celestial_pinyin = qw/jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi/;
  my @aspect = qw/yang yin/;

  my $cycle_year = ($year-4) % 60;
  my($i2, $i10, $i12) = ($cycle_year % 2, $cycle_year % 10, $cycle_year % 12);

  ($year,
   $celestial_han[$i10], $terrestrial_han[$i12],
   $celestial_pinyin[$i10], $terrestrial_pinyin[$i12],
   $elements[$i10 >> 1], $animals[$i12], $aspect[$i2], $cycle_year+1);
}

printf("%4d: %s%s (%s-%s) %s %s; %s - year %d of the cycle\n", zodiac($_))
  for (1935, 1938, 1968, 1972, 1976, 2017);
Output:
1935: 乙亥 (yĭ-hài) Wood Pig; yin - year 12 of the cycle
1938: 戊寅 (wù-yín) Earth Tiger; yang - year 15 of the cycle
1968: 戊申 (wù-shēn) Earth Monkey; yang - year 45 of the cycle
1972: 壬子 (rén-zĭ) Water Rat; yang - year 49 of the cycle
1976: 丙辰 (bĭng-chén) Fire Dragon; yang - year 53 of the cycle
2017: 丁酉 (dīng-yŏu) Fire Rooster; yin - year 34 of the cycle

Phix

with javascript_semantics
constant animals = {"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"},
         elements = {"Wood","Fire","Earth","Metal","Water"},
         yinyang = {"yang","yin"},
         years = {1935,1938,1968,1972,1976,2018}
 
for i=1 to length(years) do
    integer year = years[i],
            cycle = mod(year-4,60)
    string element = elements[floor(mod(cycle,10)/2)+1],
           animal = animals[mod(cycle,12)+1],
           yy = yinyang[mod(cycle,2)+1]        
    printf(1,"%d: %s %s; %s, year %d of the cycle.\n",
             {year,element,animal,yy,cycle+1})
end for
Output:
1935: Wood Pig; yin, year 12 of the cycle.
1938: Earth Tiger; yang, year 15 of the cycle.
1968: Earth Monkey; yang, year 45 of the cycle.
1972: Water Rat; yang, year 49 of the cycle.
1976: Fire Dragon; yang, year 53 of the cycle.
2018: Earth Dog; yang, year 35 of the cycle.

Picat

Translation of: Prolog
Works with: Picat
animals({"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}).

elements({"Wood", "Fire", "Earth", "Metal", "Water"}).

animal_chars({"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}).

element_chars({{"甲", "丙", "戊", "庚", "壬"}, {"乙", "丁", "己", "辛", "癸"}}).

years({1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017}).

year_animal(Year) = Animal =>
    I = ((Year - 4) mod 12) + 1,
    animals(Animals),
    Animal = Animals[I].

year_element(Year) = Element =>
    I = ((Year - 4) mod 10) div 2 + 1,
    elements(Elements),
    Element = Elements[I].

year_animal_char(Year) = AnimalChar =>
    I = (Year - 4) mod 12 + 1,
    animal_chars(AnimalChars),
    AnimalChar = AnimalChars[I].

year_element_char(Year) = ElementChar =>
    I1 = Year mod 2 + 1,
    element_chars(ElementChars),
    ElementChars1 = ElementChars[I1],
    I2 = (Year - 4) mod 10 div 2 + 1,
    ElementChar = ElementChars1[I2].

year_yin_yang(Year) = YinYang =>
    Year mod 2 == 0 -> YinYang = "yang" ; YinYang = "yin".

main :-
    years(Years),
    foreach (Year in Years)
        Element = year_element(Year),
        Animal = year_animal(Year),
        YinYang = year_yin_yang(Year),
        ElementChar = year_element_char(Year),
        AnimalChar = year_animal_char(Year),
        printf("%d is the year of the %w %w (%w). %w%w\n", Year, Element, Animal, YinYang, ElementChar, AnimalChar)
    end.
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

PowerShell

Translation of: Ruby
function Get-ChineseZodiac
{
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    Param
    (
        [Parameter(Mandatory=$false,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateRange(1,9999)]
        [int]
        $Year = (Get-Date).Year
    )

    Begin
    {
        $pinyin = @{
            '甲' = 'jiă'
            '乙' = 'yĭ'
            '丙' = 'bĭng'
            '丁' = 'dīng'
            '戊' = 'wù'
            '己' = 'jĭ'
            '庚' = 'gēng'
            '辛' = 'xīn'
            '壬' = 'rén'
            '癸' = 'gŭi'
            '子' = 'zĭ'
            '丑' = 'chŏu'
            '寅' = 'yín'
            '卯' = 'măo'
            '辰' = 'chén'
            '巳' = 'sì'
            '午' = 'wŭ'
            '未' = 'wèi'
            '申' = 'shēn'
            '酉' = 'yŏu'
            '戌' = 'xū'
            '亥' = 'hài'
        }

        $celestial   = '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'
        $terrestrial = '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'
        $animals     = 'Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'
        $elements    = 'Wood', 'Fire', 'Earth', 'Metal', 'Water'
        $aspects     = 'yang', 'yin'

        $base = 4
    }
    Process
    {
        foreach ($ce_year in $Year)
        {
            $cycle_year     = $ce_year - $base

            $stem_number    = $cycle_year % 10
            $stem_han       = $celestial[$stem_number]
            $stem_pinyin    = $pinyin[$stem_han]

            $element_number = [Math]::Floor($stem_number / 2)
            $element        = $elements[$element_number]

            $branch_number  = $cycle_year % 12
            $branch_han     = $terrestrial[$branch_number]
            $branch_pinyin  = $pinyin[$branch_han]
            $animal         = $animals[$branch_number]

            $aspect_number  = $cycle_year % 2
            $aspect         = $aspects[$aspect_number]

            $index          = $cycle_year % 60 + 1

            [PSCustomObject]@{
                Year        = $Year
                Element     = $element
                Animal      = $animal
                Aspect      = $aspect
                YearOfCycle = $index
                ASCII       = "$stem_pinyin-$branch_pinyin"
                Chinese     = "$stem_han$branch_han"
            }
        }
    }
}
1935, 1938, 1968, 1972, 1976 | Get-ChineseZodiac | Format-Table
Output:
Year Element Animal Aspect YearOfCycle ASCII     Chinese
---- ------- ------ ------ ----------- -----     -------
1935 Wood    Pig    yin             12 yĭ-hài    乙亥     
1938 Earth   Tiger  yang            15 wù-yín    戊寅     
1968 Earth   Monkey yang            45 wù-shēn   戊申     
1972 Water   Rat    yang            49 rén-zĭ    壬子     
1976 Fire    Dragon yang            53 bĭng-chén 丙辰     

Defaults to the current year:

Get-ChineseZodiac
Output:
Year        : 2017
Element     : Fire
Animal      : Rooster
Aspect      : yin
YearOfCycle : 34
ASCII       : dīng-yŏu
Chinese     : 丁酉

Using the Year property of a [DateTime] object:

Get-Date "11/8/2016" | Get-ChineseZodiac
Output:
Year        : 2016
Element     : Fire
Animal      : Monkey
Aspect      : yang
YearOfCycle : 33
ASCII       : bĭng-shēn
Chinese     : 丙申

Emulate the Ruby script's output:

$zodiacs = 1935, 1938, 1968, 1972, 1976 | Get-ChineseZodiac

foreach ($zodiac in $zodiacs)
{
    "{0}: {1} ({2}, {3} {4}; {5} - year {6} of the cycle)" -f $zodiac.Year,
                                                              $zodiac.Chinese,
                                                              $zodiac.ASCII,
                                                              $zodiac.Element,
                                                              $zodiac.Animal,
                                                              $zodiac.Aspect,
                                                              $zodiac.YearOfCycle
}
Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin - year 12 of the cycle)
1938: 戊寅 (wù-yín, Earth Tiger; yang - year 15 of the cycle)
1968: 戊申 (wù-shēn, Earth Monkey; yang - year 45 of the cycle)
1972: 壬子 (rén-zĭ, Water Rat; yang - year 49 of the cycle)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang - year 53 of the cycle)

Prolog

Translation of: Java
Works with: GNU Prolog
:- initialization(main).

animals(['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig']).

elements(['Wood', 'Fire', 'Earth', 'Metal', 'Water']).

animal_chars(['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']).

element_chars([['甲', '丙', '戊', '庚', '壬'], ['乙', '丁', '己', '辛', '癸']]).

years([1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017]).

year_animal(Year, Animal) :-
    I is ((Year - 4) mod 12) + 1,
    animals(Animals),
    nth(I, Animals, Animal).

year_element(Year, Element) :-
    I is ((Year - 4) mod 10) div 2 + 1,
    elements(Elements),
    nth(I, Elements, Element).

year_animal_char(Year, AnimalChar) :-
    I is (Year - 4) mod 12 + 1,
    animal_chars(AnimalChars),
    nth(I, AnimalChars, AnimalChar).

year_element_char(Year, ElementChar) :-
    I1 is Year mod 2 + 1,
    element_chars(ElementChars),
    nth(I1, ElementChars, ElementChars1),
    I2 is (Year - 4) mod 10 div 2 + 1,
    nth(I2, ElementChars1, ElementChar).

year_yin_yang(Year, YinYang) :-
    Year mod 2 =:= 0 -> YinYang = 'yang' ; YinYang = 'yin'.

main :-
    years(Years),
    forall(member(Year, Years), (
        write(Year),
        write(' is the year of the '),
        year_element(Year, Element),
        write(Element),
        write(' '),
        year_animal(Year, Animal),
        write(Animal),
        write(' '),
        year_yin_yang(Year, YinYang),
        write('('),
        write(YinYang),
        write('). '),
        year_element_char(Year, ElementChar),
        write(ElementChar),
        year_animal_char(Year, AnimalChar),
        write(AnimalChar),
        nl
    )).
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

PureBasic

EnableExplicit
#BASE=4
#SPC=Chr(32)

Procedure.s ChineseZodiac(n.i)
  Define cycle_year.i=n-#BASE,
         stem_number.i    = cycle_year%10+1,
         element_number.i = Round(stem_number/2,#PB_Round_Nearest),
         branch_number.i  = cycle_year%12+1,
         aspect_number.i  = cycle_year%2+1,
         index.i          = cycle_year%60+1,
         celestial$       = Chr(PeekU(?Celestial_stem+SizeOf(Character)*(stem_number-1))),
         c_pinyin$        = StringField(PeekS(?Stem),stem_number,"\"),
         element$         = StringField(PeekS(?Element),element_number,"\"),
         branch_han$      = Chr(PeekU(?Terrestrial_branch+SizeOf(Character)*(branch_number-1))),
         b_pinyin$        = StringField(PeekS(?Branch),branch_number,"\"),
         animal$          = StringField(PeekS(?Zodiac_animal),branch_number,"\"),
         aspect$          = StringField(PeekS(?Aspect),aspect_number,"\"),
         YearOfCycle$     = Str(index)  
  ProcedureReturn Str(n)+#SPC+
                         LSet(element$,7,#SPC)+#SPC+
                         LSet(animal$,7,#SPC)+#SPC+
                         LSet(aspect$,6,#SPC)+#SPC+
                         RSet(YearOfCycle$,11)+#SPC+
                         LSet(c_pinyin$+"-"+b_pinyin$,9,#SPC)+#SPC+
                         celestial$+branch_han$
EndProcedure

LoadFont(0,"Consolas",12)
If OpenWindow(0,#PB_Ignore,#PB_Ignore,600,400,"Chinese Zodiac",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  EditorGadget(0, 8, 8, 600-16, 400-16) : SetGadgetFont(0,FontID(0))
  Define header$="Year Element Animal  Aspect YearOfCycle ASCII     Chinese"
  AddGadgetItem(0,-1,header$)
  AddGadgetItem(0,-1,ChineseZodiac(1935))
  AddGadgetItem(0,-1,ChineseZodiac(1938))
  AddGadgetItem(0,-1,ChineseZodiac(1968))
  AddGadgetItem(0,-1,ChineseZodiac(1972))  
  AddGadgetItem(0,-1,ChineseZodiac(1976))
  AddGadgetItem(0,-1,ChineseZodiac(1984))
  AddGadgetItem(0,-1,ChineseZodiac(Year(Date()))) 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

DataSection
  Celestial_stem: : Data.u $7532, $4E59, $4E19, $4E01, $620A, $5DF1, $5E9A, $8F9B, $58EC, $7678  
  Terrestrial_branch: : Data.u $5B50, $4E11, $5BC5, $536F, $8FB0, $5DF3, $5348, $672A, $7533, $9149, $620C, $4EA5  
  Zodiac_animal: : Data.s "Rat\Ox\Tiger\Rabbit\Dragon\Snake\Horse\Goat\Monkey\Rooster\Dog\Pig"  
  Element: : Data.s "Wood\Fire\Earth\Metal\Water"  
  Aspect: : Data.s "yang\yin"  
  Stem: : Data.s "jiă\yĭ\bĭng\dīng\wù\jĭ\gēng\xīn\rén\gŭi"  
  Branch: : Data.s "zĭ\chŏu\yín\măo\chén\sì\wŭ\wèi\shēn\yŏu\xū\hài"  
EndDataSection
Output:
Year Element Animal  Aspect YearOfCycle ASCII     Chinese
1935 Wood    Pig     yin             12 yĭ-hài    乙亥
1938 Earth   Tiger   yang            15 wù-yín    戊寅
1968 Earth   Monkey  yang            45 wù-shēn   戊申
1972 Water   Rat     yang            49 rén-zĭ    壬子
1976 Fire    Dragon  yang            53 bĭng-chén 丙辰
1984 Wood    Rat     yang             1 jiă-zĭ    甲子
2017 Fire    Rooster yin             34 dīng-yŏu  丁酉

Python

Translation of: Ruby
# coding: utf-8

from __future__ import print_function
from datetime import datetime

pinyin = {
  '甲': 'jiă',
  '乙': 'yĭ',
  '丙': 'bĭng',
  '丁': 'dīng',
  '戊': 'wù',
  '己': 'jĭ',
  '庚': 'gēng',
  '辛': 'xīn',
  '壬': 'rén',
  '癸': 'gŭi',

  '子': 'zĭ',
  '丑': 'chŏu',
  '寅': 'yín',
  '卯': 'măo',
  '辰': 'chén',
  '巳': 'sì',
  '午': 'wŭ',
  '未': 'wèi',
  '申': 'shēn',
  '酉': 'yŏu',
  '戌': 'xū',
  '亥': 'hài'
}

animals = ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake',
           'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig']
elements = ['Wood', 'Fire', 'Earth', 'Metal', 'Water']

celestial = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
terrestrial = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
aspects = ['yang', 'yin']


def calculate(year):
    BASE = 4
    year = int(year)
    cycle_year = year - BASE
    stem_number = cycle_year % 10
    stem_han = celestial[stem_number]
    stem_pinyin = pinyin[stem_han]
    element_number = stem_number // 2
    element = elements[element_number]
    branch_number = cycle_year % 12
    branch_han = terrestrial[branch_number]
    branch_pinyin = pinyin[branch_han]
    animal = animals[branch_number]
    aspect_number = cycle_year % 2
    aspect = aspects[aspect_number]
    index = cycle_year % 60 + 1
    print("{}: {}{} ({}-{}, {} {}; {} - year {} of the cycle)"
          .format(year, stem_han, branch_han,
                  stem_pinyin, branch_pinyin, element, animal, aspect, index))


current_year = datetime.now().year
years = [1935, 1938, 1968, 1972, 1976, current_year]
for year in years:
    calculate(year)


Or, segmenting tokens just in time, and writing out wiki tables:

Works with: Python version 3.7
'''Chinese zodiac'''

from functools import (reduce)
from datetime import datetime


# TRADITIONAL STRINGS -------------------------------------

# zodiacNames :: Dict
def zodiacNames():
    '''天干 tiangan – 10 heavenly stems
       地支 dizhi – 12 terrestrial branches
       五行 wuxing – 5 elements
       生肖 shengxiao – 12 symbolic animals
       阴阳 yinyang - dark and light
    '''
    return dict(
        zip(
            ['tian', 'di', 'wu', 'sx', 'yy'],
            map(
                lambda tpl: list(
                    zip(* [tpl[0]] + list(
                        map(
                            lambda x: x.split(),
                            tpl[1:])
                    ))
                ),
                [
                    # 天干 tiangan – 10 heavenly stems
                    ('甲乙丙丁戊己庚辛壬癸',
                     'jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi'),

                    # 地支 dizhi – 12 terrestrial branches
                    ('子丑寅卯辰巳午未申酉戌亥',
                     'zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài'),

                    # 五行 wuxing – 5 elements
                    ('木火土金水',
                     'mù huǒ tǔ jīn shuǐ',
                     'wood fire earth metal water'),

                    # 十二生肖 shengxiao – 12 symbolic animals
                    ('鼠牛虎兔龍蛇馬羊猴鸡狗豬',
                     'shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū',
                     'rat ox tiger rabbit dragon snake horse goat ' +
                     'monkey rooster dog pig'
                     ),

                    # 阴阳 yinyang
                    ('阳阴', 'yáng yīn')
                ]
            )))


# zodiacYear :: Dict -> [[String]]
def zodiacYear(dct):
    '''A string of strings containing the
       Chinese zodiac tokens for a given year.
    '''
    def tokens(y):
        iYear = y - 4
        iStem = iYear % 10
        iBranch = iYear % 12
        (hStem, pStem) = dct['tian'][iStem]
        (hBranch, pBranch) = dct['di'][iBranch]
        yy = iYear % 2
        return [
            [str(y), '', ''],
            [
                hStem + hBranch,
                pStem + pBranch,
                str((iYear % 60) + 1) + '/60'
            ],
            list(dct['wu'][iStem // 2]),
            list(dct['sx'][iBranch]),
            list(dct['yy'][int(yy)]) + ['dark' if yy else 'light']
        ]
    return lambda year: tokens(year)


# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Writing out wiki tables displaying Chinese zodiac
       details for a given list of years.
    '''
    print('\n'.join(
        list(map(
            zodiacTable(zodiacNames()),
            [
                1935, 1938, 1949,
                1968, 1972, 1976,
                datetime.now().year
            ]
        ))
    ))


# WIKI TABLES  --------------------------------------------

# zodiacTable :: Dict -> Int -> String
def zodiacTable(tokens):
    '''A wiki table displaying Chinese zodiac
       details for a a given year.
    '''
    return lambda y: wikiTable({
        'class': 'wikitable',
        'colwidth': '70px'
    })(transpose(zodiacYear(tokens)(y)))


# wikiTable :: Dict -> [[a]] -> String
def wikiTable(opts):
    '''List of lists rendered as a wiki table string.'''
    def colWidth():
        return 'width:' + opts['colwidth'] + '; ' if (
            'colwidth' in opts
        ) else ''

    def cellStyle():
        return opts['cell'] if 'cell' in opts else ''

    return lambda rows: '{| ' + reduce(
        lambda a, k: (
            a + k + '="' + opts[k] + '" ' if k in opts else a
        ),
        ['class', 'style'],
        ''
    ) + '\n' + '\n|-\n'.join(
        '\n'.join(
            ('|' if (0 != i and ('cell' not in opts)) else (
                '|style="' + colWidth() + cellStyle() + '"|'
            )) + (
                str(x) or ' '
            ) for x in row
        ) for i, row in enumerate(rows)
    ) + '\n|}\n\n'


# GENERIC -------------------------------------------------

# transpose :: Matrix a -> Matrix a
def transpose(m):
    '''The rows and columns of the argument transposed.
       (The matrix containers and rows can be lists or tuples).'''
    if m:
        inner = type(m[0])
        z = zip(*m)
        return (type(m))(
            map(inner, z) if tuple != inner else z
        )
    else:
        return m


# MAIN ---
if __name__ == '__main__':
    main()
Output:
1935 乙亥
yĭhài zhū yīn
12/60 wood pig dark


1938 戊寅
wùyín yáng
15/60 earth tiger light


1949 己丑
jĭchŏu niú yīn
26/60 earth ox dark


1968 戊申
wùshēn hóu yáng
45/60 earth monkey light


1972 壬子
rénzĭ shuǐ shǔ yáng
49/60 water rat light


1976 丙辰
bĭngchén huǒ lóng yáng
53/60 fire dragon light


2019 己亥
jĭhài zhū yīn
36/60 earth pig dark

Quackery

  [ dup echo
    say " is the year of the "
    4 - dup 10 mod 2 /
    [ table $ "Wood"  $ "Fire"  $ "Earth"
            $ "Metal" $ "Water" ]
    do echo$
    sp
    dup 12 mod
    [ table
      $ "Rat"    $ "Ox"      $ "Tiger" $ "Rabbit"
      $ "Dragon" $ "Snake"   $ "Horse" $ "Goat"
      $ "Monkey" $ "Rooster" $ "Dog"   $ "Pig" ]
    do echo$
    say " ("
    2 mod
    [ table $ "yang" $ "yin" ]
    do echo$
    say ")." cr ]                                 is zodiac ( $ --> )

  ' [ 1935 1938 1968 1972 1976 1984 1985 2017 ]
  witheach zodiac
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
1984 is the year of the Wood Rat (yang).
1985 is the year of the Wood Ox (yin).
2017 is the year of the Fire Rooster (yin).

Racket

Translation of: Common Lisp
#lang racket

(require racket/date)

; Any CE Year that was the first of a 60-year cycle
(define base-year 1984)
 
(define celestial-stems '("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))
 
(define terrestrial-branches '("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))
 
(define zodiac-animals
  '("Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"))
 
(define elements '("Wood" "Fire" "Earth" "Metal" "Water"))
 
(define aspects '("yang" "yin"))
 
(define pinyin
  (map cons
       (append celestial-stems terrestrial-branches)
       (list "jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
             "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))
 
(define (this-year) (date-year (current-date)))

(define (pinyin-for han) (cdr (assoc han pinyin)))

(define (han/pinyin-nth n hans) (let ((han (list-ref hans n))) (values han (pinyin-for han))))

(define (chinese-zodiac ce-year)
  (let* ((cycle-year (- ce-year base-year))
         (stem-number    (modulo cycle-year (length celestial-stems)))
         (element-number (quotient stem-number 2))
         (aspect-number  (modulo cycle-year (length aspects)))
         (branch-number  (modulo cycle-year (length terrestrial-branches)))
         (element        (list-ref elements element-number)) 
         (zodiac-animal  (list-ref zodiac-animals branch-number))
         (aspect         (list-ref aspects aspect-number)))
    (let-values (([stem-han stem-pinyin]     (han/pinyin-nth stem-number celestial-stems))                  
                 ([branch-han branch-pinyin] (han/pinyin-nth branch-number terrestrial-branches)))
      (list ce-year stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect))))

(module+ test
  (for ((ce-year (in-list '(1935 1938 1941 1947 1968 1972 1976))))
  (apply printf "~a: ~a~a (~a-~a, ~a ~a; ~a)~%" (chinese-zodiac ce-year))))
Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin)
1938: 戊寅 (wù-yín, Earth Tiger; yang)
1941: 辛巳 (xīn-sì, Metal Snake; yin)
1947: 丁亥 (dīng-hài, Fire Pig; yin)
1968: 戊申 (wù-shēn, Earth Monkey; yang)
1972: 壬子 (rén-zĭ, Water Rat; yang)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang)

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.01
Translation of: Ruby
sub Chinese-zodiac ( Int $year ) {
    my @heaven  = <甲 jiă 乙 yĭ 丙 bĭng 丁 dīng 戊 wù 己 jĭ 庚 gēng 辛 xīn 壬 rén 癸 gŭi>.pairup;
    my @earth   = <子 zĭ 丑 chŏu 寅 yín 卯 măo 辰 chén 巳 sì 午 wŭ 未 wèi 申 shēn 酉 yŏu 戌 xū 亥 hài>.pairup;
    my @animal  = <Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig>;
    my @element = <Wood Fire Earth Metal Water>;
    my @aspect  = <yang yin>;

    my $cycle_year = ($year - 4) % 60;
    my $i2         = $cycle_year % 2;
    my $i10        = $cycle_year % 10;
    my $i12        = $cycle_year % 12;

    %(
        'Han'     => @heaven[$i10].key ~ @earth[$i12].key,
        'pinyin'  => @heaven[$i10].value ~ @earth[$i12].value,
        'heaven'  => @heaven[$i10],
        'earth'   => @earth[$i12],
        'element' => @element[$i10 div 2],
        'animal'  => @animal[$i12],
        'aspect'  => @aspect[$i2],
        'cycle'   => $cycle_year + 1
    )
}

# TESTING
printf "%d: %s (%s, %s %s; %s - year %d in the cycle)\n",
    $_, .&Chinese-zodiac<Han pinyin element animal aspect cycle>
    for 1935, 1938, 1968, 1972, 1976, 1984, Date.today.year;
Output:
1935: 乙亥 (yĭhài, Wood Pig; yin - year 12 in the cycle)
1938: 戊寅 (wùyín, Earth Tiger; yang - year 15 in the cycle)
1968: 戊申 (wùshēn, Earth Monkey; yang - year 45 in the cycle)
1972: 壬子 (rénzĭ, Water Rat; yang - year 49 in the cycle)
1976: 丙辰 (bĭngchén, Fire Dragon; yang - year 53 in the cycle)
1984: 甲子 (jiăzĭ, Wood Rat; yang - year 1 in the cycle)
2017: 丁酉 (dīngyŏu, Fire Rooster; yin - year 34 in the cycle)

Ring

yinyang  = ["yang", "yin"]
elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
animals  = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
            "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
years    = [1801, 1861, 1984, 2020, 2186, 76543]
output   = ""
 
for year in years
    yy      = year % 2 + 1
    element = (year - 4) % 5 + 1
    animal  = (year - 4) % 12 + 1
    output  = string(year) + " is the year of the "
    output += elements[element] + " " + animals[animal] + " (" + yinyang[yy] + ")."
    ? output
next
Output:
1801 is the year of the Earth Rooster (yin).
1861 is the year of the Earth Rooster (yin).
1984 is the year of the Wood Rat (yang).
2020 is the year of the Fire Rat (yang).
2186 is the year of the Earth Dog (yang).
76543 is the year of the Water Rabbit (yin).

RPL

Works with: Halcyon Calc version 4.2.7
≪ 4 -
  { "Wood " "Fire " "Earth " "Metal " "Water " }
  OVER 10 MOD 1 + 2 / GET 
  { "Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig" }
  3 PICK 12 MOD 1 + GET +
  SWAP 2 MOD " (yin)" " (yang)" IFTE +
≫ 'CHZOD' STO
2022 CHZOD
Output:
1: "Water Tiger (yang)"

Ruby

This is written as a command-line tool that takes a list of CE year numbers as arguments and outputs their information; if no arguments are supplied, it displays the information for the current year.

# encoding: utf-8
pinyin = {
  '甲' => 'jiă',
  '乙' => 'yĭ',
  '丙' => 'bĭng',
  '丁' => 'dīng',
  '戊' => 'wù',
  '己' => 'jĭ',
  '庚' => 'gēng',
  '辛' => 'xīn',
  '壬' => 'rén',
  '癸' => 'gŭi',

  '子' => 'zĭ',
  '丑' => 'chŏu',
  '寅' => 'yín',
  '卯' => 'măo',
  '辰' => 'chén',
  '巳' => 'sì',
  '午' => 'wŭ',
  '未' => 'wèi',
  '申' => 'shēn',
  '酉' => 'yŏu',
  '戌' => 'xū',
  '亥' => 'hài'
}
celestial     = %w(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
terrestrial   = %w(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
animals       = %w(Rat   Ox   Tiger  Rabbit  Dragon Snake
                   Horse Goat Monkey Rooster Dog    Pig)
elements      = %w(Wood Fire Earth Metal Water)
aspects       = %w(yang yin)

BASE = 4

args = if !ARGV.empty?
         ARGV
       else
         [Time.new.year]
       end

args.each do |arg|
  ce_year = Integer(arg)
  print "#{ce_year}: " if ARGV.length > 1
  cycle_year     = ce_year - BASE

  stem_number    = cycle_year % 10
  stem_han       = celestial[stem_number]
  stem_pinyin    = pinyin[stem_han]

  element_number = stem_number / 2
  element        = elements[element_number]

  branch_number  = cycle_year % 12
  branch_han     = terrestrial[branch_number]
  branch_pinyin  = pinyin[branch_han]
  animal         = animals[branch_number]

  aspect_number = cycle_year % 2
  aspect        = aspects[aspect_number]

  index         = cycle_year % 60 + 1

  print stem_han, branch_han
  puts " (#{stem_pinyin}-#{branch_pinyin}, #{element} #{animal}; #{aspect} - year #{index} of the cycle)"
end
Output:

Given arguments 1935 1938 1968 1972 1976:

1935: 乙亥 (yĭ-hài, Wood Pig; yin - year 12 of the cycle)
1938: 戊寅 (wù-yín, Earth Tiger; yang - year 15 of the cycle)
1968: 戊申 (wù-shēn, Earth Monkey; yang - year 45 of the cycle)
1972: 壬子 (rén-zĭ, Water Rat; yang - year 49 of the cycle)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang - year 53 of the cycle)

Given no arguments and run during the year 2017:

丁酉 (dīng-yŏu, Fire Rooster; yin - year 34 of the cycle)

Rust

Translation of: Kotlin
fn chinese_zodiac(year: usize) -> String {
    static ANIMALS: [&str; 12] = [
        "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig",
    ];
    static ASPECTS: [&str; 2] = ["Yang", "Yin"];
    static ELEMENTS: [&str; 5] = ["Wood", "Fire", "Earth", "Metal", "Water"];
    static STEMS: [char; 10] = [
        '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸',
    ];
    static BRANCHES: [char; 12] = [
        '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥',
    ];
    static S_NAMES: [&str; 10] = [
        "jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi",
    ];
    static B_NAMES: [&str; 12] = [
        "zĭ", "chŏu", "yín", "măo", "chén", "sì",
        "wŭ", "wèi", "shēn", "yŏu", "xū", "hài",
    ];

    let y = year - 4;
    let s = y % 10;
    let b = y % 12;

    let stem = STEMS[s];
    let branch = BRANCHES[b];
    let s_name = S_NAMES[s];
    let b_name = B_NAMES[b];
    let element = ELEMENTS[s / 2];
    let animal = ANIMALS[b];
    let aspect = ASPECTS[s % 2];
    let cycle = y % 60 + 1;

    format!(
        "{}    {}{}    {:9}  {:7}  {:7}  {:6}  {:02}/60",
        year,
        stem,
        branch,
        format!("{}-{}", s_name, b_name),
        element,
        animal,
        aspect,
        cycle
    )
}

fn main() {
    let years = [1935, 1938, 1968, 1972, 1976, 1984, 2017];
    println!("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle");
    println!("----  -------  ---------  -------  -------  ------  -----");
    for &year in &years {
        println!("{}", chinese_zodiac(year));
    }
}
Output:
Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle
----  -------  ---------  -------  -------  ------  -----
1935    乙亥    yĭ-hài     Wood     Pig      Yin     12/60
1938    戊寅    wù-yín     Earth    Tiger    Yang    15/60
1968    戊申    wù-shēn    Earth    Monkey   Yang    45/60
1972    壬子    rén-zĭ     Water    Rat      Yang    49/60
1976    丙辰    bĭng-chén  Fire     Dragon   Yang    53/60
1984    甲子    jiă-zĭ     Wood     Rat      Yang    01/60
2017    丁酉    dīng-yŏu   Fire     Rooster  Yin     34/60

Scala

object Zodiac extends App {
  val years = Seq(1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017, 2018)

  private def animals =
    Seq("Rat",
      "Ox",
      "Tiger",
      "Rabbit",
      "Dragon",
      "Snake",
      "Horse",
      "Goat",
      "Monkey",
      "Rooster",
      "Dog",
      "Pig")

  private def animalChars =
    Seq("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥")

  private def elements = Seq("Wood", "Fire", "Earth", "Metal", "Water")

  private def elementChars =
    Seq(Array("甲", "丙", "戊", "庚", "壬"), Array("乙", "丁", "己", "辛", "癸"))

  private def getYY(year: Int) = if (year % 2 == 0) "yang" else "yin"

  for (year <- years) {
    println(year
      + " is the year of the " + elements(math.floor((year - 4) % 10 / 2).toInt) + " " 
      + animals((year - 4) % 12)
      + " (" + getYY(year) + "). "
      + elementChars(year % 2)(math.floor((year - 4) % 10 / 2).toInt)
      + animalChars((year - 4) % 12))
  }
}
Output:
See it in running in your browser by ScalaFiddle (JavaScript) or by Scastie (JVM).

Seed7

The standard output file of Seed7 accepts only Latin-1 (byte) output. Therefore the output with the chinese characters is written to STD_CONSOLE. The library console.s7i defines STD_CONSOLE.

$ include "seed7_05.s7i";
  include "console.s7i";

const array string: animals is [0] ("Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig");
const array string: elements is [0] ("Wood", "Fire", "Earth", "Metal", "Water");
const array string: animalChars is [0] ("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥");
const array array string: elementChars is [0] ([0] ("甲", "丙", "戊", "庚", "壬"), [0] ("乙", "丁", "己", "辛", "癸"));

const proc: main is func
  local
    var integer: year is 0;
    var integer: eIdx is 0;
    var integer: aIdx is 0;
  begin
    OUT := STD_CONSOLE;
    for year range {1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017} do
      eIdx := (year - 4) rem 10 div 2;
      aIdx := (year - 4) rem 12;
      writeln(year <& " is the year of the " <& elements[eIdx] <& " " <& animals[aIdx] <& " (" <&
              ([0] ("yang", "yin"))[year rem 2] <& "). " <& elementChars[year rem 2][eIdx] <& animalChars[aIdx]);
    end for;
  end func;
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

Sidef

Translation of: Perl
func zodiac(year) {
  var animals = %w(Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig)
  var elements = %w(Wood Fire Earth Metal Water)
  var terrestrial_han = %w(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
  var terrestrial_pinyin = %w(zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài)
  var celestial_han = %w(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
  var celestial_pinyin = %w(jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi)
  var aspect = %w(yang yin)

  var cycle_year = ((year-4) % 60)
  var (i2, i10, i12) = (cycle_year%2, cycle_year%10, cycle_year%12)

  (year,
   celestial_han[i10],    terrestrial_han[i12],
   celestial_pinyin[i10], terrestrial_pinyin[i12],
   elements[i10 >> 1], animals[i12], aspect[i2], cycle_year+1)
}

[1935, 1938, 1968, 1972, 1976, 2017].each { |year|
    printf("%4d: %s%s (%s-%s) %s %s; %s - year %d of the cycle\n", zodiac(year))
}
Output:
1935: 乙亥 (yĭ-hài) Wood Pig; yin - year 12 of the cycle
1938: 戊寅 (wù-yín) Earth Tiger; yang - year 15 of the cycle
1968: 戊申 (wù-shēn) Earth Monkey; yang - year 45 of the cycle
1972: 壬子 (rén-zĭ) Water Rat; yang - year 49 of the cycle
1976: 丙辰 (bĭng-chén) Fire Dragon; yang - year 53 of the cycle
2017: 丁酉 (dīng-yŏu) Fire Rooster; yin - year 34 of the cycle

tbas

	DATA "甲","乙","丙","丁","戊","己","庚","辛","壬","癸"
	DECLARE celestial$(10)
	MAT READ celestial$
	
	DATA "子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"
	DECLARE terrestrial$(12)
	MAT READ terrestrial$
	
	DATA "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
	DECLARE animals$(12)
	MAT READ animals$

        DATA "Wood","Fire","Earth","Metal","Water"
	DECLARE elements$(5)
	MAT READ elements$

	DATA "yang","yin"
	DECLARE aspects$(2)
	MAT READ aspects$
	
	DATA "jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"
	DATA "zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"
	DECLARE celestialpinyin$(UBOUND(celestial$(),1))
	DECLARE terrestrialpinyin$(UBOUND(terrestrial$(),1))
	MAT READ celestialpinyin$
	MAT READ terrestrialpinyin$
	
	DATA 1935,1938,1931,1961,1963,1991,1993,1996,2001
	DECLARE years(9)
	MAT READ years
	
	DECLARE _base = 4	 
	DECLARE _year 
	DECLARE cycleyear 
	DECLARE stemnumber 
	DECLARE stemhan$    
	DECLARE stempinyin$ 
	DECLARE elementnumber 
	DECLARE element$       
	DECLARE branchnumber 
	DECLARE branchhan$    
	DECLARE branchpinyin$ 
	DECLARE animal$       
	DECLARE aspectnumber 
	DECLARE aspect$       
	DECLARE index 
	
	DECLARE i 
	DECLARE top = ubound(years(),1)
	FOR i = 1 TO top
		_year = years(i)
		cycleyear = _year - _base
		stemnumber = MOD(cycleyear, 10) 
		stemhan$    = celestial$(stemnumber + 1)
		stempinyin$ = celestialpinyin$(stemnumber + 1)
		elementnumber = div(stemnumber, 2) + 1
		element$       = elements$(elementnumber)
		branchnumber = MOD(cycleyear, 12)		
		branchhan$    = terrestrial$(branchnumber + 1)
		branchpinyin$ = terrestrialpinyin$(branchnumber + 1)
		animal$       = animals$(branchnumber + 1)
		aspectnumber = MOD(cycleyear, 2)
		aspect$       = aspects$(aspectnumber + 1)
		index = MOD(cycleyear, 60) + 1		
		PRINT _year; 
		PRINT TAB(5);stemhan$+branchhan$;
		PRINT TAB(12);stempinyin$;"-";branchpinyin$;
		PRINT TAB(25);element$;" ";animal$;" ("+aspect$+")";
		PRINT TAB(50);"year";index;"of the cycle"		
	NEXT
$ tbas chinZod.bas
 1935 乙亥 yĭ-hài     Wood Pig (yin)           year 12 of the cycle
 1938 戊寅 wù-yín     Earth Tiger (yang)       year 15 of the cycle
 1931 辛未 xīn-wèi    Metal Goat (yin)         year 8 of the cycle
 1961 辛丑 xīn-chŏu   Metal Ox (yin)           year 38 of the cycle
 1963 癸卯 gŭi-măo    Water Rabbit (yin)       year 40 of the cycle
 1991 辛未 xīn-wèi    Metal Goat (yin)         year 8 of the cycle
 1993 癸酉 gŭi-yŏu    Water Rooster (yin)      year 10 of the cycle
 1996 丙子 bĭng-zĭ    Fire Rat (yang)          year 13 of the cycle
 2001 辛巳 xīn-sì     Metal Snake (yin)        year 18 of the cycle

Tcl

proc cn_zodiac year {
   set year0 [expr $year-4]
   set animals {Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig}
   set elements {Wood Fire Earth Metal Water}
   set stems {jia3 yi3 bing3 ding1 wu4 ji3 geng1 xin1 ren2 gui3}
   set gan {\u7532 \u4E59 \u4E19 \u4E01 \u620A \u5DF1 \u5E9A \u8F9B \u58EC \u7678}
   set branches {zi3 chou3 yin2 mao3 chen2 si4 wu3 wei4 shen1 you3 xu1 hai4}
   set zhi {\u5B50 \u4E11 \u5BC5 \u536F \u8FB0 \u5DF3 \u5348 \u672A \u7533 \u9149 \u620C \u4EA5}
   set m10 [expr $year0%10]
   set m12 [expr $year0%12]
   set res [lindex $gan $m10][lindex $zhi $m12]
   lappend res [lindex $stems $m10]-[lindex $branches $m12]
   lappend res [lindex $elements [expr $m10/2]]
   lappend res [lindex $animals $m12] ([expr {$year0%2 ? "yin" : "yang"}])
   lappend res year [expr $year0%60+1]
   return $res
}
% cn_zodiac 1984
甲子 jia3-zi3 Wood Rat (yang) year 1
% cn_zodiac 2017
丁酉 ding1-you3 Fire Rooster (yin) year 34

uBasic/4tH

Works with: R3
dim @y(2)                              ' yin or yang
dim @e(5)                              ' the elements
dim @a(12)                             ' the animals

Push "yang", "yin"                     ' fill Ying/Yang table
For i = 1 to 0 Step -1 : @y(i) = Pop() : Next i
                                       ' fill Elements table
Push "Wood", "Fire", "Earth", "Metal", "Water"
For i = 4 to 0 Step -1 : @e(i) = Pop() : Next i
                                       ' fill Animals table
Push "Rat",   "Ox",   "Tiger",  "Rabbit",  "Dragon", "Snake"
Push "Horse", "Goat", "Monkey", "Rooster", "Dog",    "Pig"

For i = 11 to 0 step -1 : @a(i) = Pop() : Next i
                                       ' now push all the test years
Push 76543, 2186, 2020, 1984, 1861, 1801
                                       ' and process them all
Do While Used()                        ' until the stack is empty
  Print Show(FUNC(_Chinese(Pop())))    ' call function
Loop

End
 
_Chinese                               ' compose string
  Param (1)
  Local (3)
  
  b@ = a@ % 2
  c@ = (a@ - 4) % 5
  d@ = (a@ - 4) % 12
Return (Join(Str (a@), " is the year of the ", @e(c@), " ", @a(d@), " (", @y(b@), ")."))

Output:

1801 is the year of the Earth Rooster (yin).
1861 is the year of the Earth Rooster (yin).
1984 is the year of the Wood Rat (yang).
2020 is the year of the Fire Rat (yang).
2186 is the year of the Earth Dog (yang).
76543 is the year of the Water Rabbit (yin).

0 OK, 0:1047 

UNIX Shell

Works with: Bash version 4+
Works with: Korn Shell version 93+

The required versions introduced support for associative arrays.

#!/usr/bin/env bash
declare -A pinyin=(
  [甲]='jiă'
  [乙]='yĭ'
  [丙]='bĭng'
  [丁]='dīng'
  [戊]='wù'
  [己]='jĭ'
  [庚]='gēng'
  [辛]='xīn'
  [壬]='rén'
  [癸]='gŭi'

  [子]='zĭ'
  [丑]='chŏu'
  [寅]='yín'
  [卯]='măo'
  [辰]='chén'
  [巳]='sì'
  [午]='wŭ'
  [未]='wèi'
  [申]='shén'
  [酉]='yŏu'
  [戌]='xū'
  [亥]='hài'
)

celestial=(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
terrestrial=(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
animals=(Rat   Ox   Tiger  Rabbit  Dragon Snake
         Horse Goat Monkey Rooster Dog    Pig)
elements=(Wood Fire Earth Metal Water)
aspects=(yang yin)

BaseYear=4

function main {
  if (( !$# )); then
    set -- $(date +%Y)
  fi
  local year
  for year; do
    if (( $# > 1 )); then
      printf '%s:' "$year"
    fi
    local -i cycle_year=year-BaseYear
    local -i stem_number=$cycle_year%${#celestial[@]}
    local stem_han=${celestial[$stem_number]}
    local stem_pinyin=${pinyin[$stem_han]}

    local -i element_number=stem_number/2
    local element=${elements[$element_number]}

    local -i branch_number=$cycle_year%${#terrestrial[@]}
    local branch_han=${terrestrial[$branch_number]}
    local branch_pinyin=${pinyin[$branch_han]}
    local animal=${animals[$branch_number]}

    local -i aspect_number=$cycle_year%${#aspects[@]}
    local aspect=${aspects[$aspect_number]}

    printf '%s%s'  $stem_han $branch_han
    printf '(%s-%s, %s %s; %s)\n' $stem_pinyin $branch_pinyin $element $animal $aspect
  done
}

main "$@"
Works with: Z Shell version 5.5+

Version required for associative array initialization syntax. Main difference from bash is that we number everything starting at 1 instead of 0.

#!/usr/bin/env zsh
declare -A pinyin=(
  [甲]='jiă'
  [乙]='yĭ'
  [丙]='bĭng'
  [丁]='dīng'
  [戊]='wù'
  [己]='jĭ'
  [庚]='gēng'
  [辛]='xīn'
  [壬]='rén'
  [癸]='gŭi'

  [子]='zĭ'
  [丑]='chŏu'
  [寅]='yín'
  [卯]='măo'
  [辰]='chén'
  [巳]='sì'
  [午]='wŭ'
  [未]='wèi'
  [申]='shén'
  [酉]='yŏu'
  [戌]='xū'
  [亥]='hài'
)

celestial=(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
terrestrial=(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
animals=(Rat   Ox   Tiger  Rabbit  Dragon Snake
         Horse Goat Monkey Rooster Dog    Pig)
elements=(Wood Fire Earth Metal Water)
aspects=(yang yin)

BaseYear=4

main() {
  if (( !$# )); then
    set -- $(date +%Y)
  fi
  local year
  for year; do
    if (( $# > 1 )); then
      printf '%s:' "$year"
    fi
    local -i cycle_year=year-BaseYear+1
    local -i stem_number=$(amod $cycle_year ${#celestial[@]})
    local stem_han=$celestial[$stem_number]
    local stem_pinyin=$pinyin[$stem_han]

    local -i element_number
    (( element_number = (stem_number-1)/2+1 ))
    local element=$elements[$element_number]

    local -i branch_number=$(amod $cycle_year ${#terrestrial[@]})
    local branch_han=$terrestrial[$branch_number]
    local branch_pinyin=$pinyin[$branch_han]
    local animal=$animals[$branch_number]

    local -i aspect_number=$(amod $cycle_year ${#aspects[@]})
    local aspect=$aspects[$aspect_number]

    printf '%s%s'  $stem_han $branch_han
    printf '(%s-%s, %s %s; %s)\n' $stem_pinyin $branch_pinyin $element $animal $aspect
  done
}

amod() {
  local -i m=$1 n=$2
  printf '%d\n' $(( (m + n - 1) % n + 1 ))
}

main "$@"
Output:

Output is the same for both versions:

$ cz 1935 1938 1968 1972 1976:
1935:乙亥(yĭ-hài, Wood Pig; yin)
1938:戊寅(wù-yín, Earth Tiger; yang)
1968:戊申(wù-shén, Earth Monkey; yang)
1972:壬子(rén-zĭ, Water Rat; yang)
1976:丙辰(bĭng-chén, Fire Dragon; yang)

UTFool

···
http://rosettacode.org/wiki/Chinese_zodiac
···
■ ChineseZodiac
  § static
    tiangan⦂ String[][]: ¤ · 10 celestial stems
     ¤ "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"
     ¤ "jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi"
     
    dizhi⦂ String[][]: ¤ · 12 terrestrial branches
     ¤ "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"
     ¤ "zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu", "xū", "hài"
     
    wuxing⦂ String[][]: ¤ · 5 traditional elements
     ¤ "木", "火", "土", "金", "水"
     ¤ "mù", "huǒ", "tǔ", "jīn", "shuǐ"
     ¤ "wood", "fire", "earth", "metal", "water"
     
    shengxiao⦂ String[][]: ¤ · 12 animal deities
     ¤ "鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "鸡", "狗", "豬"
     ¤ "shǔ", "niú", "hǔ", "tù", "lóng", "shé", "mǎ", "yáng", "hóu", "jī", "gǒu", "zhū"
     ¤ "rat", "ox", "tiger", "rabbit", "dragon", "snake", "horse", "goat", "monkey", "rooster", "dog", "pig"
     
    yinyang⦂ String[][]: ¤ · 2 fundamental principles
     ¤ "阳", "阴"
     ¤ "yáng", "yīn"

    ▶ main
    • args⦂ String[]
      for each year ∈ [1935, 1938, 1968, 1972, 1976, 1984, 1985, 1986, 2017]⦂ int
          cycle⦂  int: year - 4
          stem⦂   int: cycle \ 10
          branch⦂ int: cycle \ 12
          System.out.printf "%4s  %-8s %-6s %-6s %s\n", year, tiangan[0][stem] ⊕ dizhi[0][branch],
            wuxing[0][stem / 2], shengxiao[0][branch], yinyang[0][year \ 2]
          System.out.printf "      %-9s %-7s %-7s %s\n", tiangan[1][stem] ⊕ dizhi[1][branch],
            wuxing[1][stem / 2], shengxiao[1][branch], yinyang[1][year \ 2]
          System.out.printf "      %-2s/60     %-7s %s\n\n", cycle \ 60 + 1,
            wuxing[2][stem / 2], shengxiao[2][branch]

VBScript

To run in console mode with cscript.

' Chinese zodiac - VBS

Animals  = array( "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig" )
Elements = array( "Wood","Fire","Earth","Metal","Water" )
YinYang  = array( "Yang","Yin" )
Years    = array( 1935, 1938, 1968, 1972, 1976, 1984, 2017 )

for i = LBound(Years) to UBound(Years)
	xYear    = Years(i)
	yElement = Elements(((xYear - 4) mod 10) \ 2)
	yAnimal  = Animals(  (xYear - 4) mod 12     )
	yYinYang = YinYang(   xYear      mod  2     )
	nn       =          ((xYear - 4) mod 60) + 1
	msgbox xYear & " is the year of the " & yElement & " " &  yAnimal & " (" &  yYinYang & ").",, _
		   xYear & " : " & nn & "/60"
next
Output:
1935 is the year of the Wood Pig (Yin).
1938 is the year of the Earth Tiger (Yang).
1968 is the year of the Earth Monkey (Yang).
1972 is the year of the Water Rat (Yang).
1976 is the year of the Fire Dragon (Yang).
1984 is the year of the Wood Rat (Yang).
2017 is the year of the Fire Rooster (Yin).

Visual Basic .NET

Translation of: C#
Module Module1

    ReadOnly ANIMALS As String() = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
    ReadOnly ELEMENTS As String() = {"Wood", "Fire", "Earth", "Metal", "Water"}
    ReadOnly ANIMAL_CHARS As String() = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}
    ReadOnly ELEMENT_CHARS As String(,) = {{"甲", "丙", "戊", "庚", "壬"}, {"乙", "丁", "己", "辛", "癸"}}

    Function GetYY(year As Integer) As String
        If year Mod 2 = 0 Then
            Return "yang"
        End If
        Return "yin"
    End Function

    Sub Main()
        Console.OutputEncoding = System.Text.Encoding.UTF8
        Dim years = {1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017}
        For i = 0 To years.Length - 1
            Dim t0 = years(i)
            Dim t1 = t0 - 4.0
            Dim t2 = t1 Mod 10
            Dim t3 = t2 / 2
            Dim t4 = Math.Floor(t3)

            Dim ei As Integer = Math.Floor(((years(i) - 4.0) Mod 10) / 2)
            Dim ai = (years(i) - 4) Mod 12
            Console.WriteLine("{0} is the year of the {1} {2} ({3}). {4}{5}", years(i), ELEMENTS(ei), ANIMALS(ai), GetYY(years(i)), ELEMENT_CHARS(years(i) Mod 2, ei), ANIMAL_CHARS((years(i) - 4) Mod 12))
        Next
    End Sub

End Module
Output:
1935 is the year of the Wood Pig (yin). 乙亥
1938 is the year of the Earth Tiger (yang). 戊寅
1968 is the year of the Earth Monkey (yang). 戊申
1972 is the year of the Water Rat (yang). 壬子
1976 is the year of the Fire Dragon (yang). 丙辰
1984 is the year of the Wood Rat (yang). 甲子
1985 is the year of the Wood Ox (yin). 乙丑
2017 is the year of the Fire Rooster (yin). 丁酉

V (Vlang)

Translation of: Go
const (
    animal_string = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    stem_yy_string  = ["Yang", "Yin"]
    element_string = ["Wood", "Fire", "Earth", "Metal", "Water"]
    stem_ch        = "甲乙丙丁戊己庚辛壬癸".split('')
    branch_ch      = "子丑寅卯辰巳午未申酉戌亥".split('')
)
 
fn cz(y int) (string, string, string, string, int) {
    yr := y-4
    stem := yr % 10
    branch := yr % 12
    return animal_string[branch],
        stem_yy_string[stem%2],
        element_string[stem/2],
        [stem_ch[stem], branch_ch[branch]].join(''),
        yr%60 + 1
}
 
fn main() {
    for yr in [1935, 1938, 1968, 1972, 1976] {
        a, yy, e, sb, cy := cz(yr)
        println("$yr: $e $a, $yy, Cycle year $cy $sb")
    }
}
Output:
Same as Go entry

Wren

Translation of: Kotlin
Library: Wren-fmt
import "./fmt" for Fmt

class ChineseZodiac {
    static init() {
        __animals  = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
            "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
        __aspects  = ["Yang","Yin"]
        __elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
        __stems    = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
        __branches = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
        __sNames   = ["jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi"]
        __bNames   = ["zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu",  "xū", "hài"]
    }

    construct new(year) {
        var y = year - 4
        var s = y % 10
        var b = y % 12
        _year    = year
        _stem    = __stems[s]
        _branch  = __branches[b]
        _sName   = __sNames[s]
        _bName   = __bNames[b]
        _element = __elements[(s/2).floor]
        _animal  = __animals[b]
        _aspect  = __aspects[s % 2]
        _cycle   = y % 60 + 1
    }

    toString {
        var name = Fmt.s(-9, _sName + "-" + _bName)
        var elem = Fmt.s(-7, _element)
        var anim = Fmt.s(-7, _animal)
        var aspt = Fmt.s(-6, _aspect)
        var cycl = Fmt.dz(2, _cycle) + "/60"
        return "%(_year)    %(_stem)%(_branch)   %(name)  %(elem)  %(anim)   %(aspt) %(cycl)"
    }
}

var years = [1935, 1938, 1968, 1972, 1976, 1984, 2017, 2020]
System.print("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle")
System.print("----  -------  ---------  -------  -------  ------  -----")
ChineseZodiac.init()
for (year in years) System.print(ChineseZodiac.new(year))
Output:
Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle
----  -------  ---------  -------  -------  ------  -----
1935    乙亥   yĭ-hài     Wood     Pig       Yin    12/60
1938    戊寅   wù-yín     Earth    Tiger     Yang   15/60
1968    戊申   wù-shēn    Earth    Monkey    Yang   45/60
1972    壬子   rén-zĭ     Water    Rat       Yang   49/60
1976    丙辰   bĭng-chén  Fire     Dragon    Yang   53/60
1984    甲子   jiă-zĭ     Wood     Rat       Yang   01/60
2017    丁酉   dīng-yŏu   Fire     Rooster   Yin    34/60
2020    庚子   gēng-zĭ    Metal    Rat       Yang   37/60

XPL0

Translation of: C
include xpllib; \for Print

int  Animals, Elements;

func GetElement(Year);
int  Year, Element;
[Element:= rem((Year-4)/10) / 2;
return Elements(Element);
];

func GetAnimal(Year);
int  Year;
return Animals(rem((Year-4)/12));

func GetYY(Year);
int  Year;
if rem(Year/2) = 0 then return "yang"
else return "yin";

int Year, Years, I;
[Years:= [ 1935, 1938, 1968, 1972, 1976, 2017 ];
Animals:= [ "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig" ];
Elements:= [ "Wood","Fire","Earth","Metal","Water" ];
for I:= 0 to 6-1 do
    [Year:= Years(I);
    Print("%d is the year of the %s %s (%s).\n", Year, GetElement(Year), GetAnimal(Year), GetYY(Year));
    ]
]
Output:
1935 is the year of the Wood Pig (yin).
1938 is the year of the Earth Tiger (yang).
1968 is the year of the Earth Monkey (yang).
1972 is the year of the Water Rat (yang).
1976 is the year of the Fire Dragon (yang).
2017 is the year of the Fire Rooster (yin).

Yabasic

dim Animals$(12) : for a = 0 to 11 : read Animals$(a) : next a
dim Elements$(5) : for a = 0 to 4  : read Elements$(a): next a
dim YinYang$(2)  : for a = 0 to 1  : read YinYang$(a) : next a
dim Years(7)     : for a = 0 to 6  : read Years(a)    : next a

for i = 0 to arraysize(Years(),1)-1
	xYear    = Years(i)
	yElement$ = Elements$((Mod((xYear - 4), 10)) / 2)
	yAnimal$  = Animals$(  Mod((xYear - 4), 12))
	yYinYang$ = YinYang$(  Mod(xYear, 2)       )
	nn        =         (  Mod((xYear - 4), 60)) + 1
	print xYear, " is the year of the ", yElement$, " ",  yAnimal$, " (", yYinYang$, ")."
next i
print
end

data "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
data "Wood","Fire","Earth","Metal","Water"
data "Yang","Yin"
data 1935, 1938, 1968, 1972, 1976, 1984, 2017
Output:
1935 is the year of the Wood Pig (Yin).
1938 is the year of the Earth Tiger (Yang).
1968 is the year of the Earth Monkey (Yang).
1972 is the year of the Water Rat (Yang).
1976 is the year of the Fire Dragon (Yang).
1984 is the year of the Wood Rat (Yang).
2017 is the year of the Fire Rooster (Yin).

zkl

Translation of: Ruby
fcn ceToChineseZodiac(ce_year){	// --> list of strings
   # encoding: utf-8
   var [const] pinyin=SD(  // create some static variables, SD is small fixed dictionary
     "甲","jiă",  "乙","yĭ",  "丙","bĭng", "丁","dīng", "戊","wù", "己","jĭ",
     "庚","gēng", "辛","xīn", "壬","rén",  "癸","gŭi",

     "子","zĭ",  "丑","chŏu", "寅","yín", "卯","măo",  "辰","chén", "巳","sì",
     "午","wŭ",  "未","wèi",  "申","shén","酉","yŏu",  "戌","xū",   "亥","hài"
   ),

   celestial  =T("甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"),
   terrestrial=T("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"),
   animals    =T("Rat",   "Ox",   "Tiger",  "Rabbit",  "Dragon", "Snake",
		 "Horse", "Goat", "Monkey", "Rooster", "Dog",    "Pig"),
   elements   =T("Wood", "Fire", "Earth", "Metal", "Water"),
   aspects    =T("yang","yin"),
   ;

   const BASE=4;
 
   cycle_year:=ce_year - BASE;

   cycle_year,aspect    := ce_year - BASE,         aspects[cycle_year%2];
   stem_number,element  := cycle_year%10,          elements[stem_number/2];
   stem_han,stem_pinyin := celestial[stem_number], pinyin[stem_han];

   branch_number,animal     := cycle_year%12,      animals[branch_number];
   branch_han,branch_pinyin := terrestrial[branch_number], pinyin[branch_han];

   return(stem_han,branch_han,
	  stem_pinyin,branch_pinyin, element,animal,aspect)
}
foreach ce_year in (T(1935,1938,1968,1972,1976,Time.Clock.UTC[0])){
   println("%d: %s%s (%s-%s, %s %s; %s)"
           .fmt(ce_year,ceToChineseZodiac(ce_year).xplode()));
}
Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin)
1938: 戊寅 (wù-yín, Earth Tiger; yang)
1968: 戊申 (wù-shén, Earth Monkey; yang)
1972: 壬子 (rén-zĭ, Water Rat; yang)
1976: 丙辰 (bĭng-chén, Fire Dragon; yang)
2017: 丁酉 (dīng-yŏu, Fire Rooster; yin)