source: ruby/branches/0.5/lib/open_ehr/assumed_library_types.rb@ 285

Last change on this file since 285 was 285, checked in by KOBAYASHI, Shinji, 15 years ago

ISO8601Date ISO8601Time completed

File size: 14.9 KB
RevLine 
[83]1# This module is related to the ticket #36
[70]2require 'date'
[81]3require 'time'
[70]4
[216]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
[244]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)
[255]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)
[255]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)
[244]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
[256]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)
[259]97 return !year.nil? && year >= 0
[70]98 end
99
100 def self.valid_day?(y, m, d)
[259]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)
[285]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
[282]122
[81]123 def self.valid_minute?(mi)
124 mi >= 0 and mi < MINUTES_IN_HOUR
[70]125 end
[282]126
[70]127 def self.valid_second?(s)
128 s >= 0 and s < SECONDS_IN_MINUTE
129 end
[282]130
[81]131 def self.valid_month?(mo)
132 mo >= 1 and mo <= MONTH_IN_YEAR
[70]133 end
[256]134 end # end of TimeDefinitions
[69]135
[256]136 module ISO8601DateModule
[70]137 attr_reader :year, :month, :day
[256]138
[70]139 def year=(year)
[259]140 unless ISO8601Date.valid_year?(year)
[256]141 raise ArgumentError, "Year is not valid"
142 end
[70]143 @year = year
144 end
[256]145
[70]146 def month=(month)
[256]147 raise ArgumentError, "Month is not valid" unless month.nil? or ISO8601Date.valid_month?(month)
[70]148 @month = month
149 end
[125]150
[70]151 def day=(day)
[259]152
[256]153 raise ArgumentError, "Day is not valid" unless day.nil? or ISO8601Date.valid_day?(@year, @month, day)
[70]154 @day = day
155 end
[125]156
[70]157 def as_string
158 if (!@year.nil? and !@month.nil? and !@day.nil?)
159 Date.new(@year, @month, @day).to_s
160 elsif (!@year.nil? and !@month.nil? and @day.nil?)
161 Date.new(@year, @month).to_s[0,7]
162 elsif (!@year.nil? and @month.nil? and @day.nil?)
163 Date.new(@year).to_s[0,4]
164 end
165 end
[125]166
[70]167 def month_unknown?
168 @month.nil?
169 end
[125]170
[70]171 def day_unknown?
172 @day.nil?
173 end
[125]174
[70]175 def is_extended?
176 true
177 end
[125]178
[70]179 def is_partial?
180 month_unknown? or day_unknown?
181 end
[149]182
183 protected
184 def leapyear?(year)
185 case
186 when year % 400 == 0: true
187 when year % 100 == 0: false
188 else year % 4 == 0
189 end
190 end
[120]191 end
192
[256]193 class ISO8601Date < TimeDefinitions
194 include ISO8601DateModule
[120]195 def initialize(string)
196 /(\d{4})(?:-(\d{2})(?:-(\d{2})?)?)?/ =~ string
197 if $1.nil?
198 raise ArgumentError, 'data invalid'
199 else
200 self.year = $1.to_i
201 end
202 if $2.nil?
203 self.month = nil
204 else
205 self.month = $2.to_i
206 end
207 if $3.nil?
208 self.day = nil
209 else
210 self.day = $3.to_i
211 end
212 end
[149]213
[81]214 def self.valid_iso8601_date?(string)
[70]215 begin
[81]216 Date.parse(string)
[70]217 rescue
218 return false
219 end
220 true
221 end
[79]222 end # end of ISO8601_DATE
223
[256]224 module ISO8601TimeModule
[83]225 attr_reader :hour, :minute, :second, :fractional_second, :timezone
[120]226
[83]227 def hour=(hour)
[285]228 unless ISO8601Time.valid_hour?(hour, @minute, @second)
229 raise ArgumentError, "hour is not valid"
230 end
[83]231 @hour = hour
232 end
[124]233
[83]234 def minute_unknown?
235 @minute.nil?
236 end
[124]237
[83]238 def minute=(minute)
[285]239 raise ArgumentError, "minute is not valid" if !minute.nil? and !ISO8601Time.valid_minute?(minute)
[83]240 @minute = minute
241 end
[124]242
[83]243 def second_unknown?
244 @second.nil?
245 end
[124]246
[83]247 def second=(second)
[120]248 raise ArgumentError, "minute not defined" if @minute.nil? and !second.nil?
[285]249 raise ArgumentError, "second is not valid" if !second.nil? and !ISO8601Time.valid_second?(second)
[83]250 @second = second
251 end
[124]252
[83]253 def fractional_second=(fractional_second)
[120]254 raise ArgumentError, "minute not defined" if minute_unknown? and !fractional_second.nil?
255 raise ArgumentError, "second not defined" if second_unknown? and !fractional_second.nil?
[285]256 if !fractional_second.nil? &&
257 (fractional_second < 0.0 || fractional_second >= 1.0)
258 raise ArgumentError, 'fractional second should be between 0.0 - 1.0'
259 end
[83]260 @fractional_second = fractional_second
261 end
[124]262
[83]263 def has_fractional_second?
[285]264 return !@fractional_second.nil?
[83]265 end
[124]266
[120]267 def timezone=(timezone)
268 unless timezone.nil? or timezone == 'Z'
269 if /[+-](\d{2}):?(\d{2})/ =~ timezone
270 @timezone = timezone
271 else
272 raise ArgumentError, "timezone invalid"
273 end
274 else
275 @timezone = nil
276 end
277 end
[124]278
[83]279 def is_decimal_sign_comma?
[126]280 false
[83]281 end
[124]282
[83]283 def is_extended?
284 true
285 end
[124]286
[83]287 def is_partial?
288 second_unknown? or minute_unknown?
289 end
[125]290
[81]291 def as_string
[83]292 s = sprintf("%02d", @hour)
293 if !@minute.nil?
294 s += ":" + sprintf("%02d",@minute)
295 if !@second.nil?
296 s += ":" + sprintf("%02d", @second)
297 if !@fractional_second.nil?
[125]298 s += "." + @fractional_second.to_s[2..-1]
[83]299 if !@timezone.nil?
300 s += @timezone
[81]301 end
302 end
303 end
304 end
[125]305 return s
[81]306 end
[120]307 end
308
[256]309 class ISO8601Time < TimeDefinitions
310 include ISO8601TimeModule
[120]311 def initialize(string)
312 /(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(Z|([+-](\d{2}):?(\d{2})))?/ =~ string
313 if $2.nil?
314 self.minute = nil
315 else
316 self.minute = $2.to_i
317 end
318 if $4.nil?
319 self.second = nil
320 else
321 self.second = $4.to_i
322 end
323 if $1.nil?
324 raise ArgumentError, 'data invalid'
325 else
326 self.hour = $1.to_i
327 end
328 if $7.nil?
329 self.fractional_second = nil
330 else
331 self.fractional_second = ("0." + $7).to_f
332 end
333 if $8.nil?
334 self.timezone = nil
335 else
336 self.timezone = $8
337 end
338 end
[285]339
[81]340 def self.valid_iso8601_time?(s)
[285]341 if /^(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(T?)(Z|([+-](\d{2}):?(\d{2})))?$/ =~ s
[81]342# ISO 8601 regular expression by H. Yuki
343# 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
344# (\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d))?)?(Z|([+-]\d{2}):(\d{2}))?)?)?)?
[285]345 hh = $1; mm = $2; ss = $4; msec = $7; tz = $9
[83]346 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]347 return true
348 end
349 if hh.nil? or (hh.to_i < 0 or hh.to_i >= HOURS_IN_DAY)
350 return false
351 end
352 if !mm.nil?
353 if !self.valid_minute?(mm.to_i)
354 return false
355 end
356 end
357 if !ss.nil?
358 if !self.valid_second?(ss.to_i)
359 return false
360 end
361 end
362 if !tz.nil? and tz != "Z"
363 if /[+-](\d{2}):?(\d{2})/ =~ tz
364 h = $1; m = $2
365 if h.to_i < 0 or h.to_i >= HOURS_IN_DAY
366 return false
367 end
368 if m.to_i < 0 or m.to_i >= MINUTES_IN_HOUR
369 return false
370 end
371 end
372 end
373 return true
374 else
375 return false
376 end
377 end
[79]378 end # end of ISO8601_TIME
379
[256]380 module ISO8601DateTimeModule
381 include ISO8601DateModule, ISO8601TimeModule
[149]382 def as_string
383 if (!@year.nil? and !@month.nil? and !@day.nil?)
384 s = Date.new(@year, @month, @day).to_s
385 elsif (!@year.nil? and !@month.nil? and @day.nil?)
386 return Date.new(@year, @month).to_s[0,7]
387 elsif (!@year.nil? and @month.nil? and @day.nil?)
388 return Date.new(@year).to_s[0,4]
389 end
390 unless hour.nil?
391 s += sprintf("T%02d", @hour)
392 unless @minute.nil?
393 s += ":" + sprintf("%02d",@minute)
394 unless @second.nil?
395 s += ":" + sprintf("%02d", @second)
396 unless @fractional_second.nil?
397 s += "." + @fractional_second.to_s[2..-1]
398 unless @timezone.nil?
399 s += @timezone
400 end
401 end
402 end
403 end
404 end
405 return s
406 end
407 end
408
[256]409 class ISO8601DateTime < ISO8601Date
410 include ISO8601DateTimeModule
[120]411 def initialize(string)
[121]412 /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
[120]413 if $1.empty?
414 raise ArgumentError, 'format invalid'
415 else
416 self.year = $1.to_i
417 end
418 if $2.nil?
419 self.month = nil
420 else
421 self.month = $2.to_i
422 end
423 if $3.nil?
424 self.day = nil
425 else
426 self.day = $3.to_i
427 end
428 if $5.nil?
429 self.minute = nil
430 else
431 self.minute = $5.to_i
432 end
433 if $6.nil?
434 self.second = nil
435 else
436 self.second = $6.to_i
437 end
438 if $4.nil?
439 self.hour = nil
440 else
441 self.hour = $4.to_i
442 end
[121]443 if $7.nil? or $7.empty?
[120]444 self.fractional_second = nil
445 else
446 self.fractional_second = ("0."+$7).to_f
447 end
448 if $8.nil?
449 self.timezone = nil
450 else
[121]451 self.timezone = $9+$10
[120]452 end
453 end
454 end
[149]455
[79]456 class ISO8601_TIMEZONE
457 attr_accessor :sign, :hour, :minute
[124]458
[79]459 def is_gmt?
[80]460 @sign == "+1" and @hour == 0 and @minute == 0
[79]461 end
[124]462
[79]463 def as_string
[80]464 if @sign == "+1"
465 s = "+"
466 elsif @sign == "-1"
467 s = "-"
468 end
469 sprintf("Z%s%02d%02d", s, @hour, @minute)
[79]470 end
471 end # end of ISO8601_TIMEZONE
[123]472
[149]473 module ISO8601_DURATION_MODULE
[126]474 attr_reader :years, :months, :weeks, :days
475 attr_reader :hours, :minutes, :seconds, :fractional_second
476
477 def years=(years)
[128]478 unless years.nil? || years >= 0
[126]479 raise ArgumentError, 'years must be above zero'
480 end
481 @years = years
482 end
[124]483
[126]484 def months=(months)
[128]485 unless months.nil? || months >= 0
[126]486 raise ArgumentError, 'months must be above zero'
487 end
488 @months = months
[124]489 end
[126]490
491 def weeks=(weeks)
[128]492 unless weeks.nil? || weeks >= 0
[126]493 raise ArgumentError, 'weeks must be above zero'
494 end
495 @weeks = weeks
496 end
497
498 def days=(days)
[128]499 unless days.nil? || days >= 0
[126]500 raise ArgumentError, 'days must be above zero'
501 end
502 @days = days
503 end
504
505 def hours=(hours)
[128]506 unless hours.nil? || hours >= 0
[126]507 raise ArgumentError, 'hours must be above zero'
508 end
509 @hours = hours
510 end
511
512 def minutes=(minutes)
[128]513 unless minutes.nil? || minutes >= 0
[126]514 raise ArgumentError, 'minutes must be above zero'
515 end
516 @minutes = minutes
517 end
518
519 def seconds=(seconds)
[128]520 unless seconds.nil? || seconds >= 0
[126]521 raise ArgumentError, 'seconds must be above zero'
522 end
523 @seconds = seconds
524 end
525
526 def fractional_second=(fractional_second)
[128]527 unless fractional_second.nil? || (fractional_second >= 0 && fractional_second < 1.0)
[126]528 raise ArgumentError, 'fractional_second must be between 0.0 and 1.0'
529 end
530 @fractional_second = fractional_second
531 end
532
533 def as_string
534 str = 'P'
535 unless @years.nil?
536 str += @years.to_s + 'Y'
537 end
538 unless @months.nil?
539 str += @months.to_s + 'M'
540 end
541 unless @weeks.nil?
542 str += @weeks.to_s + 'W'
543 end
544 unless @days.nil?
545 str += @days.to_s + 'D'
546 end
547 unless @hours.nil?
548 str += 'T' + @hours.to_s + 'H'
549 unless @minutes.nil?
550 str += @minutes.to_s + 'M'
551 unless @seconds.nil?
552 str += @seconds.to_s
553 unless @fractional_second.nil?
554 str += @fractional_second.to_s[1 .. -1]
555 end
556 str += 'S'
557 end
558 end
559 end
560 return str
561 end
[149]562 end
[259]563
[256]564 class ISO8601_DURATION < TimeDefinitions
[149]565 include ISO8601_DURATION_MODULE
566 def initialize(str)
567 /^P((\d+)Y)?((\d+)M)?((\d+)W)?((\d)D)?(T((\d+)H)?((\d+)M)?((\d+)(\.\d+)?S)?)?$/ =~ str
568 self.years = $2.to_i
569 self.months = $4.to_i
570 self.weeks = $6.to_i
571 self.days = $8.to_i
572 self.hours = $11.to_i
573 self.minutes = $13.to_i
574 self.seconds = $15.to_i
575 self.fractional_second = $16.to_f
576 end
[124]577 end # end of ISO8601_DURATION
[69]578 end # end of Assumed_Types
579end # end of OpenEHR
Note: See TracBrowser for help on using the repository browser.