/library/xpath/src/value/xm_xpath_date_time_value.e

http://github.com/gobo-eiffel/gobo · Specman e · 428 lines · 358 code · 44 blank · 26 comment · 36 complexity · 7407be4b040810bf472026375f799abd MD5 · raw file

  1. note
  2. description:
  3. "Objects that represent XPath xs:dateTime values"
  4. library: "Gobo Eiffel XPath Library"
  5. copyright: "Copyright (c) 2005-2018, Colin Adams and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class XM_XPATH_DATE_TIME_VALUE
  10. inherit
  11. XM_XPATH_CALENDAR_VALUE
  12. undefine
  13. is_xpath_date_time, as_xpath_date_time
  14. redefine
  15. is_date_time_value, as_date_time_value, hash_code
  16. end
  17. ST_XPATH_DATE_TIME_VALUE
  18. redefine
  19. make, make_from_date_time, make_from_zoned_date_time, make_from_date, make_from_zoned_date
  20. end
  21. DT_SHARED_SYSTEM_CLOCK
  22. export {NONE} all end
  23. create
  24. make, make_from_date_time, make_from_zoned_date_time, make_from_date, make_from_zoned_date
  25. feature {NONE} -- Initialization
  26. make (a_lexical_date_time: STRING)
  27. -- Create from lexical xs:dateTime.
  28. do
  29. make_atomic_value
  30. Precursor (a_lexical_date_time)
  31. if not zoned then
  32. set_depends_upon_implicit_timezone
  33. end
  34. end
  35. make_from_date_time (a_date_time: DT_DATE_TIME)
  36. -- Create from date_time object.
  37. do
  38. make_atomic_value
  39. Precursor (a_date_time)
  40. set_depends_upon_implicit_timezone
  41. end
  42. make_from_zoned_date_time (a_date_time: DT_FIXED_OFFSET_ZONED_DATE_TIME)
  43. -- Create from date_time object.
  44. do
  45. make_atomic_value
  46. Precursor (a_date_time)
  47. end
  48. make_from_date (a_date: DT_DATE)
  49. -- Create from date object.
  50. do
  51. make_atomic_value
  52. Precursor (a_date)
  53. set_depends_upon_implicit_timezone
  54. end
  55. make_from_zoned_date (a_date: DT_FIXED_OFFSET_ZONED_DATE)
  56. -- Create from zoned date object.
  57. do
  58. make_atomic_value
  59. Precursor (a_date)
  60. end
  61. feature -- Access
  62. item_type: XM_XPATH_ITEM_TYPE
  63. -- Data type of the expression, where know
  64. do
  65. Result := type_factory.date_time_type
  66. if Result /= Void then
  67. -- Bug in SE 1.0 and 1.1: Make sure that
  68. -- that `Result' is not optimized away.
  69. end
  70. end
  71. string_value: STRING
  72. --Value of the item as a string
  73. local
  74. a_date_time_parser: ST_XSD_DATE_TIME_FORMAT
  75. do
  76. create a_date_time_parser.make_1_1
  77. if zoned then
  78. check attached zoned_date_time as l_zoned_date_time then
  79. Result := a_date_time_parser.zoned_date_time_to_string (l_zoned_date_time)
  80. end
  81. else
  82. check attached local_date_time as l_local_date_time then
  83. Result := a_date_time_parser.date_time_to_string (l_local_date_time)
  84. end
  85. end
  86. end
  87. as_zoneless: XM_XPATH_DATE_TIME_VALUE
  88. -- Same value as `Current', but without a time zone
  89. do
  90. if zoned then
  91. check attached zoned_date_time as l_zoned_date_time then
  92. create Result.make_from_date_time (l_zoned_date_time.date_time)
  93. end
  94. else
  95. Result := Current
  96. end
  97. ensure
  98. result_not_void: Result /= Void
  99. end
  100. to_another_time_zone (an_offset: XM_XPATH_SECONDS_DURATION_VALUE): XM_XPATH_DATE_TIME_VALUE
  101. -- Same dateTime as `Current', but in `a_time_zone'
  102. require
  103. time_zone_not_void: an_offset /= Void
  104. local
  105. a_zone: DT_FIXED_OFFSET_TIME_ZONE
  106. a_zoned_dt: DT_FIXED_OFFSET_ZONED_DATE_TIME
  107. a_dt: DT_DATE_TIME
  108. do
  109. create a_zone.make (an_offset.duration.time_duration)
  110. if not zoned then
  111. check attached local_date_time as l_local_date_time then
  112. create a_zoned_dt.make (l_local_date_time, a_zone)
  113. create Result.make_from_zoned_date_time (a_zoned_dt)
  114. end
  115. else
  116. check attached zoned_date_time as l_zoned_date_time then
  117. a_dt := a_zone.date_time_from (l_zoned_date_time.date_time, l_zoned_date_time.time_zone)
  118. create a_zoned_dt.make (a_dt, a_zone)
  119. create Result.make_from_zoned_date_time (a_zoned_dt)
  120. end
  121. end
  122. ensure
  123. result_not_void: Result /= Void
  124. end
  125. hash_code: INTEGER
  126. -- Hash code value
  127. do
  128. if attached local_date_time as l_local_date_time then
  129. Result := l_local_date_time.hash_code
  130. else
  131. -- Equality implies same `hash_code', but
  132. -- not vice-versa:
  133. Result := utc_date_time.hash_code
  134. end
  135. end
  136. implicitly_zoned_date_time (a_context: XM_XPATH_CONTEXT): DT_DATE_TIME
  137. -- Date_Time adjusted to UTC via implicit time zone
  138. do
  139. check precondition_not_zoned: attached local_date_time as l_local_date_time then
  140. Result := a_context.implicit_timezone.date_time_to_utc (l_local_date_time)
  141. end
  142. end
  143. utc_date_time: DT_DATE_TIME
  144. -- Date_Time adjusted to UTC
  145. do
  146. if attached cached_utc_date_time as l_cached_utc_date_time then
  147. Result := l_cached_utc_date_time
  148. else
  149. check precondition_zoned: attached zoned_date_time as l_zoned_date_time then
  150. Result := l_zoned_date_time.date_time_to_utc
  151. cached_utc_date_time := Result
  152. end
  153. end
  154. end
  155. feature -- Comparison
  156. same_expression (other: XM_XPATH_EXPRESSION): BOOLEAN
  157. -- Are `Current' and `other' the same expression?
  158. do
  159. if other.is_date_time_value then
  160. if zoned then
  161. Result := other.as_date_time_value.zoned
  162. and then utc_date_time.three_way_comparison (other.as_date_time_value.utc_date_time) = 0
  163. elseif other.as_date_time_value.zoned then
  164. Result := False
  165. else
  166. check attached local_date_time as l_local_date_time and attached other.as_date_time_value.local_date_time as l_other_local_date_time then
  167. Result := not other.as_date_time_value.zoned
  168. and then l_local_date_time.three_way_comparison (l_other_local_date_time) = 0
  169. end
  170. end
  171. end
  172. end
  173. three_way_comparison (other: XM_XPATH_ATOMIC_VALUE; a_context: detachable XM_XPATH_CONTEXT): INTEGER
  174. -- Comparison of `Current' to `other'
  175. local
  176. a_date_time: XM_XPATH_DATE_TIME_VALUE
  177. dt1, dt2: DT_DATE_TIME
  178. l_implicit_timezone: DT_FIXED_OFFSET_TIME_ZONE
  179. do
  180. a_date_time := other.as_date_time_value
  181. if zoned = a_date_time.zoned then
  182. if zoned then
  183. check attached zoned_date_time as l_zoned_date_time and attached a_date_time.zoned_date_time as l_other_zoned_date_time then
  184. create dt2.make_from_date_time (l_other_zoned_date_time.date_time.date, l_other_zoned_date_time.date_time.time)
  185. l_other_zoned_date_time.time_zone.convert_to_utc (dt2)
  186. create dt1.make_from_date_time (l_zoned_date_time.date_time.date, l_zoned_date_time.date_time.time)
  187. l_zoned_date_time.time_zone.convert_to_utc (dt1)
  188. Result := dt1.three_way_comparison (dt2)
  189. end
  190. else
  191. check attached local_date_time as l_local_date_time and attached a_date_time.local_date_time as l_other_local_date_time then
  192. create dt2.make_from_date_time (l_other_local_date_time.date, l_other_local_date_time.time)
  193. create dt1.make_from_date_time (l_local_date_time.date, l_local_date_time.time)
  194. Result := dt1.three_way_comparison (dt2)
  195. end
  196. end
  197. elseif zoned then
  198. check attached zoned_date_time as l_zoned_date_time and attached a_date_time.local_date_time as l_other_local_date_time then
  199. create dt2.make_from_date_time (l_other_local_date_time.date, l_other_local_date_time.time)
  200. if a_context /= Void then
  201. l_implicit_timezone := a_context.implicit_timezone
  202. else
  203. create l_implicit_timezone.make (system_clock.time_now.canonical_duration (utc_system_clock.time_now))
  204. end
  205. l_implicit_timezone.convert_to_utc (dt2)
  206. create dt1.make_from_date_time (l_zoned_date_time.date_time.date, l_zoned_date_time.date_time.time)
  207. l_zoned_date_time.time_zone.convert_to_utc (dt1)
  208. Result := dt1.three_way_comparison (dt2)
  209. end
  210. else -- `other' is zoned
  211. check attached local_date_time as l_local_date_time and attached a_date_time.zoned_date_time as l_other_zoned_date_time then
  212. create dt2.make_from_date_time (l_other_zoned_date_time.date_time.date, l_other_zoned_date_time.date_time.time)
  213. l_other_zoned_date_time.time_zone.convert_to_utc (dt2)
  214. create dt1.make_from_date_time (l_local_date_time.date, l_local_date_time.time)
  215. if a_context /= Void then
  216. l_implicit_timezone := a_context.implicit_timezone
  217. else
  218. create l_implicit_timezone.make (system_clock.time_now.canonical_duration (utc_system_clock.time_now))
  219. end
  220. l_implicit_timezone.convert_to_utc (dt1)
  221. Result := dt1.three_way_comparison (dt2)
  222. end
  223. end
  224. end
  225. feature -- Status report
  226. is_date_time_value: BOOLEAN
  227. -- Is `Current' a date_time value?
  228. do
  229. Result := True
  230. end
  231. is_comparable (other: XM_XPATH_ATOMIC_VALUE): BOOLEAN
  232. -- Is `other' comparable to `Current'?
  233. do
  234. Result := other.is_date_time_value
  235. end
  236. is_convertible (a_required_type: XM_XPATH_ITEM_TYPE): BOOLEAN
  237. -- Is `Current' convertible to `a_required_type'?
  238. do
  239. if a_required_type = any_item or else a_required_type = type_factory.any_atomic_type
  240. or else a_required_type = type_factory.date_type
  241. or else a_required_type = type_factory.time_type
  242. or else a_required_type = type_factory.date_time_type
  243. or else a_required_type = type_factory.g_year_month_type
  244. or else a_required_type = type_factory.g_year_type
  245. or else a_required_type = type_factory.g_month_type
  246. or else a_required_type = type_factory.g_month_day_type
  247. or else a_required_type = type_factory.g_day_type
  248. or else a_required_type = type_factory.string_type
  249. or else a_required_type = type_factory.untyped_atomic_type then
  250. Result := True
  251. end
  252. end
  253. display (a_level: INTEGER)
  254. -- Diagnostic print of expression structure to `std.error'
  255. local
  256. a_string: STRING
  257. do
  258. a_string := STRING_.appended_string (indentation (a_level), "dateTime (")
  259. a_string := STRING_.appended_string (a_string, string_value)
  260. a_string := STRING_.appended_string (a_string, ")")
  261. std.error.put_string (a_string)
  262. std.error.put_new_line
  263. end
  264. feature -- Conversions
  265. as_date_time_value: XM_XPATH_DATE_TIME_VALUE
  266. -- `Current' seen as a dateTime value
  267. do
  268. Result := Current
  269. end
  270. convert_to_type (a_required_type: XM_XPATH_ITEM_TYPE)
  271. -- Convert `Current' to `a_required_type'
  272. do
  273. if a_required_type = any_item or else a_required_type = type_factory.any_atomic_type
  274. or else a_required_type = type_factory.date_time_type then
  275. converted_value := Current
  276. elseif a_required_type = type_factory.string_type then
  277. create {XM_XPATH_STRING_VALUE} converted_value.make (string_value)
  278. elseif a_required_type = type_factory.untyped_atomic_type then
  279. create {XM_XPATH_STRING_VALUE} converted_value.make_untyped_atomic (string_value)
  280. elseif a_required_type = type_factory.date_type then
  281. if zoned then
  282. check attached zoned_date_time as l_zoned_date_time then
  283. create {XM_XPATH_DATE_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  284. end
  285. else
  286. check attached local_date_time as l_local_date_time then
  287. create {XM_XPATH_DATE_VALUE} converted_value.make_from_date (l_local_date_time.date)
  288. end
  289. end
  290. elseif a_required_type = type_factory.time_type then
  291. if zoned then
  292. check attached zoned_date_time as l_zoned_date_time then
  293. create {XM_XPATH_TIME_VALUE} converted_value.make_from_zoned_time (l_zoned_date_time.zoned_time)
  294. end
  295. else
  296. check attached local_date_time as l_local_date_time then
  297. create {XM_XPATH_TIME_VALUE} converted_value.make_from_time (l_local_date_time.time)
  298. end
  299. end
  300. elseif a_required_type = type_factory.g_year_month_type then
  301. if zoned then
  302. check attached zoned_date_time as l_zoned_date_time then
  303. create {XM_XPATH_YEAR_MONTH_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  304. end
  305. else
  306. check attached local_date_time as l_local_date_time then
  307. create {XM_XPATH_YEAR_MONTH_VALUE} converted_value.make_from_date (l_local_date_time.date)
  308. end
  309. end
  310. elseif a_required_type = type_factory.g_year_type then
  311. if zoned then
  312. check attached zoned_date_time as l_zoned_date_time then
  313. create {XM_XPATH_YEAR_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  314. end
  315. else
  316. check attached local_date_time as l_local_date_time then
  317. create {XM_XPATH_YEAR_VALUE} converted_value.make_from_date (l_local_date_time.date)
  318. end
  319. end
  320. elseif a_required_type = type_factory.g_month_type then
  321. if zoned then
  322. check attached zoned_date_time as l_zoned_date_time then
  323. create {XM_XPATH_MONTH_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  324. end
  325. else
  326. check attached local_date_time as l_local_date_time then
  327. create {XM_XPATH_MONTH_VALUE} converted_value.make_from_date (l_local_date_time.date)
  328. end
  329. end
  330. elseif a_required_type = type_factory.g_month_day_type then
  331. if zoned then
  332. check attached zoned_date_time as l_zoned_date_time then
  333. create {XM_XPATH_MONTH_DAY_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  334. end
  335. else
  336. check attached local_date_time as l_local_date_time then
  337. create {XM_XPATH_MONTH_DAY_VALUE} converted_value.make_from_date (l_local_date_time.date)
  338. end
  339. end
  340. elseif a_required_type = type_factory.g_day_type then
  341. if zoned then
  342. check attached zoned_date_time as l_zoned_date_time then
  343. create {XM_XPATH_DAY_VALUE} converted_value.make_from_zoned_date (l_zoned_date_time.zoned_date)
  344. end
  345. else
  346. check attached local_date_time as l_local_date_time then
  347. create {XM_XPATH_DAY_VALUE} converted_value.make_from_date (l_local_date_time.date)
  348. end
  349. end
  350. end
  351. end
  352. feature -- Basic operations
  353. plus (a_duration: XM_XPATH_DURATION_VALUE): like Current
  354. -- Addition of `a_duration' to `Current'
  355. local
  356. a_date_time: DT_DATE_TIME
  357. a_zoned_date_time: like zoned_date_time
  358. do
  359. if zoned then
  360. check attached zoned_date_time as l_zoned_date_time then
  361. a_date_time := l_zoned_date_time.date_time.twin
  362. end
  363. else
  364. check attached local_date_time as l_local_date_time then
  365. a_date_time := l_local_date_time.twin
  366. end
  367. end
  368. a_date_time.add_duration (a_duration.duration)
  369. if zoned then
  370. check attached zoned_date_time as l_zoned_date_time then
  371. create a_zoned_date_time.make (a_date_time, l_zoned_date_time.time_zone.twin)
  372. create Result.make_from_zoned_date_time (a_zoned_date_time)
  373. end
  374. else
  375. create Result.make_from_date_time (a_date_time)
  376. end
  377. end
  378. feature {NONE} -- Implementation
  379. cached_utc_date_time: detachable DT_DATE_TIME
  380. -- Cached `Result' for `utc_date_time'
  381. invariant
  382. zoned_date_time: zoned implies zoned_date_time /= Void
  383. unzoned_date_time: not zoned implies local_date_time /= Void
  384. end