Chinese zodiac

From Rosetta Code
Revision as of 06:26, 1 October 2017 by rosettacode>Danaj (Add Perl)
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 simultaneous cycles, one of length 10 (the "celestial stems") and one of length 12 (the "terrestrial branches"); the combination results in a repeating 60-year pattern. Mapping the branches to twelve traditional animal deities results in the well-known "Chinese zodiac", assigning each year to a given animal. For example, Saturday, January 28, 2017 CE (in the common Gregorian calendar) begins the lunisolar year of the Rooster.

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

Thus, 2017 is also the yin year of Fire. Note that since 12 is an even number, the association between animals and yin/yang doesn't change. Consecutive Years of the Rooster will cycle through the five elements, but will always be yin, despite the apparent conceptual mismatch between the male animals and the female aspect.

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.
  • The yang year precedes the yin year within each element.
  • The current 60-year cycle began in 1984 CE; the first cycle of the Common Era began in 4 CE.

Thus, 1984 was the year of the Wood Rat (yang), 1985 was the year of the Wood Ox (yin), and 1986 the year of the Fire Tiger (yang); 2017 - which, as already noted, is the year of the Fire Rooster (yin) - is the 34th 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). 2017 is the 34th year of the current cycle, 丁酉 (dīng-yŏu or ding1-you3).


AppleScript

Translation of: JavaScript
Translation of: Haskell

<lang AppleScript>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</lang>

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     

C++

<lang c++>#include <iostream>

  1. 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;

} </lang>

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

<lang 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)))</lang>
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)

Common Lisp

Translation of: Ruby

<lang lisp>; 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))</lang>
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)

Go

<lang 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)
   }

}</lang>

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 丙辰

Haskell

(We can use Chinese characters in Haskell names, as long as the first character is lower-case alphabetic) <lang haskell>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
   (chars "子丑寅卯辰巳午未申酉戌亥") -- 地支 dizhi – 12 terrestrial branches
   (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
   (chars "木火土金水") -- 五行 wuxing – 5 elements
   (words "mù huǒ tǔ jīn shuǐ")
   (words "wood fire earth metal water")

axs :: Array Int (String, String, String) axs =

 listArray (0, 11) $
 zip3
   (chars "鼠牛虎兔龍蛇馬羊猴鸡狗豬") -- 十二生肖 shengxiao – 12 symbolic animals
   (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) ays = listArray (0, 1) $ zip (chars "阳阴") (words "yáng yīn") -- 阴阳 yinyang

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 [ [show y, h天干 : h地支, h五行, h生肖, h阴阳] -- 汉子 Chinese characters
    , [[], p天干 ++ p地支, p五行, p生肖, p阴阳] -- Pinyin roman transcription
    , [[], show (rem i年份 60 + 1) ++ "/60", e五行, e生肖, []] -- English
    ]

-- 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)

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

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   

Java

