webmcp
annotate libraries/atom/atom.lua @ 1:985024b16520
Version 1.0.1
New feature: JSON requests
Changes in ui.paginate: Current page setting is directly fetched from CGI params, instead of view params
Changed behavior of load methods of atom library to accept nil as input
Bugfixes in mondelefant_atom_connector timestamp(tz) loaders
Added global constant _WEBMCP_VERSION containing a version string
New feature: JSON requests
Changes in ui.paginate: Current page setting is directly fetched from CGI params, instead of view params
Changed behavior of load methods of atom library to accept nil as input
Bugfixes in mondelefant_atom_connector timestamp(tz) loaders
Added global constant _WEBMCP_VERSION containing a version string
author | jbe |
---|---|
date | Tue Nov 17 12:00:00 2009 +0100 (2009-11-17) |
parents | 9fdfb27f8e67 |
children | 3d43a5cf17c1 |
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 getfenv = getfenv |
jbe/bsw@0 | 8 local getmetatable = getmetatable |
jbe/bsw@0 | 9 local ipairs = ipairs |
jbe/bsw@0 | 10 local module = module |
jbe/bsw@0 | 11 local next = next |
jbe/bsw@0 | 12 local pairs = pairs |
jbe/bsw@0 | 13 local print = print |
jbe/bsw@0 | 14 local rawequal = rawequal |
jbe/bsw@0 | 15 local rawget = rawget |
jbe/bsw@0 | 16 local rawset = rawset |
jbe/bsw@0 | 17 local require = require |
jbe/bsw@0 | 18 local select = select |
jbe/bsw@0 | 19 local setfenv = setfenv |
jbe/bsw@0 | 20 local setmetatable = setmetatable |
jbe/bsw@0 | 21 local tonumber = tonumber |
jbe/bsw@0 | 22 local tostring = tostring |
jbe/bsw@0 | 23 local type = type |
jbe/bsw@0 | 24 local unpack = unpack |
jbe/bsw@0 | 25 |
jbe/bsw@0 | 26 local coroutine = coroutine |
jbe/bsw@0 | 27 local io = io |
jbe/bsw@0 | 28 local math = math |
jbe/bsw@0 | 29 local os = os |
jbe/bsw@0 | 30 local string = string |
jbe/bsw@0 | 31 local table = table |
jbe/bsw@0 | 32 |
jbe/bsw@0 | 33 module(...) |
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/bsw@0 | 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/bsw@0 | 916 return time{ 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/bsw@0 | 920 return time{ |
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/bsw@0 | 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/bsw@0 | 1081 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/bsw@0 | 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/bsw@0 | 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 |