1# the Date object is founded on the Daytime module 2 3UTC: con 1; 4msPerSec: con big 1000; 5 6# based on Daytime->Tm with big fields 7bigTm: adt { 8 ms: big; 9 sec: big; 10 min: big; 11 hour: big; 12 mday: big; 13 mon: big; 14 year: big; 15 tzoff: int; 16}; 17 18isfinite(r: real): int 19{ 20 if(math->isnan(r) || r == +Infinity || r == -Infinity) 21 return 0; 22 return 1; 23} 24 25time2Tm(t: real, utc: int): ref Daytime->Tm 26{ 27 secs := int(big t / msPerSec); 28 if(big t % msPerSec < big 0) # t<0? 29 secs -= 1; 30 if(utc) 31 tm := daytime->gmt(secs); 32 else 33 tm = daytime->local(secs); 34 return tm; 35} 36 37time2bigTm(t: real, utc: int): ref bigTm 38{ 39 tm := time2Tm(t, utc); 40 btm := ref bigTm; 41 btm.ms = big t % msPerSec; 42 if(btm.ms < big 0) 43 btm.ms += msPerSec; 44 btm.sec = big tm.sec; 45 btm.min = big tm.min; 46 btm.hour = big tm.hour; 47 btm.mday = big tm.mday; 48 btm.mon = big tm.mon; 49 btm.year = big tm.year; 50 btm.tzoff = tm.tzoff; 51 return btm; 52} 53 54bigTm2time(btm: ref bigTm): real 55{ 56 # normalize 57 if(btm.mon / big 12 != big 0){ 58 btm.year += btm.mon / big 12; 59 btm.mon %= big 12; 60 } 61 if(btm.ms / msPerSec != big 0){ 62 btm.sec += btm.ms / msPerSec; 63 btm.ms %= msPerSec; 64 } 65 if(btm.sec / big 60 != big 0){ 66 btm.min += btm.sec / big 60; 67 btm.sec %= big 60; 68 } 69 if(btm.min / big 60 != big 0){ 70 btm.hour += btm.hour / big 60; 71 btm.min %= big 60; 72 } 73 if(btm.hour / big 24 != big 0){ 74 btm.mday += btm.mday / big 24; 75 btm.hour %= big 24; 76 } 77 78 tm := ref Tm; 79 tm.sec = int btm.sec; 80 tm.min = int btm.min; 81 tm.hour = int btm.hour; 82 tm.mday = int btm.mday; 83 tm.mon = int btm.mon; 84 tm.year = int btm.year; 85 tm.tzoff = btm.tzoff; 86 secs := daytime->tm2epoch(tm); 87 # check for out-of-band times 88 if(secs == daytime->tm2epoch(daytime->gmt(secs))) 89 r := real(big secs * msPerSec + btm.ms); 90 else 91 r = Math->NaN; 92 return r; 93} 94 95str2time(s: string): real 96{ 97 tm := daytime->string2tm(s); 98 if(tm == nil) 99 r := Math->NaN; 100 else 101 r = real (big daytime->tm2epoch(tm) * msPerSec); 102 return r; 103} 104 105cdate(nil: ref Exec, nil, nil: ref Ecmascript->Obj, nil: array of ref Val): ref Val 106{ 107 return strval(daytime->time()); 108} 109 110# process arguments of Date() [called as constructor] and Date.UTC() 111datectorargs(ex: ref Exec, args: array of ref Val): (int, ref bigTm) 112{ 113 x := array[7] of { * => big 0 }; 114 ok := 1; 115 for(i := 0; i < 7 && i < len args; i++){ 116 if(!isfinite(toNumber(ex, biarg(args, i)))) 117 ok = 0; 118 else 119 x[i] = big toInteger(ex, biarg(args, i)); 120 } 121 btm := ref bigTm; 122 yr := x[0]; 123 if(yr >= big 0 && yr <= big 99) 124 btm.year = yr; 125 else 126 btm.year = yr - big 1900; 127 btm.mon = x[1]; 128 btm.mday = x[2]; 129 btm.hour = x[3]; 130 btm.min = x[4]; 131 btm.sec = x[5]; 132 btm.ms = x[6]; 133 return (ok, btm); 134} 135 136ndate(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj 137{ 138 o := mkobj(ex.dateproto, "Date"); 139 r := Math->NaN; 140 case len args{ 141 0 => 142 r = real(big daytime->now() * msPerSec); 143 1 => 144 v := toPrimitive(ex, biarg(args, 0), NoHint); 145 if(isstr(v)) 146 r = str2time(v.str); 147 else if(isfinite(toNumber(ex, v))){ 148 t := big toInteger(ex, v); 149 secs := t / msPerSec; 150 if(big t % msPerSec < big 0) 151 secs -= big 1; 152 if(secs == big int secs) 153 r = real t; 154 } 155 * => 156 (ok, btm) := datectorargs(ex, args); 157 if(ok){ 158 tm := daytime->local(daytime->now()); 159 btm.tzoff = tm.tzoff; 160 r = bigTm2time(btm); 161 } 162 } 163 o.val = numval(r); 164 return o; 165} 166 167cdateparse(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val 168{ 169 s := toString(ex, biarg(args, 0)); 170 return numval(str2time(s)); 171} 172 173cdateUTC(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val 174{ 175 r := Math->NaN; 176 if(len args == 0) 177 r = real(big daytime->now() * msPerSec); 178 else{ 179 (ok, btm) := datectorargs(ex, args); 180 if(ok){ 181 btm.tzoff = 0; 182 r = bigTm2time(btm); 183 } 184 } 185 return numval(r); 186} 187 188datecheck(ex: ref Exec, o: ref Ecmascript->Obj, f: string) 189{ 190 if(!isdateobj(o)) 191 runtime(ex, TypeError, "Date.prototype." + f + " called on non-Date object"); 192} 193 194cdateprototoString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 195{ 196 datecheck(ex, this, f.val.str); 197 secs := 0; 198 t := this.val.num; 199 if(!math->isnan(t)){ 200 secs = int(big t / msPerSec); 201 if(big t % msPerSec < big 0) 202 secs -= 1; 203 } 204 return strval(daytime->text(daytime->local(secs))); 205} 206 207cdateprototoDateString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 208{ 209 datecheck(ex, this, f.val.str); 210 secs := 0; 211 t := this.val.num; 212 if(!math->isnan(t)){ 213 secs = int(big t / msPerSec); 214 if(big t % msPerSec < big 0) 215 secs -= 1; 216 } 217 s := daytime->text(daytime->local(secs)); 218 (n, ls) := sys->tokenize(s, " "); 219 if(n < 3) 220 return strval(""); 221 return strval(hd ls + " " + hd tl ls + " " + hd tl tl ls); 222} 223 224cdateprototoTimeString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 225{ 226 datecheck(ex, this, f.val.str); 227 secs := 0; 228 t := this.val.num; 229 if(!math->isnan(t)){ 230 secs = int(big t / msPerSec); 231 if(big t % msPerSec < big 0) 232 secs -= 1; 233 } 234 s := daytime->text(daytime->local(secs)); 235 (n, ls) := sys->tokenize(s, " "); 236 if(n < 4) 237 return strval(""); 238 return strval(hd tl tl tl ls); 239} 240 241cdateprotovalueOf(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 242{ 243 datecheck(ex, this, f.val.str); 244 return this.val; 245} 246 247cdateprotoget(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val, utc: int): ref Val 248{ 249 datecheck(ex, this, f.val.str); 250 t := this.val.num; 251 if(!math->isnan(t)){ 252 tm := time2Tm(t, utc); 253 case f.val.str{ 254 "Date.prototype.getYear" => 255 if (tm.year < 0 || tm.year > 99) 256 t = real(tm.year + 1900); 257 else 258 t = real tm.year; 259 "Date.prototype.getFullYear" or 260 "Date.prototype.getUTCFullYear" => 261 t = real(tm.year + 1900); 262 "Date.prototype.getMonth" or 263 "Date.prototype.getUTCMonth" => 264 t = real tm.mon; 265 "Date.prototype.getDate" or 266 "Date.prototype.getUTCDate" => 267 t = real tm.mday; 268 "Date.prototype.getDay" or 269 "Date.prototype.getUTCDay" => 270 t = real tm.wday; 271 "Date.prototype.getHours" or 272 "Date.prototype.getUTCHours" => 273 t = real tm.hour; 274 "Date.prototype.getMinutes" or 275 "Date.prototype.getUTCMinutes" => 276 t = real tm.min; 277 "Date.prototype.getSeconds" or 278 "Date.prototype.getUTCSeconds" => 279 t = real tm.sec; 280 } 281 } 282 return numval(t); 283} 284 285cdateprotogetMilliseconds(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 286{ 287 datecheck(ex, this, f.val.str); 288 t := this.val.num; 289 if(!math->isnan(t)){ 290 ms := big t % msPerSec; 291 if(ms < big 0) 292 ms += msPerSec; 293 t = real ms; 294 } 295 return numval(t); 296} 297 298cdateprotogetTimezoneOffset(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 299{ 300 datecheck(ex, this, f.val.str); 301 t := this.val.num; 302 if(!math->isnan(t)){ 303 tm := time2Tm(t, !UTC); 304 t = real(tm.tzoff / 60); 305 } 306 return numval(t); 307} 308 309# process arguments of Date.prototype.set*() functions 310dateprotosetargs(ex: ref Exec, this: ref Ecmascript->Obj, args: array of ref Val, n: int): (int, big, big, big, big) 311{ 312 x := array[4] of { * => big 0 }; 313 ok := 1; 314 if(this != nil && !isfinite(this.val.num)) 315 ok = 0; 316 for(i := 0; i < n && i < len args; i++){ 317 if(!isfinite(toNumber(ex, biarg(args, i)))) 318 ok = 0; 319 else 320 x[i] = big toInteger(ex, biarg(args, i)); 321 } 322 return (ok, x[0], x[1], x[2], x[3]); 323} 324 325cdateprotosetTime(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val 326{ 327 datecheck(ex, this, f.val.str); 328 r := Math->NaN; 329 (ok, t, nil, nil, nil) := dateprotosetargs(ex, nil, args, 1); 330 if(ok){ 331 secs := t / msPerSec; 332 if(big t % msPerSec < big 0) 333 secs -= big 1; 334 if(secs == big int secs) 335 r = real t; 336 } 337 this.val.num = r; 338 return numval(r); 339} 340 341cdateprotosetMilliseconds(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 342{ 343 datecheck(ex, this, f.val.str); 344 r := Math->NaN; 345 (ok, ms, nil, nil, nil) := dateprotosetargs(ex, this, args, 1); 346 if(ok){ 347 btm := time2bigTm(this.val.num, utc); 348 btm.ms = ms; 349 r = bigTm2time(btm); 350 } 351 this.val.num = r; 352 return numval(r); 353} 354 355cdateprotosetSeconds(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 356{ 357 datecheck(ex, this, f.val.str); 358 r := Math->NaN; 359 (ok, sec, ms, nil, nil) := dateprotosetargs(ex, this, args, 2); 360 if(ok){ 361 btm := time2bigTm(this.val.num, utc); 362 btm.sec = sec; 363 if(len args > 1) 364 btm.ms = ms; 365 r = bigTm2time(btm); 366 } 367 this.val.num = r; 368 return numval(r); 369} 370 371cdateprotosetMinutes(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 372{ 373 datecheck(ex, this, f.val.str); 374 r := Math->NaN; 375 (ok, min, sec, ms, nil) := dateprotosetargs(ex, this, args, 3); 376 if(ok){ 377 btm := time2bigTm(this.val.num, utc); 378 btm.min = min; 379 if(len args > 1){ 380 btm.sec = sec; 381 if(len args > 2) 382 btm.ms = ms; 383 } 384 r = bigTm2time(btm); 385 } 386 this.val.num = r; 387 return numval(r); 388} 389 390cdateprotosetHours(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 391{ 392 datecheck(ex, this, f.val.str); 393 r := Math->NaN; 394 (ok, hour, min, sec, ms) := dateprotosetargs(ex, this, args, 4); 395 if(ok){ 396 btm := time2bigTm(this.val.num, utc); 397 btm.hour = hour; 398 if(len args > 1){ 399 btm.min = min; 400 if(len args > 2){ 401 btm.sec = sec; 402 if(len args > 3) 403 btm.ms = ms; 404 } 405 } 406 r = bigTm2time(btm); 407 } 408 this.val.num = r; 409 return numval(r); 410} 411 412cdateprotosetDate(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 413{ 414 datecheck(ex, this, f.val.str); 415 r := Math->NaN; 416 (ok, day, nil, nil, nil) := dateprotosetargs(ex, this, args, 1); 417 if(ok){ 418 btm := time2bigTm(this.val.num, utc); 419 btm.mday = day; 420 r = bigTm2time(btm); 421 } 422 this.val.num = r; 423 return numval(r); 424} 425 426cdateprotosetMonth(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 427{ 428 datecheck(ex, this, f.val.str); 429 r := Math->NaN; 430 (ok, mon, day, nil, nil) := dateprotosetargs(ex, this, args, 2); 431 if(ok){ 432 btm := time2bigTm(this.val.num, utc); 433 btm.mon = mon; 434 if(len args > 1) 435 btm.mday = day; 436 r = bigTm2time(btm); 437 } 438 this.val.num = r; 439 return numval(r); 440} 441 442cdateprotosetFullYear(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val 443{ 444 datecheck(ex, this, f.val.str); 445 r := Math->NaN; 446 (ok, year, mon, day, nil) := dateprotosetargs(ex, nil, args, 3); 447 if(ok){ 448 t := this.val.num; 449 if(!isfinite(t)) 450 t = 0.; 451 btm := time2bigTm(t, utc); 452 btm.year = (year - big 1900); 453 if(len args > 1){ 454 btm.mon = mon; 455 if(len args > 2) 456 btm.mday = day; 457 } 458 r = bigTm2time(btm); 459 } 460 this.val.num = r; 461 return numval(r); 462} 463 464cdateprotosetYear(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val 465{ 466 datecheck(ex, this, f.val.str); 467 r := Math->NaN; 468 (ok, year, nil, nil, nil) := dateprotosetargs(ex, nil, args, 1); 469 if(ok){ 470 t := this.val.num; 471 if(!isfinite(t)) 472 t = 0.; 473 btm := time2bigTm(t, !UTC); 474 if(year >= big 0 && year <= big 99) 475 btm.year = year; 476 else 477 btm.year = year - big 1900; 478 r = bigTm2time(btm); 479 } 480 this.val.num = r; 481 return numval(r); 482} 483 484cdateprototoUTCString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val 485{ 486 datecheck(ex, this, f.val.str); 487 secs := 0; 488 t := this.val.num; 489 if(!math->isnan(t)){ 490 secs = int(big t / msPerSec); 491 if(big t % msPerSec < big 0) 492 secs -= 1; 493 } 494 return strval(daytime->text(daytime->gmt(secs))); 495} 496