webmcp
annotate libraries/atom/atom.lua @ 438:ea8419658535
Another change to make <db_object>:try_save() work properly with "document_column"
(use "_col" proxy also for accessing self._col[primary_key.json_doc])
(use "_col" proxy also for accessing self._col[primary_key.json_doc])
| author | jbe | 
|---|---|
| date | Wed Jan 20 21:06:07 2016 +0100 (2016-01-20) | 
| parents | e3e2a03f75b2 | 
| children | b19a6b4f61f3 | 
| rev | line source | 
|---|---|
| jbe/bsw@0 | 1 #!/usr/bin/env lua | 
| jbe/bsw@0 | 2 | 
| jbe/bsw@0 | 3 local _G = _G | 
| jbe/bsw@0 | 4 local _VERSION = _VERSION | 
| jbe/bsw@0 | 5 local assert = assert | 
| jbe/bsw@0 | 6 local error = error | 
| jbe/bsw@0 | 7 local getmetatable = getmetatable | 
| jbe/bsw@0 | 8 local ipairs = ipairs | 
| jbe/bsw@0 | 9 local next = next | 
| jbe/bsw@0 | 10 local pairs = pairs | 
| jbe/bsw@0 | 11 local print = print | 
| jbe/bsw@0 | 12 local rawequal = rawequal | 
| jbe/bsw@0 | 13 local rawget = rawget | 
| jbe@64 | 14 local rawlen = rawlen | 
| jbe/bsw@0 | 15 local rawset = rawset | 
| jbe/bsw@0 | 16 local select = select | 
| jbe/bsw@0 | 17 local setmetatable = setmetatable | 
| jbe/bsw@0 | 18 local tonumber = tonumber | 
| jbe/bsw@0 | 19 local tostring = tostring | 
| jbe/bsw@0 | 20 local type = type | 
| jbe/bsw@0 | 21 | 
| jbe/bsw@0 | 22 local math = math | 
| jbe@89 | 23 local os = os | 
| jbe/bsw@0 | 24 local string = string | 
| jbe/bsw@0 | 25 local table = table | 
| jbe/bsw@0 | 26 | 
| jbe@64 | 27 local _M = {} | 
| jbe@64 | 28 if _ENV then | 
| jbe@64 | 29 _ENV = _M | 
| jbe@64 | 30 else | 
| jbe@64 | 31 _G[...] = _M | 
| jbe@64 | 32 setfenv(1, _M) | 
| jbe@64 | 33 end | 
| jbe/bsw@0 | 34 | 
| jbe/bsw@0 | 35 | 
| jbe/bsw@0 | 36 | 
| jbe/bsw@0 | 37 --------------------------------------- | 
| jbe/bsw@0 | 38 -- general functions and definitions -- | 
| jbe/bsw@0 | 39 --------------------------------------- | 
| jbe/bsw@0 | 40 | 
| jbe/bsw@0 | 41 --[[-- | 
| jbe/bsw@0 | 42 bool = -- true, if value is an integer within resolution | 
| jbe/bsw@0 | 43 atom.is_integer( | 
| jbe/bsw@0 | 44 value -- value to be tested | 
| jbe/bsw@0 | 45 ) | 
| jbe/bsw@0 | 46 | 
| jbe/bsw@0 | 47 This function returns true if the given object is an integer within resolution. | 
| jbe/bsw@0 | 48 | 
| jbe/bsw@0 | 49 --]]-- | 
| jbe/bsw@0 | 50 function is_integer(i) | 
| jbe/bsw@0 | 51 return | 
| jbe/bsw@0 | 52 type(i) == "number" and i % 1 == 0 and | 
| jbe/bsw@0 | 53 (i + 1) - i == 1 and i - (i - 1) == 1 | 
| jbe/bsw@0 | 54 end | 
| jbe/bsw@0 | 55 --//-- | 
| jbe/bsw@0 | 56 | 
| jbe/bsw@0 | 57 --[[-- | 
| jbe/bsw@0 | 58 atom.not_a_number | 
| jbe/bsw@0 | 59 | 
| jbe/bsw@0 | 60 Value representing an invalid numeric result. Used for atom.integer.invalid and atom.number.invalid. | 
| jbe/bsw@0 | 61 | 
| jbe/bsw@0 | 62 --]]-- | 
| jbe/bsw@0 | 63 not_a_number = 0 / 0 | 
| jbe/bsw@0 | 64 --//-- | 
| jbe/bsw@0 | 65 | 
| jbe/bsw@0 | 66 do | 
| jbe/bsw@0 | 67 | 
| jbe/bsw@0 | 68 local shadow = setmetatable({}, { __mode = "k" }) | 
| jbe/bsw@0 | 69 | 
| jbe/bsw@0 | 70 local type_mt = { __index = {} } | 
| jbe/bsw@0 | 71 | 
| jbe/bsw@0 | 72 function type_mt:__call(...) | 
| jbe/bsw@0 | 73 return self:new(...) | 
| jbe/bsw@0 | 74 end | 
| jbe/bsw@0 | 75 | 
| jbe/bsw@0 | 76 function type_mt.__index:_create(data) | 
| jbe/bsw@0 | 77 local value = setmetatable({}, self) | 
| jbe/bsw@0 | 78 shadow[value] = data | 
| jbe/bsw@0 | 79 return value | 
| jbe/bsw@0 | 80 end | 
| jbe/bsw@0 | 81 | 
| jbe/bsw@0 | 82 local function write_prohibited() | 
| jbe/bsw@0 | 83 error("Modification of an atom is prohibited.") | 
| jbe/bsw@0 | 84 end | 
| jbe/bsw@0 | 85 | 
| jbe/bsw@0 | 86 -- returns a new type as a table, which serves also as metatable | 
| jbe/bsw@0 | 87 function create_new_type(name) | 
| jbe/bsw@0 | 88 local t = setmetatable( | 
| jbe/bsw@0 | 89 { methods = {}, getters = {}, name = name }, | 
| jbe/bsw@0 | 90 type_mt | 
| jbe/bsw@0 | 91 ) | 
| jbe/bsw@0 | 92 function t.__index(self, key) | 
| jbe/bsw@0 | 93 local data = shadow[self] | 
| jbe/bsw@0 | 94 local value = data[key] | 
| jbe/bsw@0 | 95 if value ~= nil then return value end | 
| jbe/bsw@0 | 96 local method = t.methods[key] | 
| jbe/bsw@0 | 97 if method then return method end | 
| jbe/bsw@0 | 98 local getter = t.getters[key] | 
| jbe/bsw@0 | 99 if getter then return getter(self) end | 
| jbe/bsw@0 | 100 end | 
| jbe/bsw@0 | 101 t.__newindex = write_prohibited | 
| jbe/bsw@0 | 102 return t | 
| jbe/bsw@0 | 103 end | 
| jbe/bsw@0 | 104 | 
| jbe/bsw@0 | 105 --[[-- | 
| jbe/bsw@0 | 106 bool = -- true, if 'value' is of type 't' | 
| jbe/bsw@0 | 107 atom.has_type( | 
| jbe/bsw@0 | 108 value, -- any value | 
| jbe/bsw@0 | 109 t -- atom time, e.g. atom.date, or lua type, e.g. "string" | 
| jbe/bsw@0 | 110 ) | 
| jbe/bsw@0 | 111 | 
| jbe/bsw@0 | 112 This function checks, if a value is of a given type. The value may be an invalid value though, e.g. atom.date.invalid. | 
| jbe/bsw@0 | 113 | 
| jbe/bsw@0 | 114 --]]-- | 
| jbe/bsw@0 | 115 function has_type(value, t) | 
| jbe/bsw@0 | 116 if t == nil then error("No type passed to has_type(...) function.") end | 
| jbe/bsw@0 | 117 local lua_type = type(value) | 
| jbe/bsw@0 | 118 return | 
| jbe/bsw@0 | 119 lua_type == t or | 
| jbe/bsw@0 | 120 getmetatable(value) == t or | 
| jbe/bsw@0 | 121 (lua_type == "boolean" and t == _M.boolean) or | 
| jbe/bsw@0 | 122 (lua_type == "string" and t == _M.string) or ( | 
| jbe/bsw@0 | 123 lua_type == "number" and | 
| jbe/bsw@0 | 124 (t == _M.number or ( | 
| jbe/bsw@0 | 125 t == _M.integer and ( | 
| jbe/bsw@0 | 126 not (value <= 0 or value >= 0) or ( | 
| jbe/bsw@0 | 127 value % 1 == 0 and | 
| jbe/bsw@0 | 128 (value + 1) - value == 1 and | 
| jbe/bsw@0 | 129 value - (value - 1) == 1 | 
| jbe/bsw@0 | 130 ) | 
| jbe/bsw@0 | 131 ) | 
| jbe/bsw@0 | 132 )) | 
| jbe/bsw@0 | 133 ) | 
| jbe/bsw@0 | 134 end | 
| jbe/bsw@0 | 135 --//-- | 
| jbe/bsw@0 | 136 | 
| jbe/bsw@0 | 137 --[[-- | 
| jbe/bsw@0 | 138 bool = -- true, if 'value' is of type 't' | 
| jbe/bsw@0 | 139 atom.is_valid( | 
| jbe/bsw@0 | 140 value, -- any value | 
| jbe/bsw@0 | 141 t -- atom time, e.g. atom.date, or lua type, e.g. "string" | 
| jbe/bsw@0 | 142 ) | 
| jbe/bsw@0 | 143 | 
| jbe/bsw@0 | 144 This function checks, if a value is valid. It optionally checks, if the value is of a given type. | 
| jbe/bsw@0 | 145 | 
| jbe/bsw@0 | 146 --]]-- | 
| jbe/bsw@0 | 147 function is_valid(value, t) | 
| jbe/bsw@0 | 148 local lua_type = type(value) | 
| jbe/bsw@0 | 149 if lua_type == "table" then | 
| jbe/bsw@0 | 150 local mt = getmetatable(value) | 
| jbe/bsw@0 | 151 if t then | 
| jbe/bsw@0 | 152 return t == mt and not value.invalid | 
| jbe/bsw@0 | 153 else | 
| jbe/bsw@0 | 154 return (getmetatable(mt) == type_mt) and not value.invalid | 
| jbe/bsw@0 | 155 end | 
| jbe/bsw@0 | 156 elseif lua_type == "boolean" then | 
| jbe/bsw@0 | 157 return not t or t == "boolean" or t == _M.boolean | 
| jbe/bsw@0 | 158 elseif lua_type == "string" then | 
| jbe/bsw@0 | 159 return not t or t == "string" or t == _M.string | 
| jbe/bsw@0 | 160 elseif lua_type == "number" then | 
| jbe/bsw@0 | 161 if t == _M.integer then | 
| jbe/bsw@0 | 162 return | 
| jbe/bsw@0 | 163 value % 1 == 0 and | 
| jbe/bsw@0 | 164 (value + 1) - value == 1 and | 
| jbe/bsw@0 | 165 value - (value - 1) == 1 | 
| jbe/bsw@0 | 166 else | 
| jbe/bsw@0 | 167 return | 
| jbe/bsw@0 | 168 (not t or t == "number" or t == _M.number) and | 
| jbe/bsw@0 | 169 (value <= 0 or value >= 0) | 
| jbe/bsw@0 | 170 end | 
| jbe/bsw@0 | 171 else | 
| jbe/bsw@0 | 172 return false | 
| jbe/bsw@0 | 173 end | 
| jbe/bsw@0 | 174 end | 
| jbe/bsw@0 | 175 --//-- | 
| jbe/bsw@0 | 176 | 
| jbe/bsw@0 | 177 end | 
| jbe/bsw@0 | 178 | 
| jbe/bsw@0 | 179 --[[-- | 
| jbe/bsw@0 | 180 string = -- string representation to be passed to a load function | 
| jbe/bsw@0 | 181 atom.dump( | 
| jbe/bsw@0 | 182 value -- value to be dumped | 
| jbe/bsw@0 | 183 ) | 
| jbe/bsw@0 | 184 | 
| jbe/bsw@0 | 185 This function returns a string representation of the given value. | 
| jbe/bsw@0 | 186 | 
| jbe/bsw@0 | 187 --]]-- | 
| jbe/bsw@0 | 188 function dump(obj) | 
| jbe/bsw@0 | 189 if obj == nil then | 
| jbe/bsw@0 | 190 return "" | 
| jbe/bsw@0 | 191 else | 
| jbe/bsw@0 | 192 return tostring(obj) | 
| jbe/bsw@0 | 193 end | 
| jbe/bsw@0 | 194 end | 
| jbe/bsw@0 | 195 --//-- | 
| jbe/bsw@0 | 196 | 
| jbe/bsw@0 | 197 | 
| jbe/bsw@0 | 198 | 
| jbe/bsw@0 | 199 ------------- | 
| jbe/bsw@0 | 200 -- boolean -- | 
| jbe/bsw@0 | 201 ------------- | 
| jbe/bsw@0 | 202 | 
| jbe/bsw@0 | 203 boolean = { name = "boolean" } | 
| jbe/bsw@0 | 204 | 
| jbe/bsw@0 | 205 --[[-- | 
| jbe/bsw@0 | 206 bool = -- true, false, or nil | 
| jbe/bsw@0 | 207 atom.boolean:load( | 
| jbe/bsw@0 | 208 string -- string to be interpreted as boolean | 
| jbe/bsw@0 | 209 ) | 
| jbe/bsw@0 | 210 | 
| jbe/bsw@0 | 211 This method returns true or false or nil, depending on the input string. | 
| jbe/bsw@0 | 212 | 
| jbe/bsw@0 | 213 --]]-- | 
| jbe/bsw@0 | 214 function boolean:load(str) | 
| jbe@1 | 215 if str == nil or str == "" then | 
| jbe@1 | 216 return nil | 
| jbe@1 | 217 elseif type(str) ~= "string" then | 
| jbe/bsw@0 | 218 error("String expected") | 
| jbe/bsw@0 | 219 elseif string.find(str, "^[TtYy1]") then | 
| jbe/bsw@0 | 220 return true | 
| jbe/bsw@0 | 221 elseif string.find(str, "^[FfNn0]") then | 
| jbe/bsw@0 | 222 return false | 
| jbe/bsw@0 | 223 else | 
| jbe/bsw@0 | 224 return nil -- we don't have an undefined bool | 
| jbe/bsw@0 | 225 end | 
| jbe/bsw@0 | 226 end | 
| jbe/bsw@0 | 227 --//-- | 
| jbe/bsw@0 | 228 | 
| jbe/bsw@0 | 229 | 
| jbe/bsw@0 | 230 | 
| jbe/bsw@0 | 231 ------------ | 
| jbe/bsw@0 | 232 -- string -- | 
| jbe/bsw@0 | 233 ------------ | 
| jbe/bsw@0 | 234 | 
| jbe/bsw@0 | 235 _M.string = { name = "string" } | 
| jbe/bsw@0 | 236 | 
| jbe/bsw@0 | 237 --[[-- | 
| jbe/bsw@0 | 238 string = -- the same string | 
| jbe/bsw@0 | 239 atom.string:load( | 
| jbe/bsw@0 | 240 string -- a string | 
| jbe/bsw@0 | 241 ) | 
| jbe/bsw@0 | 242 | 
| jbe/bsw@0 | 243 This method returns the passed string, or throws an error, if the passed argument is not a string. | 
| jbe/bsw@0 | 244 | 
| jbe/bsw@0 | 245 --]]-- | 
| jbe/bsw@0 | 246 function _M.string:load(str) | 
| jbe@1 | 247 if str == nil then | 
| jbe@1 | 248 return nil | 
| jbe@1 | 249 elseif type(str) ~= "string" then | 
| jbe/bsw@0 | 250 error("String expected") | 
| jbe/bsw@0 | 251 else | 
| jbe/bsw@0 | 252 return str | 
| jbe/bsw@0 | 253 end | 
| jbe/bsw@0 | 254 end | 
| jbe/bsw@0 | 255 --//-- | 
| jbe/bsw@0 | 256 | 
| jbe/bsw@0 | 257 | 
| jbe/bsw@0 | 258 | 
| jbe/bsw@0 | 259 ------------- | 
| jbe/bsw@0 | 260 -- integer -- | 
| jbe/bsw@0 | 261 ------------- | 
| jbe/bsw@0 | 262 | 
| jbe/bsw@0 | 263 integer = { name = "integer" } | 
| jbe/bsw@0 | 264 | 
| jbe/bsw@0 | 265 --[[-- | 
| jbe/bsw@0 | 266 int = -- an integer or atom.integer.invalid (atom.not_a_number) | 
| jbe/bsw@0 | 267 atom.integer:load( | 
| jbe/bsw@0 | 268 string -- a string representing an integer | 
| jbe/bsw@0 | 269 ) | 
| jbe/bsw@0 | 270 | 
| jbe/bsw@0 | 271 This method returns an integer represented by the given string. If the string doesn't represent a valid integer, then not-a-number is returned. | 
| jbe/bsw@0 | 272 | 
| jbe/bsw@0 | 273 --]]-- | 
| jbe/bsw@0 | 274 function integer:load(str) | 
| jbe@1 | 275 if str == nil or str == "" then | 
| jbe@1 | 276 return nil | 
| jbe@1 | 277 elseif type(str) ~= "string" then | 
| jbe/bsw@0 | 278 error("String expected") | 
| jbe/bsw@0 | 279 else | 
| jbe/bsw@0 | 280 local num = tonumber(str) | 
| jbe/bsw@0 | 281 if is_integer(num) then return num else return not_a_number end | 
| jbe/bsw@0 | 282 end | 
| jbe/bsw@0 | 283 end | 
| jbe/bsw@0 | 284 --//-- | 
| jbe/bsw@0 | 285 | 
| jbe/bsw@0 | 286 --[[-- | 
| jbe/bsw@0 | 287 atom.integer.invalid | 
| jbe/bsw@0 | 288 | 
| jbe/bsw@0 | 289 This represents an invalid integer. | 
| jbe/bsw@0 | 290 | 
| jbe/bsw@0 | 291 --]]-- | 
| jbe/bsw@0 | 292 integer.invalid = not_a_number | 
| jbe@196 | 293 --//-- | 
| jbe/bsw@0 | 294 | 
| jbe/bsw@0 | 295 | 
| jbe/bsw@0 | 296 | 
| jbe/bsw@0 | 297 ------------ | 
| jbe/bsw@0 | 298 -- number -- | 
| jbe/bsw@0 | 299 ------------ | 
| jbe/bsw@0 | 300 | 
| jbe/bsw@0 | 301 number = create_new_type("number") | 
| jbe/bsw@0 | 302 | 
| jbe/bsw@0 | 303 --[[-- | 
| jbe/bsw@0 | 304 int = -- a number or atom.number.invalid (atom.not_a_number) | 
| jbe/bsw@0 | 305 atom.number:load( | 
| jbe/bsw@0 | 306 string -- a string representing a number | 
| jbe/bsw@0 | 307 ) | 
| jbe/bsw@0 | 308 | 
| jbe/bsw@0 | 309 This method returns a number represented by the given string. If the string doesn't represent a valid number, then not-a-number is returned. | 
| jbe/bsw@0 | 310 | 
| jbe/bsw@0 | 311 --]]-- | 
| jbe/bsw@0 | 312 function number:load(str) | 
| jbe@1 | 313 if str == nil or str == "" then | 
| jbe@1 | 314 return nil | 
| jbe@1 | 315 elseif type(str) ~= "string" then | 
| jbe/bsw@0 | 316 error("String expected") | 
| jbe/bsw@0 | 317 else | 
| jbe/bsw@0 | 318 return tonumber(str) or not_a_number | 
| jbe/bsw@0 | 319 end | 
| jbe/bsw@0 | 320 end | 
| jbe/bsw@0 | 321 --//-- | 
| jbe/bsw@0 | 322 | 
| jbe/bsw@0 | 323 --[[-- | 
| jbe/bsw@0 | 324 atom.number.invalid | 
| jbe/bsw@0 | 325 | 
| jbe/bsw@0 | 326 This represents an invalid number. | 
| jbe/bsw@0 | 327 | 
| jbe/bsw@0 | 328 --]]-- | 
| jbe/bsw@0 | 329 number.invalid = not_a_number | 
| jbe/bsw@0 | 330 --//-- | 
| jbe/bsw@0 | 331 | 
| jbe/bsw@0 | 332 | 
| jbe/bsw@0 | 333 | 
| jbe/bsw@0 | 334 -------------- | 
| jbe/bsw@0 | 335 -- fraction -- | 
| jbe/bsw@0 | 336 -------------- | 
| jbe/bsw@0 | 337 | 
| jbe/bsw@0 | 338 fraction = create_new_type("fraction") | 
| jbe/bsw@0 | 339 | 
| jbe/bsw@0 | 340 --[[-- | 
| jbe/bsw@0 | 341 i = -- the greatest common divisor (GCD) of all given natural numbers | 
| jbe/bsw@0 | 342 atom.gcd( | 
| jbe/bsw@0 | 343 a, -- a natural number | 
| jbe/bsw@0 | 344 b, -- another natural number | 
| jbe/bsw@0 | 345 ... -- optionally more natural numbers | 
| jbe/bsw@0 | 346 ) | 
| jbe/bsw@0 | 347 | 
| jbe/bsw@0 | 348 This function returns the greatest common divisor (GCD) of two or more natural numbers. | 
| jbe/bsw@0 | 349 | 
| jbe/bsw@0 | 350 --]]-- | 
| jbe/bsw@0 | 351 function gcd(a, b, ...) | 
| jbe/bsw@0 | 352 if a % 1 ~= 0 or a <= 0 then return 0 / 0 end | 
| jbe/bsw@0 | 353 if b == nil then | 
| jbe/bsw@0 | 354 return a | 
| jbe/bsw@0 | 355 else | 
| jbe/bsw@0 | 356 if b % 1 ~= 0 or b <= 0 then return 0 / 0 end | 
| jbe/bsw@0 | 357 if ... == nil then | 
| jbe/bsw@0 | 358 local k = 0 | 
| jbe/bsw@0 | 359 local t | 
| jbe/bsw@0 | 360 while a % 2 == 0 and b % 2 == 0 do | 
| jbe/bsw@0 | 361 a = a / 2; b = b / 2; k = k + 1 | 
| jbe/bsw@0 | 362 end | 
| jbe/bsw@0 | 363 if a % 2 == 0 then t = a else t = -b end | 
| jbe/bsw@0 | 364 while t ~= 0 do | 
| jbe/bsw@0 | 365 while t % 2 == 0 do t = t / 2 end | 
| jbe/bsw@0 | 366 if t > 0 then a = t else b = -t end | 
| jbe/bsw@0 | 367 t = a - b | 
| jbe/bsw@0 | 368 end | 
| jbe/bsw@0 | 369 return a * 2 ^ k | 
| jbe/bsw@0 | 370 else | 
| jbe/bsw@0 | 371 return gcd(gcd(a, b), ...) | 
| jbe/bsw@0 | 372 end | 
| jbe/bsw@0 | 373 end | 
| jbe/bsw@0 | 374 end | 
| jbe/bsw@0 | 375 --//-- | 
| jbe/bsw@0 | 376 | 
| jbe/bsw@0 | 377 --[[-- | 
| jbe/bsw@0 | 378 i = --the least common multiple (LCD) of all given natural numbers | 
| jbe/bsw@0 | 379 atom.lcm( | 
| jbe/bsw@0 | 380 a, -- a natural number | 
| jbe/bsw@0 | 381 b, -- another natural number | 
| jbe/bsw@0 | 382 ... -- optionally more natural numbers | 
| jbe/bsw@0 | 383 ) | 
| jbe/bsw@0 | 384 | 
| jbe/bsw@0 | 385 This function returns the least common multiple (LCD) of two or more natural numbers. | 
| jbe/bsw@0 | 386 | 
| jbe/bsw@0 | 387 --]]-- | 
| jbe/bsw@0 | 388 function lcm(a, b, ...) | 
| jbe/bsw@0 | 389 if a % 1 ~= 0 or a <= 0 then return 0 / 0 end | 
| jbe/bsw@0 | 390 if b == nil then | 
| jbe/bsw@0 | 391 return a | 
| jbe/bsw@0 | 392 else | 
| jbe/bsw@0 | 393 if b % 1 ~= 0 or b <= 0 then return 0 / 0 end | 
| jbe/bsw@0 | 394 if ... == nil then | 
| jbe/bsw@0 | 395 return a * b / gcd(a, b) | 
| jbe/bsw@0 | 396 else | 
| jbe/bsw@0 | 397 return lcm(lcm(a, b), ...) | 
| jbe/bsw@0 | 398 end | 
| jbe/bsw@0 | 399 end | 
| jbe/bsw@0 | 400 end | 
| jbe/bsw@0 | 401 --//-- | 
| jbe/bsw@0 | 402 | 
| jbe/bsw@0 | 403 --[[-- | 
| jbe/bsw@0 | 404 atom.fraction.invalid | 
| jbe/bsw@0 | 405 | 
| jbe/bsw@0 | 406 Value representing an invalid fraction. | 
| jbe/bsw@0 | 407 | 
| jbe/bsw@0 | 408 --]]-- | 
| jbe/bsw@0 | 409 fraction.invalid = fraction:_create{ | 
| jbe/bsw@0 | 410 numerator = not_a_number, denominator = not_a_number, invalid = true | 
| jbe/bsw@0 | 411 } | 
| jbe/bsw@0 | 412 --//-- | 
| jbe/bsw@0 | 413 | 
| jbe/bsw@0 | 414 --[[-- | 
| jbe/bsw@0 | 415 frac = -- fraction | 
| jbe/bsw@0 | 416 atom.fraction:new( | 
| jbe/bsw@0 | 417 numerator, -- numerator | 
| jbe/bsw@0 | 418 denominator -- denominator | 
| jbe/bsw@0 | 419 ) | 
| jbe/bsw@0 | 420 | 
| jbe/bsw@0 | 421 This method creates a new fraction. | 
| jbe/bsw@0 | 422 | 
| jbe/bsw@0 | 423 --]]-- | 
| jbe/bsw@0 | 424 function fraction:new(numerator, denominator) | 
| jbe/bsw@0 | 425 if not ( | 
| jbe/bsw@0 | 426 (numerator == nil or type(numerator) == "number") and | 
| jbe/bsw@0 | 427 (denominator == nil or type(denominator) == "number") | 
| jbe/bsw@0 | 428 ) then | 
| jbe/bsw@0 | 429 error("Invalid arguments passed to fraction constructor.") | 
| jbe/bsw@0 | 430 elseif | 
| jbe/bsw@0 | 431 (not is_integer(numerator)) or | 
| jbe/bsw@0 | 432 (denominator and (not is_integer(denominator))) | 
| jbe/bsw@0 | 433 then | 
| jbe/bsw@0 | 434 return fraction.invalid | 
| jbe/bsw@0 | 435 elseif denominator then | 
| jbe/bsw@0 | 436 if denominator == 0 then | 
| jbe/bsw@0 | 437 return fraction.invalid | 
| jbe/bsw@0 | 438 elseif numerator == 0 then | 
| jbe/bsw@0 | 439 return fraction:_create{ numerator = 0, denominator = 1, float = 0 } | 
| jbe/bsw@0 | 440 else | 
| jbe/bsw@0 | 441 local d = gcd(math.abs(numerator), math.abs(denominator)) | 
| jbe/bsw@0 | 442 if denominator < 0 then d = -d end | 
| jbe/bsw@0 | 443 local numerator2, denominator2 = numerator / d, denominator / d | 
| jbe/bsw@0 | 444 return fraction:_create{ | 
| jbe/bsw@0 | 445 numerator = numerator2, | 
| jbe/bsw@0 | 446 denominator = denominator2, | 
| jbe/bsw@0 | 447 float = numerator2 / denominator2 | 
| jbe/bsw@0 | 448 } | 
| jbe/bsw@0 | 449 end | 
| jbe/bsw@0 | 450 else | 
| jbe/bsw@0 | 451 return fraction:_create{ | 
| jbe/bsw@0 | 452 numerator = numerator, denominator = 1, float = numerator | 
| jbe/bsw@0 | 453 } | 
| jbe/bsw@0 | 454 end | 
| jbe/bsw@0 | 455 end | 
| jbe/bsw@0 | 456 --//-- | 
| jbe/bsw@0 | 457 | 
| jbe/bsw@0 | 458 --[[-- | 
| jbe/bsw@0 | 459 frac = -- fraction represented by the given string | 
| jbe/bsw@0 | 460 atom.fraction:load( | 
| jbe/bsw@0 | 461 string -- string representation of a fraction | 
| jbe/bsw@0 | 462 ) | 
| jbe/bsw@0 | 463 | 
| jbe/bsw@0 | 464 This method returns a fraction represented by the given string. | 
| jbe/bsw@0 | 465 | 
| jbe/bsw@0 | 466 --]]-- | 
| jbe/bsw@0 | 467 function fraction:load(str) | 
| jbe@1 | 468 if str == nil or str == "" then | 
| jbe/bsw@0 | 469 return nil | 
| jbe@1 | 470 elseif type(str) ~= "string" then | 
| jbe@1 | 471 error("String expected") | 
| jbe/bsw@0 | 472 else | 
| jbe/bsw@0 | 473 local sign, int = string.match(str, "^(%-?)([0-9]+)$") | 
| jbe/bsw@0 | 474 if sign == "" then return fraction:new(tonumber(int)) | 
| jbe/bsw@0 | 475 elseif sign == "-" then return fraction:new(- tonumber(int)) | 
| jbe/bsw@0 | 476 end | 
| jbe/bsw@0 | 477 local sign, n, d = string.match(str, "^(%-?)([0-9]+)/([0-9]+)$") | 
| jbe/bsw@0 | 478 if sign == "" then return fraction:new(tonumber(n), tonumber(d)) | 
| jbe/bsw@0 | 479 elseif sign == "-" then return fraction:new(- tonumber(n), tonumber(d)) | 
| jbe/bsw@0 | 480 end | 
| jbe/bsw@0 | 481 return fraction.invalid | 
| jbe/bsw@0 | 482 end | 
| jbe/bsw@0 | 483 end | 
| jbe/bsw@0 | 484 --//-- | 
| jbe/bsw@0 | 485 | 
| jbe/bsw@0 | 486 function fraction:__tostring() | 
| jbe/bsw@0 | 487 if self.invalid then | 
| jbe/bsw@0 | 488 return "not_a_fraction" | 
| jbe/bsw@0 | 489 else | 
| jbe/bsw@0 | 490 return self.numerator .. "/" .. self.denominator | 
| jbe/bsw@0 | 491 end | 
| jbe/bsw@0 | 492 end | 
| jbe/bsw@0 | 493 | 
| jbe/bsw@0 | 494 function fraction.__eq(value1, value2) | 
| jbe/bsw@0 | 495 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 496 return false | 
| jbe/bsw@0 | 497 else | 
| jbe/bsw@0 | 498 return | 
| jbe/bsw@0 | 499 value1.numerator == value2.numerator and | 
| jbe/bsw@0 | 500 value1.denominator == value2.denominator | 
| jbe/bsw@0 | 501 end | 
| jbe/bsw@0 | 502 end | 
| jbe/bsw@0 | 503 | 
| jbe/bsw@0 | 504 function fraction.__lt(value1, value2) | 
| jbe/bsw@0 | 505 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 506 return false | 
| jbe/bsw@0 | 507 else | 
| jbe/bsw@0 | 508 return value1.float < value2.float | 
| jbe/bsw@0 | 509 end | 
| jbe/bsw@0 | 510 end | 
| jbe/bsw@0 | 511 | 
| jbe/bsw@0 | 512 function fraction.__le(value1, value2) | 
| jbe/bsw@0 | 513 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 514 return false | 
| jbe/bsw@0 | 515 else | 
| jbe/bsw@0 | 516 return value1.float <= value2.float | 
| jbe/bsw@0 | 517 end | 
| jbe/bsw@0 | 518 end | 
| jbe/bsw@0 | 519 | 
| jbe/bsw@0 | 520 function fraction:__unm() | 
| jbe/bsw@0 | 521 return fraction(-self.numerator, self.denominator) | 
| jbe/bsw@0 | 522 end | 
| jbe/bsw@0 | 523 | 
| jbe/bsw@0 | 524 do | 
| jbe/bsw@0 | 525 | 
| jbe/bsw@0 | 526 local function extract(value1, value2) | 
| jbe/bsw@0 | 527 local n1, d1, n2, d2 | 
| jbe/bsw@0 | 528 if getmetatable(value1) == fraction then | 
| jbe/bsw@0 | 529 n1 = value1.numerator | 
| jbe/bsw@0 | 530 d1 = value1.denominator | 
| jbe/bsw@0 | 531 elseif type(value1) == "number" then | 
| jbe/bsw@0 | 532 n1 = value1 | 
| jbe/bsw@0 | 533 d1 = 1 | 
| jbe/bsw@0 | 534 else | 
| jbe/bsw@0 | 535 error("Left operand of operator has wrong type.") | 
| jbe/bsw@0 | 536 end | 
| jbe/bsw@0 | 537 if getmetatable(value2) == fraction then | 
| jbe/bsw@0 | 538 n2 = value2.numerator | 
| jbe/bsw@0 | 539 d2 = value2.denominator | 
| jbe/bsw@0 | 540 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 541 n2 = value2 | 
| jbe/bsw@0 | 542 d2 = 1 | 
| jbe/bsw@0 | 543 else | 
| jbe/bsw@0 | 544 error("Right operand of operator has wrong type.") | 
| jbe/bsw@0 | 545 end | 
| jbe/bsw@0 | 546 return n1, d1, n2, d2 | 
| jbe/bsw@0 | 547 end | 
| jbe/bsw@0 | 548 | 
| jbe/bsw@0 | 549 function fraction.__add(value1, value2) | 
| jbe/bsw@0 | 550 local n1, d1, n2, d2 = extract(value1, value2) | 
| jbe/bsw@0 | 551 return fraction(n1 * d2 + n2 * d1, d1 * d2) | 
| jbe/bsw@0 | 552 end | 
| jbe/bsw@0 | 553 | 
| jbe/bsw@0 | 554 function fraction.__sub(value1, value2) | 
| jbe/bsw@0 | 555 local n1, d1, n2, d2 = extract(value1, value2) | 
| jbe/bsw@0 | 556 return fraction(n1 * d2 - n2 * d1, d1 * d2) | 
| jbe/bsw@0 | 557 end | 
| jbe/bsw@0 | 558 | 
| jbe/bsw@0 | 559 function fraction.__mul(value1, value2) | 
| jbe/bsw@0 | 560 local n1, d1, n2, d2 = extract(value1, value2) | 
| jbe/bsw@0 | 561 return fraction(n1 * n2, d1 * d2) | 
| jbe/bsw@0 | 562 end | 
| jbe/bsw@0 | 563 | 
| jbe/bsw@0 | 564 function fraction.__div(value1, value2) | 
| jbe/bsw@0 | 565 local n1, d1, n2, d2 = extract(value1, value2) | 
| jbe/bsw@0 | 566 return fraction(n1 * d2, d1 * n2) | 
| jbe/bsw@0 | 567 end | 
| jbe/bsw@0 | 568 | 
| jbe/bsw@0 | 569 function fraction.__pow(value1, value2) | 
| jbe/bsw@0 | 570 local n1, d1, n2, d2 = extract(value1, value2) | 
| jbe/bsw@0 | 571 local n1_abs = math.abs(n1) | 
| jbe/bsw@0 | 572 local d1_abs = math.abs(d1) | 
| jbe/bsw@0 | 573 local n2_abs = math.abs(n2) | 
| jbe/bsw@0 | 574 local d2_abs = math.abs(d2) | 
| jbe/bsw@0 | 575 local numerator, denominator | 
| jbe/bsw@0 | 576 if d2_abs == 1 then | 
| jbe/bsw@0 | 577 numerator = n1_abs | 
| jbe/bsw@0 | 578 denominator = d1_abs | 
| jbe/bsw@0 | 579 else | 
| jbe/bsw@0 | 580 numerator = 0 | 
| jbe/bsw@0 | 581 while true do | 
| jbe/bsw@0 | 582 local t = numerator ^ d2_abs | 
| jbe/bsw@0 | 583 if t == n1_abs then break end | 
| jbe/bsw@0 | 584 if not (t < n1_abs) then return value1.float / value2.float end | 
| jbe/bsw@0 | 585 numerator = numerator + 1 | 
| jbe/bsw@0 | 586 end | 
| jbe/bsw@0 | 587 denominator = 1 | 
| jbe/bsw@0 | 588 while true do | 
| jbe/bsw@0 | 589 local t = denominator ^ d2_abs | 
| jbe/bsw@0 | 590 if t == d1_abs then break end | 
| jbe/bsw@0 | 591 if not (t < d1_abs) then return value1.float / value2.float end | 
| jbe/bsw@0 | 592 denominator = denominator + 1 | 
| jbe/bsw@0 | 593 end | 
| jbe/bsw@0 | 594 end | 
| jbe/bsw@0 | 595 if n1 < 0 then | 
| jbe/bsw@0 | 596 if d2_abs % 2 == 1 then | 
| jbe/bsw@0 | 597 numerator = -numerator | 
| jbe/bsw@0 | 598 else | 
| jbe/bsw@0 | 599 return fraction.invalid | 
| jbe/bsw@0 | 600 end | 
| jbe/bsw@0 | 601 end | 
| jbe/bsw@0 | 602 if n2 < 0 then | 
| jbe/bsw@0 | 603 numerator, denominator = denominator, numerator | 
| jbe/bsw@0 | 604 end | 
| jbe/bsw@0 | 605 return fraction(numerator ^ n2_abs, denominator ^ n2_abs) | 
| jbe/bsw@0 | 606 end | 
| jbe/bsw@0 | 607 | 
| jbe/bsw@0 | 608 end | 
| jbe/bsw@0 | 609 | 
| jbe/bsw@0 | 610 | 
| jbe/bsw@0 | 611 | 
| jbe/bsw@0 | 612 ---------- | 
| jbe/bsw@0 | 613 -- date -- | 
| jbe/bsw@0 | 614 ---------- | 
| jbe/bsw@0 | 615 | 
| jbe/bsw@0 | 616 date = create_new_type("date") | 
| jbe/bsw@0 | 617 | 
| jbe/bsw@0 | 618 do | 
| jbe/bsw@0 | 619 local c1 = 365 -- days of a non-leap year | 
| jbe/bsw@0 | 620 local c4 = 4 * c1 + 1 -- days of a full 4 year cycle | 
| jbe/bsw@0 | 621 local c100 = 25 * c4 - 1 -- days of a full 100 year cycle | 
| jbe/bsw@0 | 622 local c400 = 4 * c100 + 1 -- days of a full 400 year cycle | 
| jbe/bsw@0 | 623 local get_month_offset -- function returning days elapsed within | 
| jbe/bsw@0 | 624 -- the given year until the given month | 
| jbe/bsw@0 | 625 -- (exclusive the given month) | 
| jbe/bsw@0 | 626 do | 
| jbe/bsw@0 | 627 local normal_month_offsets = {} | 
| jbe/bsw@0 | 628 local normal_month_lengths = { | 
| jbe/bsw@0 | 629 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | 
| jbe/bsw@0 | 630 } | 
| jbe/bsw@0 | 631 local sum = 0 | 
| jbe/bsw@0 | 632 for i = 1, 12 do | 
| jbe/bsw@0 | 633 normal_month_offsets[i] = sum | 
| jbe/bsw@0 | 634 sum = sum + normal_month_lengths[i] | 
| jbe/bsw@0 | 635 end | 
| jbe/bsw@0 | 636 function get_month_offset(year, month) | 
| jbe/bsw@0 | 637 if | 
| jbe/bsw@0 | 638 (((year % 4 == 0) and not (year % 100 == 0)) or (year % 400 == 0)) | 
| jbe/bsw@0 | 639 and month > 2 | 
| jbe/bsw@0 | 640 then | 
| jbe/bsw@0 | 641 return normal_month_offsets[month] + 1 | 
| jbe/bsw@0 | 642 else | 
| jbe/bsw@0 | 643 return normal_month_offsets[month] | 
| jbe/bsw@0 | 644 end | 
| jbe/bsw@0 | 645 end | 
| jbe/bsw@0 | 646 end | 
| jbe/bsw@0 | 647 | 
| jbe/bsw@0 | 648 --[[-- | 
| jbe/bsw@0 | 649 jd = -- days from January 1st 1970 | 
| jbe/bsw@0 | 650 atom.date.ymd_to_jd( | 
| jbe/bsw@0 | 651 year, -- year | 
| jbe/bsw@0 | 652 month, -- month from 1 to 12 | 
| jbe/bsw@0 | 653 day -- day from 1 to 31 | 
| jbe/bsw@0 | 654 ) | 
| jbe/bsw@0 | 655 | 
| jbe/bsw@0 | 656 This function calculates the days from January 1st 1970 for a given year, month and day. | 
| jbe/bsw@0 | 657 | 
| jbe/bsw@0 | 658 --]]-- | 
| jbe/bsw@0 | 659 local offset = 0 | 
| jbe/bsw@0 | 660 function date.ymd_to_jd(year, month, day) | 
| jbe/bsw@0 | 661 assert(is_integer(year), "Invalid year specified.") | 
| jbe/bsw@0 | 662 assert(is_integer(month), "Invalid month specified.") | 
| jbe/bsw@0 | 663 assert(is_integer(day), "Invalid day specified.") | 
| jbe/bsw@0 | 664 local calc_year = year - 1 | 
| jbe/bsw@0 | 665 local n400 = math.floor(calc_year / 400) | 
| jbe/bsw@0 | 666 local r400 = calc_year % 400 | 
| jbe/bsw@0 | 667 local n100 = math.floor(r400 / 100) | 
| jbe/bsw@0 | 668 local r100 = r400 % 100 | 
| jbe/bsw@0 | 669 local n4 = math.floor(r100 / 4) | 
| jbe/bsw@0 | 670 local n1 = r100 % 4 | 
| jbe/bsw@0 | 671 local jd = ( | 
| jbe/bsw@0 | 672 c400 * n400 + c100 * n100 + c4 * n4 + c1 * n1 + | 
| jbe/bsw@0 | 673 get_month_offset(year, month) + (day - 1) | 
| jbe/bsw@0 | 674 ) | 
| jbe/bsw@0 | 675 return jd - offset | 
| jbe/bsw@0 | 676 end | 
| jbe/bsw@0 | 677 offset = date.ymd_to_jd(1970, 1, 1) | 
| jbe/bsw@0 | 678 --//-- | 
| jbe/bsw@0 | 679 | 
| jbe/bsw@0 | 680 --[[-- | 
| jbe/bsw@0 | 681 year, -- year | 
| jbe/bsw@0 | 682 month, -- month from 1 to 12 | 
| jbe/bsw@0 | 683 day = -- day from 1 to 31 | 
| jbe/bsw@0 | 684 atom.date.jd_to_ymd( | 
| jbe/bsw@0 | 685 jd, -- days from January 1st 1970 | 
| jbe/bsw@0 | 686 ) | 
| jbe/bsw@0 | 687 | 
| jbe/bsw@0 | 688 Given the days from January 1st 1970 this function returns year, month and day. | 
| jbe/bsw@0 | 689 | 
| jbe/bsw@0 | 690 --]]-- | 
| jbe/bsw@0 | 691 function date.jd_to_ymd(jd) | 
| jbe/bsw@0 | 692 assert(is_integer(jd), "Invalid julian date specified.") | 
| jbe/bsw@0 | 693 local calc_jd = jd + offset | 
| jbe/bsw@0 | 694 assert(is_integer(calc_jd), "Julian date is out of range.") | 
| jbe/bsw@0 | 695 local n400 = math.floor(calc_jd / c400) | 
| jbe/bsw@0 | 696 local r400 = calc_jd % c400 | 
| jbe/bsw@0 | 697 local n100 = math.floor(r400 / c100) | 
| jbe/bsw@0 | 698 local r100 = r400 % c100 | 
| jbe/bsw@0 | 699 if n100 == 4 then n100, r100 = 3, c100 end | 
| jbe/bsw@0 | 700 local n4 = math.floor(r100 / c4) | 
| jbe/bsw@0 | 701 local r4 = r100 % c4 | 
| jbe/bsw@0 | 702 local n1 = math.floor(r4 / c1) | 
| jbe/bsw@0 | 703 local r1 = r4 % c1 | 
| jbe/bsw@0 | 704 if n1 == 4 then n1, r1 = 3, c1 end | 
| jbe/bsw@0 | 705 local year = 1 + 400 * n400 + 100 * n100 + 4 * n4 + n1 | 
| jbe/bsw@0 | 706 local month = 1 + math.floor(r1 / 31) | 
| jbe/bsw@0 | 707 local month_offset = get_month_offset(year, month) | 
| jbe/bsw@0 | 708 if month < 12 then | 
| jbe/bsw@0 | 709 local next_month_offset = get_month_offset(year, month + 1) | 
| jbe/bsw@0 | 710 if r1 >= next_month_offset then | 
| jbe/bsw@0 | 711 month = month + 1 | 
| jbe/bsw@0 | 712 month_offset = next_month_offset | 
| jbe/bsw@0 | 713 end | 
| jbe/bsw@0 | 714 end | 
| jbe/bsw@0 | 715 local day = 1 + r1 - month_offset | 
| jbe/bsw@0 | 716 return year, month, day | 
| jbe/bsw@0 | 717 end | 
| jbe/bsw@0 | 718 --//-- | 
| jbe/bsw@0 | 719 end | 
| jbe/bsw@0 | 720 | 
| jbe/bsw@0 | 721 --[[-- | 
| jbe/bsw@0 | 722 atom.date.invalid | 
| jbe/bsw@0 | 723 | 
| jbe/bsw@0 | 724 Value representing an invalid date. | 
| jbe/bsw@0 | 725 | 
| jbe/bsw@0 | 726 --]]-- | 
| jbe/bsw@0 | 727 date.invalid = date:_create{ | 
| jbe/bsw@0 | 728 jd = not_a_number, | 
| jbe/bsw@0 | 729 year = not_a_number, month = not_a_number, day = not_a_number, | 
| jbe/bsw@0 | 730 invalid = true | 
| jbe/bsw@0 | 731 } | 
| jbe/bsw@0 | 732 --//-- | 
| jbe/bsw@0 | 733 | 
| jbe/bsw@0 | 734 --[[-- | 
| jbe/bsw@0 | 735 d = -- date based on the given data | 
| jbe/bsw@0 | 736 atom.date:new{ | 
| jbe/bsw@0 | 737 jd = jd, -- days since January 1st 1970 | 
| jbe/bsw@0 | 738 year = year, -- year | 
| jbe/bsw@0 | 739 month = month, -- month from 1 to 12 | 
| jbe/bsw@0 | 740 day = day, -- day from 1 to 31 | 
| jbe/bsw@0 | 741 iso_weekyear = iso_weekyear, -- year according to ISO 8601 | 
| jbe/bsw@0 | 742 iso_week = iso_week, -- week number according to ISO 8601 | 
| jbe/bsw@0 | 743 iso_weekday = iso_weekday, -- day of week from 1 for monday to 7 for sunday | 
| jbe/bsw@0 | 744 us_weekyear = us_weekyear, -- year | 
| jbe/bsw@0 | 745 us_week = us_week, -- week number according to US style counting | 
| jbe/bsw@0 | 746 us_weekday = us_weekday -- day of week from 1 for sunday to 7 for saturday | 
| jbe/bsw@0 | 747 } | 
| jbe/bsw@0 | 748 | 
| jbe/bsw@0 | 749 This method returns a new date value, based on given data. | 
| jbe/bsw@0 | 750 | 
| jbe/bsw@0 | 751 --]]-- | 
| jbe/bsw@0 | 752 function date:new(args) | 
| jbe/bsw@0 | 753 local args = args | 
| jbe/bsw@0 | 754 if type(args) == "number" then args = { jd = args } end | 
| jbe/bsw@0 | 755 if type(args) == "table" then | 
| jbe/bsw@0 | 756 local year, month, day = args.year, args.month, args.day | 
| jbe/bsw@0 | 757 local jd = args.jd | 
| jbe/bsw@0 | 758 local iso_weekyear = args.iso_weekyear | 
| jbe/bsw@0 | 759 local iso_week = args.iso_week | 
| jbe/bsw@0 | 760 local iso_weekday = args.iso_weekday | 
| jbe/bsw@0 | 761 local us_week = args.us_week | 
| jbe/bsw@0 | 762 local us_weekday = args.us_weekday | 
| jbe/bsw@0 | 763 if | 
| jbe/bsw@0 | 764 type(year) == "number" and | 
| jbe/bsw@0 | 765 type(month) == "number" and | 
| jbe/bsw@0 | 766 type(day) == "number" | 
| jbe/bsw@0 | 767 then | 
| jbe/bsw@0 | 768 if | 
| jbe/bsw@0 | 769 is_integer(year) and year >= 1 and year <= 9999 and | 
| jbe/bsw@0 | 770 is_integer(month) and month >= 1 and month <= 12 and | 
| jbe/bsw@0 | 771 is_integer(day) and day >= 1 and day <= 31 | 
| jbe/bsw@0 | 772 then | 
| jbe/bsw@0 | 773 return date:_create{ | 
| jbe/bsw@0 | 774 jd = date.ymd_to_jd(year, month, day), | 
| jbe/bsw@0 | 775 year = year, month = month, day = day | 
| jbe/bsw@0 | 776 } | 
| jbe/bsw@0 | 777 else | 
| jbe/bsw@0 | 778 return date.invalid | 
| jbe/bsw@0 | 779 end | 
| jbe/bsw@0 | 780 elseif type(jd) == "number" then | 
| jbe/bsw@0 | 781 if is_integer(jd) and jd >= -719162 and jd <= 2932896 then | 
| jbe/bsw@0 | 782 local year, month, day = date.jd_to_ymd(jd) | 
| jbe/bsw@0 | 783 return date:_create{ | 
| jbe/bsw@0 | 784 jd = jd, year = year, month = month, day = day | 
| jbe/bsw@0 | 785 } | 
| jbe/bsw@0 | 786 else | 
| jbe/bsw@0 | 787 return date.invalid | 
| jbe/bsw@0 | 788 end | 
| jbe/bsw@0 | 789 elseif | 
| jbe/bsw@0 | 790 type(year) == "number" and not iso_weekyear and | 
| jbe/bsw@0 | 791 type(iso_week) == "number" and | 
| jbe/bsw@0 | 792 type(iso_weekday) == "number" | 
| jbe/bsw@0 | 793 then | 
| jbe/bsw@0 | 794 if | 
| jbe/bsw@0 | 795 is_integer(year) and | 
| jbe/bsw@0 | 796 is_integer(iso_week) and iso_week >= 0 and iso_week <= 53 and | 
| jbe/bsw@0 | 797 is_integer(iso_weekday) and iso_weekday >= 1 and iso_weekday <= 7 | 
| jbe/bsw@0 | 798 then | 
| jbe/bsw@0 | 799 local jan4 = date{ year = year, month = 1, day = 4 } | 
| jbe/bsw@0 | 800 local reference = jan4 - jan4.iso_weekday - 7 -- Sun. of week -1 | 
| jbe/bsw@0 | 801 return date(reference + 7 * iso_week + iso_weekday) | 
| jbe/bsw@0 | 802 else | 
| jbe/bsw@0 | 803 return date.invalid | 
| jbe/bsw@0 | 804 end | 
| jbe/bsw@0 | 805 elseif | 
| jbe/bsw@0 | 806 type(iso_weekyear) == "number" and not year and | 
| jbe/bsw@0 | 807 type(iso_week) == "number" and | 
| jbe/bsw@0 | 808 type(iso_weekday) == "number" | 
| jbe/bsw@0 | 809 then | 
| jbe/bsw@0 | 810 if | 
| jbe/bsw@0 | 811 is_integer(iso_weekyear) and | 
| jbe/bsw@0 | 812 is_integer(iso_week) and iso_week >= 0 and iso_week <= 53 and | 
| jbe/bsw@0 | 813 is_integer(iso_weekday) and iso_weekday >= 1 and iso_weekday <= 7 | 
| jbe/bsw@0 | 814 then | 
| jbe/bsw@0 | 815 local guessed = date{ | 
| jbe/bsw@0 | 816 year = iso_weekyear, | 
| jbe/bsw@0 | 817 iso_week = iso_week, | 
| jbe/bsw@0 | 818 iso_weekday = iso_weekday | 
| jbe/bsw@0 | 819 } | 
| jbe/bsw@0 | 820 if guessed.invalid or guessed.iso_weekyear == iso_weekyear then | 
| jbe/bsw@0 | 821 return guessed | 
| jbe/bsw@0 | 822 else | 
| jbe/bsw@0 | 823 local year | 
| jbe/bsw@0 | 824 if iso_week <= 1 then | 
| jbe/bsw@0 | 825 year = iso_weekyear - 1 | 
| jbe/bsw@0 | 826 elseif iso_week >= 52 then | 
| jbe/bsw@0 | 827 year = iso_weekyear + 1 | 
| jbe/bsw@0 | 828 else | 
| jbe/bsw@0 | 829 error("Internal error in ISO week computation occured.") | 
| jbe/bsw@0 | 830 end | 
| jbe/bsw@0 | 831 return date{ | 
| jbe/bsw@0 | 832 year = year, iso_week = iso_week, iso_weekday = iso_weekday | 
| jbe/bsw@0 | 833 } | 
| jbe/bsw@0 | 834 end | 
| jbe/bsw@0 | 835 else | 
| jbe/bsw@0 | 836 return date.invalid | 
| jbe/bsw@0 | 837 end | 
| jbe/bsw@0 | 838 elseif | 
| jbe/bsw@0 | 839 type(year) == "number" and | 
| jbe/bsw@0 | 840 type(us_week) == "number" and | 
| jbe/bsw@0 | 841 type(us_weekday) == "number" | 
| jbe/bsw@0 | 842 then | 
| jbe/bsw@0 | 843 if | 
| jbe/bsw@0 | 844 is_integer(year) and | 
| jbe/bsw@0 | 845 is_integer(us_week) and us_week >= 0 and us_week <= 54 and | 
| jbe/bsw@0 | 846 is_integer(us_weekday) and us_weekday >= 1 and us_weekday <= 7 | 
| jbe/bsw@0 | 847 then | 
| jbe/bsw@0 | 848 local jan1 = date{ year = year, month = 1, day = 1 } | 
| jbe/bsw@0 | 849 local reference = jan1 - jan1.us_weekday - 7 -- Sat. of week -1 | 
| jbe/bsw@0 | 850 return date(reference + 7 * us_week + us_weekday) | 
| jbe/bsw@0 | 851 else | 
| jbe/bsw@0 | 852 return date.invalid | 
| jbe/bsw@0 | 853 end | 
| jbe/bsw@0 | 854 end | 
| jbe/bsw@0 | 855 end | 
| jbe/bsw@0 | 856 error("Illegal arguments passed to date constructor.") | 
| jbe/bsw@0 | 857 end | 
| jbe/bsw@0 | 858 --//-- | 
| jbe/bsw@0 | 859 | 
| jbe/bsw@0 | 860 --[[-- | 
| jbe/bsw@0 | 861 atom.date:get_current() | 
| jbe/bsw@0 | 862 | 
| jbe/bsw@0 | 863 This function returns today's date. | 
| jbe/bsw@0 | 864 | 
| jbe/bsw@0 | 865 --]]-- | 
| jbe/bsw@0 | 866 function date:get_current() | 
| jbe/bsw@0 | 867 local now = os.date("*t") | 
| jbe/bsw@0 | 868 return date{ | 
| jbe/bsw@0 | 869 year = now.year, month = now.month, day = now.day | 
| jbe/bsw@0 | 870 } | 
| jbe/bsw@0 | 871 end | 
| jbe/bsw@0 | 872 --//-- | 
| jbe/bsw@0 | 873 | 
| jbe/bsw@0 | 874 --[[-- | 
| jbe/bsw@0 | 875 date = -- date represented by the string | 
| jbe/bsw@0 | 876 atom.date:load( | 
| jbe/bsw@0 | 877 string -- string representing a date | 
| jbe/bsw@0 | 878 ) | 
| jbe/bsw@0 | 879 | 
| jbe/bsw@0 | 880 This method returns a date represented by the given string. | 
| jbe/bsw@0 | 881 | 
| jbe/bsw@0 | 882 --]]-- | 
| jbe/bsw@0 | 883 function date:load(str) | 
| jbe@1 | 884 if str == nil or str == "" then | 
| jbe/bsw@0 | 885 return nil | 
| jbe@1 | 886 elseif type(str) ~= "string" then | 
| jbe@1 | 887 error("String expected") | 
| jbe/bsw@0 | 888 else | 
| jbe/bsw@0 | 889 local year, month, day = string.match( | 
| jbe/bsw@0 | 890 str, "^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$" | 
| jbe/bsw@0 | 891 ) | 
| jbe/bsw@0 | 892 if year then | 
| jbe/bsw@0 | 893 return date{ | 
| jbe/bsw@0 | 894 year = tonumber(year), | 
| jbe/bsw@0 | 895 month = tonumber(month), | 
| jbe/bsw@0 | 896 day = tonumber(day) | 
| jbe/bsw@0 | 897 } | 
| jbe/bsw@0 | 898 else | 
| jbe/bsw@0 | 899 return date.invalid | 
| jbe/bsw@0 | 900 end | 
| jbe/bsw@0 | 901 end | 
| jbe/bsw@0 | 902 end | 
| jbe/bsw@0 | 903 --//-- | 
| jbe/bsw@0 | 904 | 
| jbe/bsw@0 | 905 function date:__tostring() | 
| jbe/bsw@0 | 906 if self.invalid then | 
| jbe/bsw@0 | 907 return "invalid_date" | 
| jbe/bsw@0 | 908 else | 
| jbe/bsw@0 | 909 return string.format( | 
| jbe/bsw@0 | 910 "%04i-%02i-%02i", self.year, self.month, self.day | 
| jbe/bsw@0 | 911 ) | 
| jbe/bsw@0 | 912 end | 
| jbe/bsw@0 | 913 end | 
| jbe/bsw@0 | 914 | 
| jbe/bsw@0 | 915 function date.getters:midnight() | 
| jbe@90 | 916 return timestamp{ year = self.year, month = self.month, day = self.day } | 
| jbe/bsw@0 | 917 end | 
| jbe/bsw@0 | 918 | 
| jbe/bsw@0 | 919 function date.getters:midday() | 
| jbe@90 | 920 return timestamp{ | 
| jbe/bsw@0 | 921 year = self.year, month = self.month, day = self.day, | 
| jbe/bsw@0 | 922 hour = 12 | 
| jbe/bsw@0 | 923 } | 
| jbe/bsw@0 | 924 end | 
| jbe/bsw@0 | 925 | 
| jbe/bsw@0 | 926 function date.getters:iso_weekday() -- 1 = Monday | 
| jbe/bsw@0 | 927 return (self.jd + 3) % 7 + 1 | 
| jbe/bsw@0 | 928 end | 
| jbe/bsw@0 | 929 | 
| jbe/bsw@0 | 930 function date.getters:us_weekday() -- 1 = Sunday | 
| jbe/bsw@0 | 931 return (self.jd + 4) % 7 + 1 | 
| jbe/bsw@0 | 932 end | 
| jbe/bsw@0 | 933 | 
| jbe/bsw@0 | 934 function date.getters:iso_weekyear() -- ISO week-numbering year | 
| jbe/bsw@0 | 935 local year, month, day = self.year, self.month, self.day | 
| jbe/bsw@0 | 936 local iso_weekday = self.iso_weekday | 
| jbe/bsw@0 | 937 if month == 1 then | 
| jbe/bsw@0 | 938 if | 
| jbe/bsw@0 | 939 (day == 3 and iso_weekday == 7) or | 
| jbe/bsw@0 | 940 (day == 2 and iso_weekday >= 6) or | 
| jbe/bsw@0 | 941 (day == 1 and iso_weekday >= 5) | 
| jbe/bsw@0 | 942 then | 
| jbe/bsw@0 | 943 return year - 1 | 
| jbe/bsw@0 | 944 end | 
| jbe/bsw@0 | 945 elseif month == 12 then | 
| jbe/bsw@0 | 946 if | 
| jbe/bsw@0 | 947 (day == 29 and iso_weekday == 1) or | 
| jbe/bsw@0 | 948 (day == 30 and iso_weekday <= 2) or | 
| jbe/bsw@0 | 949 (day == 31 and iso_weekday <= 3) | 
| jbe/bsw@0 | 950 then | 
| jbe/bsw@0 | 951 return year + 1 | 
| jbe/bsw@0 | 952 end | 
| jbe/bsw@0 | 953 end | 
| jbe/bsw@0 | 954 return year | 
| jbe/bsw@0 | 955 end | 
| jbe/bsw@0 | 956 | 
| jbe/bsw@0 | 957 function date.getters:iso_week() | 
| jbe/bsw@0 | 958 local jan4 = date{ year = self.iso_weekyear, month = 1, day = 4 } | 
| jbe/bsw@0 | 959 local reference = jan4.jd - jan4.iso_weekday - 6 -- monday of week 0 | 
| jbe/bsw@0 | 960 return math.floor((self.jd - reference) / 7) | 
| jbe/bsw@0 | 961 end | 
| jbe/bsw@0 | 962 | 
| jbe/bsw@0 | 963 function date.getters:us_week() | 
| jbe/bsw@0 | 964 local jan1 = date{ year = self.year, month = 1, day = 1 } | 
| jbe/bsw@0 | 965 local reference = jan1.jd - jan1.us_weekday - 6 -- sunday of week 0 | 
| jbe/bsw@0 | 966 return math.floor((self.jd - reference) / 7) | 
| jbe/bsw@0 | 967 end | 
| jbe/bsw@0 | 968 | 
| jbe/bsw@0 | 969 function date.__eq(value1, value2) | 
| jbe/bsw@0 | 970 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 971 return false | 
| jbe/bsw@0 | 972 else | 
| jbe/bsw@0 | 973 return value1.jd == value2.jd | 
| jbe/bsw@0 | 974 end | 
| jbe/bsw@0 | 975 end | 
| jbe/bsw@0 | 976 | 
| jbe/bsw@0 | 977 function date.__lt(value1, value2) | 
| jbe/bsw@0 | 978 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 979 return false | 
| jbe/bsw@0 | 980 else | 
| jbe/bsw@0 | 981 return value1.jd < value2.jd | 
| jbe/bsw@0 | 982 end | 
| jbe/bsw@0 | 983 end | 
| jbe/bsw@0 | 984 | 
| jbe/bsw@0 | 985 function date.__le(value1, value2) | 
| jbe/bsw@0 | 986 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 987 return false | 
| jbe/bsw@0 | 988 else | 
| jbe/bsw@0 | 989 return value1.jd <= value2.jd | 
| jbe/bsw@0 | 990 end | 
| jbe/bsw@0 | 991 end | 
| jbe/bsw@0 | 992 | 
| jbe/bsw@0 | 993 function date.__add(value1, value2) | 
| jbe/bsw@0 | 994 if getmetatable(value1) == date then | 
| jbe/bsw@0 | 995 if getmetatable(value2) == date then | 
| jbe/bsw@0 | 996 error("Can not add two dates.") | 
| jbe/bsw@0 | 997 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 998 return date(value1.jd + value2) | 
| jbe/bsw@0 | 999 else | 
| jbe/bsw@0 | 1000 error("Right operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1001 end | 
| jbe/bsw@0 | 1002 elseif type(value1) == "number" then | 
| jbe/bsw@0 | 1003 if getmetatable(value2) == date then | 
| jbe/bsw@0 | 1004 return date(value1 + value2.jd) | 
| jbe/bsw@0 | 1005 else | 
| jbe/bsw@0 | 1006 error("Assertion failed") | 
| jbe/bsw@0 | 1007 end | 
| jbe/bsw@0 | 1008 else | 
| jbe/bsw@0 | 1009 error("Left operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1010 end | 
| jbe/bsw@0 | 1011 end | 
| jbe/bsw@0 | 1012 | 
| jbe/bsw@0 | 1013 function date.__sub(value1, value2) | 
| jbe/bsw@0 | 1014 if not getmetatable(value1) == date then | 
| jbe/bsw@0 | 1015 error("Left operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1016 end | 
| jbe/bsw@0 | 1017 if getmetatable(value2) == date then | 
| jbe@107 | 1018 return value1.jd - value2.jd -- TODO: transform to interval | 
| jbe/bsw@0 | 1019 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 1020 return date(value1.jd - value2) | 
| jbe/bsw@0 | 1021 else | 
| jbe/bsw@0 | 1022 error("Right operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1023 end | 
| jbe/bsw@0 | 1024 end | 
| jbe/bsw@0 | 1025 | 
| jbe/bsw@0 | 1026 | 
| jbe/bsw@0 | 1027 | 
| jbe/bsw@0 | 1028 --------------- | 
| jbe/bsw@0 | 1029 -- timestamp -- | 
| jbe/bsw@0 | 1030 --------------- | 
| jbe/bsw@0 | 1031 | 
| jbe/bsw@0 | 1032 timestamp = create_new_type("timestamp") | 
| jbe/bsw@0 | 1033 | 
| jbe/bsw@0 | 1034 --[[-- | 
| jbe/bsw@0 | 1035 tsec = -- seconds since January 1st 1970 00:00 | 
| jbe/bsw@0 | 1036 atom.timestamp.ymdhms_to_tsec( | 
| jbe/bsw@0 | 1037 year, -- year | 
| jbe/bsw@0 | 1038 month, -- month from 1 to 12 | 
| jbe/bsw@0 | 1039 day, -- day from 1 to 31 | 
| jbe/bsw@0 | 1040 hour, -- hour from 0 to 23 | 
| jbe/bsw@0 | 1041 minute, -- minute from 0 to 59 | 
| jbe/bsw@0 | 1042 second -- second from 0 to 59 | 
| jbe/bsw@0 | 1043 ) | 
| jbe/bsw@0 | 1044 | 
| jbe/bsw@0 | 1045 Given the year, month, day, hour, minute and second, this function returns the number of seconds since January 1st 1970 00:00. | 
| jbe/bsw@0 | 1046 | 
| jbe/bsw@0 | 1047 --]]-- | 
| jbe/bsw@0 | 1048 function timestamp.ymdhms_to_tsec(year, month, day, hour, minute, second) | 
| jbe/bsw@0 | 1049 return | 
| jbe/bsw@0 | 1050 86400 * date.ymd_to_jd(year, month, day) + | 
| jbe/bsw@0 | 1051 3600 * hour + 60 * minute + second | 
| jbe/bsw@0 | 1052 end | 
| jbe/bsw@0 | 1053 --//-- | 
| jbe/bsw@0 | 1054 | 
| jbe/bsw@0 | 1055 --[[-- | 
| jbe/bsw@0 | 1056 year, -- year | 
| jbe/bsw@0 | 1057 month, -- month from 1 to 12 | 
| jbe/bsw@0 | 1058 day, -- day from 1 to 31 | 
| jbe/bsw@0 | 1059 hour, -- hour from 0 to 23 | 
| jbe/bsw@0 | 1060 minute, -- minute from 0 to 59 | 
| jbe/bsw@0 | 1061 second = -- second from 0 to 59 | 
| jbe/bsw@0 | 1062 atom.timestamp.tsec_to_ymdhms( | 
| jbe/bsw@0 | 1063 tsec -- seconds since January 1st 1970 00:00 | 
| jbe/bsw@0 | 1064 ) | 
| jbe/bsw@0 | 1065 | 
| jbe/bsw@0 | 1066 Given the seconds since January 1st 1970 00:00, this function returns the year, month, day, hour, minute and second. | 
| jbe/bsw@0 | 1067 | 
| jbe/bsw@0 | 1068 --]]-- | 
| jbe/bsw@0 | 1069 function timestamp.tsec_to_ymdhms(tsec) | 
| jbe/bsw@0 | 1070 local jd = math.floor(tsec / 86400) | 
| jbe/bsw@0 | 1071 local dsec = tsec % 86400 | 
| jbe/bsw@0 | 1072 local year, month, day = date.jd_to_ymd(jd) | 
| jbe/bsw@0 | 1073 local hour = math.floor(dsec / 3600) | 
| jbe/bsw@0 | 1074 local minute = math.floor((dsec % 3600) / 60) | 
| jbe/bsw@0 | 1075 local second = dsec % 60 | 
| jbe/bsw@0 | 1076 return year, month, day, hour, minute, second | 
| jbe/bsw@0 | 1077 end | 
| jbe/bsw@0 | 1078 --//-- | 
| jbe/bsw@0 | 1079 | 
| jbe/bsw@0 | 1080 --[[-- | 
| jbe@320 | 1081 atom.timestamp.invalid | 
| jbe/bsw@0 | 1082 | 
| jbe/bsw@0 | 1083 Value representing an invalid timestamp. | 
| jbe/bsw@0 | 1084 | 
| jbe/bsw@0 | 1085 --]]-- | 
| jbe/bsw@0 | 1086 timestamp.invalid = timestamp:_create{ | 
| jbe/bsw@0 | 1087 tsec = not_a_number, | 
| jbe/bsw@0 | 1088 year = not_a_number, month = not_a_number, day = not_a_number, | 
| jbe/bsw@0 | 1089 hour = not_a_number, minute = not_a_number, second = not_a_number, | 
| jbe/bsw@0 | 1090 invalid = true | 
| jbe/bsw@0 | 1091 } | 
| jbe/bsw@0 | 1092 --//-- | 
| jbe/bsw@0 | 1093 | 
| jbe/bsw@0 | 1094 --[[-- | 
| jbe/bsw@0 | 1095 ts = -- timestamp based on given data | 
| jbe/bsw@0 | 1096 atom.timestamp:new{ | 
| jbe/bsw@0 | 1097 tsec = tsec, -- seconds since January 1st 1970 00:00 | 
| jbe/bsw@0 | 1098 year = year, -- year | 
| jbe/bsw@0 | 1099 month = month, -- month from 1 to 12 | 
| jbe/bsw@0 | 1100 day = day, -- day from 1 to 31 | 
| jbe/bsw@0 | 1101 hour = hour, -- hour from 0 to 23 | 
| jbe/bsw@0 | 1102 minute = minute, -- minute from 0 to 59 | 
| jbe/bsw@0 | 1103 second = second -- second from 0 to 59 | 
| jbe/bsw@0 | 1104 } | 
| jbe/bsw@0 | 1105 | 
| jbe/bsw@0 | 1106 This method returns a new timestamp value, based on given data. | 
| jbe/bsw@0 | 1107 | 
| jbe/bsw@0 | 1108 --]]-- | 
| jbe/bsw@0 | 1109 function timestamp:new(args) | 
| jbe/bsw@0 | 1110 local args = args | 
| jbe/bsw@0 | 1111 if type(args) == "number" then args = { tsec = args } end | 
| jbe/bsw@0 | 1112 if type(args) == "table" then | 
| jbe/bsw@0 | 1113 if not args.second then | 
| jbe/bsw@0 | 1114 args.second = 0 | 
| jbe/bsw@0 | 1115 if not args.minute then | 
| jbe/bsw@0 | 1116 args.minute = 0 | 
| jbe/bsw@0 | 1117 if not args.hour then | 
| jbe/bsw@0 | 1118 args.hour = 0 | 
| jbe/bsw@0 | 1119 end | 
| jbe/bsw@0 | 1120 end | 
| jbe/bsw@0 | 1121 end | 
| jbe/bsw@0 | 1122 if | 
| jbe/bsw@0 | 1123 type(args.year) == "number" and | 
| jbe/bsw@0 | 1124 type(args.month) == "number" and | 
| jbe/bsw@0 | 1125 type(args.day) == "number" and | 
| jbe/bsw@0 | 1126 type(args.hour) == "number" and | 
| jbe/bsw@0 | 1127 type(args.minute) == "number" and | 
| jbe/bsw@0 | 1128 type(args.second) == "number" | 
| jbe/bsw@0 | 1129 then | 
| jbe/bsw@0 | 1130 if | 
| jbe/bsw@0 | 1131 is_integer(args.year) and | 
| jbe/bsw@0 | 1132 args.year >= 1 and args.year <= 9999 and | 
| jbe/bsw@0 | 1133 is_integer(args.month) and | 
| jbe/bsw@0 | 1134 args.month >= 1 and args.month <= 12 and | 
| jbe/bsw@0 | 1135 is_integer(args.day) and | 
| jbe/bsw@0 | 1136 args.day >= 1 and args.day <= 31 and | 
| jbe/bsw@0 | 1137 is_integer(args.hour) and | 
| jbe/bsw@0 | 1138 args.hour >= 0 and args.hour <= 23 and | 
| jbe/bsw@0 | 1139 is_integer(args.minute) and | 
| jbe/bsw@0 | 1140 args.minute >= 0 and args.minute <= 59 and | 
| jbe/bsw@0 | 1141 is_integer(args.second) and | 
| jbe/bsw@0 | 1142 args.second >= 0 and args.second <= 59 | 
| jbe/bsw@0 | 1143 then | 
| jbe/bsw@0 | 1144 return timestamp:_create{ | 
| jbe/bsw@0 | 1145 tsec = timestamp.ymdhms_to_tsec( | 
| jbe/bsw@0 | 1146 args.year, args.month, args.day, | 
| jbe/bsw@0 | 1147 args.hour, args.minute, args.second | 
| jbe/bsw@0 | 1148 ), | 
| jbe/bsw@0 | 1149 year = args.year, | 
| jbe/bsw@0 | 1150 month = args.month, | 
| jbe/bsw@0 | 1151 day = args.day, | 
| jbe/bsw@0 | 1152 hour = args.hour, | 
| jbe/bsw@0 | 1153 minute = args.minute, | 
| jbe/bsw@0 | 1154 second = args.second | 
| jbe/bsw@0 | 1155 } | 
| jbe/bsw@0 | 1156 else | 
| jbe/bsw@0 | 1157 return timestamp.invalid | 
| jbe/bsw@0 | 1158 end | 
| jbe/bsw@0 | 1159 elseif type(args.tsec) == "number" then | 
| jbe/bsw@0 | 1160 if | 
| jbe/bsw@0 | 1161 is_integer(args.tsec) and | 
| jbe/bsw@0 | 1162 args.tsec >= -62135596800 and args.tsec <= 253402300799 | 
| jbe/bsw@0 | 1163 then | 
| jbe/bsw@0 | 1164 local year, month, day, hour, minute, second = | 
| jbe/bsw@0 | 1165 timestamp.tsec_to_ymdhms(args.tsec) | 
| jbe/bsw@0 | 1166 return timestamp:_create{ | 
| jbe/bsw@0 | 1167 tsec = args.tsec, | 
| jbe/bsw@0 | 1168 year = year, month = month, day = day, | 
| jbe/bsw@0 | 1169 hour = hour, minute = minute, second = second | 
| jbe/bsw@0 | 1170 } | 
| jbe/bsw@0 | 1171 else | 
| jbe/bsw@0 | 1172 return timestamp.invalid | 
| jbe/bsw@0 | 1173 end | 
| jbe/bsw@0 | 1174 end | 
| jbe/bsw@0 | 1175 end | 
| jbe/bsw@0 | 1176 error("Invalid arguments passed to timestamp constructor.") | 
| jbe/bsw@0 | 1177 end | 
| jbe/bsw@0 | 1178 --//-- | 
| jbe/bsw@0 | 1179 | 
| jbe/bsw@0 | 1180 --[[-- | 
| jbe/bsw@0 | 1181 ts = -- current date/time as timestamp | 
| jbe/bsw@0 | 1182 atom.timestamp:get_current() | 
| jbe/bsw@0 | 1183 | 
| jbe/bsw@0 | 1184 This function returns the current date and time as timestamp. | 
| jbe/bsw@0 | 1185 | 
| jbe/bsw@0 | 1186 --]]-- | 
| jbe/bsw@0 | 1187 function timestamp:get_current() | 
| jbe/bsw@0 | 1188 local now = os.date("*t") | 
| jbe/bsw@0 | 1189 return timestamp{ | 
| jbe/bsw@0 | 1190 year = now.year, month = now.month, day = now.day, | 
| jbe/bsw@0 | 1191 hour = now.hour, minute = now.min, second = now.sec | 
| jbe/bsw@0 | 1192 } | 
| jbe/bsw@0 | 1193 end | 
| jbe/bsw@0 | 1194 --//-- | 
| jbe/bsw@0 | 1195 | 
| jbe/bsw@0 | 1196 --[[-- | 
| jbe/bsw@0 | 1197 ts = -- timestamp represented by the string | 
| jbe/bsw@0 | 1198 atom.timestamp:load( | 
| jbe/bsw@0 | 1199 string -- string representing a timestamp | 
| jbe/bsw@0 | 1200 ) | 
| jbe/bsw@0 | 1201 | 
| jbe/bsw@0 | 1202 This method returns a timestamp represented by the given string. | 
| jbe/bsw@0 | 1203 | 
| jbe/bsw@0 | 1204 --]]-- | 
| jbe/bsw@0 | 1205 function timestamp:load(str) | 
| jbe@1 | 1206 if str == nil or str == "" then | 
| jbe/bsw@0 | 1207 return nil | 
| jbe@1 | 1208 elseif type(str) ~= "string" then | 
| jbe@1 | 1209 error("String expected") | 
| jbe/bsw@0 | 1210 else | 
| jbe/bsw@0 | 1211 local year, month, day, hour, minute, second = string.match( | 
| jbe/bsw@0 | 1212 str, | 
| jbe/bsw@0 | 1213 "^([0-9][0-9][0-9][0-9])%-([0-9][0-9])%-([0-9][0-9]) ([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$" | 
| jbe/bsw@0 | 1214 ) | 
| jbe/bsw@0 | 1215 if year then | 
| jbe/bsw@0 | 1216 return timestamp{ | 
| jbe/bsw@0 | 1217 year = tonumber(year), | 
| jbe/bsw@0 | 1218 month = tonumber(month), | 
| jbe/bsw@0 | 1219 day = tonumber(day), | 
| jbe/bsw@0 | 1220 hour = tonumber(hour), | 
| jbe/bsw@0 | 1221 minute = tonumber(minute), | 
| jbe/bsw@0 | 1222 second = tonumber(second) | 
| jbe/bsw@0 | 1223 } | 
| jbe/bsw@0 | 1224 else | 
| jbe/bsw@0 | 1225 return timestamp.invalid | 
| jbe/bsw@0 | 1226 end | 
| jbe/bsw@0 | 1227 end | 
| jbe/bsw@0 | 1228 end | 
| jbe/bsw@0 | 1229 | 
| jbe/bsw@0 | 1230 function timestamp:__tostring() | 
| jbe/bsw@0 | 1231 if self.invalid then | 
| jbe/bsw@0 | 1232 return "invalid_timestamp" | 
| jbe/bsw@0 | 1233 else | 
| jbe/bsw@0 | 1234 return string.format( | 
| jbe/bsw@0 | 1235 "%04i-%02i-%02i %02i:%02i:%02i", | 
| jbe/bsw@0 | 1236 self.year, self.month, self.day, self.hour, self.minute, self.second | 
| jbe/bsw@0 | 1237 ) | 
| jbe/bsw@0 | 1238 end | 
| jbe/bsw@0 | 1239 end | 
| jbe/bsw@0 | 1240 | 
| jbe/bsw@0 | 1241 function timestamp.getters:date() | 
| jbe/bsw@0 | 1242 return date{ year = self.year, month = self.month, day = self.day } | 
| jbe/bsw@0 | 1243 end | 
| jbe/bsw@0 | 1244 | 
| jbe/bsw@0 | 1245 function timestamp.getters:time() | 
| jbe/bsw@0 | 1246 return time{ | 
| jbe/bsw@0 | 1247 hour = self.hour, | 
| jbe/bsw@0 | 1248 minute = self.minute, | 
| jbe/bsw@0 | 1249 second = self.second | 
| jbe/bsw@0 | 1250 } | 
| jbe/bsw@0 | 1251 end | 
| jbe/bsw@0 | 1252 | 
| jbe/bsw@0 | 1253 function timestamp.__eq(value1, value2) | 
| jbe/bsw@0 | 1254 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1255 return false | 
| jbe/bsw@0 | 1256 else | 
| jbe/bsw@0 | 1257 return value1.tsec == value2.tsec | 
| jbe/bsw@0 | 1258 end | 
| jbe/bsw@0 | 1259 end | 
| jbe/bsw@0 | 1260 | 
| jbe/bsw@0 | 1261 function timestamp.__lt(value1, value2) | 
| jbe/bsw@0 | 1262 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1263 return false | 
| jbe/bsw@0 | 1264 else | 
| jbe/bsw@0 | 1265 return value1.tsec < value2.tsec | 
| jbe/bsw@0 | 1266 end | 
| jbe/bsw@0 | 1267 end | 
| jbe/bsw@0 | 1268 | 
| jbe/bsw@0 | 1269 function timestamp.__le(value1, value2) | 
| jbe/bsw@0 | 1270 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1271 return false | 
| jbe/bsw@0 | 1272 else | 
| jbe/bsw@0 | 1273 return value1.tsec <= value2.tsec | 
| jbe/bsw@0 | 1274 end | 
| jbe/bsw@0 | 1275 end | 
| jbe/bsw@0 | 1276 | 
| jbe/bsw@0 | 1277 function timestamp.__add(value1, value2) | 
| jbe/bsw@0 | 1278 if getmetatable(value1) == timestamp then | 
| jbe/bsw@0 | 1279 if getmetatable(value2) == timestamp then | 
| jbe/bsw@0 | 1280 error("Can not add two timestamps.") | 
| jbe/bsw@0 | 1281 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 1282 return timestamp(value1.tsec + value2) | 
| jbe/bsw@0 | 1283 else | 
| jbe/bsw@0 | 1284 error("Right operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1285 end | 
| jbe/bsw@0 | 1286 elseif type(value1) == "number" then | 
| jbe/bsw@0 | 1287 if getmetatable(value2) == timestamp then | 
| jbe/bsw@0 | 1288 return timestamp(value1 + value2.tsec) | 
| jbe/bsw@0 | 1289 else | 
| jbe/bsw@0 | 1290 error("Assertion failed") | 
| jbe/bsw@0 | 1291 end | 
| jbe/bsw@0 | 1292 else | 
| jbe/bsw@0 | 1293 error("Left operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1294 end | 
| jbe/bsw@0 | 1295 end | 
| jbe/bsw@0 | 1296 | 
| jbe/bsw@0 | 1297 function timestamp.__sub(value1, value2) | 
| jbe/bsw@0 | 1298 if not getmetatable(value1) == timestamp then | 
| jbe/bsw@0 | 1299 error("Left operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1300 end | 
| jbe/bsw@0 | 1301 if getmetatable(value2) == timestamp then | 
| jbe@107 | 1302 return value1.tsec - value2.tsec -- TODO: transform to interval | 
| jbe/bsw@0 | 1303 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 1304 return timestamp(value1.tsec - value2) | 
| jbe/bsw@0 | 1305 else | 
| jbe/bsw@0 | 1306 error("Right operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1307 end | 
| jbe/bsw@0 | 1308 end | 
| jbe/bsw@0 | 1309 | 
| jbe/bsw@0 | 1310 | 
| jbe/bsw@0 | 1311 | 
| jbe/bsw@0 | 1312 ---------- | 
| jbe/bsw@0 | 1313 -- time -- | 
| jbe/bsw@0 | 1314 ---------- | 
| jbe/bsw@0 | 1315 | 
| jbe/bsw@0 | 1316 time = create_new_type("time") | 
| jbe/bsw@0 | 1317 | 
| jbe/bsw@0 | 1318 function time.hms_to_dsec(hour, minute, second) | 
| jbe/bsw@0 | 1319 return 3600 * hour + 60 * minute + second | 
| jbe/bsw@0 | 1320 end | 
| jbe/bsw@0 | 1321 | 
| jbe/bsw@0 | 1322 function time.dsec_to_hms(dsec) | 
| jbe/bsw@0 | 1323 local hour = math.floor(dsec / 3600) | 
| jbe/bsw@0 | 1324 local minute = math.floor((dsec % 3600) / 60) | 
| jbe/bsw@0 | 1325 local second = dsec % 60 | 
| jbe/bsw@0 | 1326 return hour, minute, second | 
| jbe/bsw@0 | 1327 end | 
| jbe/bsw@0 | 1328 | 
| jbe/bsw@0 | 1329 --[[-- | 
| jbe/bsw@0 | 1330 atom.time.invalid | 
| jbe/bsw@0 | 1331 | 
| jbe/bsw@0 | 1332 Value representing an invalid time of day. | 
| jbe/bsw@0 | 1333 | 
| jbe/bsw@0 | 1334 --]]-- | 
| jbe/bsw@0 | 1335 time.invalid = time:_create{ | 
| jbe/bsw@0 | 1336 dsec = not_a_number, | 
| jbe/bsw@0 | 1337 hour = not_a_number, minute = not_a_number, second = not_a_number, | 
| jbe/bsw@0 | 1338 invalid = true | 
| jbe/bsw@0 | 1339 } | 
| jbe/bsw@0 | 1340 --//-- | 
| jbe/bsw@0 | 1341 | 
| jbe/bsw@0 | 1342 --[[-- | 
| jbe/bsw@0 | 1343 t = -- time based on given data | 
| jbe/bsw@0 | 1344 atom.time:new{ | 
| jbe/bsw@0 | 1345 dsec = dsec, -- seconds since 00:00:00 | 
| jbe/bsw@0 | 1346 hour = hour, -- hour from 0 to 23 | 
| jbe/bsw@0 | 1347 minute = minute, -- minute from 0 to 59 | 
| jbe/bsw@0 | 1348 second = second -- second from 0 to 59 | 
| jbe/bsw@0 | 1349 } | 
| jbe/bsw@0 | 1350 | 
| jbe/bsw@0 | 1351 This method returns a new time value, based on given data. | 
| jbe/bsw@0 | 1352 | 
| jbe/bsw@0 | 1353 --]]-- | 
| jbe/bsw@0 | 1354 function time:new(args) | 
| jbe/bsw@0 | 1355 local args = args | 
| jbe/bsw@0 | 1356 if type(args) == "number" then args = { dsec = args } end | 
| jbe/bsw@0 | 1357 if type(args) == "table" then | 
| jbe/bsw@0 | 1358 if not args.second then | 
| jbe/bsw@0 | 1359 args.second = 0 | 
| jbe/bsw@0 | 1360 if not args.minute then | 
| jbe/bsw@0 | 1361 args.minute = 0 | 
| jbe/bsw@0 | 1362 end | 
| jbe/bsw@0 | 1363 end | 
| jbe/bsw@0 | 1364 if | 
| jbe/bsw@0 | 1365 type(args.hour) == "number" and | 
| jbe/bsw@0 | 1366 type(args.minute) == "number" and | 
| jbe/bsw@0 | 1367 type(args.second) == "number" | 
| jbe/bsw@0 | 1368 then | 
| jbe/bsw@0 | 1369 if | 
| jbe/bsw@0 | 1370 is_integer(args.hour) and | 
| jbe/bsw@0 | 1371 args.hour >= 0 and args.hour <= 23 and | 
| jbe/bsw@0 | 1372 is_integer(args.minute) and | 
| jbe/bsw@0 | 1373 args.minute >= 0 and args.minute <= 59 and | 
| jbe/bsw@0 | 1374 is_integer(args.second) and | 
| jbe/bsw@0 | 1375 args.second >= 0 and args.second <= 59 | 
| jbe/bsw@0 | 1376 then | 
| jbe/bsw@0 | 1377 return time:_create{ | 
| jbe/bsw@0 | 1378 dsec = time.hms_to_dsec(args.hour, args.minute, args.second), | 
| jbe/bsw@0 | 1379 hour = args.hour, | 
| jbe/bsw@0 | 1380 minute = args.minute, | 
| jbe/bsw@0 | 1381 second = args.second | 
| jbe/bsw@0 | 1382 } | 
| jbe/bsw@0 | 1383 else | 
| jbe/bsw@0 | 1384 return time.invalid | 
| jbe/bsw@0 | 1385 end | 
| jbe/bsw@0 | 1386 elseif type(args.dsec) == "number" then | 
| jbe/bsw@0 | 1387 if | 
| jbe/bsw@0 | 1388 is_integer(args.dsec) and | 
| jbe/bsw@0 | 1389 args.dsec >= 0 and args.dsec <= 86399 | 
| jbe/bsw@0 | 1390 then | 
| jbe/bsw@0 | 1391 local hour, minute, second = | 
| jbe/bsw@0 | 1392 time.dsec_to_hms(args.dsec) | 
| jbe/bsw@0 | 1393 return time:_create{ | 
| jbe/bsw@0 | 1394 dsec = args.dsec, | 
| jbe/bsw@0 | 1395 hour = hour, minute = minute, second = second | 
| jbe/bsw@0 | 1396 } | 
| jbe/bsw@0 | 1397 else | 
| jbe/bsw@0 | 1398 return time.invalid | 
| jbe/bsw@0 | 1399 end | 
| jbe/bsw@0 | 1400 end | 
| jbe/bsw@0 | 1401 end | 
| jbe/bsw@0 | 1402 error("Invalid arguments passed to time constructor.") | 
| jbe/bsw@0 | 1403 end | 
| jbe/bsw@0 | 1404 --//-- | 
| jbe/bsw@0 | 1405 | 
| jbe/bsw@0 | 1406 --[[-- | 
| jbe/bsw@0 | 1407 t = -- current time of day | 
| jbe/bsw@0 | 1408 atom.time:get_current() | 
| jbe/bsw@0 | 1409 | 
| jbe/bsw@0 | 1410 This method returns the current time of the day. | 
| jbe/bsw@0 | 1411 | 
| jbe/bsw@0 | 1412 --]]-- | 
| jbe/bsw@0 | 1413 function time:get_current() | 
| jbe/bsw@0 | 1414 local now = os.date("*t") | 
| jbe/bsw@0 | 1415 return time{ hour = now.hour, minute = now.min, second = now.sec } | 
| jbe/bsw@0 | 1416 end | 
| jbe/bsw@0 | 1417 --//-- | 
| jbe/bsw@0 | 1418 | 
| jbe/bsw@0 | 1419 --[[-- | 
| jbe/bsw@0 | 1420 t = -- time represented by the string | 
| jbe/bsw@0 | 1421 atom.time:load( | 
| jbe/bsw@0 | 1422 string -- string representing a time of day | 
| jbe/bsw@0 | 1423 ) | 
| jbe/bsw@0 | 1424 | 
| jbe/bsw@0 | 1425 This method returns a time represented by the given string. | 
| jbe/bsw@0 | 1426 | 
| jbe/bsw@0 | 1427 --]]-- | 
| jbe/bsw@0 | 1428 function time:load(str) | 
| jbe@1 | 1429 if str == nil or str == "" then | 
| jbe/bsw@0 | 1430 return nil | 
| jbe@1 | 1431 elseif type(str) ~= "string" then | 
| jbe@1 | 1432 error("String expected") | 
| jbe/bsw@0 | 1433 else | 
| jbe/bsw@0 | 1434 local hour, minute, second = string.match( | 
| jbe/bsw@0 | 1435 str, | 
| jbe/bsw@0 | 1436 "^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$" | 
| jbe/bsw@0 | 1437 ) | 
| jbe/bsw@0 | 1438 if hour then | 
| jbe/bsw@0 | 1439 return time{ | 
| jbe/bsw@0 | 1440 hour = tonumber(hour), | 
| jbe/bsw@0 | 1441 minute = tonumber(minute), | 
| jbe/bsw@0 | 1442 second = tonumber(second) | 
| jbe/bsw@0 | 1443 } | 
| jbe/bsw@0 | 1444 else | 
| jbe/bsw@0 | 1445 return time.invalid | 
| jbe/bsw@0 | 1446 end | 
| jbe/bsw@0 | 1447 end | 
| jbe/bsw@0 | 1448 end | 
| jbe/bsw@0 | 1449 --//-- | 
| jbe/bsw@0 | 1450 | 
| jbe/bsw@0 | 1451 function time:__tostring() | 
| jbe/bsw@0 | 1452 if self.invalid then | 
| jbe/bsw@0 | 1453 return "invalid_time" | 
| jbe/bsw@0 | 1454 else | 
| jbe/bsw@0 | 1455 return string.format( | 
| jbe/bsw@0 | 1456 "%02i:%02i:%02i", | 
| jbe/bsw@0 | 1457 self.hour, self.minute, self.second | 
| jbe/bsw@0 | 1458 ) | 
| jbe/bsw@0 | 1459 end | 
| jbe/bsw@0 | 1460 end | 
| jbe/bsw@0 | 1461 | 
| jbe/bsw@0 | 1462 function time.__eq(value1, value2) | 
| jbe/bsw@0 | 1463 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1464 return false | 
| jbe/bsw@0 | 1465 else | 
| jbe/bsw@0 | 1466 return value1.dsec == value2.dsec | 
| jbe/bsw@0 | 1467 end | 
| jbe/bsw@0 | 1468 end | 
| jbe/bsw@0 | 1469 | 
| jbe/bsw@0 | 1470 function time.__lt(value1, value2) | 
| jbe/bsw@0 | 1471 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1472 return false | 
| jbe/bsw@0 | 1473 else | 
| jbe/bsw@0 | 1474 return value1.dsec < value2.dsec | 
| jbe/bsw@0 | 1475 end | 
| jbe/bsw@0 | 1476 end | 
| jbe/bsw@0 | 1477 | 
| jbe/bsw@0 | 1478 function time.__le(value1, value2) | 
| jbe/bsw@0 | 1479 if value1.invalid or value2.invalid then | 
| jbe/bsw@0 | 1480 return false | 
| jbe/bsw@0 | 1481 else | 
| jbe/bsw@0 | 1482 return value1.dsec <= value2.dsec | 
| jbe/bsw@0 | 1483 end | 
| jbe/bsw@0 | 1484 end | 
| jbe/bsw@0 | 1485 | 
| jbe/bsw@0 | 1486 function time.__add(value1, value2) | 
| jbe/bsw@0 | 1487 if getmetatable(value1) == time then | 
| jbe/bsw@0 | 1488 if getmetatable(value2) == time then | 
| jbe/bsw@0 | 1489 error("Can not add two times.") | 
| jbe/bsw@0 | 1490 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 1491 return time((value1.dsec + value2) % 86400) | 
| jbe/bsw@0 | 1492 else | 
| jbe/bsw@0 | 1493 error("Right operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1494 end | 
| jbe/bsw@0 | 1495 elseif type(value1) == "number" then | 
| jbe/bsw@0 | 1496 if getmetatable(value2) == time then | 
| jbe/bsw@0 | 1497 return time((value1 + value2.dsec) % 86400) | 
| jbe/bsw@0 | 1498 else | 
| jbe/bsw@0 | 1499 error("Assertion failed") | 
| jbe/bsw@0 | 1500 end | 
| jbe/bsw@0 | 1501 else | 
| jbe/bsw@0 | 1502 error("Left operand of '+' operator has wrong type.") | 
| jbe/bsw@0 | 1503 end | 
| jbe/bsw@0 | 1504 end | 
| jbe/bsw@0 | 1505 | 
| jbe/bsw@0 | 1506 function time.__sub(value1, value2) | 
| jbe/bsw@0 | 1507 if not getmetatable(value1) == time then | 
| jbe/bsw@0 | 1508 error("Left operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1509 end | 
| jbe/bsw@0 | 1510 if getmetatable(value2) == time then | 
| jbe@107 | 1511 return value1.dsec - value2.dsec -- TODO: transform to interval | 
| jbe/bsw@0 | 1512 elseif type(value2) == "number" then | 
| jbe/bsw@0 | 1513 return time((value1.dsec - value2) % 86400) | 
| jbe/bsw@0 | 1514 else | 
| jbe/bsw@0 | 1515 error("Right operand of '-' operator has wrong type.") | 
| jbe/bsw@0 | 1516 end | 
| jbe/bsw@0 | 1517 end | 
| jbe/bsw@0 | 1518 | 
| jbe/bsw@0 | 1519 function time.__concat(value1, value2) | 
| jbe/bsw@0 | 1520 local mt1, mt2 = getmetatable(value1), getmetatable(value2) | 
| jbe/bsw@0 | 1521 if mt1 == date and mt2 == time then | 
| jbe/bsw@0 | 1522 return timestamp{ | 
| jbe/bsw@0 | 1523 year = value1.year, month = value1.month, day = value1.day, | 
| jbe/bsw@0 | 1524 hour = value2.hour, minute = value2.minute, second = value2.second | 
| jbe/bsw@0 | 1525 } | 
| jbe/bsw@0 | 1526 elseif mt1 == time and mt2 == date then | 
| jbe/bsw@0 | 1527 return timestamp{ | 
| jbe/bsw@0 | 1528 year = value2.year, month = value2.month, day = value2.day, | 
| jbe/bsw@0 | 1529 hour = value1.hour, minute = value1.minute, second = value1.second | 
| jbe/bsw@0 | 1530 } | 
| jbe/bsw@0 | 1531 elseif mt1 == time then | 
| jbe/bsw@0 | 1532 error("Right operand of '..' operator has wrong type.") | 
| jbe/bsw@0 | 1533 elseif mt2 == time then | 
| jbe/bsw@0 | 1534 error("Left operand of '..' operator has wrong type.") | 
| jbe/bsw@0 | 1535 else | 
| jbe/bsw@0 | 1536 error("Assertion failed") | 
| jbe/bsw@0 | 1537 end | 
| jbe/bsw@0 | 1538 end | 
| jbe/bsw@0 | 1539 | 
| jbe@64 | 1540 | 
| jbe@64 | 1541 | 
| jbe@64 | 1542 return _M |