diff --git a/lib/date.rb b/lib/date.rb
index 0cb7630..05449fd 100644
--- a/lib/date.rb
+++ b/lib/date.rb
@@ -6,6 +6,61 @@ require 'date_core'
 class Date
   VERSION = "3.5.1" # :nodoc:
 
+  RUBY_BIRTHDAYS = { # :nodoc:
+    nil  => [1993, 2, 24].freeze,  # The name "Ruby" was decided
+    0.95 => [1995, 12, 21].freeze, # First public release
+    1.0  => [1996, 12, 25].freeze, # First stable release
+  }.freeze
+
+  # call-seq:
+  #   Date.birthday         -> date
+  #   Date.birthday(nil)    -> date
+  #   Date.birthday(0.95)   -> date
+  #   Date.birthday(1.0)    -> date
+  #
+  # Returns the birthday of the Ruby programming language.
+  #
+  # With no argument (or +nil+), returns the day the name "Ruby" was decided
+  # (1993-02-24). With +0.95+, returns the first public release date
+  # (1995-12-21). With +1.0+, returns the first stable release date
+  # (1996-12-25).
+  #
+  #   Date.birthday.to_s       # => "1993-02-24"
+  #   Date.birthday(0.95).to_s # => "1995-12-21"
+  #   Date.birthday(1.0).to_s  # => "1996-12-25"
+  #
+  # Raises ArgumentError for any other argument.
+  def self.birthday(version = nil)
+    ymd = RUBY_BIRTHDAYS[version]
+    raise ArgumentError, "unsupported version: #{version.inspect}" unless ymd
+    new(*ymd)
+  end
+
+  # call-seq:
+  #   Date.age         -> integer
+  #   Date.age(nil)    -> integer
+  #   Date.age(0.95)   -> integer
+  #   Date.age(1.0)    -> integer
+  #
+  # Returns the age of the Ruby programming language in years.
+  #
+  # Calculates the number of full years elapsed since the birthday
+  # returned by Date.birthday with the same argument.
+  #
+  #   Date.age       # => 33  (as of 2026-03-24)
+  #   Date.age(0.95) # => 30
+  #   Date.age(1.0)  # => 29
+  #
+  # Raises ArgumentError for any unsupported or invalid argument.
+  def self.age(version = nil)
+    bd = birthday(version)
+    today = self.today
+    age = today.year - bd.year
+    age -= 1 if today.month < bd.month ||
+                (today.month == bd.month && today.day < bd.day)
+    age
+  end
+
   # call-seq:
   #   infinite? -> false
   #
