Index: /ruby/trunk/lib/models/assumed_library_types.rb
===================================================================
--- /ruby/trunk/lib/models/assumed_library_types.rb	(revision 148)
+++ /ruby/trunk/lib/models/assumed_library_types.rb	(revision 149)
@@ -165,4 +165,13 @@
         month_unknown? or day_unknown?
       end
+
+      protected
+      def leapyear?(year)
+        case
+        when year % 400 == 0: true
+        when year % 100 == 0: false
+        else year % 4 == 0
+        end
+      end
     end
 
@@ -187,4 +196,5 @@
         end
       end
+
       def self.valid_iso8601_date?(string)
         begin
@@ -353,50 +363,6 @@
     end # end of ISO8601_TIME
 
-    class ISO8601_DATE_TIME < ISO8601_DATE
-      include ISO8601_TIME_MODULE, ISO8601_DATE_MODULE
-      def initialize(string)
-        /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
-        if $1.empty?
-          raise ArgumentError, 'format invalid'
-        else
-          self.year = $1.to_i
-        end
-        if $2.nil?
-          self.month = nil
-        else
-          self.month = $2.to_i
-        end
-        if $3.nil?
-          self.day = nil
-        else
-          self.day = $3.to_i
-        end
-        if $5.nil?
-          self.minute = nil
-        else
-          self.minute = $5.to_i
-        end
-        if $6.nil?
-          self.second = nil
-        else
-          self.second = $6.to_i
-        end
-        if $4.nil?
-          self.hour = nil
-        else
-          self.hour = $4.to_i
-        end
-        if $7.nil? or $7.empty?
-          self.fractional_second = nil
-        else
-          self.fractional_second = ("0."+$7).to_f
-        end
-        if $8.nil?
-          self.timezone = nil
-        else
-          self.timezone = $9+$10
-        end
-      end
-
+    module ISO8601_DATE_TIME_MODULE
+      include ISO8601_DATE_MODULE, ISO8601_TIME_MODULE
       def as_string
         if (!@year.nil? and !@month.nil? and !@day.nil?)
@@ -424,7 +390,53 @@
         return s
       end
-
     end
 
+    class ISO8601_DATE_TIME < ISO8601_DATE
+      include ISO8601_DATE_TIME_MODULE
+      def initialize(string)
+        /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
+        if $1.empty?
+          raise ArgumentError, 'format invalid'
+        else
+          self.year = $1.to_i
+        end
+        if $2.nil?
+          self.month = nil
+        else
+          self.month = $2.to_i
+        end
+        if $3.nil?
+          self.day = nil
+        else
+          self.day = $3.to_i
+        end
+        if $5.nil?
+          self.minute = nil
+        else
+          self.minute = $5.to_i
+        end
+        if $6.nil?
+          self.second = nil
+        else
+          self.second = $6.to_i
+        end
+        if $4.nil?
+          self.hour = nil
+        else
+          self.hour = $4.to_i
+        end
+        if $7.nil? or $7.empty?
+          self.fractional_second = nil
+        else
+          self.fractional_second = ("0."+$7).to_f
+        end
+        if $8.nil?
+          self.timezone = nil
+        else
+          self.timezone = $9+$10
+        end
+      end
+    end
+  
     class ISO8601_TIMEZONE
       attr_accessor :sign, :hour, :minute
@@ -444,19 +456,7 @@
     end # end of ISO8601_TIMEZONE
 
-    class ISO8601_DURATION < TIME_DEFINITIONS
+    module ISO8601_DURATION_MODULE
       attr_reader :years, :months, :weeks, :days
       attr_reader :hours, :minutes, :seconds, :fractional_second
-
-      def initialize(str)
-        /^P((\d+)Y)?((\d+)M)?((\d+)W)?((\d)D)?(T((\d+)H)?((\d+)M)?((\d+)(\.\d+)?S)?)?$/ =~ str
-        self.years = $2.to_i
-        self.months = $4.to_i
-        self.weeks = $6.to_i
-        self.days = $8.to_i
-        self.hours = $11.to_i
-        self.minutes = $13.to_i
-        self.seconds = $15.to_i
-        self.fractional_second = $16.to_f
-      end
 
       def years=(years)
