[#34033] The rights of ruby-core people and Myth of ruby-dev — "NARUSE, Yui" <naruse@...>

Some of you may don't know your rights.

32 messages 2011/01/03
[#34067] Re: The rights of ruby-core people and Myth of ruby-dev — Aaron Patterson <aaron@...> 2011/01/04

On Tue, Jan 04, 2011 at 06:55:47AM +0900, NARUSE, Yui wrote:

[#34043] proposal: gem_prelude needs to die — Ryan Davis <ryand-ruby@...>

I think it is time for gem_prelude to die.

21 messages 2011/01/04
[#34077] Re: proposal: gem_prelude needs to die — Tanaka Akira <akr@...> 2011/01/05

2011/1/4 Ryan Davis <ryand-ruby@zenspider.com>:

[#34091] Moving to Git? — Lucas Nussbaum <lucas@...>

Hi,

87 messages 2011/01/05
[#34099] Re: Moving to Git? — KOSAKI Motohiro <kosaki.motohiro@...> 2011/01/05

> Hi,

[#34103] Re: Moving to Git? — "U.Nakamura" <usa@...> 2011/01/05

Hello,

[#34105] Re: Moving to Git? — Rodrigo Rosenfeld Rosas <rr.rosas@...> 2011/01/05

Em 05-01-2011 13:15, U.Nakamura escreveu:

[#34106] Re: Moving to Git? — "NARUSE, Yui" <naruse@...> 2011/01/05

(2011/01/06 0:46), Rodrigo Rosenfeld Rosas wrote:

[#34112] Re: Moving to Git? — Jon <jon.forums@...> 2011/01/05

> > Well, I guess I can help listing some advantages. Using git:

[#34118] Re: Moving to Git? — mathew <meta@...> 2011/01/05

On Wed, Jan 5, 2011 at 11:28, Jon <jon.forums@gmail.com> wrote:

[#34121] Re: Moving to Git? — Rodrigo Rosenfeld Rosas <rr.rosas@...> 2011/01/05

Em 05-01-2011 17:16, mathew escreveu:

[#34129] Re: Moving to Git? — mathew <meta@...> 2011/01/05

On Wed, Jan 5, 2011 at 13:23, Rodrigo Rosenfeld Rosas

[#34138] Re: Moving to Git? — Czarek <cezary.baginski@...> 2011/01/05

On Thu, Jan 06, 2011 at 06:50:24AM +0900, mathew wrote:

[#34188] Re: Moving to Git? — mathew <meta@...> 2011/01/06

On Wed, Jan 5, 2011 at 17:02, Czarek <cezary.baginski@gmail.com> wrote:

[#34191] Re: Moving to Git? — Lucas Nussbaum <lucas@...> 2011/01/06

On 07/01/11 at 01:05 +0900, mathew wrote:

[#34201] Re: Moving to Git? — mathew <meta@...> 2011/01/06

On Thu, Jan 6, 2011 at 10:36, Lucas Nussbaum <lucas@lucas-nussbaum.net> wrote:

[#34206] Re: Moving to Git? — Lucas Nussbaum <lucas@...> 2011/01/07

On 07/01/11 at 08:07 +0900, mathew wrote:

[#34227] Re: Moving to Git? — mathew <meta@...> 2011/01/07

On Thu, Jan 6, 2011 at 23:50, Lucas Nussbaum <lucas@lucas-nussbaum.net> wrote:

[#34231] Re: Moving to Git? — Daniel Bovensiepen <bovensiepen@...> 2011/01/07

Dear all,

[#34116] Re: Moving to Git? — Yukihiro Matsumoto <matz@...> 2011/01/05

Hi,

[#34117] Re: Moving to Git? — Rodrigo Rosenfeld Rosas <rr.rosas@...> 2011/01/05

What kind of Redmine integration you are talking about? We use Redmine

[#34120] Re: Moving to Git? — Yukihiro Matsumoto <matz@...> 2011/01/05

Hi,

[#34125] Re: Moving to Git? — Nikolai Weibull <now@...> 2011/01/05

On Wed, Jan 5, 2011 at 19:57, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

[#34124] [Ruby 1.9-Bug#4235][Open] svn keywords in code prevent correct building of ruby using git mirror — Stephen Bannasch <redmine@...>

Bug #4235: svn keywords in code prevent correct building of ruby using git mirror

12 messages 2011/01/05

[#34171] [Ruby 1.8-Feature#4239][Open] Let's begin a talk for "1.8.8" -- How's needed for surviving 1.8? — Shota Fukumori <redmine@...>

Feature #4239: Let's begin a talk for "1.8.8" -- How's needed for surviving 1.8?

104 messages 2011/01/06
[#34514] [Ruby 1.8-Feature#4239] Let's begin a talk for "1.8.8" -- How's needed for surviving 1.8? — Zeno Davatz <redmine@...> 2011/01/15

Issue #4239 has been updated by Zeno Davatz.

[#34516] Re: [Ruby 1.8-Feature#4239] Let's begin a talk for "1.8.8" -- How's needed for surviving 1.8? — "NARUSE, Yui" <naruse@...> 2011/01/15

(2011/01/16 0:11), Zeno Davatz wrote:

[#34214] [Ruby 1.9-Feature#4247][Open] New features for Array#sample, Array#choice — Yoji Ojima <redmine@...>

Feature #4247: New features for Array#sample, Array#choice

10 messages 2011/01/07

[#34267] [Ruby 1.9-Feature#4254][Open] Allow method transplanting — Jonas Pfenniger <redmine@...>

Feature #4254: Allow method transplanting

23 messages 2011/01/09
[#34280] Re: [Ruby 1.9-Feature#4254][Open] Allow method transplanting — Yukihiro Matsumoto <matz@...> 2011/01/10

Hi,

[#34299] [Ruby 1.9-Bug#4256][Open] [BUG] Segmentation fault ruby 1.9.2p0 (2010-08-18) [i386-mingw32] — Rama Mahendravada <redmine@...>

Bug #4256: [BUG] Segmentation fault ruby 1.9.2p0 (2010-08-18) [i386-mingw32]

9 messages 2011/01/10

[#34318] ext/bigdecimal/lib/bigdecimal/util.rb — Aaron Patterson <aaron@...>

Hi Murata!

14 messages 2011/01/11
[#34321] Re: ext/bigdecimal/lib/bigdecimal/util.rb — Yukihiro Matsumoto <matz@...> 2011/01/11

Hi,

[#34354] [Ruby 1.9-Feature#4264][Open] General type coercion protocol for Ruby — Charles Nutter <redmine@...>

Feature #4264: General type coercion protocol for Ruby

33 messages 2011/01/11
[#34359] Re: [Ruby 1.9-Feature#4264][Open] General type coercion protocol for Ruby — Jim Weirich <jim.weirich@...> 2011/01/11

[#34355] [Ruby 1.9-Feature#4265][Open] Provide a core method Kernel#ruby for invoking a new Ruby instance — Charles Nutter <redmine@...>

Feature #4265: Provide a core method Kernel#ruby for invoking a new Ruby instance

15 messages 2011/01/11

[#34362] [Ruby 1.9-Bug#4266][Open] Timeouts in threads cause "ThreadError: deadlock; recursive locking" — Christopher Bottaro <redmine@...>

Bug #4266: Timeouts in threads cause "ThreadError: deadlock; recursive locking"

12 messages 2011/01/11

[#34399] [Ruby 1.9-Bug#4272][Open] rb_enc_str_new() causes segmentfault when using threads in parallel — Iñaki Baz Castillo <redmine@...>

Bug #4272: rb_enc_str_new() causes segmentfault when using threads in parallel

14 messages 2011/01/12

[#34534] [Ruby 1.9-Bug#4283][Open] Timeout.timeout may cause application exit unintetionally — Motohiro KOSAKI <redmine@...>

Bug #4283: Timeout.timeout may cause application exit unintetionally

11 messages 2011/01/17

[#34537] [Ruby 1.9-Bug#4285][Open] Ruby don't have asynchrounous exception safe syntax and It should have. — Motohiro KOSAKI <redmine@...>

Bug #4285: Ruby don't have asynchrounous exception safe syntax and It should have.

12 messages 2011/01/17

[#34550] [Ruby 1.9-Feature#4288][Open] Allow invoking arbitrary method names with foo."something" syntax — Charles Nutter <redmine@...>

Feature #4288: Allow invoking arbitrary method names with foo."something" syntax

13 messages 2011/01/18
[#34616] Re: [Ruby 1.9-Feature#4288][Open] Allow invoking arbitrary method names with foo."something" syntax — Gary Wright <gwtmp01@...> 2011/01/19

[#34577] Importing rubygems 1.5.0 (release candidate) into trunk. — Ryan Davis <ryand-ruby@...>

I'm going to be committing rubygems 1.5.0 into trunk in a bit.

13 messages 2011/01/18

[#34632] Ruby operator equivalent to Groovy's "?." — Rodrigo Rosenfeld Rosas <rr.rosas@...>

One of the few things I like in Groovy that Ruby doesn't support is

19 messages 2011/01/20

[#34634] Returning from the callee — Rodrigo Rosenfeld Rosas <rr.rosas@...>

Sometimes it is useful to be able to return from the callee method.

15 messages 2011/01/20

[#34648] [Ruby 1.9-Bug#4298][Open] Duration of calling String#[] with the same index is strangely related to string length. — Radosław Bułat <redmine@...>

Bug #4298: Duration of calling String#[] with the same index is strangely related to string length.

13 messages 2011/01/20

[#34861] [Ruby 1.9-Feature#4326][Open] Fiber should respond to call() and [] — Aaron Patterson <redmine@...>

Feature #4326: Fiber should respond to call() and []

21 messages 2011/01/26
[#34943] [Ruby 1.9-Feature#4326] Fiber should respond to call() and [] — Charles Nutter <redmine@...> 2011/01/28

Issue #4326 has been updated by Charles Nutter.

[#34954] Re: [Ruby 1.9-Feature#4326] Fiber should respond to call() and [] — Aaron Patterson <aaron@...> 2011/01/28

On Sat, Jan 29, 2011 at 02:58:46AM +0900, Charles Nutter wrote:

[#34957] Re: [Ruby 1.9-Feature#4326] Fiber should respond to call() and [] — Charles Oliver Nutter <headius@...> 2011/01/29

On Fri, Jan 28, 2011 at 5:29 PM, Aaron Patterson

[#34869] make ruby support line continuations ? — Marc Chantreux <khatar@...>

hello,

22 messages 2011/01/26
[#34878] Re: make ruby support line continuations ? — Jim Freeze <jimfreeze@...> 2011/01/26

> I love it so much i tried it in ruby. trying to rewrite:

[#34887] Re: make ruby support line continuations ? — Marc Chantreux <khatar@...> 2011/01/27

hello,

[#34889] Re: make ruby support line continuations ? — V咜 Ondruch <v.ondruch@...> 2011/01/27

Dne 27.1.2011 7:15, Marc Chantreux napsal(a):

[#34911] The ruby-lang.org downloads page should include RVM for OS X — Andrew Vos <andrew.vos@...>

(I sent this before I subscribed and I'm not sure if it bounced. Sorry if

21 messages 2011/01/27
[#34912] Re: The ruby-lang.org downloads page should include RVM for OS X — "Shota Fukumori (sora_h)" <sorah@...> 2011/01/27

RVM is not official, and makes problem more difficult. (magically

[#34913] Re: The ruby-lang.org downloads page should include RVM for OS X — Andrew Vos <andrew.vos@...> 2011/01/27

What do you mean by "official"? Also, what does it make more difficult? Do

[#34914] Re: The ruby-lang.org downloads page should include RVM for OS X — "Shota Fukumori (sora_h)" <sorah@...> 2011/01/27

return mail is gmail thing. I have same problem.

[#34970] [Ruby 1.9-Bug#4343][Open] Dir.glob does match files without extension — Vit Ondruch <redmine@...>

Bug #4343: Dir.glob does match files without extension

26 messages 2011/01/29
[#34975] [Ruby 1.9-Bug#4343] Dir.glob does match files without extension — Nobuyoshi Nakada <redmine@...> 2011/01/29

Issue #4343 has been updated by Nobuyoshi Nakada.

[#34978] Re: [Ruby 1.9-Bug#4343] Dir.glob does match files without extension — Jeremy Bopp <jeremy@...> 2011/01/29

On 01/29/2011 10:19 AM, Nobuyoshi Nakada wrote:

[#34979] Re: [Ruby 1.9-Bug#4343] Dir.glob does match files without extension — Vít Ondruch <v.ondruch@...> 2011/01/29

Dne 29.1.2011 17:27, Jeremy Bopp napsal(a):

[#34981] Re: [Ruby 1.9-Bug#4343] Dir.glob does match files without extension — Jeremy Bopp <jeremy@...> 2011/01/29

On 01/29/2011 10:33 AM, Vテュt Ondruch wrote:

[#34982] Re: [Ruby 1.9-Bug#4343] Dir.glob does match files without extension — Vít Ondruch <v.ondruch@...> 2011/01/29

Dne 29.1.2011 17:53, Jeremy Bopp napsal(a):

[ruby-core:34305] [Ruby 1.9-Feature#4257][Open] switch_hitter - an acceleration of date library

From: tadayoshi funaba <redmine@...>
Date: 2011-01-10 12:52:28 UTC
List: ruby-core #34305
Feature #4257: switch_hitter - an acceleration of date library
http://redmine.ruby-lang.org/issues/show/4257

Author: tadayoshi funaba
Status: Open, Priority: Low
Assigned to: tadayoshi funaba, Category: ext

switch_hitter'ed already passed nearly all of tests (except some tests
of class name and some confirmations of format of inspect).

* The constructors may return Date::Light instead of Date.
* as fast as home_run when it represents simple date of proleptic
  gregorian of the age of the human race.
* keeps compatibility.
  - can load ruby 1.9.2 dumped marshal.
* accepts flonum explicitly with limitations.
  - If the given offset is flonum, DateTime assumes its precision is
    at most second.
  - If the given +/- argument is flonum, DateTime assumes its
    precision is at most nanosecond.

I'd like to apply this to trunk in the near future.
I also have a plan of improvement about some format methods.

see also http://redmine.ruby-lang.org/issues/show/4068


----------------------------------------
http://redmine.ruby-lang.org

Attachments (1)

switch_hitter.patch2 (83.8 KB, text/x-diff)
Index: lib/date.rb
===================================================================
--- lib/date.rb	(revision 30506)
+++ lib/date.rb	(working copy)
@@ -1,5 +1,5 @@
 #
-# date.rb - date and time library
+# date.rb <switch_hitter> - date and time library
 #
 # Author: Tadayoshi Funaba 1998-2010
 #
@@ -280,6 +280,15 @@
       end
     end
 
+    def to_f
+      return 0 if @d == 0
+      if @d > 0
+	Float::INFINITY
+      else
+	-Float::INFINITY
+      end
+    end
+
   end
 
   # The Julian Day Number of the Day of Calendar Reform for Italy
@@ -443,8 +452,14 @@
     # [commercial_year, week_of_year, day_of_week]
     def jd_to_commercial(jd, sg=GREGORIAN) # :nodoc:
       a = jd_to_civil(jd - 3, sg)[0]
-      y = if jd >= commercial_to_jd(a + 1, 1, 1, sg) then a + 1 else a end
-      w = 1 + ((jd - commercial_to_jd(y, 1, 1, sg)) / 7).floor
+      j = commercial_to_jd(a + 1, 1, 1, sg)
+      if jd >= j
+	y = a + 1
+      else
+	j = commercial_to_jd(a, 1, 1, sg)
+	y = a
+      end
+      w = 1 + ((jd - j) / 7).floor
       d = (jd + 1) % 7
       d = 7 if d == 0
       return y, w, d
@@ -719,26 +734,39 @@
   def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end
 
   class << self; alias_method :leap?, :gregorian_leap? end
-  class << self; alias_method :new!, :new end
 
-  def self.valid_jd? (jd, sg=ITALY)
+  def self.valid_jd_r? (jd, sg=ITALY)
     !!_valid_jd?(jd, sg)
   end
 
-  def self.valid_ordinal? (y, d, sg=ITALY)
+  private_class_method :valid_jd_r?
+
+  def self.valid_ordinal_r? (y, d, sg=ITALY)
     !!_valid_ordinal?(y, d, sg)
   end
 
-  def self.valid_civil? (y, m, d, sg=ITALY)
+  private_class_method :valid_ordinal_r?
+
+  def self.valid_civil_r? (y, m, d, sg=ITALY)
     !!_valid_civil?(y, m, d, sg)
   end
 
-  class << self; alias_method :valid_date?, :valid_civil? end
+  class << self; alias_method :valid_date_r?, :valid_civil_r? end
 
-  def self.valid_commercial? (y, w, d, sg=ITALY)
+  private_class_method :valid_civil_r?, :valid_date_r?
+
+  def self.valid_commercial_r? (y, w, d, sg=ITALY)
     !!_valid_commercial?(y, w, d, sg)
   end
 
+  def self.valid_jd?(*args) raise NotImplementedError end
+  def self.valid_ordinal?(*args) raise NotImplementedError end
+  def self.valid_civil?(*args) raise NotImplementedError end
+
+  class << self; alias_method :valid_date?, :valid_civil? end
+
+  def self.valid_commercial?(*args) raise NotImplementedError end
+
   def self.valid_weeknum? (y, w, d, f, sg=ITALY) # :nodoc:
     !!_valid_weeknum?(y, w, d, f, sg)
   end
@@ -757,16 +785,38 @@
 
   private_class_method :valid_time?
 
+  def self.new_r!(ajd=0, of=0, sg=ITALY)
+    d = allocate
+    d.instance_eval do
+      @ajd, @of, @sg = ajd, of, sg
+      @__ca__ = {}
+    end
+    d
+  end
+
+  def self.new!(ajd=0, of=0, sg=ITALY)
+    jd, df = ajd_to_jd(ajd, 0)
+    df, sf = (df * 86400).divmod(1)
+    if !(Fixnum === jd) || ajd < sg || df !=0 || of != 0
+      return new_r!(ajd, of, sg)
+    end
+    new_l!(jd, sg)
+  end
+
   # Create a new Date object from a Julian Day Number.
   #
   # +jd+ is the Julian Day Number; if not specified, it defaults to
   # 0.
   # +sg+ specifies the Day of Calendar Reform.
-  def self.jd(jd=0, sg=ITALY)
+  def self.jd_r(jd=0, sg=ITALY)
     jd = _valid_jd?(jd, sg)
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
+  private_class_method :jd_r
+
+  def self.jd(*args) raise NotImplementedError end
+
   # Create a new Date object from an Ordinal Date, specified
   # by year +y+ and day-of-year +d+. +d+ can be negative,
   # in which it counts backwards from the end of the year.
@@ -777,13 +827,17 @@
   # Number day 0.
   #
   # +sg+ specifies the Day of Calendar Reform.
-  def self.ordinal(y=-4712, d=1, sg=ITALY)
+  def self.ordinal_r(y=-4712, d=1, sg=ITALY)
     unless jd = _valid_ordinal?(y, d, sg)
       raise ArgumentError, 'invalid date'
     end
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
+  private_class_method :ordinal_r
+
+  def self.ordinal(*args) raise NotImplementedError end
+
   # Create a new Date object for the Civil Date specified by
   # year +y+, month +m+, and day-of-month +d+.
   #
@@ -797,13 +851,19 @@
   # Julian Day Number day 0.
   #
   # +sg+ specifies the Day of Calendar Reform.
-  def self.civil(y=-4712, m=1, d=1, sg=ITALY)
+  def self.civil_r(y=-4712, m=1, d=1, sg=ITALY)
     unless jd = _valid_civil?(y, m, d, sg)
       raise ArgumentError, 'invalid date'
     end
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
+  class << self; alias_method :new_r, :civil_r end
+
+  private_class_method :civil_r, :new_r
+
+  def self.civil(*args) raise NotImplementedError end
+
   class << self; alias_method :new, :civil end
 
   # Create a new Date object for the Commercial Date specified by
@@ -820,18 +880,22 @@
   # Julian Day Number day 0.
   #
   # +sg+ specifies the Day of Calendar Reform.
-  def self.commercial(y=-4712, w=1, d=1, sg=ITALY)
+  def self.commercial_r(y=-4712, w=1, d=1, sg=ITALY)
     unless jd = _valid_commercial?(y, w, d, sg)
       raise ArgumentError, 'invalid date'
     end
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
+  private_class_method :commercial_r
+
+  def self.commercial(*args) raise NotImplementedError end
+
   def self.weeknum(y=-4712, w=0, d=1, f=0, sg=ITALY)
     unless jd = _valid_weeknum?(y, w, d, f, sg)
       raise ArgumentError, 'invalid date'
     end
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
   private_class_method :weeknum
@@ -840,7 +904,7 @@
     unless jd = _valid_nth_kday?(y, m, n, k, sg)
       raise ArgumentError, 'invalid date'
     end
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+    new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
   end
 
   private_class_method :nth_kday
@@ -1103,7 +1167,7 @@
 	  end
 	end;
       end
-    end
+    end # <<dummy
 
     private :once
 
@@ -1128,20 +1192,17 @@
   #
   # Using one of the factory methods such as Date::civil is
   # generally easier and safer.
-  def initialize(ajd=0, of=0, sg=ITALY)
-    @ajd, @of, @sg = ajd, of, sg
-    @__ca__ = {}
-  end
+  def initialize(*args) raise NotImplementedError end
 
   # Get the date as an Astronomical Julian Day Number.
   def ajd() @ajd end
 
   # Get the date as an Astronomical Modified Julian Day Number.
-  def amjd() ajd_to_amjd(@ajd) end
+  def amjd() ajd_to_amjd(ajd) end
 
   once :amjd
 
-  def daynum() ajd_to_jd(@ajd, @of) end
+  def daynum() ajd_to_jd(ajd, offset) end
 
   once :daynum
   private :daynum
@@ -1162,16 +1223,16 @@
   once :jd, :day_fraction, :mjd, :ld
 
   # Get the date as a Civil Date, [year, month, day_of_month]
-  def civil() jd_to_civil(jd, @sg) end # :nodoc:
+  def civil() jd_to_civil(jd, start) end # :nodoc:
 
   # Get the date as an Ordinal Date, [year, day_of_year]
-  def ordinal() jd_to_ordinal(jd, @sg) end # :nodoc:
+  def ordinal() jd_to_ordinal(jd, start) end # :nodoc:
 
   # Get the date as a Commercial Date, [year, week_of_year, day_of_week]
-  def commercial() jd_to_commercial(jd, @sg) end # :nodoc:
+  def commercial() jd_to_commercial(jd, start) end # :nodoc:
 
-  def weeknum0() jd_to_weeknum(jd, 0, @sg) end # :nodoc:
-  def weeknum1() jd_to_weeknum(jd, 1, @sg) end # :nodoc:
+  def weeknum0() jd_to_weeknum(jd, 0, start) end # :nodoc:
+  def weeknum1() jd_to_weeknum(jd, 1, start) end # :nodoc:
 
   once :civil, :ordinal, :commercial, :weeknum0, :weeknum1
   private :civil, :ordinal, :commercial, :weeknum0, :weeknum1
@@ -1275,7 +1336,7 @@
   private :nth_kday?
 
   # Is the current date old-style (Julian Calendar)?
-  def julian? () jd < @sg end
+  def julian? () jd < start end
 
   # Is the current date new-style (Gregorian Calendar)?
   def gregorian? () !julian? end
@@ -1302,7 +1363,7 @@
   def start() @sg end
 
   # Create a copy of this Date object using a new Day of Calendar Reform.
-  def new_start(sg=self.class::ITALY) self.class.new!(@ajd, @of, sg) end
+  def new_start(sg=self.class::ITALY) self.class.new_r!(ajd, offset, sg) end
 
   # Create a copy of this Date object that uses the Italian/Catholic
   # Day of Calendar Reform.
@@ -1325,8 +1386,10 @@
   def new_offset(of=0)
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    self.class.new!(@ajd, of, @sg)
+    self.class.new_r!(ajd, of, start)
   end
 
   private :offset, :new_offset
@@ -1342,7 +1405,11 @@
   # particular, two Dates cannot be added to each other.
   def + (n)
     case n
-    when Numeric; return self.class.new!(@ajd + n, @of, @sg)
+    when Numeric
+      if Float === n
+	n = Rational((n * 86400000000000).round, 86400000000000)
+      end
+      return self.class.new_r!(ajd + n, offset, start)
     end
     raise TypeError, 'expected numeric'
   end
@@ -1357,8 +1424,13 @@
   # If +x+ is neither Numeric nor a Date, a TypeError is raised.
   def - (x)
     case x
-    when Numeric; return self.class.new!(@ajd - x, @of, @sg)
-    when Date;    return @ajd - x.ajd
+    when Numeric
+      if Float === x
+	x = Rational((x * 86400000000000).round, 86400000000000)
+      end
+      return self.class.new_r!(ajd - x, offset, start)
+    when Date
+      return ajd - x.ajd
     end
     raise TypeError, 'expected numeric or date'
   end
@@ -1376,8 +1448,8 @@
   # considered as falling on midnight UTC.
   def <=> (other)
     case other
-    when Numeric; return @ajd <=> other
-    when Date;    return @ajd <=> other.ajd
+    when Numeric; return ajd <=> other
+    when Date;    return ajd <=> other.ajd
     else
       begin
         l, r = other.coerce(self)
@@ -1388,6 +1460,17 @@
     nil
   end
 
+  def coerce(other)
+    case other
+    when Light
+      return other.to_right, self
+    when Right
+      return other, self.to_right
+    else
+      super
+    end
+  end
+
   # The relationship operator for Date.
   #
   # Compares dates by Julian Day Number.  When comparing
@@ -1423,7 +1506,7 @@
     y, m = (year * 12 + (mon - 1) + n).divmod(12)
     m,   = (m + 1)                    .divmod(1)
     d = mday
-    until jd2 = _valid_civil?(y, m, d, @sg)
+    until jd2 = _valid_civil?(y, m, d, start)
       d -= 1
       raise ArgumentError, 'invalid date' unless d > 0
     end
@@ -1486,11 +1569,11 @@
   def eql? (other) Date === other && self == other end
 
   # Calculate a hash value for this date.
-  def hash() @ajd.hash end
+  def hash() ajd.hash end
 
   # Return internal object state as a programmer-readable string.
   def inspect
-    format('#<%s: %s (%s,%s,%s)>', self.class, to_s, @ajd, @of, @sg)
+    format('#<%s: %s (%s,%s,%s)>', self.class, to_s, ajd, offset, start)
   end
 
   # Return the date as a human-readable string.
@@ -1559,6 +1642,17 @@
 #
 class DateTime < Date
 
+  def self.new!(ajd=0, of=0, sg=ITALY)
+    jd, df = ajd_to_jd(ajd, 0)
+    df, sf = (df * 86400).divmod(1)
+    sf, ssf = (sf * 1000000000).divmod(1)
+    odf, osf = (of * 86400).divmod(1)
+    if !(Fixnum === jd) || ajd < sg || ssf != 0 || osf != 0
+      return new_r!(ajd, of, sg)
+    end
+    new_l!(jd, df, sf, odf, sg)
+  end
+
   # Create a new DateTime object corresponding to the specified
   # Julian Day Number +jd+ and hour +h+, minute +min+, second +s+.
   #
@@ -1572,17 +1666,23 @@
   # +sg+ specifies the Day of Calendar Reform.
   #
   # All day/time values default to 0.
-  def self.jd(jd=0, h=0, min=0, s=0, of=0, sg=ITALY)
+  def self.jd_r(jd=0, h=0, min=0, s=0, of=0, sg=ITALY)
     unless (jd = _valid_jd?(jd, sg)) &&
 	   (fr = _valid_time?(h, min, s))
       raise ArgumentError, 'invalid date'
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    new!(jd_to_ajd(jd, fr, of), of, sg)
+    new_r!(jd_to_ajd(jd, fr, of), of, sg)
   end
 
+  private_class_method :jd_r
+
+  def self.jd(*args) raise NotImplementedError end
+
   # Create a new DateTime object corresponding to the specified
   # Ordinal Date and hour +h+, minute +min+, second +s+.
   #
@@ -1597,17 +1697,23 @@
   #
   # +y+ defaults to -4712, and +d+ to 1; this is Julian Day Number
   # day 0.  The time values default to 0.
-  def self.ordinal(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
+  def self.ordinal_r(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
     unless (jd = _valid_ordinal?(y, d, sg)) &&
 	   (fr = _valid_time?(h, min, s))
       raise ArgumentError, 'invalid date'
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    new!(jd_to_ajd(jd, fr, of), of, sg)
+    new_r!(jd_to_ajd(jd, fr, of), of, sg)
   end
 
+  private_class_method :ordinal_r
+
+  def self.ordinal(*args) raise NotImplementedError end
+
   # Create a new DateTime object corresponding to the specified
   # Civil Date and hour +h+, minute +min+, second +s+.
   #
@@ -1622,19 +1728,25 @@
   #
   # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is Julian Day
   # Number day 0.  The time values default to 0.
-  def self.civil(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
+  def self.civil_r(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
     unless (jd = _valid_civil?(y, m, d, sg)) &&
 	   (fr = _valid_time?(h, min, s))
       raise ArgumentError, 'invalid date'
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    new!(jd_to_ajd(jd, fr, of), of, sg)
+    new_r!(jd_to_ajd(jd, fr, of), of, sg)
   end
 
-  class << self; alias_method :new, :civil end
+  class << self; alias_method :new_r, :civil_r end
 
+  private_class_method :civil_r, :new_r
+
+  def self.civil(*args) raise NotImplementedError end
+
   # Create a new DateTime object corresponding to the specified
   # Commercial Date and hour +h+, minute +min+, second +s+.
   #
@@ -1650,17 +1762,23 @@
   # +y+ defaults to -4712, +w+ to 1, and +d+ to 1; this is
   # Julian Day Number day 0.
   # The time values default to 0.
-  def self.commercial(y=-4712, w=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
+  def self.commercial_r(y=-4712, w=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
     unless (jd = _valid_commercial?(y, w, d, sg)) &&
 	   (fr = _valid_time?(h, min, s))
       raise ArgumentError, 'invalid date'
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    new!(jd_to_ajd(jd, fr, of), of, sg)
+    new_r!(jd_to_ajd(jd, fr, of), of, sg)
   end
 
+  private_class_method :commercial_r
+
+  def self.commercial(*args) raise NotImplementedError end
+
   def self.weeknum(y=-4712, w=0, d=1, f=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
     unless (jd = _valid_weeknum?(y, w, d, f, sg)) &&
 	   (fr = _valid_time?(h, min, s))
@@ -1668,8 +1786,10 @@
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
-    new!(jd_to_ajd(jd, fr, of), of, sg)
+    new_r!(jd_to_ajd(jd, fr, of), of, sg)
   end
 
   private_class_method :weeknum
@@ -1681,6 +1801,8 @@
     end
     if String === of
       of = Rational(zone_to_diff(of) || 0, 86400)
+    elsif Float === of
+      of = Rational((of * 86400).round, 86400)
     end
     new!(jd_to_ajd(jd, fr, of), of, sg)
   end
@@ -1783,16 +1905,14 @@
 
   def to_date
     jd = Date.__send__(:civil_to_jd, year, mon, mday, Date::ITALY)
-    Date.new!(Date.__send__(:jd_to_ajd, jd, 0, 0), 0, Date::ITALY)
+    Date.new_l!(jd, Date::ITALY)
   end
 
   def to_datetime
-    jd = DateTime.__send__(:civil_to_jd, year, mon, mday, DateTime::ITALY)
-    fr = DateTime.__send__(:time_to_day_fraction, hour, min, [sec, 59].min) +
-      Rational(subsec, 86400)
-    of = Rational(utc_offset, 86400)
-    DateTime.new!(DateTime.__send__(:jd_to_ajd, jd, fr, of),
-		  of, DateTime::ITALY)
+    u = getutc
+    jd = DateTime.__send__(:civil_to_jd, u.year, u.mon, u.mday, DateTime::ITALY)
+    df = u.hour * 3600 + u.min * 60 + u.sec
+    DateTime.new_l!(jd, df, u.nsec, utc_offset, DateTime::ITALY)
   end
 
 end
@@ -1801,48 +1921,77 @@
 
   def to_time() Time.local(year, mon, mday) end
   def to_date() self end
-  def to_datetime() DateTime.new!(jd_to_ajd(jd, 0, 0), @of, @sg) end
+  def to_datetime() DateTime.new_r!(jd_to_ajd(jd, 0, 0), offset, start) end
 
-  # Create a new Date object representing today.
-  #
-  # +sg+ specifies the Day of Calendar Reform.
-  def self.today(sg=ITALY)
-    t = Time.now
-    jd = civil_to_jd(t.year, t.mon, t.mday, sg)
-    new!(jd_to_ajd(jd, 0, 0), 0, sg)
-  end
-
-  # Create a new DateTime object representing the current time.
-  #
-  # +sg+ specifies the Day of Calendar Reform.
-  def self.now(sg=ITALY)
-    t = Time.now
-    jd = civil_to_jd(t.year, t.mon, t.mday, sg)
-    fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) +
-      Rational(t.subsec, 86400)
-    of = Rational(t.utc_offset, 86400)
-    new!(jd_to_ajd(jd, fr, of), of, sg)
-  end
-
-  private_class_method :now
-
 end
 
 class DateTime < Date
 
   def to_time
-    d = new_offset(0)
-    d.instance_eval do
-      Time.utc(year, mon, mday, hour, min, sec +
-	       sec_fraction)
+    instance_eval do
+      Time.new(year, mon, mday, hour, min, sec +
+	       sec_fraction, zone)
     end.
 	getlocal
   end
 
-  def to_date() Date.new!(jd_to_ajd(jd, 0, 0), 0, @sg) end
+  def to_date() Date.new_r!(jd_to_ajd(jd, 0, 0), 0, start) end
   def to_datetime() self end
 
-  private_class_method :today
-  public_class_method  :now
+end
 
+class Date::Light < Date
+
+  def to_datetime() DateTime.new_l!(jd, 0, 0, 0, start) end
+
 end
+
+class DateTime::Light < DateTime
+
+  def to_date() Date.new_l!(jd, start) end
+
+end
+
+
+require 'date_core'
+
+class Date
+
+  def to_right() self end
+
+  def to_light
+    raise RangeError, "cannot create" unless gregorian?
+    j, f, = (ajd + Rational(1, 2)).divmod(1)
+    raise RangeError, "cannot create" unless f == 0
+    Date.new_l!(j, start.to_f)
+  end
+
+end
+
+class DateTime < Date
+
+  def to_right() self end
+
+  def to_light
+    raise RangeError, "cannot create" unless gregorian?
+    j, f, = (ajd + Rational(1, 2)).divmod(1)
+    df, f, = f.divmod(SECONDS_IN_DAY)
+    sf = f.div(NANOSECONDS_IN_DAY).round
+    DateTime.new_l!(j, df, sf, (offset * 86400).round, start.to_f)
+  end
+
+end
+
+class Date::Light < Date
+
+  def to_right() Date.new_r!(ajd, offset, start) end
+  def to_light() self end
+
+end
+
+class DateTime::Light < DateTime
+
+  def to_right() DateTime.new_r!(ajd, offset, start) end
+  def to_light() self end
+
+end
Index: ext/date/date_core.c
===================================================================
--- ext/date/date_core.c	(revision 0)
+++ ext/date/date_core.c	(revision 0)
@@ -0,0 +1,3059 @@
+/*
+  date_core.c <switch_hitter>: Coded by Tadayoshi Funaba 2010, 2011
+*/
+
+#include "ruby.h"
+#include <math.h>
+#include <time.h>
+
+#define NDEBUG
+#include <assert.h>
+
+#define HAVE_JD 1
+#define HAVE_DF 2
+#define HAVE_CIVIL 4
+#define HAVE_TIME 8
+
+#define ITALY 2299161
+
+#define LIGHTABLE_JD(j) (j >= min_jd && j <= max_jd)
+#define LIGHTABLE_YEAR(y) (y >= min_year && y <= max_year)
+#define LIGHTABLE_CWYEAR(y) LIGHTABLE_YEAR(y)
+
+#define DAY_IN_SECONDS 86400
+#define SECOND_IN_NANOSECONDS 1000000000
+#define DAY_IN_NANOSECONDS 86400000000000LL
+
+/* copied from time.c */
+#define NDIV(x,y) (-(-((x)+1)/(y))-1)
+#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
+#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
+#define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
+
+struct DateLightData
+{
+  long jd;	/* as utc */
+  double sg;
+  /* decoded */
+  int year;
+  int mon;
+  int mday;
+  unsigned flags;
+};
+
+struct DateTimeLightData
+{
+  long jd;	/* as utc */
+  int df;	/* as utc, in secs */
+  long long sf;	/* in nano secs */
+  int of;	/* in secs */
+  double sg;
+  /* decoded */
+  int year;
+  int mon;
+  int mday;
+  int hour;
+  int min;
+  int sec;
+  unsigned flags;
+};
+
+#define get_d1(x) \
+  struct DateLightData *dat;\
+  Data_Get_Struct(x, struct DateLightData, dat)
+
+#define get_d2(x,y) \
+  struct DateLightData *adat, *bdat;\
+  Data_Get_Struct(x, struct DateLightData, adat);\
+  Data_Get_Struct(y, struct DateLightData, bdat)
+
+#define get_d1_dt1(x,y) \
+  struct DateLightData *adat, *bdat;\
+  Data_Get_Struct(x, struct DateLightData, adat);\
+  Data_Get_Struct(y, struct DateTimeLightData, bdat)
+
+#define get_dt1(x) \
+  struct DateTimeLightData *dat;\
+  Data_Get_Struct(x, struct DateTimeLightData, dat)
+
+#define get_dt2(x,y) \
+  struct DateTimeLightData *adat, *bdat;\
+  Data_Get_Struct(x, struct DateTimeLightData, adat);\
+  Data_Get_Struct(y, struct DateTimeLightData, bdat)
+
+#define get_dt1_d1(x,y) \
+  struct DateTimeLightData *adat, *bdat;\
+  Data_Get_Struct(x, struct DateTimeLightData, adat);\
+  Data_Get_Struct(y, struct DateTimeData, bdat)
+
+#define forward(k,m) rb_funcall2(k, rb_intern(m), argc, argv)
+#define to_right(x) rb_funcall(x, rb_intern("to_right"), 0)
+
+static VALUE cDate, cDateLight, cDateTime, cDateTimeLight;
+static VALUE rzero, rhalf;
+static long min_jd, max_jd;
+static int min_year, max_year;
+
+static int valid_civil_p(int y, int m, int d, double sg,
+			 int *rm, int *rd, long *rjd, int *ns);
+
+static int
+find_fdoy(int y, double sg, long *rjd, int *ns)
+{
+  int d, rm, rd;
+
+  for (d = 1; d < 31; d++)
+    if (valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns))
+      return 1;
+  return 0;
+}
+
+static int
+find_ldoy(int y, double sg, long *rjd, int *ns)
+{
+  int i, rm, rd;
+
+  for (i = 0; i < 30; i++)
+    if (valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns))
+      return 1;
+  return 0;
+}
+
+static int
+find_fdom(int y, int m, double sg, long *rjd, int *ns)
+{
+  int d, rm, rd;
+
+  for (d = 1; d < 31; d++)
+    if (valid_civil_p(y, m, d, sg, &rm, &rd, rjd, ns))
+      return 1;
+  return 0;
+}
+
+static int
+find_ldom(int y, int m, double sg, long *rjd, int *ns)
+{
+  int i, rm, rd;
+
+  for (i = 0; i < 30; i++)
+    if (valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns))
+      return 1;
+  return 0;
+}
+
+static void
+civil_to_jd(int y, int m, int d, double sg, long *rjd, int *ns)
+{
+  double a, b, jd;
+
+  if (m <= 2) {
+    y -= 1;
+    m += 12;
+  }
+  a = floor(y / 100.0);
+  b = 2 - a + floor(a / 4.0);
+  jd = floor(365.25 * (y + 4716)) +
+    floor(30.6001 * (m + 1)) +
+    d + b - 1524;
+  if (jd < sg) {
+    jd -= b;
+    *ns = 0;
+  } else
+    *ns = 1;
+
+  *rjd = jd;
+}
+
+static void
+jd_to_civil(long jd, double sg, int *ry, int *rm, int *rdom)
+{
+  double x, a, b, c, d, e, y, m, dom;
+
+  if (jd < sg)
+    a = jd;
+  else {
+    x = floor((jd - 1867216.25) / 36524.25);
+    a = jd + 1 + x - floor(x / 4.0);
+  }
+  b = a + 1524;
+  c = floor((b - 122.1) / 365.25);
+  d = floor(365.25 * c);
+  e = floor((b - d) / 30.6001);
+  dom = b - d - floor(30.6001 * e);
+  if (e <= 13) {
+    m = e - 1;
+    y = c - 4716;
+  } else {
+    m = e - 13;
+    y = c - 4715;
+  }
+
+  *ry = y;
+  *rm = m;
+  *rdom = dom;
+}
+
+static void
+ordinal_to_jd(int y, int d, double sg, long *rjd, int *ns)
+{
+  int ns2;
+
+  find_fdoy(y, sg, rjd, &ns2);
+  *rjd += d - 1;
+  *ns = (*rjd < sg) ? 0 : 1;
+}
+
+static void
+jd_to_ordinal(long jd, double sg, int *ry, int *rd)
+{
+  int rm2, rd2, ns;
+  long rjd;
+
+  jd_to_civil(jd, sg, ry, &rm2, &rd2);
+  find_fdoy(*ry, sg, &rjd, &ns);
+  *rd = jd - rjd + 1;
+}
+
+static void
+commercial_to_jd(int y, int w, int d, double sg, long *rjd, int *ns)
+{
+  long rjd2;
+  int ns2;
+
+  find_fdoy(y, sg, &rjd2, &ns2);
+  rjd2 += 3;
+  *rjd =
+    (rjd2 - MOD((rjd2 - 1) + 1, 7)) +
+    7 * (w - 1) +
+    (d - 1);
+  *ns = (*rjd < sg) ? 0 : 1;
+}
+
+static void
+jd_to_commercial(long jd, double sg, int *ry, int *rw, int *rd)
+{
+  int ry2, rm2, rd2, a, ns2;
+  long rjd2;
+
+  jd_to_civil(jd - 3, sg, &ry2, &rm2, &rd2);
+  a = ry2;
+  commercial_to_jd(a + 1, 1, 1, sg, &rjd2, &ns2);
+  if (jd >= rjd2)
+    *ry = a + 1;
+  else {
+    commercial_to_jd(a, 1, 1, sg, &rjd2, &ns2);
+    *ry = a;
+  }
+  *rw = 1 + DIV(jd - rjd2,  7);
+  *rd = MOD(jd + 1, 7);
+  if (*rd == 0)
+    *rd = 7;
+}
+
+static void
+weeknum_to_jd(int y, int w, int d, int f, double sg, long *rjd, int *ns)
+{
+  long rjd2;
+  int ns2;
+
+  find_fdoy(y, sg, &rjd2, &ns2);
+  rjd2 += 6;
+  *rjd = (rjd2 - MOD(((rjd2 - f) + 1), 7) - 7) + 7 * w + d;
+  *ns = (*rjd < sg) ? 0 : 1;
+}
+
+static void
+jd_to_weeknum(long jd, int f, double sg, int *ry, int *rw, int *rd)
+{
+  int rm, rd2, ns;
+  long rjd, j;
+
+  jd_to_civil(jd, sg, ry, &rm, &rd2);
+  find_fdoy(*ry, sg, &rjd, &ns);
+  rjd += 6;
+  j = jd - (rjd - MOD((rjd - f) + 1, 7)) + 7;
+  *rw = DIV(j, 7);
+  *rd = MOD(j, 7);
+}
+
+static void
+nth_kday_to_jd(int y, int m, int n, int k, double sg, long *rjd, int *ns)
+{
+  long rjd2;
+  int ns2;
+
+  if (n > 0) {
+    find_fdom(y, m, sg, &rjd2, &ns2);
+    rjd2 -= 1;
+  } else {
+    find_ldom(y, m, sg, &rjd2, &ns2);
+    rjd2 += 7;
+  }
+  *rjd = (rjd2 - MOD((rjd2 - k) + 1, 7)) + 7 * n;
+  *ns = (*rjd < sg) ? 0 : 1;
+}
+
+inline static int jd_to_wday(long jd);
+
+static void
+jd_to_nth_kday(long jd, double sg, int *ry, int *rm, int *rn, int *rk)
+{
+  int rd, ns2;
+  long rjd;
+
+  jd_to_civil(jd, sg, ry, rm, &rd);
+  find_fdom(*ry, *rm, sg, &rjd, &ns2);
+  *rn = DIV(jd - rjd, 7) + 1;
+  *rk = jd_to_wday(jd);
+}
+
+static int
+valid_ordinal_p(int y, int d, double sg,
+		int *rd, long *rjd, int *ns)
+{
+  int ry2, rd2;
+
+  if (d < 0) {
+    long rjd2;
+    int ns2;
+
+    if (!find_ldoy(y, sg, &rjd2, &ns2))
+      return 0;
+    jd_to_ordinal(rjd2 + d + 1, sg, &ry2, &rd2);
+    if (ry2 != y)
+      return 0;
+    d = rd2;
+  }
+  ordinal_to_jd(y, d, sg, rjd, ns);
+  jd_to_ordinal(*rjd, sg, &ry2, &rd2);
+  if (ry2 != y || rd2 != d)
+    return 0;
+  return 1;
+}
+
+static const int monthtab[2][13] = {
+  { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+  { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+inline static int
+leap_p(int y)
+{
+  return MOD(y, 4) == 0 && y % 100 != 0 || MOD(y, 400) == 0;
+}
+
+static int
+last_day_of_month(int y, int m)
+{
+  return monthtab[leap_p(y) ? 1 : 0][m];
+}
+
+static int
+valid_gregorian_p(int y, int m, int d, int *rm, int *rd)
+{
+  int last;
+
+  if (m < 0)
+    m += 13;
+  last = last_day_of_month(y, m);
+  if (d < 0)
+    d = last + d + 1;
+
+  *rm = m;
+  *rd = d;
+
+  return !(m < 0 || m > 12 ||
+	   d < 1 || d > last);
+}
+
+static int
+valid_civil_p(int y, int m, int d, double sg,
+	      int *rm, int *rd, long *rjd, int *ns)
+{
+  int ry;
+
+  if (m < 0)
+    m += 13;
+  if (d < 0) {
+    if (!find_ldom(y, m, sg, rjd, ns))
+      return 0;
+    jd_to_civil(*rjd + d + 1, sg, &ry, rm, rd);
+    if (ry != y || *rm != m)
+      return 0;
+    d = *rd;
+  }
+  civil_to_jd(y, m, d, sg, rjd, ns);
+  jd_to_civil(*rjd, sg, &ry, rm, rd);
+  if (ry != y || *rm != m || *rd != d)
+    return 0;
+  return 1;
+}
+
+static int
+valid_commercial_p(int y, int w, int d, double sg,
+		   int *rw, int *rd, long *rjd, int *ns)
+{
+  int ns2, ry2, rw2, rd2;
+
+  if (d < 0)
+    d += 8;
+  if (w < 0) {
+    long rjd2;
+
+    commercial_to_jd(y + 1, 1, 1, sg, &rjd2, &ns2);
+    jd_to_commercial(rjd2 + w * 7, sg, &ry2, &rw2, &rd2);
+    if (ry2 != y)
+      return 0;
+    w = rw2;
+  }
+  commercial_to_jd(y, w, d, sg, rjd, ns);
+  jd_to_commercial(*rjd, sg, &ry2, rw, rd);
+  if (y != ry2 || w != *rw || d != *rd)
+    return 0;
+  return 1;
+}
+
+static int
+valid_time_p(int h, int min, int s, int *rh, int *rmin, int *rs)
+{
+  if (h < 0)
+    h += 24;
+  if (min < 0)
+    min += 60;
+  if (s < 0)
+    s += 60;
+  *rh = h;
+  *rmin = min;
+  *rs = s;
+  return !(h   < 0 || h   > 24 ||
+	   min < 0 || min > 59 ||
+	   s   < 0 || s   > 59 ||
+	   (h == 24 && (min > 0 || s > 0)));
+}
+
+inline static int
+df_local_to_utc(int df, int of)
+{
+  df -= of;
+  if (df < 0)
+    df += DAY_IN_SECONDS;
+  else if (df >= DAY_IN_SECONDS)
+    df -= DAY_IN_SECONDS;
+  return df;
+}
+
+inline static int
+df_utc_to_local(int df, int of)
+{
+  df += of;
+  if (df < 0)
+    df += DAY_IN_SECONDS;
+  else if (df >= DAY_IN_SECONDS)
+    df -= DAY_IN_SECONDS;
+  return df;
+}
+
+inline static long
+jd_local_to_utc(long jd, int df, int of)
+{
+  df -= of;
+  if (df < 0)
+    jd -= 1;
+  else if (df >= DAY_IN_SECONDS)
+    jd += 1;
+  return jd;
+}
+
+inline static long
+jd_utc_to_local(long jd, int df, int of)
+{
+  df += of;
+  if (df < 0)
+    jd -= 1;
+  else if (df >= DAY_IN_SECONDS)
+    jd += 1;
+  return jd;
+}
+
+inline static int
+time_to_df(int h, int min, int s)
+{
+  return h * 3600 + min * 60 + s;
+}
+
+inline static int
+jd_to_wday(long jd)
+{
+  return MOD(jd + 1, 7);
+}
+
+static int
+daydiff_to_sec(VALUE vof, int *rof)
+{
+  switch (TYPE(vof)) {
+  case T_FIXNUM:
+    {
+      int n;
+
+      n = FIX2INT(vof);
+      if (n != -1 && n != 0 && n != 1)
+	return 0;
+      *rof = n * DAY_IN_SECONDS;
+      return 1;
+    }
+  case T_FLOAT:
+    {
+      double n;
+
+      n = NUM2DBL(vof);
+      if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
+	return 0;
+      *rof = round(n * DAY_IN_SECONDS);
+      return 1;
+    }
+  case T_RATIONAL:
+    {
+      VALUE vs = rb_funcall(vof, '*', 1, INT2FIX(DAY_IN_SECONDS));
+      VALUE vn = RRATIONAL(vs)->num;
+      VALUE vd = RRATIONAL(vs)->den;
+      int n, d;
+
+      if (!FIXNUM_P(vn) || !FIXNUM_P(vd))
+	return 0;
+      n = FIX2INT(vn);
+      d = FIX2INT(vd);
+      if (d != 1)
+	return 0;
+      if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
+	return 0;
+      *rof = n;
+      return 1;
+    }
+  case T_STRING:
+    {
+      VALUE vs = rb_funcall(cDate, rb_intern("zone_to_diff"), 1, vof);
+      int n;
+
+      if (!FIXNUM_P(vs))
+	return 0;
+      n = FIX2INT(vs);
+      if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
+	return 0;
+      *rof = n;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+inline static void
+get_d_jd(struct DateLightData *x)
+{
+  if (!(x->flags & HAVE_JD)) {
+    long jd;
+    int ns;
+
+    assert(x->flags & HAVE_CIVIL);
+
+    civil_to_jd(x->year, x->mon, x->mday, x->sg, &jd, &ns);
+    x->jd = jd;
+    x->flags |= HAVE_JD;
+  }
+}
+
+inline static void
+get_d_civil(struct DateLightData *x)
+{
+  if (!(x->flags & HAVE_CIVIL)) {
+    int y, m, d;
+
+    assert(x->flags & HAVE_JD);
+
+    jd_to_civil(x->jd, x->sg, &y, &m, &d);
+    x->year = y;
+    x->mon = m;
+    x->mday = d;
+    x->flags |= HAVE_CIVIL;
+  }
+}
+
+inline static void
+get_dt_df(struct DateTimeLightData *x)
+{
+  if (!(x->flags & HAVE_DF)) {
+    assert(x->flags & HAVE_TIME);
+
+    x->df = df_local_to_utc(time_to_df(x->hour, x->min, x->sec), x->of);
+    x->flags |= HAVE_DF;
+  }
+}
+
+inline static void
+get_dt_time(struct DateTimeLightData *x)
+{
+  int r;
+
+  if (!(x->flags & HAVE_TIME)) {
+    assert(x->flags & HAVE_DF);
+
+    r = df_utc_to_local(x->df, x->of);
+    x->hour = r / 3600;
+    r %= 3600;
+    x->min = r / 60;
+    x->sec = r % 60;
+    x->flags |= HAVE_TIME;
+  }
+}
+
+inline static void
+get_dt_jd(struct DateTimeLightData *x)
+{
+  if (!(x->flags & HAVE_JD)) {
+    long jd;
+    int ns;
+
+    assert(x->flags & HAVE_CIVIL);
+
+    civil_to_jd(x->year, x->mon, x->mday, x->sg, &jd, &ns);
+
+    get_dt_time(x);
+    x->jd = jd_local_to_utc(jd,
+			    time_to_df(x->hour, x->min, x->sec),
+			    x->of);
+    x->flags |= HAVE_JD;
+  }
+}
+
+inline static void
+get_dt_civil(struct DateTimeLightData *x)
+{
+  if (!(x->flags & HAVE_CIVIL)) {
+    long jd;
+    int y, m, d;
+
+    assert(x->flags & HAVE_JD);
+
+    get_dt_df(x);
+    jd = jd_utc_to_local(x->jd, x->df, x->of);
+    jd_to_civil(jd, x->sg, &y, &m, &d);
+    x->year = y;
+    x->mon = m;
+    x->mday = d;
+    x->flags |= HAVE_CIVIL;
+  }
+}
+
+inline static VALUE
+f_kind_of_p(VALUE x, VALUE c)
+{
+  return rb_obj_is_kind_of(x, c);
+}
+
+inline static VALUE
+k_date_p(VALUE x)
+{
+  return f_kind_of_p(x, cDate);
+}
+
+inline static VALUE
+k_datetime_p(VALUE x)
+{
+  return f_kind_of_p(x, cDateTime);
+}
+
+inline static VALUE
+k_d_lite_p(VALUE x)
+{
+  return f_kind_of_p(x, cDateLight);
+}
+
+inline static VALUE
+k_dt_lite_p(VALUE x)
+{
+  return f_kind_of_p(x, cDateTimeLight);
+}
+
+inline static VALUE
+k_numeric_p(VALUE x)
+{
+  return f_kind_of_p(x, rb_cNumeric);
+}
+
+static VALUE
+date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vjd, vsg;
+
+  rb_scan_args(argc, argv, "11", &vjd, &vsg);
+
+  return Qtrue;
+}
+
+static VALUE
+date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vm, vd, vsg;
+  int y, m, d, rm, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg);
+
+  if (!(FIXNUM_P(vy) &&
+	FIXNUM_P(vm) &&
+	FIXNUM_P(vd)))
+    return forward(cDate, "valid_civil_r?");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  m = 1;
+  d = 1;
+
+  switch (argc) {
+  case 4:
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    m = NUM2LONG(vm);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDate, "valid_civil_r?");
+  }
+
+  if (isinf(sg) && sg < 0) {
+    if (!valid_gregorian_p(y, m, d, &rm, &rd))
+      return Qfalse;
+    return Qtrue;
+  } else {
+    long jd;
+    int ns;
+
+    if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns))
+      return Qfalse;
+    return Qtrue;
+  }
+}
+
+static VALUE
+date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vd, vsg;
+  int y, d, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "21", &vy, &vd, &vsg);
+
+  if (!(FIXNUM_P(vy) &&
+	FIXNUM_P(vd)))
+    return forward(cDate, "valid_ordinal_r?");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  d = 1;
+
+  switch (argc) {
+  case 3:
+  case 2:
+    d = NUM2LONG(vd);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDate, "valid_ordinal_r?");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns))
+      return Qfalse;
+    return Qtrue;
+  }
+}
+
+static VALUE
+date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vw, vd, vsg;
+  int y, w, d, rw, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg);
+
+  if (!(FIXNUM_P(vy) &&
+	FIXNUM_P(vw) &&
+	FIXNUM_P(vd)))
+    return forward(cDate, "valid_commercial_r?");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  w = 1;
+  d = 1;
+
+  switch (argc) {
+  case 4:
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    w = NUM2LONG(vw);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_CWYEAR(y))
+      return forward(cDate, "valid_commercial_r?");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns))
+      return Qfalse;
+    return Qtrue;
+  }
+}
+
+inline static VALUE
+d_lite_s_new_internal(VALUE klass, long jd, double sg,
+		      int y, int m, int d, unsigned flags)
+{
+  struct DateLightData *dat;
+  VALUE obj;
+
+  obj = Data_Make_Struct(klass, struct DateLightData, 0, -1, dat);
+
+  dat->jd = jd;
+  dat->sg = sg;
+  dat->year = y;
+  dat->mon = m;
+  dat->mday = d;
+  dat->flags = flags;
+
+  return obj;
+}
+
+static VALUE
+d_lite_s_new_internal_wo_civil(VALUE klass, long jd, double sg,
+			       unsigned flags)
+{
+  return d_lite_s_new_internal(klass, jd, sg, 0, 0, 0, flags);
+}
+
+static VALUE
+d_lite_s_alloc(VALUE klass)
+{
+  return d_lite_s_new_internal_wo_civil(klass, 0, 0, 0);
+}
+
+static VALUE
+d_lite_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vjd, vsg;
+  long jd;
+  double sg;
+
+  rb_scan_args(argc, argv, "02", &vjd, &vsg);
+
+  if (argc < 1)
+    jd = 0;
+  else {
+    if (!FIXNUM_P(vjd))
+      rb_raise(rb_eArgError, "cannot create");
+    jd = NUM2LONG(vjd);
+    if (!LIGHTABLE_JD(jd))
+      rb_raise(rb_eArgError, "cannot create");
+  }
+  if (argc < 2)
+    sg = 0;
+  else
+    sg = NUM2DBL(vsg);
+
+  return d_lite_s_new_internal_wo_civil(klass,
+					jd,
+					sg,
+					HAVE_JD);
+}
+
+static VALUE
+date_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
+{
+  return d_lite_s_new_l_bang(argc, argv, cDateLight);
+}
+
+static VALUE
+date_s_jd(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vjd, vsg;
+  long jd;
+  double sg;
+
+  rb_scan_args(argc, argv, "02", &vjd, &vsg);
+
+  if (!FIXNUM_P(vjd))
+    return forward(cDate, "jd_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  if (argc >= 1) {
+    jd = NUM2LONG(vjd);
+    if (!LIGHTABLE_JD(jd))
+      return forward(cDate, "jd_r");
+  } else
+    jd = 0;
+
+  if (jd < sg)
+    return forward(cDate, "jd_r");
+
+  return d_lite_s_new_internal_wo_civil(cDateLight, jd, sg, HAVE_JD);
+}
+
+static VALUE
+date_s_ordinal(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vd, vsg;
+  int y, d, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "03", &vy, &vd, &vsg);
+
+  if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+	(NIL_P(vd) || FIXNUM_P(vd))))
+    return forward(cDate, "ordinal_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  d = 1;
+
+  switch (argc) {
+  case 3:
+  case 2:
+    d = NUM2LONG(vd);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDate, "ordinal_r");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDate, "ordinal_r");
+
+    return d_lite_s_new_internal_wo_civil(cDateLight, jd, sg, HAVE_JD);
+  }
+}
+
+static VALUE
+date_s_civil(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vm, vd, vsg;
+  int y, m, d, rm, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg);
+
+  if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+	(NIL_P(vm) || FIXNUM_P(vm)) &&
+	(NIL_P(vd) || FIXNUM_P(vd))))
+    return forward(cDate, "civil_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  m = 1;
+  d = 1;
+
+  switch (argc) {
+  case 4:
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    m = NUM2LONG(vm);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDate, "civil_r");
+  }
+
+  if (isinf(sg) && sg < 0) {
+    if (!valid_gregorian_p(y, m, d, &rm, &rd))
+      rb_raise(rb_eArgError, "invalid date");
+
+    return d_lite_s_new_internal(cDateLight, 0, sg, y, rm, rd, HAVE_CIVIL);
+  } else {
+    long jd;
+    int ns;
+
+    if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDate, "civil_r");
+
+    return d_lite_s_new_internal(cDateLight, jd, sg, y, rm, rd,
+				 HAVE_JD | HAVE_CIVIL);
+  }
+}
+
+static VALUE
+date_s_commercial(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vw, vd, vsg;
+  int y, w, d, rw, rd;
+  double sg;
+
+  rb_scan_args(argc, argv, "04", &vy, &vw, &vd, &vsg);
+
+  if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+	(NIL_P(vw) || FIXNUM_P(vw)) &&
+	(NIL_P(vd) || FIXNUM_P(vd))))
+    return forward(cDate, "commercial_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  w = 1;
+  d = 1;
+
+  switch (argc) {
+  case 4:
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    w = NUM2LONG(vw);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_CWYEAR(y))
+      return forward(cDate, "commercial_r");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDate, "commercial_r");
+
+    return d_lite_s_new_internal_wo_civil(cDateLight, jd, sg, HAVE_JD);
+  }
+}
+
+#if !defined(HAVE_GMTIME_R)
+static struct tm*
+localtime_r(const time_t *t, struct tm *tm)
+{
+  auto struct tm *tmp = localtime(t);
+  if (tmp)
+    *tm = *tmp;
+  return tmp;
+}
+#endif
+
+static VALUE
+date_s_today(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vsg;
+  double sg;
+  time_t t;
+  struct tm tm;
+  int y, m, d;
+
+  rb_scan_args(argc, argv, "01", &vsg);
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  if (time(&t) == -1)
+    rb_sys_fail("time");
+  localtime_r(&t, &tm);
+
+  y = tm.tm_year + 1900;
+  m = tm.tm_mon + 1;
+  d = tm.tm_mday;
+
+  if (isinf(sg) && sg < 0)
+    return d_lite_s_new_internal(cDateLight, 0, sg, y, m, d, HAVE_CIVIL);
+  else {
+    long jd;
+    int ns;
+
+    civil_to_jd(y, m, d, sg, &jd, &ns);
+
+    return d_lite_s_new_internal(cDateLight, jd, sg, y, m, d,
+				 HAVE_JD | HAVE_CIVIL);
+  }
+}
+
+static VALUE
+d_lite_ajd(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return rb_funcall(INT2FIX(dat->jd), '-', 1, rhalf);
+}
+
+static VALUE
+d_lite_amjd(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return rb_rational_new1(LONG2NUM(dat->jd - 2400001L));
+}
+
+static VALUE
+d_lite_jd(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return INT2FIX(dat->jd);
+}
+
+static VALUE
+d_lite_mjd(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return LONG2NUM(dat->jd - 2400001L);
+}
+
+static VALUE
+d_lite_ld(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return LONG2NUM(dat->jd - 2299160L);
+}
+
+static VALUE
+d_lite_year(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+  return INT2FIX(dat->year);
+}
+
+static VALUE
+d_lite_yday(VALUE self)
+{
+  int ry, rd;
+
+  get_d1(self);
+  get_d_jd(dat);
+  jd_to_ordinal(dat->jd, dat->sg, &ry, &rd);
+  return INT2FIX(rd);
+}
+
+static VALUE
+d_lite_mon(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+  return INT2FIX(dat->mon);
+}
+
+static VALUE
+d_lite_mday(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+  return INT2FIX(dat->mday);
+}
+
+static VALUE
+d_lite_wnum0(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_d1(self);
+  get_d_jd(dat);
+  jd_to_weeknum(dat->jd, 0, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+d_lite_wnum1(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_d1(self);
+  get_d_jd(dat);
+  jd_to_weeknum(dat->jd, 1, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+d_lite_zone(VALUE self)
+{
+  return rb_str_new2("+00:00");
+}
+
+static VALUE
+d_lite_cwyear(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_d1(self);
+  get_d_jd(dat);
+  jd_to_commercial(dat->jd, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(ry);
+}
+
+static VALUE
+d_lite_cweek(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_d1(self);
+  get_d_jd(dat);
+  jd_to_commercial(dat->jd, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+d_lite_cwday(VALUE self)
+{
+  int w;
+
+  get_d1(self);
+  get_d_jd(dat);
+  w = jd_to_wday(dat->jd);
+  if (w == 0)
+    w = 7;
+  return INT2FIX(w);
+}
+
+static VALUE
+d_lite_wday(VALUE self)
+{
+  get_d1(self);
+  get_d_jd(dat);
+  return INT2FIX(jd_to_wday(dat->jd));
+}
+
+static VALUE
+d_lite_leap_p(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+
+  return leap_p(dat->year) ? Qtrue : Qfalse;
+}
+
+static VALUE
+d_lite_start(VALUE self)
+{
+  get_d1(self);
+  return DBL2NUM(dat->sg);
+}
+
+static VALUE
+d_lite_new_start(int argc, VALUE *argv, VALUE self)
+{
+  VALUE vsg;
+  double sg;
+
+  rb_scan_args(argc, argv, "01", &vsg);
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  {
+    get_d1(self);
+    get_d_jd(dat);
+
+    if (dat->jd < sg)
+      return forward(to_right(self), "new_start");
+
+    return d_lite_s_new_internal_wo_civil(CLASS_OF(self),
+					  dat->jd,
+					  sg,
+					  HAVE_JD);
+  }
+}
+
+static VALUE
+d_lite_new_offset(int argc, VALUE *argv, VALUE self)
+{
+  VALUE vof;
+  int rof;
+
+  rb_scan_args(argc, argv, "01", &vof);
+
+  if (NIL_P(vof))
+    rof = 0;
+  else {
+    if (!daydiff_to_sec(vof, &rof) || rof != 0)
+      return forward(to_right(self), "new_offset");
+  }
+
+  {
+    get_d1(self);
+    get_d_jd(dat);
+
+    return d_lite_s_new_internal_wo_civil(CLASS_OF(self),
+					  dat->jd,
+					  dat->sg,
+					  HAVE_JD);
+  }
+}
+
+static VALUE
+d_lite_plus(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+    {
+      long jd;
+
+      get_d1(self);
+      get_d_jd(dat);
+
+      jd = dat->jd + FIX2LONG(other);
+
+      if (LIGHTABLE_JD(jd) && jd >= dat->sg)
+	return d_lite_s_new_internal(CLASS_OF(self),
+				     jd, dat->sg,
+				     0, 0, 0,
+				     dat->flags & ~HAVE_CIVIL);
+    }
+    break;
+  case T_FLOAT:
+    {
+      double d = NUM2DBL(other);
+      long l = round(d);
+      if (l == d && LIGHTABLE_JD(l))
+	return d_lite_plus(self, INT2FIX(l));
+    }
+    break;
+  }
+  return rb_funcall(to_right(self), '+', 1, other);
+}
+
+static VALUE
+d_lite_minus(VALUE self, VALUE other)
+{
+  if (k_d_lite_p(other)) {
+    long d;
+    get_d2(self, other);
+
+    get_d_jd(adat);
+    get_d_jd(bdat);
+    d = adat->jd - bdat->jd;
+    return rb_rational_new1(LONG2NUM(d));
+  }
+
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+    return d_lite_plus(self, LONG2NUM(-FIX2LONG(other)));
+  case T_FLOAT:
+    return d_lite_plus(self, DBL2NUM(-NUM2DBL(other)));
+  }
+  return rb_funcall(to_right(self), '-', 1, other);
+}
+
+static VALUE
+d_lite_cmp(VALUE self, VALUE other)
+{
+  if (k_d_lite_p(other)) {
+    get_d2(self, other);
+
+    if (adat->flags & HAVE_JD &&
+	bdat->flags & HAVE_JD) {
+      if (adat->jd == bdat->jd)
+	return INT2FIX(0);
+      if (adat->jd < bdat->jd)
+	return INT2FIX(-1);
+      return INT2FIX(1);
+    } else {
+      get_d_civil(adat);
+      get_d_civil(bdat);
+      if (adat->year == bdat->year) {
+	if (adat->mon == bdat->mon) {
+	  if (adat->mday == bdat->mday) {
+	    return INT2FIX(0);
+	  } else if (adat->mday < bdat->mday) {
+	    return INT2FIX(-1);
+	  } else {
+	    return INT2FIX(1);
+	  }
+	} else if (adat->mon < bdat->mon) {
+	  return INT2FIX(-1);
+	} else {
+	  return INT2FIX(1);
+	}
+      } else if (adat->year < bdat->year) {
+	return INT2FIX(-1);
+      } else {
+	return INT2FIX(1);
+      }
+    }
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(d_lite_ajd(self),
+			     rb_funcall(other, rb_intern("ajd"), 0),
+			     rb_intern("<=>"));
+  if (k_numeric_p(other))
+    return rb_num_coerce_cmp(d_lite_ajd(self),
+			     other,
+			     rb_intern("<=>"));
+  return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
+}
+
+static VALUE
+d_lite_eqeqeq(VALUE self, VALUE other)
+{
+  if (k_d_lite_p(other)) {
+    get_d2(self, other);
+
+    if (adat->flags & HAVE_JD &&
+	bdat->flags & HAVE_JD) {
+      if (adat->jd == bdat->jd)
+	return Qtrue;
+      return Qfalse;
+    } else {
+      get_d_civil(adat);
+      get_d_civil(bdat);
+      if (adat->year == bdat->year)
+	if (adat->mon == bdat->mon)
+	  if (adat->mday == bdat->mday)
+	    return Qtrue;
+      return Qfalse;
+    }
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(d_lite_jd(self),
+			     rb_funcall(other, rb_intern("jd"), 0),
+			     rb_intern("=="));
+  if (k_numeric_p(other))
+    return rb_num_coerce_cmp(d_lite_jd(self),
+			     other,
+			     rb_intern("=="));
+  return rb_num_coerce_cmp(self, other, rb_intern("==="));
+}
+
+static VALUE
+d_lite_eql_p(VALUE self, VALUE other)
+{
+  if (k_d_lite_p(other)) {
+    get_d2(self, other);
+
+    if (adat->flags & HAVE_JD &&
+	bdat->flags & HAVE_JD) {
+      if (adat->jd == bdat->jd)
+	return Qtrue;
+      return Qfalse;
+    } else {
+      get_d_civil(adat);
+      get_d_civil(bdat);
+      if (adat->year == bdat->year)
+	if (adat->mon == bdat->mon)
+	  if (adat->mday == bdat->mday)
+	    return Qtrue;
+      return Qfalse;
+    }
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(d_lite_ajd(self),
+			     rb_funcall(other, rb_intern("ajd"), 0),
+			     rb_intern("=="));
+  return Qfalse;
+}
+
+static VALUE
+d_lite_hash(VALUE self)
+{
+  get_d1(self);
+
+  return rb_funcall(d_lite_ajd(self), rb_intern("hash"), 0);
+}
+
+static VALUE
+d_lite_to_s(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+  return rb_sprintf("%.4d-%02d-%02d", dat->year, dat->mon, dat->mday);
+}
+
+static VALUE
+d_lite_inspect(VALUE self)
+{
+  get_d1(self);
+  get_d_civil(dat);
+  get_d_jd(dat);
+  return rb_sprintf("#<Date::Light: %.4d-%02d-%02d (%ldj,0,%.0f)>",
+		    dat->year, dat->mon, dat->mday, dat->jd, dat->sg);
+}
+
+static VALUE
+d_lite_zero(VALUE self)
+{
+  return INT2FIX(0);
+}
+
+static VALUE
+d_lite_rzero(VALUE self)
+{
+  return rzero;
+}
+
+static VALUE
+d_lite_false(VALUE self)
+{
+  return Qfalse;
+}
+
+static VALUE
+d_lite_true(VALUE self)
+{
+  return Qtrue;
+}
+
+static VALUE
+d_lite_marshal_dump(VALUE self)
+{
+  VALUE a;
+
+  get_d1(self);
+  get_d_jd(dat);
+  a = rb_assoc_new(INT2FIX(dat->jd), DBL2NUM(dat->sg));
+
+  if (FL_TEST(self, FL_EXIVAR)) {
+    rb_copy_generic_ivar(a, self);
+    FL_SET(a, FL_EXIVAR);
+  }
+
+  return a;
+}
+
+static VALUE
+d_lite_marshal_load(VALUE self, VALUE a)
+{
+  get_d1(self);
+
+  dat->jd = FIX2INT(RARRAY_PTR(a)[0]);
+  dat->sg = NUM2DBL(RARRAY_PTR(a)[1]);
+  dat->year = 0;
+  dat->mon = 0;
+  dat->mday = 0;
+  dat->flags |= HAVE_JD;
+
+  if (FL_TEST(a, FL_EXIVAR)) {
+    rb_copy_generic_ivar(self, a);
+    FL_SET(self, FL_EXIVAR);
+  }
+
+  return self;
+}
+
+/* datetime light */
+
+inline static VALUE
+dt_lite_s_new_internal(VALUE klass, long jd, int df,
+		       long long sf, int of, double sg,
+		       int y, int m, int d,
+		       int h, int min, int s,
+		       unsigned flags)
+{
+  struct DateTimeLightData *dat;
+  VALUE obj;
+
+  obj = Data_Make_Struct(klass, struct DateTimeLightData, 0, -1, dat);
+
+  dat->jd = jd;
+  dat->df = df;
+  dat->sf = sf;
+  dat->of = of;
+  dat->sg = sg;
+  dat->year = y;
+  dat->mon = m;
+  dat->mday = d;
+  dat->hour = h;
+  dat->min = min;
+  dat->sec = s;
+  dat->flags = flags;
+
+  return obj;
+}
+
+static VALUE
+dt_lite_s_new_internal_wo_civil(VALUE klass, long jd, int df,
+				long long sf, int of, double sg,
+				unsigned flags)
+{
+  return dt_lite_s_new_internal(klass, jd, df, sf, of, sg,
+				0, 0, 0, 0, 0, 0, flags);
+}
+
+static VALUE
+dt_lite_s_alloc(VALUE klass)
+{
+  return dt_lite_s_new_internal_wo_civil(klass, 0, 0, 0, 0, 0, 0);
+}
+
+static VALUE
+dt_lite_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vjd, vdf, vsf, vof, vsg;
+
+  rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg);
+
+  if (argc < 1)
+    vjd = INT2FIX(0);
+  if (argc < 2)
+    vdf = INT2FIX(0);
+  if (argc < 3)
+    vsf = INT2FIX(0);
+  if (argc < 4)
+    vof = INT2FIX(0);
+  if (argc < 5)
+    vsg = INT2FIX(0);
+
+  if (!FIXNUM_P(vjd) ||
+      !FIXNUM_P(vdf) ||
+      !FIXNUM_P(vsf) ||
+      !FIXNUM_P(vof))
+    rb_raise(rb_eArgError, "cannot create");
+
+  return dt_lite_s_new_internal_wo_civil(klass,
+					 FIX2INT(vjd),
+					 FIX2INT(vdf),
+					 FIX2INT(vsf),
+					 FIX2INT(vof),
+					 NUM2DBL(vsg),
+					 HAVE_JD | HAVE_DF);
+}
+
+static VALUE
+datetime_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
+{
+  return dt_lite_s_new_l_bang(argc, argv, cDateTimeLight);
+}
+
+static VALUE
+datetime_s_jd(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vjd, vh, vmin, vs, vof, vsg;
+  long jd;
+  int h, min, s, rh, rmin, rs, rof;
+  double sg;
+
+  rb_scan_args(argc, argv, "06", &vjd, &vh, &vmin, &vs, &vof, &vsg);
+
+  if (!FIXNUM_P(vjd))
+    return forward(cDateTime, "jd_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  jd = h = min = s = 0;
+  rof = 0;
+
+  switch (argc) {
+  case 6:
+  case 5:
+    if (!daydiff_to_sec(vof, &rof))
+      return forward(cDateTime, "jd_r");
+  case 4:
+    s = NUM2LONG(vs);
+  case 3:
+    min = NUM2LONG(vmin);
+  case 2:
+    h = NUM2LONG(vh);
+  case 1:
+    jd = NUM2LONG(vjd);
+    if (!LIGHTABLE_JD(jd))
+      return forward(cDateTime, "jd_r");
+  }
+
+  if (jd < sg)
+    return forward(cDateTime, "jd_r");
+
+  if (!valid_time_p(h, min, s, &rh, &rmin, &rs))
+    rb_raise(rb_eArgError, "invalid date");
+
+  return dt_lite_s_new_internal(cDateTimeLight,
+				jd_local_to_utc(jd,
+						time_to_df(rh, rmin, rs),
+						rof),
+				0, 0, rof, sg, 0, 0, 0, rh, rmin, rs,
+				HAVE_JD | HAVE_TIME);
+}
+
+static VALUE
+datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vd, vh, vmin, vs, vof, vsg;
+  int y, d, rd, h, min, s, rh, rmin, rs, rof;
+  double sg;
+
+  rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg);
+
+  if (!((NIL_P(vy)   || FIXNUM_P(vy)) &&
+	(NIL_P(vd)   || FIXNUM_P(vd)) &&
+	(NIL_P(vh)   || FIXNUM_P(vh)) &&
+	(NIL_P(vmin) || FIXNUM_P(vmin)) &&
+	(NIL_P(vs)   || FIXNUM_P(vs))))
+    return forward(cDateTime, "ordinal_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  d = 1;
+
+  h = min = s = 0;
+  rof = 0;
+
+  switch (argc) {
+  case 7:
+  case 6:
+    if (!daydiff_to_sec(vof, &rof))
+      return forward(cDateTime, "ordinal_r");
+  case 5:
+    s = NUM2LONG(vs);
+  case 4:
+    min = NUM2LONG(vmin);
+  case 3:
+    h = NUM2LONG(vh);
+  case 2:
+    d = NUM2LONG(vd);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDateTime, "ordinal_r");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+    if (!valid_time_p(h, min, s, &rh, &rmin, &rs))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDateTime, "ordinal_r");
+
+    return dt_lite_s_new_internal(cDateTimeLight,
+				  jd_local_to_utc(jd,
+						  time_to_df(rh, rmin, rs),
+						  rof),
+				  0, 0, rof, sg,
+				  0, 0, 0, rh, rmin, rs,
+				  HAVE_JD | HAVE_TIME);
+  }
+}
+
+static VALUE
+datetime_s_civil(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vm, vd, vh, vmin, vs, vof, vsg;
+  int y, m, d, rm, rd, h, min, s, rh, rmin, rs, rof;
+  double sg;
+
+  rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg);
+
+  if (!((NIL_P(vy)   || FIXNUM_P(vy)) &&
+	(NIL_P(vm)   || FIXNUM_P(vm)) &&
+	(NIL_P(vd)   || FIXNUM_P(vd)) &&
+	(NIL_P(vh)   || FIXNUM_P(vh)) &&
+	(NIL_P(vmin) || FIXNUM_P(vmin)) &&
+	(NIL_P(vs)   || FIXNUM_P(vs))))
+    return forward(cDateTime, "civil_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  m = 1;
+  d = 1;
+
+  h = min = s = 0;
+  rof = 0;
+
+  switch (argc) {
+  case 8:
+  case 7:
+    if (!daydiff_to_sec(vof, &rof))
+      return forward(cDateTime, "civil_r");
+  case 6:
+    s = NUM2LONG(vs);
+  case 5:
+    min = NUM2LONG(vmin);
+  case 4:
+    h = NUM2LONG(vh);
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    m = NUM2LONG(vm);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_YEAR(y))
+      return forward(cDateTime, "civil_r");
+  }
+
+  if (isinf(sg) && sg < 0) {
+    if (!valid_gregorian_p(y, m, d, &rm, &rd))
+      rb_raise(rb_eArgError, "invalid date");
+    if (!valid_time_p(h, min, s, &rh, &rmin, &rs))
+      rb_raise(rb_eArgError, "invalid date");
+
+    return dt_lite_s_new_internal(cDateTimeLight, 0, 0, 0, rof, sg,
+				  y, rm, rd, rh, rmin, rs,
+				  HAVE_CIVIL | HAVE_TIME);
+  } else {
+    long jd;
+    int ns;
+
+    if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+    if (!valid_time_p(h, min, s, &rh, &rmin, &rs))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDateTime, "civil_r");
+
+    return dt_lite_s_new_internal(cDateTimeLight,
+				  jd_local_to_utc(jd,
+						  time_to_df(rh, rmin, rs),
+						  rof),
+				  0, 0, rof, sg,
+				  y, rm, rd, rh, rmin, rs,
+				  HAVE_JD | HAVE_CIVIL | HAVE_TIME);
+  }
+}
+
+static VALUE
+datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vy, vw, vd, vh, vmin, vs, vof, vsg;
+  int y, w, d, rw, rd, h, min, s, rh, rmin, rs, rof;
+  double sg;
+
+  rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg);
+
+  if (!((NIL_P(vy)   || FIXNUM_P(vy)) &&
+	(NIL_P(vw)   || FIXNUM_P(vw)) &&
+	(NIL_P(vd)   || FIXNUM_P(vd)) &&
+	(NIL_P(vh)   || FIXNUM_P(vh)) &&
+	(NIL_P(vmin) || FIXNUM_P(vmin)) &&
+	(NIL_P(vs)   || FIXNUM_P(vs))))
+    return forward(cDateTime, "commercial_r");
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  y = -4712;
+  w = 1;
+  d = 1;
+
+  h = min = s = 0;
+  rof = 0;
+
+  switch (argc) {
+  case 8:
+  case 7:
+    if (!daydiff_to_sec(vof, &rof))
+      return forward(cDateTime, "commercial_r");
+  case 6:
+    s = NUM2LONG(vs);
+  case 5:
+    min = NUM2LONG(vmin);
+  case 4:
+    h = NUM2LONG(vh);
+  case 3:
+    d = NUM2LONG(vd);
+  case 2:
+    w = NUM2LONG(vw);
+  case 1:
+    y = NUM2LONG(vy);
+    if (!LIGHTABLE_CWYEAR(y))
+      return forward(cDateTime, "commercial_r");
+  }
+
+  {
+    long jd;
+    int ns;
+
+    if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns))
+      rb_raise(rb_eArgError, "invalid date");
+    if (!valid_time_p(h, min, s, &rh, &rmin, &rs))
+      rb_raise(rb_eArgError, "invalid date");
+
+    if (!LIGHTABLE_JD(jd) || !ns)
+      return forward(cDateTime, "commercial_r");
+
+    return dt_lite_s_new_internal(cDateTimeLight,
+				  jd_local_to_utc(jd,
+						  time_to_df(rh, rmin, rs),
+						  rof),
+				  0, 0, rof, sg,
+				  0, 0, 0, rh, rmin, rs,
+				  HAVE_JD | HAVE_TIME);
+  }
+}
+
+static VALUE
+datetime_s_now(int argc, VALUE *argv, VALUE klass)
+{
+  VALUE vsg;
+  double sg;
+#ifdef HAVE_CLOCK_GETTIME
+  struct timespec ts;
+#else
+  struct timeval tv;
+#endif
+  struct tm tm;
+  int y, m, d, h, min, s, of, sf;
+
+  rb_scan_args(argc, argv, "01", &vsg);
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+#ifdef HAVE_CLOCK_GETTIME
+  if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+    rb_sys_fail("clock_gettime");
+  localtime_r(&ts.tv_sec, &tm);
+#else
+  if (gettimeofday(&tv, NULL) == -1)
+    rb_sys_fail("gettimeofday");
+  localtime_r(&tv.tv_sec, &tm);
+#endif
+
+  y = tm.tm_year + 1900;
+  m = tm.tm_mon + 1;
+  d = tm.tm_mday;
+  h = tm.tm_hour;
+  min = tm.tm_min;
+  s = tm.tm_sec;
+  if (s == 60)
+    s = 59;
+#ifdef HAVE_STRUCT_TM_TM_GMTOFF
+  of = tm.tm_gmtoff;
+#else
+  of = (int)-timezone;
+#endif
+#ifdef HAVE_CLOCK_GETTIME
+  sf = ts.tv_nsec;
+#else
+  sf = tv.tv_usec * 1000;
+#endif
+
+  if (isinf(sg) && sg < 0)
+    return dt_lite_s_new_internal(cDateTimeLight, 0, 0, sf, of, sg,
+				  y, m, d, h, min, s,
+				  HAVE_CIVIL | HAVE_TIME);
+  else {
+    long jd;
+    int ns;
+
+    civil_to_jd(y, m, d, sg, &jd, &ns);
+
+    return dt_lite_s_new_internal(cDateTimeLight,
+				  jd_local_to_utc(jd,
+						  time_to_df(h, min, s),
+						  of),
+				  0, sf, of, sg,
+				  y, m, d, h, min, s,
+				  HAVE_JD | HAVE_CIVIL | HAVE_TIME);
+  }
+}
+
+static VALUE
+dt_lite_ajd(VALUE self)
+{
+  VALUE r;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  r = rb_funcall(INT2FIX(dat->jd), '-', 1, rhalf);
+  if (dat->df)
+    r = rb_funcall(r, '+', 1,
+		   rb_rational_new2(INT2FIX(dat->df),
+				    INT2FIX(DAY_IN_SECONDS)));
+  if (dat->sf)
+    r = rb_funcall(r, '+', 1,
+		   rb_rational_new2(INT2FIX(dat->sf),
+				    rb_ll2inum(DAY_IN_NANOSECONDS)));
+  return r;
+}
+
+static VALUE
+dt_lite_amjd(VALUE self)
+{
+  VALUE r;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  r = rb_rational_new1(LONG2NUM(dat->jd - 2400001L));
+  if (dat->df)
+    r = rb_funcall(r, '+', 1,
+		   rb_rational_new2(INT2FIX(dat->df),
+				    INT2FIX(DAY_IN_SECONDS)));
+  if (dat->sf)
+    r = rb_funcall(r, '+', 1,
+		   rb_rational_new2(INT2FIX(dat->sf),
+				    rb_ll2inum(DAY_IN_NANOSECONDS)));
+  return r;
+}
+
+#define local_jd jd_utc_to_local(dat->jd, dat->df, dat->of)
+#define local_df df_utc_to_local(dat->df, dat->of)
+
+static VALUE
+dt_lite_jd(VALUE self)
+{
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  return INT2FIX(local_jd);
+}
+
+static VALUE
+dt_lite_mjd(VALUE self)
+{
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  return LONG2NUM(local_jd - 2400001L);
+}
+
+static VALUE
+dt_lite_ld(VALUE self)
+{
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  return LONG2NUM(local_jd - 2299160L);
+}
+
+static VALUE
+dt_lite_year(VALUE self)
+{
+  get_dt1(self);
+  get_dt_civil(dat);
+  return INT2FIX(dat->year);
+}
+
+static VALUE
+dt_lite_yday(VALUE self)
+{
+  int ry, rd;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  jd_to_ordinal(local_jd, dat->sg, &ry, &rd);
+  return INT2FIX(rd);
+}
+
+static VALUE
+dt_lite_mon(VALUE self)
+{
+  get_dt1(self);
+  get_dt_civil(dat);
+  return INT2FIX(dat->mon);
+}
+
+static VALUE
+dt_lite_mday(VALUE self)
+{
+  get_dt1(self);
+  get_dt_civil(dat);
+  return INT2FIX(dat->mday);
+}
+
+static VALUE
+dt_lite_day_fraction(VALUE self)
+{
+  get_dt1(self);
+  get_dt_df(dat);
+  return rb_rational_new2(INT2FIX(local_df), INT2FIX(DAY_IN_SECONDS));
+}
+
+static VALUE
+dt_lite_wnum0(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  jd_to_weeknum(local_jd, 0, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+dt_lite_wnum1(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  jd_to_weeknum(local_jd, 1, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+dt_lite_hour(VALUE self)
+{
+  get_dt1(self);
+  get_dt_time(dat);
+  return INT2FIX(dat->hour);
+}
+
+static VALUE
+dt_lite_min(VALUE self)
+{
+  get_dt1(self);
+  get_dt_time(dat);
+  return INT2FIX(dat->min);
+}
+
+static VALUE
+dt_lite_sec(VALUE self)
+{
+  get_dt1(self);
+  get_dt_time(dat);
+  return INT2FIX(dat->sec);
+}
+
+static VALUE
+dt_lite_sec_fraction(VALUE self)
+{
+  get_dt1(self);
+  return rb_rational_new2(INT2FIX(dat->sf), INT2FIX(SECOND_IN_NANOSECONDS));
+}
+
+static VALUE
+dt_lite_offset(VALUE self)
+{
+  get_dt1(self);
+  return rb_rational_new2(INT2FIX(dat->of), INT2FIX(DAY_IN_SECONDS));
+}
+
+#define decode_offset(of,s,h,m) \
+{ \
+  int a; \
+  s = (of < 0) ? '-' : '+'; \
+  a = (of < 0) ? -of : of; \
+  h = a / 3600; \
+  m = a % 3600 / 60; \
+}
+
+static VALUE
+dt_lite_zone(VALUE self)
+{
+  int s, h, m;
+
+  get_dt1(self);
+  decode_offset(dat->of, s, h, m);
+  return rb_sprintf("%c%02d:%02d", s, h, m);
+}
+
+static VALUE
+dt_lite_cwyear(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  jd_to_commercial(local_jd, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(ry);
+}
+
+static VALUE
+dt_lite_cweek(VALUE self)
+{
+  int ry, rw, rd;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  jd_to_commercial(local_jd, dat->sg, &ry, &rw, &rd);
+  return INT2FIX(rw);
+}
+
+static VALUE
+dt_lite_cwday(VALUE self)
+{
+  int w;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  w = jd_to_wday(local_jd);
+  if (w == 0)
+    w = 7;
+  return INT2FIX(w);
+}
+
+static VALUE
+dt_lite_wday(VALUE self)
+{
+  int w;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  w = jd_to_wday(local_jd);
+  return INT2FIX(w);
+}
+
+static VALUE
+dt_lite_leap_p(VALUE self)
+{
+  get_dt1(self);
+  get_dt_civil(dat);
+
+  return leap_p(dat->year) ? Qtrue : Qfalse;
+}
+
+static VALUE
+dt_lite_start(VALUE self)
+{
+  get_dt1(self);
+  return DBL2NUM(dat->sg);
+}
+
+static VALUE
+dt_lite_new_start(int argc, VALUE *argv, VALUE self)
+{
+  VALUE vsg;
+  double sg;
+
+  rb_scan_args(argc, argv, "01", &vsg);
+
+  if (!NIL_P(vsg))
+    sg = NUM2DBL(vsg);
+  else
+    sg = ITALY;
+
+  {
+    get_dt1(self);
+    get_dt_jd(dat);
+    get_dt_df(dat);
+
+    if (dat->jd < sg)
+      return forward(to_right(self), "new_start");
+
+    return dt_lite_s_new_internal_wo_civil(CLASS_OF(self),
+					   dat->jd,
+					   dat->df,
+					   dat->sf,
+					   dat->of,
+					   sg,
+					   HAVE_JD | HAVE_DF);
+  }
+}
+
+static VALUE
+dt_lite_new_offset(int argc, VALUE *argv, VALUE self)
+{
+  VALUE vof;
+  int rof;
+
+  rb_scan_args(argc, argv, "01", &vof);
+
+  if (NIL_P(vof))
+    rof = 0;
+  else {
+    if (!daydiff_to_sec(vof, &rof))
+      return forward(to_right(self), "new_offset");
+  }
+
+  {
+    get_dt1(self);
+    get_dt_jd(dat);
+    get_dt_df(dat);
+
+    return dt_lite_s_new_internal_wo_civil(CLASS_OF(self),
+					   dat->jd,
+					   dat->df,
+					   dat->sf,
+					   rof,
+					   dat->sg,
+					   HAVE_JD | HAVE_DF);
+  }
+}
+
+static VALUE
+dt_lite_plus(VALUE self, VALUE other)
+{
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+    {
+      long jd;
+
+      get_dt1(self);
+      get_dt_jd(dat);
+      get_dt_df(dat);
+
+      jd = dat->jd + FIX2LONG(other);
+
+      if (LIGHTABLE_JD(jd) && jd >= dat->sg)
+	return dt_lite_s_new_internal(CLASS_OF(self),
+				      jd,
+				      dat->df,
+				      dat->sf,
+				      dat->of,
+				      dat->sg,
+				      0, 0, 0,
+				      dat->hour,
+				      dat->min,
+				      dat->sec,
+				      dat->flags & ~HAVE_CIVIL);
+    }
+    break;
+  case T_FLOAT:
+    {
+      long jd, df;
+      long long sf;
+      long double o;
+      int s;
+
+      get_dt1(self);
+      get_dt_jd(dat);
+      get_dt_df(dat);
+
+      jd = dat->jd;
+      o = NUM2DBL(other);
+
+      if (o < 0) {
+	s = -1;
+	o = -o;
+      } else
+	s = +1;
+
+      jd = (long)floorl(o);
+      o = o - jd;
+      o *= DAY_IN_SECONDS;
+      df = (long)floorl(o);
+      o = o - df;
+      o *= SECOND_IN_NANOSECONDS;
+      sf = (long)roundl(o);
+
+      if (s < 0) {
+	jd = -jd;
+	df = -df;
+	sf = -sf;
+      }
+
+      sf = dat->sf + sf;
+      if (sf < 0) {
+	df -= 1;
+	sf += SECOND_IN_NANOSECONDS;
+      } else if (sf >= SECOND_IN_NANOSECONDS) {
+	df += 1;
+	sf -= SECOND_IN_NANOSECONDS;
+      }
+
+      df = dat->df + df;
+      if (df < 0) {
+	jd -= 1;
+	df += DAY_IN_SECONDS;
+      } else if (df >= DAY_IN_SECONDS) {
+	jd += 1;
+	df -= DAY_IN_SECONDS;
+      }
+
+      jd = dat->jd + jd;
+
+      if (LIGHTABLE_JD(jd) && jd >= dat->sg)
+	return dt_lite_s_new_internal(CLASS_OF(self),
+				      jd,
+				      df,
+				      sf,
+				      dat->of,
+				      dat->sg,
+				      0, 0, 0,
+				      dat->hour,
+				      dat->min,
+				      dat->sec,
+				      dat->flags & ~HAVE_CIVIL & ~HAVE_TIME);
+    }
+    break;
+  }
+  return rb_funcall(to_right(self), '+', 1, other);
+}
+
+static VALUE
+dt_lite_minus(VALUE self, VALUE other)
+{
+  if (k_d_lite_p(other))
+    return rb_funcall(dt_lite_ajd(self), '-', 1, dt_lite_ajd(other));
+
+  switch (TYPE(other)) {
+  case T_FIXNUM:
+    return dt_lite_plus(self, LONG2NUM(-FIX2LONG(other)));
+  case T_FLOAT:
+    return dt_lite_plus(self, DBL2NUM(-NUM2DBL(other)));
+  }
+  return rb_funcall(to_right(self), '-', 1, other);
+}
+
+static VALUE
+dt_lite_cmp(VALUE self, VALUE other)
+{
+  if (k_dt_lite_p(other)) {
+    get_dt2(self, other);
+
+    get_dt_jd(adat);
+    get_dt_jd(bdat);
+    get_dt_df(adat);
+    get_dt_df(bdat);
+
+    if (adat->jd == bdat->jd) {
+      if (adat->df == bdat->df) {
+	if (adat->sf == bdat->sf) {
+	  return INT2FIX(0);
+	} else if (adat->sf < bdat->sf) {
+	  return INT2FIX(-1);
+	} else {
+	  return INT2FIX(1);
+	}
+      } else if (adat->df < bdat->df) {
+	return INT2FIX(-1);
+      } else {
+	return INT2FIX(1);
+      }
+    } else if (adat->jd < bdat->jd) {
+      return INT2FIX(-1);
+    } else {
+      return INT2FIX(1);
+    }
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(dt_lite_ajd(self),
+			     rb_funcall(other, rb_intern("ajd"), 0),
+			     rb_intern("<=>"));
+  if (k_numeric_p(other))
+    return rb_num_coerce_cmp(dt_lite_ajd(self),
+			     other,
+			     rb_intern("<=>"));
+  return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
+}
+
+static VALUE
+dt_lite_eqeqeq(VALUE self, VALUE other)
+{
+  if (k_dt_lite_p(other)) {
+    get_dt2(self, other);
+
+    if (adat->flags & HAVE_JD &&
+	bdat->flags & HAVE_JD) {
+      if (adat->jd == bdat->jd)
+	return Qtrue;
+      return Qfalse;
+    } else {
+      get_dt_civil(adat);
+      get_dt_civil(bdat);
+      if (adat->year == bdat->year)
+	if (adat->mon == bdat->mon)
+	  if (adat->mday == bdat->mday)
+	    return Qtrue;
+      return Qfalse;
+    }
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(dt_lite_jd(self),
+			     rb_funcall(other, rb_intern("jd"), 0),
+			     rb_intern("=="));
+  if (k_numeric_p(other))
+    return rb_num_coerce_cmp(dt_lite_jd(self),
+			     other,
+			     rb_intern("=="));
+  return rb_num_coerce_cmp(self, other, rb_intern("==="));
+}
+
+static VALUE
+dt_lite_eql_p(VALUE self, VALUE other)
+{
+  if (k_dt_lite_p(other)) {
+    get_dt2(self, other);
+
+    get_dt_jd(adat);
+    get_dt_jd(bdat);
+    get_dt_df(adat);
+    get_dt_df(bdat);
+
+    if (adat->jd == bdat->jd)
+      if (adat->df == bdat->df)
+	if (adat->sf == bdat->sf)
+	  return Qtrue;
+    return Qfalse;
+  }
+  if (k_date_p(other))
+    return rb_num_coerce_cmp(dt_lite_ajd(self),
+			     rb_funcall(other, rb_intern("ajd"), 0),
+			     rb_intern("=="));
+  return Qfalse;
+}
+
+static VALUE
+dt_lite_hash(VALUE self)
+{
+  get_dt1(self);
+  return rb_funcall(dt_lite_ajd(self), rb_intern("hash"), 0);
+}
+
+static VALUE
+dt_lite_to_s(VALUE self)
+{
+  int s, h, m;
+
+  get_dt1(self);
+  get_dt_civil(dat);
+  get_dt_time(dat);
+  decode_offset(dat->of, s, h, m);
+  return rb_sprintf("%.4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+		    dat->year, dat->mon, dat->mday,
+		    dat->hour, dat->min, dat->sec,
+		    s, h, m);
+}
+
+static VALUE
+dt_lite_inspect(VALUE self)
+{
+  int s, h, m;
+
+  get_dt1(self);
+  get_dt_civil(dat);
+  get_dt_time(dat);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  decode_offset(dat->of, s, h, m);
+  return rb_sprintf("#<DateTime::Light: "
+		    "%.4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d "
+		    "((%ldj,%ds,%.0fn),%d/86400,%.0f)>",
+		    dat->year, dat->mon, dat->mday,
+		    dat->hour, dat->min, dat->sec,
+		    s, h, m,
+		    dat->jd, dat->df, (double)dat->sf, dat->of, dat->sg);
+}
+
+static VALUE
+dt_lite_marshal_dump(VALUE self)
+{
+  VALUE a;
+
+  get_dt1(self);
+  get_dt_jd(dat);
+  get_dt_df(dat);
+  a = rb_ary_new3(5,
+		  INT2FIX(dat->jd), INT2FIX(dat->df), INT2FIX(dat->sf),
+		  INT2FIX(dat->of), DBL2NUM(dat->sg));
+
+  if (FL_TEST(self, FL_EXIVAR)) {
+    rb_copy_generic_ivar(a, self);
+    FL_SET(a, FL_EXIVAR);
+  }
+
+  return a;
+}
+
+static VALUE
+dt_lite_marshal_load(VALUE self, VALUE a)
+{
+  get_dt1(self);
+
+  dat->jd = FIX2INT(RARRAY_PTR(a)[0]);
+  dat->df = FIX2INT(RARRAY_PTR(a)[1]);
+  dat->sf = FIX2INT(RARRAY_PTR(a)[2]);
+  dat->of = FIX2INT(RARRAY_PTR(a)[3]);
+  dat->sg = NUM2DBL(RARRAY_PTR(a)[4]);
+  dat->year = 0;
+  dat->mon = 0;
+  dat->mday = 0;
+  dat->hour = 0;
+  dat->min = 0;
+  dat->sec = 0;
+  dat->flags |= HAVE_JD | HAVE_DF;
+
+  if (FL_TEST(a, FL_EXIVAR)) {
+    rb_copy_generic_ivar(self, a);
+    FL_SET(self, FL_EXIVAR);
+  }
+
+  return self;
+}
+
+#ifndef NDEBUG
+static int
+test_civil(long from, long to, double sg)
+{
+  long j;
+
+  fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+  for (j = from; j <= to; j++) {
+    int y, m, d, ns;
+    long rj;
+
+    jd_to_civil(j, sg, &y, &m, &d);
+    civil_to_jd(y, m, d, sg, &rj, &ns);
+    if (j != rj) {
+      fprintf(stderr, "%ld != %ld\n", j, rj);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static VALUE
+date_s_test_civil(VALUE klass)
+{
+  double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+
+  if (!test_civil(min_jd, min_jd + 366, greg))
+    return Qfalse;
+  if (!test_civil(2305814, 2598007, greg))
+    return Qfalse;
+  if (!test_civil(max_jd - 366, max_jd, greg))
+    return Qfalse;
+
+  if (!test_civil(min_jd, min_jd + 366, ITALY))
+    return Qfalse;
+  if (!test_civil(2305814, 2598007, ITALY))
+    return Qfalse;
+  if (!test_civil(max_jd - 366, max_jd, ITALY))
+    return Qfalse;
+
+  return Qtrue;
+}
+
+static int
+test_ordinal(long from, long to, double sg)
+{
+  long j;
+
+  fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+  for (j = from; j <= to; j++) {
+    int y, d, ns;
+    long rj;
+
+    jd_to_ordinal(j, sg, &y, &d);
+    ordinal_to_jd(y, d, sg, &rj, &ns);
+    if (j != rj) {
+      fprintf(stderr, "%ld != %ld\n", j, rj);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static VALUE
+date_s_test_ordinal(VALUE klass)
+{
+  double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+
+  if (!test_ordinal(min_jd, min_jd + 366, greg))
+    return Qfalse;
+  if (!test_ordinal(2305814, 2598007, greg))
+    return Qfalse;
+  if (!test_ordinal(max_jd - 366, max_jd, greg))
+    return Qfalse;
+
+  if (!test_ordinal(min_jd, min_jd + 366, ITALY))
+    return Qfalse;
+  if (!test_ordinal(2305814, 2598007, ITALY))
+    return Qfalse;
+  if (!test_ordinal(max_jd - 366, max_jd, ITALY))
+    return Qfalse;
+
+  return Qtrue;
+}
+
+static int
+test_commercial(long from, long to, double sg)
+{
+  long j;
+
+  fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+  for (j = from; j <= to; j++) {
+    int y, w, d, ns;
+    long rj;
+
+    jd_to_commercial(j, sg, &y, &w, &d);
+    commercial_to_jd(y, w, d, sg, &rj, &ns);
+    if (j != rj) {
+      fprintf(stderr, "%ld != %ld\n", j, rj);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static VALUE
+date_s_test_commercial(VALUE klass)
+{
+  double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+
+  if (!test_commercial(min_jd, min_jd + 366, greg))
+    return Qfalse;
+  if (!test_commercial(2305814, 2598007, greg))
+    return Qfalse;
+  if (!test_commercial(max_jd - 366, max_jd, greg))
+    return Qfalse;
+
+  if (!test_commercial(min_jd, min_jd + 366, ITALY))
+    return Qfalse;
+  if (!test_commercial(2305814, 2598007, ITALY))
+    return Qfalse;
+  if (!test_commercial(max_jd - 366, max_jd, ITALY))
+    return Qfalse;
+
+  return Qtrue;
+}
+
+static int
+test_weeknum(long from, long to, int f, double sg)
+{
+  long j;
+
+  fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+  for (j = from; j <= to; j++) {
+    int y, w, d, ns;
+    long rj;
+
+    jd_to_weeknum(j, f, sg, &y, &w, &d);
+    weeknum_to_jd(y, w, d, f, sg, &rj, &ns);
+    if (j != rj) {
+      fprintf(stderr, "%ld != %ld\n", j, rj);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static VALUE
+date_s_test_weeknum(VALUE klass)
+{
+  double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+  int f;
+
+  for (f = 0; f <= 1; f++) {
+    if (!test_weeknum(min_jd, min_jd + 366, f, greg))
+      return Qfalse;
+    if (!test_weeknum(2305814, 2598007, f, greg))
+      return Qfalse;
+    if (!test_weeknum(max_jd - 366, max_jd, f, greg))
+      return Qfalse;
+
+    if (!test_weeknum(min_jd, min_jd + 366, f, ITALY))
+      return Qfalse;
+    if (!test_weeknum(2305814, 2598007, f, ITALY))
+      return Qfalse;
+    if (!test_weeknum(max_jd - 366, max_jd, f, ITALY))
+      return Qfalse;
+  }
+
+  return Qtrue;
+}
+
+
+static int
+test_nth_kday(long from, long to, double sg)
+{
+  long j;
+
+  fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+  for (j = from; j <= to; j++) {
+    int y, m, n, k, ns;
+    long rj;
+
+    jd_to_nth_kday(j, sg, &y, &m, &n, &k);
+    nth_kday_to_jd(y, m, n, k, sg, &rj, &ns);
+    if (j != rj) {
+      fprintf(stderr, "%ld != %ld\n", j, rj);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static VALUE
+date_s_test_nth_kday(VALUE klass)
+{
+  double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+
+  if (!test_nth_kday(min_jd, min_jd + 366, greg))
+    return Qfalse;
+  if (!test_nth_kday(2305814, 2598007, greg))
+    return Qfalse;
+  if (!test_nth_kday(max_jd - 366, max_jd, greg))
+    return Qfalse;
+
+  if (!test_nth_kday(min_jd, min_jd + 366, ITALY))
+    return Qfalse;
+  if (!test_nth_kday(2305814, 2598007, ITALY))
+    return Qfalse;
+  if (!test_nth_kday(max_jd - 366, max_jd, ITALY))
+    return Qfalse;
+
+  return Qtrue;
+}
+
+static VALUE
+date_s_test_all(VALUE klass)
+{
+  if (date_s_test_civil(klass) == Qfalse)
+    return Qfalse;
+  if (date_s_test_ordinal(klass) == Qfalse)
+    return Qfalse;
+  if (date_s_test_commercial(klass) == Qfalse)
+    return Qfalse;
+  if (date_s_test_weeknum(klass) == Qfalse)
+    return Qfalse;
+  if (date_s_test_nth_kday(klass) == Qfalse)
+    return Qfalse;
+  return Qtrue;
+}
+#endif
+
+void
+Init_date_core(void)
+{
+  assert(fprintf(stderr, "assert() is now active\n"));
+
+  rzero = rb_rational_new1(INT2FIX(0));
+  rhalf = rb_rational_new2(INT2FIX(1), INT2FIX(2));
+
+  rb_gc_register_mark_object(rzero);
+  rb_gc_register_mark_object(rhalf);
+
+  {
+    double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY")));
+    int ry, rm, rd, ry2, rw, rd2, ns;
+    long rjd;
+
+    jd_to_civil(FIXNUM_MIN + 2, greg, &ry, &rm, &rd);
+    jd_to_commercial(FIXNUM_MIN + 2, greg, &ry2, &rw, &rd2);
+    if (ry > ry2)
+      min_year = ry + 1;
+    else
+      min_year = ry2 + 1;
+    civil_to_jd(min_year, 1, 1, greg, &rjd, &ns);
+    min_jd = rjd;
+
+    jd_to_civil(FIXNUM_MAX - 2, greg, &ry, &rm, &rd);
+    jd_to_commercial(FIXNUM_MAX + 2, greg, &ry2, &rw, &rd2);
+    if (ry < ry2)
+      max_year = ry - 1;
+    else
+      max_year = ry2 - 1;
+    civil_to_jd(max_year, 12, 31, greg, &rjd, &ns);
+    max_jd = rjd;
+  }
+
+  /* date light */
+
+  cDate = rb_define_class("Date", rb_cObject);
+  cDateLight = rb_define_class_under(cDate, "Light", cDate);
+
+  rb_define_alloc_func(cDateLight, d_lite_s_alloc);
+  rb_define_singleton_method(cDate, "new_l!", date_s_new_l_bang, -1);
+
+  rb_define_singleton_method(cDate, "valid_jd?", date_s_valid_jd_p, -1);
+  rb_define_singleton_method(cDate, "valid_ordinal?",
+			     date_s_valid_ordinal_p, -1);
+  rb_define_singleton_method(cDate, "valid_civil?", date_s_valid_civil_p, -1);
+  rb_define_singleton_method(cDate, "valid_date?", date_s_valid_civil_p, -1);
+  rb_define_singleton_method(cDate, "valid_commercial?",
+			     date_s_valid_commercial_p, -1);
+  rb_define_singleton_method(cDate, "jd", date_s_jd, -1);
+  rb_define_singleton_method(cDate, "ordinal", date_s_ordinal, -1);
+  rb_define_singleton_method(cDate, "civil", date_s_civil, -1);
+  rb_define_singleton_method(cDate, "new", date_s_civil, -1);
+  rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1);
+  rb_define_singleton_method(cDate, "today", date_s_today, -1);
+
+  rb_define_method(cDateLight, "ajd", d_lite_ajd, 0);
+  rb_define_method(cDateLight, "amjd", d_lite_amjd, 0);
+  rb_define_method(cDateLight, "jd", d_lite_jd, 0);
+  rb_define_method(cDateLight, "mjd", d_lite_mjd, 0);
+  rb_define_method(cDateLight, "ld", d_lite_ld, 0);
+
+  rb_define_method(cDateLight, "year", d_lite_year, 0);
+  rb_define_method(cDateLight, "yday", d_lite_yday, 0);
+  rb_define_method(cDateLight, "mon", d_lite_mon, 0);
+  rb_define_method(cDateLight, "month", d_lite_mon, 0);
+  rb_define_method(cDateLight, "mday", d_lite_mday, 0);
+  rb_define_method(cDateLight, "day", d_lite_mday, 0);
+  rb_define_method(cDateLight, "day_fraction", d_lite_rzero, 0);
+
+  rb_define_private_method(cDateLight, "wnum0", d_lite_wnum0, 0);
+  rb_define_private_method(cDateLight, "wnum1", d_lite_wnum1, 0);
+
+  rb_define_private_method(cDateLight, "hour", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "min", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "minute", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "sec", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "second", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "sec_fraction", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "second_fraction", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "offset", d_lite_zero, 0);
+  rb_define_private_method(cDateLight, "zone", d_lite_zone, 0);
+
+  rb_define_method(cDateLight, "cwyear", d_lite_cwyear, 0);
+  rb_define_method(cDateLight, "cweek", d_lite_cweek, 0);
+  rb_define_method(cDateLight, "cwday", d_lite_cwday, 0);
+
+  rb_define_method(cDateLight, "wday", d_lite_wday, 0);
+
+  rb_define_method(cDateLight, "julian?", d_lite_false, 0);
+  rb_define_method(cDateLight, "gregorian?", d_lite_true, 0);
+  rb_define_method(cDateLight, "leap?", d_lite_leap_p, 0);
+
+  rb_define_method(cDateLight, "start", d_lite_start, 0);
+  rb_define_method(cDateLight, "new_start", d_lite_new_start, -1);
+  rb_define_private_method(cDateLight, "new_offset", d_lite_new_offset, -1);
+
+  rb_define_method(cDateLight, "+", d_lite_plus, 1);
+  rb_define_method(cDateLight, "-", d_lite_minus, 1);
+
+  rb_define_method(cDateLight, "<=>", d_lite_cmp, 1);
+  rb_define_method(cDateLight, "===", d_lite_eqeqeq, 1);
+  rb_define_method(cDateLight, "eql?", d_lite_eql_p, 1);
+  rb_define_method(cDateLight, "hash", d_lite_hash, 0);
+
+  rb_define_method(cDateLight, "to_s", d_lite_to_s, 0);
+  rb_define_method(cDateLight, "inspect", d_lite_inspect, 0);
+
+  rb_define_method(cDateLight, "marshal_dump", d_lite_marshal_dump, 0);
+  rb_define_method(cDateLight, "marshal_load", d_lite_marshal_load, 1);
+
+  /* datetime light */
+
+  cDateTime = rb_define_class("DateTime", cDate);
+  cDateTimeLight = rb_define_class_under(cDateTime, "Light", cDateTime);
+
+  rb_define_alloc_func(cDateTimeLight, dt_lite_s_alloc);
+  rb_define_singleton_method(cDateTime, "new_l!", datetime_s_new_l_bang, -1);
+
+  rb_undef_method(CLASS_OF(cDateTime), "today");
+
+  rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1);
+  rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1);
+  rb_define_singleton_method(cDateTime, "civil", datetime_s_civil, -1);
+  rb_define_singleton_method(cDateTime, "new", datetime_s_civil, -1);
+  rb_define_singleton_method(cDateTime, "commercial",
+			     datetime_s_commercial, -1);
+  rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1);
+
+  rb_define_method(cDateTimeLight, "ajd", dt_lite_ajd, 0);
+  rb_define_method(cDateTimeLight, "amjd", dt_lite_amjd, 0);
+  rb_define_method(cDateTimeLight, "jd", dt_lite_jd, 0);
+  rb_define_method(cDateTimeLight, "mjd", dt_lite_mjd, 0);
+  rb_define_method(cDateTimeLight, "ld", dt_lite_ld, 0);
+
+  rb_define_method(cDateTimeLight, "year", dt_lite_year, 0);
+  rb_define_method(cDateTimeLight, "yday", dt_lite_yday, 0);
+  rb_define_method(cDateTimeLight, "mon", dt_lite_mon, 0);
+  rb_define_method(cDateTimeLight, "month", dt_lite_mon, 0);
+  rb_define_method(cDateTimeLight, "mday", dt_lite_mday, 0);
+  rb_define_method(cDateTimeLight, "day", dt_lite_mday, 0);
+  rb_define_method(cDateTimeLight, "day_fraction", dt_lite_day_fraction, 0);
+
+  rb_define_private_method(cDateTimeLight, "wnum0", dt_lite_wnum0, 0);
+  rb_define_private_method(cDateTimeLight, "wnum1", dt_lite_wnum1, 0);
+
+  rb_define_method(cDateTimeLight, "hour", dt_lite_hour, 0);
+  rb_define_method(cDateTimeLight, "min", dt_lite_min, 0);
+  rb_define_method(cDateTimeLight, "minute", dt_lite_min, 0);
+  rb_define_method(cDateTimeLight, "sec", dt_lite_sec, 0);
+  rb_define_method(cDateTimeLight, "second", dt_lite_sec, 0);
+  rb_define_method(cDateTimeLight, "sec_fraction", dt_lite_sec_fraction, 0);
+  rb_define_method(cDateTimeLight, "second_fraction", dt_lite_sec_fraction, 0);
+  rb_define_method(cDateTimeLight, "offset", dt_lite_offset, 0);
+  rb_define_method(cDateTimeLight, "zone", dt_lite_zone, 0);
+
+  rb_define_method(cDateTimeLight, "cwyear", dt_lite_cwyear, 0);
+  rb_define_method(cDateTimeLight, "cweek", dt_lite_cweek, 0);
+  rb_define_method(cDateTimeLight, "cwday", dt_lite_cwday, 0);
+
+  rb_define_method(cDateTimeLight, "wday", dt_lite_wday, 0);
+
+  rb_define_method(cDateTimeLight, "julian?", d_lite_false, 0);
+  rb_define_method(cDateTimeLight, "gregorian?", d_lite_true, 0);
+  rb_define_method(cDateTimeLight, "leap?", dt_lite_leap_p, 0);
+
+  rb_define_method(cDateTimeLight, "start", dt_lite_start, 0);
+  rb_define_method(cDateTimeLight, "new_start", dt_lite_new_start, -1);
+  rb_define_method(cDateTimeLight, "new_offset", dt_lite_new_offset, -1);
+
+  rb_define_method(cDateTimeLight, "+", dt_lite_plus, 1);
+  rb_define_method(cDateTimeLight, "-", dt_lite_minus, 1);
+
+  rb_define_method(cDateTimeLight, "<=>", dt_lite_cmp, 1);
+  rb_define_method(cDateTimeLight, "===", dt_lite_eqeqeq, 1);
+  rb_define_method(cDateTimeLight, "eql?", dt_lite_eql_p, 1);
+  rb_define_method(cDateTimeLight, "hash", dt_lite_hash, 0);
+
+  rb_define_method(cDateTimeLight, "to_s", dt_lite_to_s, 0);
+  rb_define_method(cDateTimeLight, "inspect", dt_lite_inspect, 0);
+
+  rb_define_method(cDateTimeLight, "marshal_dump", dt_lite_marshal_dump, 0);
+  rb_define_method(cDateTimeLight, "marshal_load", dt_lite_marshal_load, 1);
+
+#ifndef NDEBUG
+  rb_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0);
+  rb_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0);
+  rb_define_singleton_method(cDate, "test_commercial", date_s_test_commercial, 0);
+  rb_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0);
+  rb_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0);
+  rb_define_singleton_method(cDate, "test_all", date_s_test_all, 0);
+#endif
+}

Property changes on: ext/date/date_core.c
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: ext/date/extconf.rb
===================================================================
--- ext/date/extconf.rb	(revision 0)
+++ ext/date/extconf.rb	(revision 0)
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile('date_core')

Property changes on: ext/date/extconf.rb
___________________________________________________________________
Added: svn:mime-type
   + text/plain

In This Thread

Prev Next