diff --git a/test/date/test_date_birthday.rb b/test/date/test_date_birthday.rb
new file mode 100644
index 0000000..0cd24ab
--- /dev/null
+++ b/test/date/test_date_birthday.rb
@@ -0,0 +1,202 @@
+# frozen_string_literal: true
+
+require "test/unit"
+require "date"
+
+class TestDateBirthday < Test::Unit::TestCase
+  # --- Normal cases ---
+
+  def test_birthday_no_argument
+    d = Date.birthday
+    assert_equal(Date.new(1993, 2, 24), d)
+    assert_equal("1993-02-24", d.to_s)
+  end
+
+  def test_birthday_nil
+    d = Date.birthday(nil)
+    assert_equal(Date.new(1993, 2, 24), d)
+  end
+
+  def test_birthday_0_95
+    d = Date.birthday(0.95)
+    assert_equal(Date.new(1995, 12, 21), d)
+    assert_equal("1995-12-21", d.to_s)
+  end
+
+  def test_birthday_1_0
+    d = Date.birthday(1.0)
+    assert_equal(Date.new(1996, 12, 25), d)
+    assert_equal("1996-12-25", d.to_s)
+  end
+
+  # --- Return type ---
+
+  def test_birthday_returns_date_instance
+    assert_instance_of(Date, Date.birthday)
+    assert_instance_of(Date, Date.birthday(0.95))
+    assert_instance_of(Date, Date.birthday(1.0))
+  end
+
+  # --- ArgumentError for unsupported versions ---
+
+  def test_birthday_unsupported_version
+    assert_raise(ArgumentError) { Date.birthday(0.0) }
+    assert_raise(ArgumentError) { Date.birthday(1.8) }
+    assert_raise(ArgumentError) { Date.birthday(1.9) }
+    assert_raise(ArgumentError) { Date.birthday(2.0) }
+    assert_raise(ArgumentError) { Date.birthday(3.0) }
+    assert_raise(ArgumentError) { Date.birthday(99.0) }
+  end
+
+  # --- Boundary: values close to valid versions ---
+
+  def test_birthday_boundary_close_to_0_95
+    assert_raise(ArgumentError) { Date.birthday(0.94) }
+    assert_raise(ArgumentError) { Date.birthday(0.96) }
+  end
+
+  def test_birthday_boundary_close_to_1_0
+    assert_raise(ArgumentError) { Date.birthday(0.99) }
+    assert_raise(ArgumentError) { Date.birthday(1.01) }
+  end
+
+  # --- ArgumentError for invalid types ---
+
+  def test_birthday_invalid_type_string
+    assert_raise(ArgumentError) { Date.birthday("1.0") }
+    assert_raise(ArgumentError) { Date.birthday("0.95") }
+    assert_raise(ArgumentError) { Date.birthday("ruby") }
+  end
+
+  def test_birthday_invalid_type_symbol
+    assert_raise(ArgumentError) { Date.birthday(:ruby) }
+  end
+
+  def test_birthday_invalid_type_array
+    assert_raise(ArgumentError) { Date.birthday([1.0]) }
+  end
+
+  def test_birthday_invalid_type_hash
+    assert_raise(ArgumentError) { Date.birthday({}) }
+  end
+
+  def test_birthday_invalid_type_boolean
+    assert_raise(ArgumentError) { Date.birthday(true) }
+    assert_raise(ArgumentError) { Date.birthday(false) }
+  end
+
+  # --- Edge: negative and special floats ---
+
+  def test_birthday_negative_version
+    assert_raise(ArgumentError) { Date.birthday(-1.0) }
+  end
+
+  def test_birthday_infinity
+    assert_raise(ArgumentError) { Date.birthday(Float::INFINITY) }
+    assert_raise(ArgumentError) { Date.birthday(-Float::INFINITY) }
+  end
+
+  def test_birthday_nan
+    assert_raise(ArgumentError) { Date.birthday(Float::NAN) }
+  end
+
+  # ==========================================================================
+  # Date.age
+  # ==========================================================================
+
+  # --- Normal cases ---
+
+  def test_age_no_argument
+    today = Date.today
+    expected = calc_expected_age(Date.new(1993, 2, 24), today)
+    assert_equal(expected, Date.age)
+  end
+
+  def test_age_nil
+    today = Date.today
+    expected = calc_expected_age(Date.new(1993, 2, 24), today)
+    assert_equal(expected, Date.age(nil))
+  end
+
+  def test_age_0_95
+    today = Date.today
+    expected = calc_expected_age(Date.new(1995, 12, 21), today)
+    assert_equal(expected, Date.age(0.95))
+  end
+
+  def test_age_1_0
+    today = Date.today
+    expected = calc_expected_age(Date.new(1996, 12, 25), today)
+    assert_equal(expected, Date.age(1.0))
+  end
+
+  # --- Return type ---
+
+  def test_age_returns_integer
+    assert_instance_of(Integer, Date.age)
+    assert_instance_of(Integer, Date.age(0.95))
+    assert_instance_of(Integer, Date.age(1.0))
+  end
+
+  # --- Age is non-negative ---
+
+  def test_age_is_non_negative
+    assert_operator(Date.age, :>=, 0)
+    assert_operator(Date.age(0.95), :>=, 0)
+    assert_operator(Date.age(1.0), :>=, 0)
+  end
+
+  # --- Consistency: age without version >= age with version ---
+
+  def test_age_ordering
+    assert_operator(Date.age, :>=, Date.age(0.95))
+    assert_operator(Date.age(0.95), :>=, Date.age(1.0))
+  end
+
+  # --- Birthday boundary: exact birthday date ---
+
+  def test_age_on_exact_birthday
+    bd = Date.new(1993, 2, 24)
+    this_year_bd = Date.new(Date.today.year, bd.month, bd.day)
+    expected = this_year_bd.year - bd.year
+    assert_equal(expected, calc_expected_age(bd, this_year_bd))
+  end
+
+  def test_age_day_before_birthday
+    bd = Date.new(1993, 2, 24)
+    day_before = Date.new(Date.today.year, bd.month, bd.day) - 1
+    expected = day_before.year - bd.year - 1
+    assert_equal(expected, calc_expected_age(bd, day_before))
+  end
+
+  # --- ArgumentError (delegates to birthday) ---
+
+  def test_age_unsupported_version
+    assert_raise(ArgumentError) { Date.age(0.0) }
+    assert_raise(ArgumentError) { Date.age(1.8) }
+    assert_raise(ArgumentError) { Date.age(2.0) }
+    assert_raise(ArgumentError) { Date.age(99.0) }
+  end
+
+  def test_age_invalid_type
+    assert_raise(ArgumentError) { Date.age("1.0") }
+    assert_raise(ArgumentError) { Date.age(:ruby) }
+    assert_raise(ArgumentError) { Date.age([1.0]) }
+    assert_raise(ArgumentError) { Date.age(true) }
+  end
+
+  def test_age_special_floats
+    assert_raise(ArgumentError) { Date.age(Float::INFINITY) }
+    assert_raise(ArgumentError) { Date.age(-Float::INFINITY) }
+    assert_raise(ArgumentError) { Date.age(Float::NAN) }
+  end
+
+  private
+
+  def calc_expected_age(birthday, today)
+    age = today.year - birthday.year
+    age -= 1 if today.month < birthday.month ||
+                (today.month == birthday.month && today.day < birthday.day)
+    age
+  end
+end