@@ -545,4 +545,18 @@
         return str
       end
+    end
+    class ISO8601_DURATION < TIME_DEFINITIONS
+      include ISO8601_DURATION_MODULE
+      def initialize(str)
+        /^P((\d+)Y)?((\d+)M)?((\d+)W)?((\d)D)?(T((\d+)H)?((\d+)M)?((\d+)(\.\d+)?S)?)?$/ =~ str
+        self.years = $2.to_i
+        self.months = $4.to_i
+        self.weeks = $6.to_i
+        self.days = $8.to_i
+        self.hours = $11.to_i
+        self.minutes = $13.to_i
+        self.seconds = $15.to_i
+        self.fractional_second = $16.to_f
+      end
     end # end of ISO8601_DURATION
   end # end of Assumed_Types
Index: /ruby/trunk/lib/models/rm/data_types/quantity.rb
===================================================================
--- /ruby/trunk/lib/models/rm/data_types/quantity.rb	(revision 148)
+++ /ruby/trunk/lib/models/rm/data_types/quantity.rb	(revision 149)
@@ -150,5 +150,5 @@
                          normal_range=nil, normal_status = nil,
                          other_reference_ranges=nil)
-            super (magnitude, magnitude_status, normal_range,
+            super(magnitude, magnitude_status, normal_range,
                    normal_status, other_reference_ranges)
             self.accuracy = accuracy
@@ -156,13 +156,13 @@
 
           def add(a_diff)
-            raise NotImplementError, 'add must be implemented'
+            raise NotImplementedError, 'add must be implemented'
           end
 
           def diff(other)
-            raise NotImplementError, 'diff must be implemented'
+            raise NotImplementedError, 'diff must be implemented'
           end
 
           def subtract(a_diff)
-            raise NotImplementError, 'subtract must be implemented'
+            raise NotImplementedError, 'subtract must be implemented'
           end
         end
Index: /ruby/trunk/lib/models/rm/data_types/quantity/date_time.rb
===================================================================
--- /ruby/trunk/lib/models/rm/data_types/quantity/date_time.rb	(revision 148)
+++ /ruby/trunk/lib/models/rm/data_types/quantity/date_time.rb	(revision 149)
@@ -2,4 +2,6 @@
 # http://www.openehr.org/uml/release-1.0.1/Browsable/_9_0_76d0249_1109696321450_28117_5362Report.html
 # Ticket refs #49
+require 'assumed_library_types'
+
 module OpenEHR
   module RM
@@ -10,17 +12,20 @@
             attr_reader :value
 
-            def initialize(value)
+            def initialize(value, magnitude_status=nil, accuracy=nil,
+                         normal_range=nil, normal_status=nil,
+                         other_reference_ranges=nil)
               self.value = value
+              self.magnitude_status = magnitude_status
+              self.accuracy = accuracy
+              self.normal_range = normal_range
+              self.normal_status = normal_status
+              self.other_reference_ranges = other_reference_ranges
             end
 
             def value=(value)
-              if value.empty? or value.nil?
+              if value.nil? or value.empty?
                 raise ArgumentError, 'invalid value'
               end
               @value = value
-            end
-
-            def diff(value)
-              raise NotImplementedError, 'diff must be implemented'
             end
           end
@@ -28,8 +33,60 @@
           class DV_Date < DV_Temporal
             include OpenEHR::Assumed_Library_Types::ISO8601_DATE_MODULE
-            def initialize
-              
+
+            DAYS_IN_MONTH = [0,31,28,31,30,31,30,31,31,30,31,30,31]
+
+            def initialize(value, magnitude_status=nil, accuracy=nil,
+                           normal_range=nil, normal_status=nil,
+                           other_reference_range=nil)
+              super(value, magnitude_status, accuracy, normal_range,
+                    normal_status, other_reference_range)
             end
 
+            def value=(value)
+              super(value)
+              iso8601_date = Assumed_Library_Types::ISO8601_DATE.new(value)
+              @year = iso8601_date.year
+              @month = iso8601_date.month
+              @day = iso8601_date.day
+            end
+
+            undef magnitude=
+
+            def magnitude
+              return Date.new(@year, @month, @day)-Date.new(1601,1,1)
+            end
+
+            def diff(other)
+              if self.magnitude > other.magnitude
+                past, future = other, self
+              else
+                past, future = self, other
+              end
+              year, month, day = 0, 0, 0
+              if (future.day >= past.day)
+                day = future.day - past.day
+              else
+                month -= 1
+                previous_month = future.month - 1
+                if previous_month <= 0
+                  previous_month = 12
+                end
+                day = DAYS_IN_MONTH[previous_month] + future.day - past.day
+                if leapyear?(future.year) && (previous_month == 2)
+                  day += 1
+                end
+              end
+              week = day / 7
+              if (future.month >= past.month)
+                month += future.month - past.month
+              else
+                year -= 1
+                month += future.month + 12 - past.month
+              end
+              year += future.year - past.year
+              return DV_Duration.new(
+                   'P' + year.to_s + 'Y' + month.to_s + 'M' + 
+                         week.to_s + 'W' + day.to_s + 'D')
+            end
           end
           
@@ -43,4 +100,38 @@
             end
           end
+
+          class DV_Duration < DV_Amount
+            include Assumed_Library_Types::ISO8601_DURATION_MODULE
+            attr_reader :value
+            
+            def initialize(value, magnitude_status=nil, accuracy=nil,
+                         accuracy_percent=nil, normal_range=nil,
+                         normal_status = nil, other_reference_ranges=nil)
+              self.value = value
+            end
+
+            def value=(value)
+              raise ArgumentError, 'value must be not nil' if value.nil?
+              @value = value
+              iso8601_duration = Assumed_Library_Types::ISO8601_DURATION.new(value)
+              self.years = iso8601_duration.years
+              self.months = iso8601_duration.months
+              self.weeks = iso8601_duration.weeks
+              self.days = iso8601_duration.days
+              self.hours = iso8601_duration.hours
+              self.minutes = iso8601_duration.minutes
+              self.seconds = iso8601_duration.seconds
+              self.fractional_second = iso8601_duration.fractional_second
+            end
+
+            def magnitude
+              return ((((@year + @month/MONTH_IN_YEAR)*NOMINAL_DAYS_IN_MONTH) +
+                @week * DAYS_IN_WEEK + @days) * HOURS_IN_DAY * MINUTES_IN_HOUR*
+                SECONDS_IN_MINUTE) + @second + @fractional_second
+            end
+            
+            undef magnitude=
+
+          end
         end # of Date_Time
       end # of Quantity
Index: /ruby/trunk/lib/models/tests/rm/test_data_types.rb
===================================================================
--- /ruby/trunk/lib/models/tests/rm/test_data_types.rb	(revision 148)
+++ /ruby/trunk/lib/models/tests/rm/test_data_types.rb	(revision 149)
@@ -2,4 +2,5 @@
 require 'set'
 require 'rm'
+require 'tests/rm/quantity/ts_date_time'
 
 class RM_Data_Types_Basic_Test < Test::Unit::TestCase
@@ -360,19 +361,4 @@
 end
 
-class QuantityDateTimeTest < Test::Unit::TestCase
-  def setup
-    assert_nothing_raised(Exception){
-      @dv_temporal = OpenEHR::RM::Data_Types::Quantity::Date_Time::DV_Temporal.new('2008')}
-  end
-  def test_init
-    assert_instance_of OpenEHR::RM::Data_Types::Quantity::Date_Time::DV_Temporal, @dv_temporal
-  end
-
-  def test_dv_temporal
-    assert_equal '2008', @dv_temporal.value
-    assert_raise(NotImplementedError){@dv_temporal.diff('2009')}
-  end
-end
-
 class EncapsulatedTest < Test::Unit::TestCase
   def setup
Index: /ruby/trunk/lib/models/tests/test_assumed_library_types.rb
===================================================================
--- /ruby/trunk/lib/models/tests/test_assumed_library_types.rb	(revision 148)
+++ /ruby/trunk/lib/models/tests/test_assumed_library_types.rb	(revision 149)
@@ -1,4 +1,6 @@
 require 'test/unit'
 require 'assumed_library_types.rb'
+
+include OpenEHR::Assumed_Library_Types
 
 class Assumed_Library_Test < Test::Unit::TestCase
