1 /** 2 * Bindings for the script Date class. This module contains both the D class definition and the script bindings. 3 */ 4 module mildew.stdlib.date; 5 6 import core.time: TimeException; 7 import std.datetime.systime; 8 import std.datetime.date; 9 import std.datetime.timezone; 10 11 import mildew.binder; 12 import mildew.context; 13 import mildew.interpreter; 14 import mildew.types; 15 16 /// Initializes the Date library 17 void initializeDateLibrary(Interpreter interpreter) 18 { 19 auto Date_ctor = new ScriptFunction("Date", &native_Date_ctor, true); 20 Date_ctor["prototype"]["getDate"] = new ScriptFunction("Date.prototype.getDate", &native_Date_getDate); 21 Date_ctor["prototype"]["getDay"] = new ScriptFunction("Date.prototype.getDay", &native_Date_getDay); 22 Date_ctor["prototype"]["getFullYear"] = new ScriptFunction("Date.prototype.getFullYear", 23 &native_Date_getFullYear); 24 Date_ctor["prototype"]["getHours"] = new ScriptFunction("Date.prototype.getHours", 25 &native_Date_getHours); 26 Date_ctor["prototype"]["getMilliseconds"] = new ScriptFunction("Date.prototype.getMilliseconds", 27 &native_Date_getMilliseconds); 28 Date_ctor["prototype"]["getMinutes"] = new ScriptFunction("Date.prototype.getMinutes", 29 &native_Date_getMinutes); 30 Date_ctor["prototype"]["getMonth"] = new ScriptFunction("Date.prototype.getMonth", 31 &native_Date_getMonth); 32 Date_ctor["prototype"]["getSeconds"] = new ScriptFunction("Date.prototype.getSeconds", 33 &native_Date_getSeconds); 34 Date_ctor["prototype"]["getTime"] = new ScriptFunction("Date.prototype.getTime", 35 &native_Date_getTime); 36 Date_ctor["prototype"]["getTimezone"] = new ScriptFunction("Date.prototype.getTimezone", 37 &native_Date_getTimezone); 38 Date_ctor["prototype"]["setDate"] = new ScriptFunction("Date.prototype.setDate", 39 &native_Date_setDate); 40 Date_ctor["prototype"]["setFullYear"] = new ScriptFunction("Date.prototype.setFullYear", 41 &native_Date_setFullYear); 42 Date_ctor["prototype"]["setHours"] = new ScriptFunction("Date.prototype.setHours", 43 &native_Date_setHours); 44 Date_ctor["prototype"]["setMilliseconds"] = new ScriptFunction("Date.prototype.setMillseconds", 45 &native_Date_setMilliseconds); 46 Date_ctor["prototype"]["setMinutes"] = new ScriptFunction("Date.prototype.setMinutes", 47 &native_Date_setMinutes); 48 Date_ctor["prototype"]["setMonth"] = new ScriptFunction("Date.prototype.setMonth", 49 &native_Date_setMonth); 50 Date_ctor["prototype"]["setSeconds"] = new ScriptFunction("Date.prototype.setSeconds", 51 &native_Date_setSeconds); 52 Date_ctor["prototype"]["setTime"] = new ScriptFunction("Date.prototype.setTime", 53 &native_Date_setTime); 54 Date_ctor["prototype"]["toDateString"] = new ScriptFunction("Date.prototype.toDateString", 55 &native_Date_toDateString); 56 Date_ctor["prototype"]["toISOString"] = new ScriptFunction("Date.prototype.toISOString", 57 &native_Date_toISOString); 58 Date_ctor["prototype"]["toUTC"] = new ScriptFunction("Date.prototype.toUTC", 59 &native_Date_toUTC); 60 interpreter.forceSetGlobal("Date", Date_ctor, false); 61 } 62 63 package: 64 65 /** 66 * The Date class 67 */ 68 class ScriptDate 69 { 70 public: 71 /** 72 * Creates a Date representing the time and date of object creation 73 */ 74 this() 75 { 76 _sysTime = Clock.currTime(); 77 } 78 79 this(in long num) 80 { 81 _sysTime = SysTime.fromUnixTime(num); 82 } 83 84 /// takes month 0-11 like JavaScript 85 this(in int year, in int monthIndex, in int day=1, in int hours=0, in int minutes=0, 86 in int seconds=0, in int milliseconds=0) 87 { 88 import core.time: msecs; 89 auto dt = DateTime(year, monthIndex+1, day, hours, minutes, seconds); 90 _sysTime = SysTime(dt, msecs(milliseconds), UTC()); 91 } 92 93 /// This string has to be formatted as "2020-Jan-01 00:00:00" for example. Anything different throws an exception 94 this(in string str) 95 { 96 auto dt = DateTime.fromSimpleString(str); 97 _sysTime = SysTime(dt, UTC()); 98 } 99 100 /// returns day of month 101 int getDate() const 102 { 103 auto dt = cast(DateTime)_sysTime; 104 return dt.day; 105 } 106 107 /// returns day of week 108 int getDay() const 109 { 110 auto dt = cast(DateTime)_sysTime; 111 return dt.dayOfWeek; 112 } 113 114 int getFullYear() const 115 { 116 auto dt = cast(DateTime)_sysTime; 117 return dt.year; 118 } 119 120 /// get the hour of the date 121 int getHours() const 122 { 123 return _sysTime.hour; 124 } 125 126 long getMilliseconds() const 127 { 128 return _sysTime.fracSecs.total!"msecs"; 129 } 130 131 int getMinutes() const 132 { 133 return _sysTime.minute; 134 } 135 136 /// returns month from 0-11 137 int getMonth() const 138 { 139 return cast(int)(_sysTime.month) - 1; 140 } 141 142 int getSeconds() const 143 { 144 return _sysTime.second; 145 } 146 147 long getTime() const 148 { 149 return _sysTime.toUnixTime * 1000; // TODO fix 150 } 151 152 long getTimezone() const 153 { 154 return _sysTime.timezone.utcOffsetAt(_sysTime.stdTime).total!"minutes"; 155 } 156 157 // TODO UTC stuff 158 159 void setDate(in int d) 160 { 161 _sysTime.day = d; 162 } 163 164 void setFullYear(in int year) 165 { 166 _sysTime.year = year; 167 } 168 169 void setHours(in int hours, in int minutes=0, in int seconds=0) 170 { 171 _sysTime.hour = hours; 172 _sysTime.minute = minutes; 173 _sysTime.second = seconds; 174 } 175 176 void setMilliseconds(in uint ms) 177 { 178 import core.time: msecs, Duration; 179 _sysTime.fracSecs = msecs(ms); 180 } 181 182 void setMinutes(in uint minutes) 183 { 184 _sysTime.minute = minutes; 185 } 186 187 void setMonth(in uint month) 188 { 189 _sysTime.month = cast(Month)(month % 12 + 1); 190 } 191 192 void setSeconds(in uint s) 193 { 194 _sysTime.second = cast(ubyte)(s%60); 195 } 196 197 void setTime(in long unixTimeMs) 198 { 199 _sysTime = _sysTime.fromUnixTime(unixTimeMs / 1000); // TODO fix 200 } 201 202 string toISOString() const 203 { 204 auto dt = cast(DateTime)_sysTime; 205 return dt.toISOString(); 206 } 207 208 ScriptDate toUTC() const 209 { 210 auto newSD = new ScriptDate(0); 211 newSD._sysTime = _sysTime.toUTC(); 212 return newSD; 213 } 214 215 override string toString() const 216 { 217 auto tz = _sysTime.timezone.dstName; 218 return (cast(DateTime)_sysTime).toString() ~ " " ~ tz; 219 } 220 221 private: 222 SysTime _sysTime; 223 } 224 225 private: 226 227 ScriptAny native_Date_ctor(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 228 { 229 if(!thisObj.isObject) 230 { 231 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 232 return ScriptAny.UNDEFINED; 233 } 234 auto obj = thisObj.toValue!ScriptObject; 235 try 236 { 237 if(args.length == 0) 238 obj.nativeObject = new ScriptDate(); 239 else if(args.length == 1) 240 { 241 if(args[0].isNumber) 242 obj.nativeObject = new ScriptDate(args[0].toValue!long); 243 else 244 obj.nativeObject = new ScriptDate(args[0].toString()); 245 } 246 else if(args.length >= 2) 247 { 248 immutable year = args[0].toValue!int; 249 immutable month = args[1].toValue!int; 250 immutable day = args.length > 2? args[2].toValue!int : 1; 251 immutable hours = args.length > 3 ? args[3].toValue!int : 0; 252 immutable minutes = args.length > 4 ? args[4].toValue!int : 0; 253 immutable seconds = args.length > 5 ? args[5].toValue!int : 0; 254 immutable mseconds = args.length > 6 ? args[6].toValue!int : 0; 255 obj.nativeObject = new ScriptDate(year, month, day, hours, minutes, seconds, mseconds); 256 } 257 else 258 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 259 } 260 catch(TimeException tex) 261 { 262 nfe = NativeFunctionError.RETURN_VALUE_IS_EXCEPTION; 263 return ScriptAny(tex.msg); 264 } 265 return ScriptAny.UNDEFINED; 266 } 267 268 ScriptAny native_Date_getDate(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 269 { 270 auto date = thisObj.toNativeObject!ScriptDate; 271 if(date is null) 272 { 273 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 274 return ScriptAny.UNDEFINED; 275 } 276 return ScriptAny(date.getDate()); 277 } 278 279 ScriptAny native_Date_getDay(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 280 { 281 auto date = thisObj.toNativeObject!ScriptDate; 282 if(date is null) 283 { 284 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 285 return ScriptAny.UNDEFINED; 286 } 287 return ScriptAny(date.getDay()); 288 } 289 290 ScriptAny native_Date_getFullYear(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 291 { 292 auto date = thisObj.toNativeObject!ScriptDate; 293 if(date is null) 294 { 295 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 296 return ScriptAny.UNDEFINED; 297 } 298 return ScriptAny(date.getFullYear()); 299 } 300 301 ScriptAny native_Date_getHours(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 302 { 303 auto date = thisObj.toNativeObject!ScriptDate; 304 if(date is null) 305 { 306 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 307 return ScriptAny.UNDEFINED; 308 } 309 return ScriptAny(date.getHours()); 310 } 311 312 ScriptAny native_Date_getMilliseconds(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 313 { 314 auto date = thisObj.toNativeObject!ScriptDate; 315 if(date is null) 316 { 317 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 318 return ScriptAny.UNDEFINED; 319 } 320 return ScriptAny(date.getMilliseconds()); 321 } 322 323 ScriptAny native_Date_getMinutes(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 324 { 325 auto date = thisObj.toNativeObject!ScriptDate; 326 if(date is null) 327 { 328 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 329 return ScriptAny.UNDEFINED; 330 } 331 return ScriptAny(date.getMinutes()); 332 } 333 334 ScriptAny native_Date_getMonth(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 335 { 336 if(!thisObj.isObject) 337 { 338 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 339 return ScriptAny.UNDEFINED; 340 } 341 auto dateObj = (*thisObj).toValue!ScriptDate; 342 if(dateObj is null) 343 { 344 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 345 return ScriptAny.UNDEFINED; 346 } 347 return ScriptAny(dateObj.getMonth); 348 } 349 350 ScriptAny native_Date_getSeconds(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 351 { 352 auto date = thisObj.toNativeObject!ScriptDate; 353 if(date is null) 354 { 355 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 356 return ScriptAny.UNDEFINED; 357 } 358 return ScriptAny(date.getSeconds()); 359 } 360 361 ScriptAny native_Date_getTime(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 362 { 363 auto date = thisObj.toNativeObject!ScriptDate; 364 if(date is null) 365 { 366 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 367 return ScriptAny.UNDEFINED; 368 } 369 return ScriptAny(date.getTime()); 370 } 371 372 ScriptAny native_Date_getTimezone(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 373 { 374 auto date = thisObj.toNativeObject!ScriptDate; 375 if(date is null) 376 { 377 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 378 return ScriptAny.UNDEFINED; 379 } 380 return ScriptAny(date.getTimezone()); 381 } 382 383 ScriptAny native_Date_setDate(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 384 { 385 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 386 mixin(TO_ARG_CHECK_INDEX!("d", 0, int)); 387 try 388 { 389 date.setDate(d); 390 } 391 catch(TimeException ex) 392 { 393 nfe = NativeFunctionError.RETURN_VALUE_IS_EXCEPTION; 394 return ScriptAny(ex.msg); 395 } 396 return ScriptAny.UNDEFINED; 397 } 398 399 ScriptAny native_Date_setFullYear(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 400 { 401 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 402 mixin(TO_ARG_CHECK_INDEX!("year", 0, int)); 403 try // this might not be needed here 404 { 405 date.setFullYear(year); 406 } 407 catch(TimeException ex) 408 { 409 nfe = NativeFunctionError.RETURN_VALUE_IS_EXCEPTION; 410 return ScriptAny(ex.msg); 411 } 412 return ScriptAny.UNDEFINED; 413 } 414 415 ScriptAny native_Date_setHours(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 416 { 417 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 418 mixin(TO_ARG_CHECK_INDEX!("hour", 0, int)); 419 mixin(TO_ARG_OPT!("minute", 1, 0, int)); 420 mixin(TO_ARG_OPT!("second", 2, 0, int)); 421 date.setHours(hour%24, minute%60, second%60); 422 return ScriptAny.UNDEFINED; 423 } 424 425 ScriptAny native_Date_setMilliseconds(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 426 { 427 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 428 mixin(TO_ARG_CHECK_INDEX!("ms", 0, uint)); 429 date.setMilliseconds(ms % 1000); 430 return ScriptAny.UNDEFINED; 431 } 432 433 ScriptAny native_Date_setMinutes(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 434 { 435 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 436 mixin(TO_ARG_CHECK_INDEX!("minutes", 0, uint)); 437 date.setMinutes(minutes % 60); 438 return ScriptAny.UNDEFINED; 439 } 440 441 ScriptAny native_Date_setMonth(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 442 { 443 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 444 mixin(TO_ARG_CHECK_INDEX!("m", 0, uint)); 445 try 446 { 447 date.setMonth(m); 448 } 449 catch(TimeException ex) 450 { 451 nfe = NativeFunctionError.RETURN_VALUE_IS_EXCEPTION; 452 return ScriptAny(ex.msg); 453 } 454 return ScriptAny.UNDEFINED; 455 } 456 457 ScriptAny native_Date_setSeconds(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 458 { 459 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 460 mixin(TO_ARG_CHECK_INDEX!("s", 0, uint)); 461 date.setSeconds(s); 462 return ScriptAny.UNDEFINED; 463 } 464 465 ScriptAny native_Date_setTime(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 466 { 467 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 468 mixin(TO_ARG_CHECK_INDEX!("t", 0, long)); 469 date.setTime(t); 470 return ScriptAny.UNDEFINED; 471 } 472 473 ScriptAny native_Date_toDateString(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 474 { 475 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 476 return ScriptAny(date.toString()); 477 } 478 479 ScriptAny native_Date_toISOString(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 480 { 481 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 482 return ScriptAny(date.toISOString()); 483 } 484 485 ScriptAny native_Date_toUTC(Context c, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError nfe) 486 { 487 mixin(CHECK_THIS_NATIVE_OBJECT!("date", ScriptDate)); 488 auto newDate = date.toUTC(); 489 auto newSD = new ScriptObject("Date", thisObj.toValue!ScriptObject.prototype, newDate); 490 return ScriptAny(newSD); 491 }