Author image Daisuke Maki
and 1 contributors


DateTime::Calendar::Chinese - Traditional Chinese Calendar Implementation


  use DateTime::Calendar::Chinese;

  my $dt = DateTime::Calendar::Chinese->now();
  my $dt = DateTime::Calendar::Chinese->new(
    cycle      => $cycle,
    cycle_year => $cycle_year,
    month      => $month,
    leap_month => $leap_month,
    day        => $day,

  $dt->cycle_year; # 1 - 60
  $dt->month;      # 1-12
  $dt->leap_month; # true/false
  $dt->day;        # 1-30 
  $dt->elapsed_years; # years since "Chinese Epoch"

  my ($rd_days, $rd_secs, $rd_nanosecs) = $dt->utc_rd_values();


This is an implementation of the Chinese calendar as described in "Calendrical Calculations" [1]. Please note that the following description is the description from [1], and the author has not made attempts to verify the correctness of statements with other sources.

The Chinese calendar described in [1] is expressed in terms of "cycle", "cycle_year", "month", "a boolean leap_month", and "day".

Traditional Chinese years have been counted using the "Sexagecimal Cycle of Names", which is a cycle of 60 names for each year. The names are the combination of a "celestial stem" (tian1 gan1), with a "terrestrial branch" (di4 zhi1):

    Celestial Stems         Terrestrial Branches
  -------------------     -----------------------
  | Jia3            |     | Zi (Rat)            |
  -------------------     -----------------------
  | Yi3             |     | Chou3 (Ox)          |
  -------------------     -----------------------
  | Bing3           |     | Yin2 (Tiger)        |
  -------------------     -----------------------
  | Ding1           |     | Mao3 (Hare)         |
  -------------------     -----------------------
  | Wu4             |     | Chen2 (Dragon)      |
  -------------------     -----------------------
  | Ji3             |     | Si4 (Snake)         |
  -------------------     -----------------------
  | Geng1           |     | Wu3 (Horse)         |
  -------------------     -----------------------
  | Xin1            |     | Wei4 (Sheep)        |
  -------------------     -----------------------
  | Ren2            |     | Shen1 (Monkey)      |
  -------------------     -----------------------
  | Gui3            |     | You3 (Fowl)         |
  -------------------     -----------------------
                          | Xu1 (Dog)           |
                          | Hai4 (Pig)          |

Names are assigned by running each list sequentially, so the first year woud be jia1zi, then yi3chou3, bing1yin2, and so on. The numbers after each syllable indicates the tone used for the syllable.

The animal names of the Chinese "Zodiac" are not translations of the terrestrial branches, which have different meanings. For example, the first branch, "zi", can mean "child" or "son", as well as several other things.

Chinese months are true lunar months, which starts on a new moon and runs until the day before the next new moon. Therefore each month consists of exactly 29 or 30 days. The month numbers are calculated based on a logic that combines lunar months and solar terms (which is too hard to explain here -- read "Calendrical Calculation" if you must know), and may include leap months.

Leap months can be inserted anywhere in the year, so months are numbered from 1 to 12, with the boolean flag "leap_month" that indicates if the month is a leap month or not.



This class method accepts parameters for each date and time component: "cycle", "cycle_year", "month", "leap_month", "day", "hour", "minute", "second", "nanosecond". It also accepts "locale" and "time_zone" parameters.

Note that in order to avoid confusion between the official Chinese Calendar which is based on Chinese time zone, the default value for time_zone is *not* "floating", but is instead "Asia/Shanghai". See CAVEATS.

  XXX The time zone settings may change in a few ture version such
  XXX that the calculation is done in Asia/Shanghai, but the
  XXX resulting object is set to "floating" time zone.

Note that currently there's no way to verify if a given date is "correct" -- i.e. if you give a date as a leap_month when it in fact isn't a leap month, all sorts of wacky things will happen. Perhaps there's a simple way to do this. If there is, please let me know


This class method is equivalent to calling from_epoch() with the value returned from Perl's time() function.

from_object(object => ...)

This class method can be used to construct a new DateTime::Calendar::Chinese object from any object that implements the utc_rd_values() method.

from_epoch(epoch => ...)

This class method can be used to construct a new DateTime::Calendar::Chinese object from an epoch time instead of components.


This method is identical to that of DateTime, except the date components that can be set are restricted to the Chinese ones ("cycle", "cycle_year", "month", "leap_month", "day"). The time components are the same as that of DateTime (See CAVEATS).


Sets the time zone. This method is identical to that of DateTime.


Gets the time zone. This method is identical to that of DateTime.


Returns the current UTC Rata Die days, seconds, and nanoseconds as a three element list. This method is identical to that of DateTime.


Returns the current cycle of the sexagecimal names since the Chinese epoch (defined to be 25 Feb, -2636 gregorian).


Returns the current year in the current cycle.


Returns the current lunar month.


Returns true if the current month is a leap month.


Returns the current day in the lunar month.


This returns the number of years elapsed since the Chinese Epoch as defined by [1] (Which is 15 Feb. -2646 gregorian). Some documents use different epoch dates, and hence this may not match with whatever source you have.


Returns the name of the year (the celestial stem and the terrestrial branch) as UTF8 (or a sequence of bytes in Perl 5.00503).


Returns the celestial stem as UTF8 (or a sequence of bytes in Perl 5.00503).


Returns the terrestrial branch as UTF8 (or a sequence of bytes in Perl 5.00503).




These methods return the various names in Pinyin, with the tones given as numbers at the end of each syllable. The first terrestrial branch is generally pronounced without a tone, and is returned as "zi".


Returns the year's Zodiac animal.









Be careful with time zones! The "official" Chinese Calendar is based on date/time in China, not your local time zone nor "floating" time zone. This is because the Chinese Calendar is based on astronomical events, but dates such as Chinese New Year are calculated in Chinese time and then transferred over to wherever you're at.

For example, the Chinese New Year in 2004 is Jan 22, but that is Jan 22 in China time. The same time is Jan 21 UTC, and now you'd be off by one day.

So when you're calculating Chinese Calendars, always set the time zone to something like 'Asia/Hong_Kong', 'Asia/Shanghai', 'Asia/Taipei'


Because "Calendrical Calculations" did not go much in detail about the Chinese time system, this module simply uses the time components from the underlying DateTime module (XXX - Note: we may implement this later, so be careful not to use the time components too much for now)


Yes, this module is slow, because the underlying calculations are slow. If you can contribute to the speed, please let me know. So far I've concentrated on porting the algorithms from [1] straight over, and not on performance. I'm sure there's a lot that could be done.


(c) Copyright 2004-2007 Daisuke Maki <>.


This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.



  [1] Edward M. Reingold, Nachum Dershowitz
      "Calendrical Calculations (Millenium Edition)", 2nd ed.
       Cambridge University Press, Cambridge, UK 2002


DateTime DateTime::Event::Chinese