source: ruby/trunk/lib/open_ehr/assumed_library_types.rb@ 397

Last change on this file since 397 was 397, checked in by KOBAYASHI, Shinji, 14 years ago

refs #71

File size: 15.6 KB
RevLine 
[83]1# This module is related to the ticket #36
[70]2require 'date'
[81]3require 'time'
[70]4
[297]5module OpenEHR
[167]6 module AssumedLibraryTypes
[69]7 class Any < Object
8
9 end # of Any
[143]10
[69]11 class Interval < Any
[143]12 attr_reader :lower, :upper
13
[297]14 def initialize(args = {})
15 check_lower_upper(args[:lower], args[:upper])
16 self.lower_included = args[:lower_included]
17 self.upper_included = args[:upper_included]
[4]18 end
[21]19
[143]20 def lower=(lower)
[4]21 check_lower_upper(lower, @upper)
22 end
[21]23
[143]24 def upper=(upper)
[4]25 check_lower_upper(@lower, upper)
26 end
[21]27
[143]28 def lower_included?
29 return @lower_included
30 end
31
32 def lower_included=(lower_included)
[4]33 if (lower == nil) && (lower_included != nil)
34 raise ArgumentError, "lower is not set"
35 end
36 @lower_included = lower_included
37 end
[143]38
39 def lower_unbounded?
40 return @lower.nil?
41 end
[21]42
[143]43 def upper_included?
44 return @upper_included
45 end
46
47 def upper_included=(upper_included)
[297]48 if (@upper.nil?) && (upper_included != nil)
[4]49 raise ArgumentError, "upper is not set"
50 end
[143]51 @upper_included = upper_included
[4]52 end
[21]53
[143]54 def upper_unbounded?
55 return @upper.nil?
56 end
57
[4]58 def has?(value)
[297]59 if ((@lower.nil?||@lower < value||((@lower_included == true) && (@lower == value)))&&
60 (@upper.nil?||value < @upper||((@upper_included == true) && (@upper == value))))
[4]61 true
62 else
63 false
64 end
65 end
[21]66
[4]67 private
[21]68
[4]69 def check_lower_upper(lower, upper)
[297]70 if lower.nil? && upper.nil?
[4]71 raise ArgumentError, "Either lower or upper must be assigned"
72 end
[143]73 unless (lower.nil? || upper.nil?)
74 if lower > upper
75 raise ArgumentError, "Upper must be larger than lower."
76 end
[4]77 end
78 @lower = lower
79 @upper = upper
[143]80 end
[69]81 end # end of Interval
[143]82
[297]83 class TimeDefinitions < Any
[69]84 DAYS_IN_LEAP_YEAR = 366
85 DAYS_IN_WEEK = 7
86 DAYS_IN_YEAR = 365
87 HOURS_IN_DAY = 24
88 MAX_DAYS_IN_MONTH = 31
89 MAX_DAYS_IN_YEAR = 366
90 MINUTES_IN_HOUR = 60
91 MONTH_IN_YEAR = 12
92 NOMINAL_DAYS_IN_MONTH = 30.42
93 NOMINAL_DAYS_IN_YEAR = 365.24
94 SECONDS_IN_MINUTE = 60
[70]95
96 def self.valid_year?(year)
[297]97 return !year.nil? && year >= 0
[70]98 end
99
100 def self.valid_day?(y, m, d)
[297]101 unless y.nil? || m.nil? || d.nil?
102 return Date.valid_date?(y,m,d)
103 end
104 if (y.nil?) || (m.nil? && !d.nil?)
105 return false
106 end
107 return self.valid_year?(y) && self.valid_month?(m)
[70]108 end
109
[83]110 def self.valid_hour?(h,m = nil, s = nil)
[297]111 if h.nil?
112 return false
113 end
[83]114 if !m.nil? and !valid_minute?(m)
115 return false
116 end
117 if !s.nil? and (!m.nil? and !valid_second?(s))
118 return false
119 end
120 (h >= 0 and h < HOURS_IN_DAY) or (h == HOURS_IN_DAY and m == 0 and s == 0)
[70]121 end
[297]122
[81]123 def self.valid_minute?(mi)
124 mi >= 0 and mi < MINUTES_IN_HOUR
[70]125 end
[297]126
[70]127 def self.valid_second?(s)
128 s >= 0 and s < SECONDS_IN_MINUTE
129 end
[297]130
[81]131 def self.valid_month?(mo)
132 mo >= 1 and mo <= MONTH_IN_YEAR
[70]133 end
[297]134 end # end of TimeDefinitions
[69]135
[297]136 module ISO8601DateModule
[397]137 include Comparable
[70]138 attr_reader :year, :month, :day
[297]139
[70]140 def year=(year)
[297]141 unless ISO8601Date.valid_year?(year)
142 raise ArgumentError, "Year is not valid"
143 end
[70]144 @year = year
145 end
[297]146
[70]147 def month=(month)
[297]148 raise ArgumentError, "Month is not valid" unless month.nil? or ISO8601Date.valid_month?(month)
[70]149 @month = month
150 end
[125]151
[70]152 def day=(day)
[297]153
154 raise ArgumentError, "Day is not valid" unless day.nil? or ISO8601Date.valid_day?(@year, @month, day)
[70]155 @day = day
156 end
[125]157
[70]158 def as_string
159 if (!@year.nil? and !@month.nil? and !@day.nil?)
160 Date.new(@year, @month, @day).to_s
161 elsif (!@year.nil? and !@month.nil? and @day.nil?)
162 Date.new(@year, @month).to_s[0,7]
163 elsif (!@year.nil? and @month.nil? and @day.nil?)
164 Date.new(@year).to_s[0,4]
165 end
166 end
[125]167
[70]168 def month_unknown?
169 @month.nil?
170 end
[125]171
[70]172 def day_unknown?
173 @day.nil?
174 end
[125]175
[70]176 def is_extended?
177 true
178 end
[125]179
[70]180 def is_partial?
181 month_unknown? or day_unknown?
182 end
[397]183
184 def <=>(other)
185 (@year*TimeDefinitions::NOMINAL_DAYS_IN_YEAR +
186 @month*TimeDefinitions::NOMINAL_DAYS_IN_MONTH + @day) <=>
187 (other.year*TimeDefinitions::NOMINAL_DAYS_IN_YEAR +
188 other.month*TimeDefinitions::NOMINAL_DAYS_IN_MONTH + other.month)
189 end
[149]190 protected
191 def leapyear?(year)
192 case
193 when year % 400 == 0: true
194 when year % 100 == 0: false
195 else year % 4 == 0
196 end
197 end
[120]198 end
199
[297]200 class ISO8601Date < TimeDefinitions
201 include ISO8601DateModule
[120]202 def initialize(string)
203 /(\d{4})(?:-(\d{2})(?:-(\d{2})?)?)?/ =~ string
204 if $1.nil?
205 raise ArgumentError, 'data invalid'
206 else
207 self.year = $1.to_i
208 end
209 if $2.nil?
210 self.month = nil
211 else
212 self.month = $2.to_i
213 end
214 if $3.nil?
215 self.day = nil
216 else
217 self.day = $3.to_i
218 end
219 end
[149]220
[81]221 def self.valid_iso8601_date?(string)
[70]222 begin
[81]223 Date.parse(string)
[70]224 rescue
225 return false
226 end
227 true
228 end
[79]229 end # end of ISO8601_DATE
230
[297]231 module ISO8601TimeModule
[83]232 attr_reader :hour, :minute, :second, :fractional_second, :timezone
[120]233
[83]234 def hour=(hour)
[297]235 unless ISO8601Time.valid_hour?(hour, @minute, @second)
236 raise ArgumentError, "hour is not valid"
237 end
[83]238 @hour = hour
239 end
[124]240
[83]241 def minute_unknown?
242 @minute.nil?
243 end
[124]244
[83]245 def minute=(minute)
[297]246 raise ArgumentError, "minute is not valid" if !minute.nil? and !ISO8601Time.valid_minute?(minute)
[83]247 @minute = minute
248 end
[124]249
[83]250 def second_unknown?
251 @second.nil?
252 end
[124]253
[83]254 def second=(second)
[120]255 raise ArgumentError, "minute not defined" if @minute.nil? and !second.nil?
[297]256 raise ArgumentError, "second is not valid" if !second.nil? and !ISO8601Time.valid_second?(second)
[83]257 @second = second
258 end
[124]259
[83]260 def fractional_second=(fractional_second)
[120]261 raise ArgumentError, "minute not defined" if minute_unknown? and !fractional_second.nil?
262 raise ArgumentError, "second not defined" if second_unknown? and !fractional_second.nil?
[297]263 if !fractional_second.nil? &&
264 (fractional_second < 0.0 || fractional_second >= 1.0)
265 raise ArgumentError, 'fractional second should be between 0.0 - 1.0'
266 end
[83]267 @fractional_second = fractional_second
268 end
[124]269
[83]270 def has_fractional_second?
[297]271 return !@fractional_second.nil?
[83]272 end
[124]273
[120]274 def timezone=(timezone)
275 unless timezone.nil? or timezone == 'Z'
276 if /[+-](\d{2}):?(\d{2})/ =~ timezone
277 @timezone = timezone
278 else
279 raise ArgumentError, "timezone invalid"
280 end
281 else
282 @timezone = nil
283 end
284 end
[124]285
[83]286 def is_decimal_sign_comma?
[126]287 false
[83]288 end
[124]289
[83]290 def is_extended?
291 true
292 end
[124]293
[83]294 def is_partial?
295 second_unknown? or minute_unknown?
296 end
[125]297
[81]298 def as_string
[83]299 s = sprintf("%02d", @hour)
300 if !@minute.nil?
301 s += ":" + sprintf("%02d",@minute)
302 if !@second.nil?
303 s += ":" + sprintf("%02d", @second)
304 if !@fractional_second.nil?
[125]305 s += "." + @fractional_second.to_s[2..-1]
[83]306 if !@timezone.nil?
307 s += @timezone
[81]308 end
309 end
310 end
311 end
[125]312 return s
[81]313 end
[120]314 end
315
[297]316 class ISO8601Time < TimeDefinitions
317 include ISO8601TimeModule
[120]318 def initialize(string)
319 /(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(Z|([+-](\d{2}):?(\d{2})))?/ =~ string
320 if $2.nil?
321 self.minute = nil
322 else
323 self.minute = $2.to_i
324 end
325 if $4.nil?
326 self.second = nil
327 else
328 self.second = $4.to_i
329 end
330 if $1.nil?
331 raise ArgumentError, 'data invalid'
332 else
333 self.hour = $1.to_i
334 end
335 if $7.nil?
336 self.fractional_second = nil
337 else
338 self.fractional_second = ("0." + $7).to_f
339 end
340 if $8.nil?
341 self.timezone = nil
342 else
343 self.timezone = $8
344 end
345 end
[297]346
[81]347 def self.valid_iso8601_time?(s)
[297]348 if /^(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(Z|([+-](\d{2}):?(\d{2})))?$/ =~ s
[81]349# ISO 8601 regular expression by H. Yuki
350# http://digit.que.ne.jp/work/wiki.cgi?Perl%E3%83%A1%E3%83%A2%2FW3C%E5%BD%A2%E5%BC%8F%E3%81%AE%E6%97%A5%E6%99%82%E3%81%AE%E8%A7%A3%E6%9E%90
351# (\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d))?)?(Z|([+-]\d{2}):(\d{2}))?)?)?)?
352 hh = $1; mm = $2; ss = $4; msec = $7; tz = $8
[83]353 if hh.to_i == HOURS_IN_DAY and (mm.nil? or mm.to_i == 0) and (ss.nil? or ss.to_i == 0) and (msec.nil? or msec.to_i==0)
[81]354 return true
355 end
356 if hh.nil? or (hh.to_i < 0 or hh.to_i >= HOURS_IN_DAY)
357 return false
358 end
359 if !mm.nil?
360 if !self.valid_minute?(mm.to_i)
361 return false
362 end
363 end
364 if !ss.nil?
365 if !self.valid_second?(ss.to_i)
366 return false
367 end
368 end
369 if !tz.nil? and tz != "Z"
370 if /[+-](\d{2}):?(\d{2})/ =~ tz
371 h = $1; m = $2
372 if h.to_i < 0 or h.to_i >= HOURS_IN_DAY
373 return false
374 end
375 if m.to_i < 0 or m.to_i >= MINUTES_IN_HOUR
376 return false
377 end
378 end
379 end
380 return true
381 else
382 return false
383 end
384 end
[79]385 end # end of ISO8601_TIME
386
[297]387 module ISO8601DateTimeModule
388 include ISO8601DateModule, ISO8601TimeModule
[149]389 def as_string
390 if (!@year.nil? and !@month.nil? and !@day.nil?)
391 s = Date.new(@year, @month, @day).to_s
392 elsif (!@year.nil? and !@month.nil? and @day.nil?)
393 return Date.new(@year, @month).to_s[0,7]
394 elsif (!@year.nil? and @month.nil? and @day.nil?)
395 return Date.new(@year).to_s[0,4]
396 end
397 unless hour.nil?
398 s += sprintf("T%02d", @hour)
399 unless @minute.nil?
400 s += ":" + sprintf("%02d",@minute)
401 unless @second.nil?
402 s += ":" + sprintf("%02d", @second)
403 unless @fractional_second.nil?
404 s += "." + @fractional_second.to_s[2..-1]
405 unless @timezone.nil?
406 s += @timezone
407 end
408 end
409 end
410 end
411 end
412 return s
413 end
414 end
415
[297]416 class ISO8601DateTime < ISO8601Date
417 include ISO8601DateTimeModule
[120]418 def initialize(string)
[297]419 unless /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
[120]420 raise ArgumentError, 'format invalid'
421 else
422 self.year = $1.to_i
423 end
424 if $2.nil?
425 self.month = nil
426 else
427 self.month = $2.to_i
428 end
429 if $3.nil?
430 self.day = nil
431 else
432 self.day = $3.to_i
433 end
434 if $5.nil?
435 self.minute = nil
436 else
437 self.minute = $5.to_i
438 end
439 if $6.nil?
440 self.second = nil
441 else
442 self.second = $6.to_i
443 end
444 if $4.nil?
445 self.hour = nil
446 else
447 self.hour = $4.to_i
448 end
[121]449 if $7.nil? or $7.empty?
[120]450 self.fractional_second = nil
451 else
452 self.fractional_second = ("0."+$7).to_f
453 end
454 if $8.nil?
455 self.timezone = nil
456 else
[121]457 self.timezone = $9+$10
[120]458 end
459 end
460 end
[149]461
[297]462 class ISO8601Timezone
[79]463 attr_accessor :sign, :hour, :minute
[124]464
[297]465 def initialize(string)
466 unless /(Z|(([+-])(\d{2}):?(\d{2})))/ =~ string
467 raise ArgumentError, 'invaild format'
468 end
469 if $1 == 'Z'
470 @sign, @hour, @minute = +1, 0, 0
471 else
472 @sign, @hour, @minute = ($3+'1').to_i, $4.to_i , $5.to_i
473 end
474 end
475
[79]476 def is_gmt?
[297]477 @sign == +1 and @hour == 0 and @minute == 0
[79]478 end
[124]479
[79]480 def as_string
[297]481 if @sign == +1
[80]482 s = "+"
[297]483 elsif @sign == -1
[80]484 s = "-"
485 end
[297]486 sprintf("%s%02d%02d", s, @hour, @minute)
[79]487 end
[297]488 end # end of ISO8601Timezone
[123]489
[297]490 module ISO8601DurationModule
[126]491 attr_reader :years, :months, :weeks, :days
492 attr_reader :hours, :minutes, :seconds, :fractional_second
493
494 def years=(years)
[128]495 unless years.nil? || years >= 0
[126]496 raise ArgumentError, 'years must be above zero'
497 end
498 @years = years
499 end
[124]500
[126]501 def months=(months)
[128]502 unless months.nil? || months >= 0
[126]503 raise ArgumentError, 'months must be above zero'
504 end
505 @months = months
[124]506 end
[126]507
508 def weeks=(weeks)
[128]509 unless weeks.nil? || weeks >= 0
[126]510 raise ArgumentError, 'weeks must be above zero'
511 end
512 @weeks = weeks
513 end
514
515 def days=(days)
[128]516 unless days.nil? || days >= 0
[126]517 raise ArgumentError, 'days must be above zero'
518 end
519 @days = days
520 end
521
522 def hours=(hours)
[128]523 unless hours.nil? || hours >= 0
[126]524 raise ArgumentError, 'hours must be above zero'
525 end
526 @hours = hours
527 end
528
529 def minutes=(minutes)
[128]530 unless minutes.nil? || minutes >= 0
[126]531 raise ArgumentError, 'minutes must be above zero'
532 end
533 @minutes = minutes
534 end
535
536 def seconds=(seconds)
[128]537 unless seconds.nil? || seconds >= 0
[126]538 raise ArgumentError, 'seconds must be above zero'
539 end
540 @seconds = seconds
541 end
542
543 def fractional_second=(fractional_second)
[128]544 unless fractional_second.nil? || (fractional_second >= 0 && fractional_second < 1.0)
[126]545 raise ArgumentError, 'fractional_second must be between 0.0 and 1.0'
546 end
547 @fractional_second = fractional_second
548 end
549
550 def as_string
551 str = 'P'
552 unless @years.nil?
553 str += @years.to_s + 'Y'
554 end
555 unless @months.nil?
556 str += @months.to_s + 'M'
557 end
558 unless @weeks.nil?
559 str += @weeks.to_s + 'W'
560 end
561 unless @days.nil?
562 str += @days.to_s + 'D'
563 end
564 unless @hours.nil?
565 str += 'T' + @hours.to_s + 'H'
566 unless @minutes.nil?
567 str += @minutes.to_s + 'M'
568 unless @seconds.nil?
569 str += @seconds.to_s
570 unless @fractional_second.nil?
571 str += @fractional_second.to_s[1 .. -1]
572 end
573 str += 'S'
574 end
575 end
576 end
577 return str
578 end
[149]579 end
[297]580
581 class ISO8601Duration < TimeDefinitions
582 include ISO8601DurationModule
[149]583 def initialize(str)
584 /^P((\d+)Y)?((\d+)M)?((\d+)W)?((\d)D)?(T((\d+)H)?((\d+)M)?((\d+)(\.\d+)?S)?)?$/ =~ str
585 self.years = $2.to_i
586 self.months = $4.to_i
587 self.weeks = $6.to_i
588 self.days = $8.to_i
589 self.hours = $11.to_i
590 self.minutes = $13.to_i
591 self.seconds = $15.to_i
[369]592 unless $16.nil?
593 self.fractional_second = $16.to_f
594 end
[149]595 end
[297]596 end # end of ISO8601Duration
[69]597 end # end of Assumed_Types
598end # end of OpenEHR
Note: See TracBrowser for help on using the repository browser.