Clamp dates when going from long months to short months
diff --git a/lib/clock.dart b/lib/clock.dart
index 933dee8..e2b4ea6 100644
--- a/lib/clock.dart
+++ b/lib/clock.dart
@@ -23,6 +23,18 @@
 /// A predefined instance of [Clock] that's based on system clock.
 const SYSTEM_CLOCK = const Clock();
 
+/// Days in a month. This array uses 1-based month numbers, i.e. January is
+/// the 1-st element in the array, not the 0-th.
+const _DAYS_IN_MONTH =
+    const [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+
+int _daysInMonth(int year, int month) =>
+    (month == DateTime.FEBRUARY && _isLeapYear(year))
+    ? 29 : _DAYS_IN_MONTH[month];
+
+bool _isLeapYear(int year) =>
+    (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
+
 /// Provides points in time relative to the current point in time, for example:
 /// now, 2 days ago, 4 weeks from now, etc.
 ///
@@ -133,10 +145,13 @@
   /// Return the point in time [months] ago on the same date.
   DateTime monthsAgo(int months) {
     var time = now();
+    var m = (time.month - months - 1) % 12 + 1;
+    var y = time.year - (months + 12 - time.month) ~/ 12;
+    var d = time.day.clamp(1, _daysInMonth(y, m));
     return new DateTime(
-        time.year,
-        time.month - months,
-        time.day,
+        y,
+        m,
+        d,
         time.hour,
         time.minute,
         time.second,
@@ -145,7 +160,21 @@
   }
 
   /// Return the point in time [months] from now on the same date.
-  DateTime monthsFromNow(int months) => monthsAgo(-months);
+  DateTime monthsFromNow(int months) {
+    var time = now();
+    var m = (time.month + months - 1) % 12 + 1;
+    var y = time.year + (months + time.month - 1) ~/ 12;
+    var d = time.day.clamp(1, _daysInMonth(y, m));
+    return new DateTime(
+        y,
+        m,
+        d,
+        time.hour,
+        time.minute,
+        time.second,
+        time.millisecond
+    );
+  }
 
   /// Return the point in time [years] ago on the same date.
   DateTime yearsAgo(int years) {
diff --git a/test/clock_test.dart b/test/clock_test.dart
index a9e3bc6..bacb8e3 100644
--- a/test/clock_test.dart
+++ b/test/clock_test.dart
@@ -17,9 +17,19 @@
 import 'package:unittest/unittest.dart';
 import 'package:quiver/time.dart';
 
+Clock from(int y, int m, int d) => new Clock.fixed(new DateTime(y, m, d));
+
+expectDate(DateTime date, int y, int m, int d) {
+  expect(date, new DateTime(y, m, d));
+}
+
 main() {
   group('clock', () {
-    var subject = new Clock.fixed(new DateTime(2013));
+    Clock subject;
+
+    setUp(() {
+      subject = new Clock.fixed(new DateTime(2013));
+    });
 
     test("should return a non-null value from system clock", () {
       expect(new Clock().now(), isNotNull);
@@ -162,6 +172,30 @@
           new DateTime(2013, 5, 1, 0, 0, 0, 0));
     });
 
+    test("should go from 2013-05-31 to 2012-11-30", () {
+      expectDate(from(2013, 5, 31).monthsAgo(6), 2012, 11, 30);
+    });
+
+    test("should go from 2013-03-31 to 2013-02-28 (common year)", () {
+      expectDate(from(2013, 3, 31).monthsAgo(1), 2013, 2, 28);
+    });
+
+    test("should go from 2013-05-31 to 2013-02-28 (common year)", () {
+      expectDate(from(2013, 5, 31).monthsAgo(3), 2013, 2, 28);
+    });
+
+    test("should go from 2004-03-31 to 2004-02-29 (leap year)", () {
+      expectDate(from(2004, 3, 31).monthsAgo(1), 2004, 2, 29);
+    });
+
+    test("should go from 2013-03-31 to 2013-06-30", () {
+      expectDate(from(2013, 3, 31).monthsFromNow(3), 2013, 6, 30);
+    });
+
+    test("should go from 2003-12-31 to 2004-02-29 (common to leap)", () {
+      expectDate(from(2003, 12, 31).monthsFromNow(2), 2004, 2, 29);
+    });
+
     test("should return time years ago on the same date", () {
       expect(subject.yearsAgo(1),
           new DateTime(2012, 1, 1, 0, 0, 0, 000));  // leap year