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