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

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

date and time are seeds of headache

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