<lang Java>public class Zodiac {

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"; } 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]); } } } </lang>

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

<lang JavaScript>(() => {

   'use strict';
   // GENERIC FUNCTIONS -----------------------------------------------------
   // chars :: String -> [Char]
   const chars = s => s.split();
   // concat :: a -> [a] | [String] -> String
   const concat = xs =>
       xs.length > 0 ? (() => {
           const unit = typeof xs[0] === 'string' ?  : [];
           return unit.concat.apply(unit, xs);
       })() : [];
   // intercalate :: String -> [a] -> String
   const intercalate = (s, xs) => xs.join(s);
   // justifyLeft :: Int -> Char -> Text -> Text
   const justifyLeft = (n, cFiller, strText) =>
       n > strText.length ? (
           (strText + cFiller.repeat(n))
           .substr(0, n)
       ) : strText;
   // map :: (a -> b) -> [a] -> [b]
   const map = (f, xs) => xs.map(f);
   // quot :: Int -> Int -> Int
   const quot = (n, m) => Math.floor(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
       );
   // unlines :: [String] -> String
   const unlines = xs => xs.join('\n');
   // words :: String -> [String]
   const words = s => s.split(/\s+/);
   // zip :: [a] -> [b] -> [(a,b)]
   const zip = (xs, ys) =>
       xs.slice(0, Math.min(xs.length, ys.length))
       .map((x, i) => [x, ys[i]]);
   // zip3 :: [a] -> [b] -> [c] -> [(a,b,c)]
   const zip3 = (xs, ys, zs) =>
       xs.slice(0, Math.min(xs.length, ys.length, zs.length))
       .map((x, i) => [x, ys[i], zs[i]]);
   // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
   const zipWith = (f, xs, ys) =>
       Array.from({
           length: Math.min(xs.length, ys.length)
       }, (_, i) => f(xs[i], ys[i]));
   // TRADITIONAL STRINGS ---------------------------------------------------
   // ats :: Array Int (String, String)
   const ats = zip(
       chars("甲乙丙丁戊己庚辛壬癸"), // 天干 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)
   const ads = zip(
       chars("子丑寅卯辰巳午未申酉戌亥"), // 地支 dizhi – 12 terrestrial branches
       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 = zip3(
       chars("木火土金水"), // 五行 wuxing – 5 elements
       words("mù huǒ tǔ jīn shuǐ"),
       words("wood fire earth metal water")
   );
   // axs :: Array Int (String, String, String)
   const axs = zip3(
       chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬"), // 十二生肖 shengxiao – 12 symbolic animals
       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 = zip(
       chars("阳阴"), // 阴阳 yinyang
       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, ]
       ];
   };
   // 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 =>
       unlines(map(
           row => concat(map(([n, s]) => justifyLeft(n, ' ', s), row)),
           zipWith(zip, fieldWidths, zodiac(y))
       ));
   // TEST OUTPUT -----------------------------------------------------------
   return intercalate(
       '\n\n',
       map(
           showYear, [1935, 1938, 1968, 1972, 1976, 1984, new Date()
               .getFullYear()
           ]
       )
   );

})();</lang>

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   

Julia

<lang julia># v0.6.0

function chinese(year::Int)

   const 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"
   )
   const ELEMENTS    = ["Wood", "Fire", "Earth", "Metal", "Water"]
   const ANIMALS     = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
                        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
   const CELESTIAL   = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
   const TERRESTRIAL = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
   const ASPECTS     = ["yang", "yin"]
   const 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

using Dates currentyear = year(now())

map(x -> chinese(x) |> println, [1935, 1938, 1968, 1972, 1976, currentyear]) </lang>

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)
2017: 丁酉 (dīng-yŏu, Earth Rooster; yin - year 34 of the cycle)

Kotlin

<lang scala>// 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))

}</lang>

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

Maple

<lang 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: </lang>

Perl

<lang 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);</lang>
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

Perl 6

Works with: Rakudo version 2017.01
Translation of: Ruby

<lang perl6>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
   )

}

  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;</lang>
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)

PowerShell

Translation of: Ruby

<lang PowerShell> 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"
           }
       }
   }

} </lang> <lang PowerShell> 1935, 1938, 1968, 1972, 1976 | Get-ChineseZodiac | Format-Table </lang>

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: <lang PowerShell> Get-ChineseZodiac </lang>

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: <lang PowerShell> Get-Date "11/8/2016" | Get-ChineseZodiac </lang>

Output:
Year        : 2016
Element     : Fire
Animal      : Monkey
Aspect      : yang
YearOfCycle : 33
ASCII       : bĭng-shēn
Chinese     : 丙申

Emulate the Ruby script's output: <lang PowerShell> $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

} </lang>

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)

PureBasic

<lang pureBasic>EnableExplicit

  1. BASE=4
  2. 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</lang>

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

<lang Python>

  1. 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)

</lang>

Racket

Translation of: Common Lisp

<lang racket>#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))))</lang>
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)

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.

<lang ruby># 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</lang>

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)

Tcl

<lang 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

}

</lang>

% cn_zodiac 1984
甲子 jia3-zi3 Wood Rat (yang) year 1
% cn_zodiac 2017
丁酉 ding1-you3 Fire Rooster (yin) year 34

zkl

Translation of: Ruby

<lang zkl>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) }</lang> <lang zkl>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()));

}</lang>

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)