1from ..base import * 2from .time_helpers import * 3 4TZ_OFFSET = (time.altzone // 3600) 5ABS_OFFSET = abs(TZ_OFFSET) 6TZ_NAME = time.tzname[1] 7ISO_FORMAT = '%s-%s-%sT%s:%s:%s.%sZ' 8 9 10@Js 11def Date(year, month, date, hours, minutes, seconds, ms): 12 return now().to_string() 13 14 15Date.Class = 'Date' 16 17 18def now(): 19 return PyJsDate(int(time.time() * 1000), prototype=DatePrototype) 20 21 22@Js 23def UTC(year, month, date, hours, minutes, seconds, ms): # todo complete this 24 args = arguments 25 y = args[0].to_number() 26 m = args[1].to_number() 27 l = len(args) 28 dt = args[2].to_number() if l > 2 else Js(1) 29 h = args[3].to_number() if l > 3 else Js(0) 30 mi = args[4].to_number() if l > 4 else Js(0) 31 sec = args[5].to_number() if l > 5 else Js(0) 32 mili = args[6].to_number() if l > 6 else Js(0) 33 if not y.is_nan() and 0 <= y.value <= 99: 34 y = y + Js(1900) 35 return TimeClip(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili))) 36 37 38@Js 39def parse(string): 40 return PyJsDate( 41 TimeClip(parse_date(string.to_string().value)), 42 prototype=DatePrototype) 43 44 45Date.define_own_property('now', { 46 'value': Js(now), 47 'enumerable': False, 48 'writable': True, 49 'configurable': True 50}) 51 52Date.define_own_property('parse', { 53 'value': parse, 54 'enumerable': False, 55 'writable': True, 56 'configurable': True 57}) 58 59Date.define_own_property('UTC', { 60 'value': UTC, 61 'enumerable': False, 62 'writable': True, 63 'configurable': True 64}) 65 66 67class PyJsDate(PyJs): 68 Class = 'Date' 69 extensible = True 70 71 def __init__(self, value, prototype=None): 72 self.value = value 73 self.own = {} 74 self.prototype = prototype 75 76 # todo fix this problematic datetime part 77 def to_local_dt(self): 78 return datetime.datetime(1970, 1, 1) + datetime.timedelta( 79 seconds=UTCToLocal(self.value) // 1000) 80 81 def to_utc_dt(self): 82 return datetime.datetime(1970, 1, 1) + datetime.timedelta( 83 seconds=self.value // 1000) 84 85 def local_strftime(self, pattern): 86 if self.value is NaN: 87 return 'Invalid Date' 88 try: 89 dt = self.to_local_dt() 90 except: 91 raise MakeError( 92 'TypeError', 93 'unsupported date range. Will fix in future versions') 94 try: 95 return dt.strftime(pattern) 96 except: 97 raise MakeError( 98 'TypeError', 99 'Could not generate date string from this date (limitations of python.datetime)' 100 ) 101 102 def utc_strftime(self, pattern): 103 if self.value is NaN: 104 return 'Invalid Date' 105 try: 106 dt = self.to_utc_dt() 107 except: 108 raise MakeError( 109 'TypeError', 110 'unsupported date range. Will fix in future versions') 111 try: 112 return dt.strftime(pattern) 113 except: 114 raise MakeError( 115 'TypeError', 116 'Could not generate date string from this date (limitations of python.datetime)' 117 ) 118 119 120def parse_date(py_string): # todo support all date string formats 121 date_formats = ( 122 "%Y-%m-%d", 123 "%m/%d/%Y", 124 "%b %d %Y", 125 ) 126 # Supports these hour formats and with or hour. 127 hour_formats = ( 128 "T%H:%M:%S.%f", 129 "T%H:%M:%S", 130 ) + ('',) 131 # Supports with or without Z indicator. 132 z_formats = ("Z",) + ('',) 133 supported_formats = [ 134 d + t + z 135 for d in date_formats 136 for t in hour_formats 137 for z in z_formats 138 ] 139 for date_format in supported_formats: 140 try: 141 dt = datetime.datetime.strptime(py_string, date_format) 142 except ValueError: 143 continue 144 else: 145 return MakeDate( 146 MakeDay(Js(dt.year), Js(dt.month - 1), Js(dt.day)), 147 MakeTime( 148 Js(dt.hour), Js(dt.minute), Js(dt.second), 149 Js(dt.microsecond // 1000))) 150 151 raise MakeError( 152 'TypeError', 153 'Could not parse date %s - unsupported date format. Currently only supported formats are RFC3339 utc, ISO Date, Short Date, and Long Date. Sorry!' 154 % py_string) 155 156 157def date_constructor(*args): 158 if len(args) >= 2: 159 return date_constructor2(*args) 160 elif len(args) == 1: 161 return date_constructor1(args[0]) 162 else: 163 return date_constructor0() 164 165 166def date_constructor0(): 167 return now() 168 169 170def date_constructor1(value): 171 v = value.to_primitive() 172 if v._type() == 'String': 173 v = parse_date(v.value) 174 else: 175 v = v.to_int() 176 return PyJsDate(TimeClip(v), prototype=DatePrototype) 177 178 179def date_constructor2(*args): 180 y = args[0].to_number() 181 m = args[1].to_number() 182 l = len(args) 183 dt = args[2].to_number() if l > 2 else Js(1) 184 h = args[3].to_number() if l > 3 else Js(0) 185 mi = args[4].to_number() if l > 4 else Js(0) 186 sec = args[5].to_number() if l > 5 else Js(0) 187 mili = args[6].to_number() if l > 6 else Js(0) 188 if not y.is_nan() and 0 <= y.value <= 99: 189 y = y + Js(1900) 190 t = TimeClip( 191 LocalToUTC(MakeDate(MakeDay(y, m, dt), MakeTime(h, mi, sec, mili)))) 192 return PyJsDate(t, prototype=DatePrototype) 193 194 195Date.create = date_constructor 196 197DatePrototype = PyJsDate(float('nan'), prototype=ObjectPrototype) 198 199 200def check_date(obj): 201 if obj.Class != 'Date': 202 raise MakeError('TypeError', 'this is not a Date object') 203 204 205class DateProto: 206 def toString(): 207 check_date(this) 208 if this.value is NaN: 209 return 'Invalid Date' 210 offset = (UTCToLocal(this.value) - this.value) // msPerHour 211 return this.local_strftime( 212 '%a %b %d %Y %H:%M:%S GMT') + '%s00 (%s)' % (pad( 213 offset, 2, True), GetTimeZoneName(this.value)) 214 215 def toDateString(): 216 check_date(this) 217 return this.local_strftime('%d %B %Y') 218 219 def toTimeString(): 220 check_date(this) 221 return this.local_strftime('%H:%M:%S') 222 223 def toLocaleString(): 224 check_date(this) 225 return this.local_strftime('%d %B %Y %H:%M:%S') 226 227 def toLocaleDateString(): 228 check_date(this) 229 return this.local_strftime('%d %B %Y') 230 231 def toLocaleTimeString(): 232 check_date(this) 233 return this.local_strftime('%H:%M:%S') 234 235 def valueOf(): 236 check_date(this) 237 return this.value 238 239 def getTime(): 240 check_date(this) 241 return this.value 242 243 def getFullYear(): 244 check_date(this) 245 if this.value is NaN: 246 return NaN 247 return YearFromTime(UTCToLocal(this.value)) 248 249 def getUTCFullYear(): 250 check_date(this) 251 if this.value is NaN: 252 return NaN 253 return YearFromTime(this.value) 254 255 def getMonth(): 256 check_date(this) 257 if this.value is NaN: 258 return NaN 259 return MonthFromTime(UTCToLocal(this.value)) 260 261 def getDate(): 262 check_date(this) 263 if this.value is NaN: 264 return NaN 265 return DateFromTime(UTCToLocal(this.value)) 266 267 def getUTCMonth(): 268 check_date(this) 269 if this.value is NaN: 270 return NaN 271 return MonthFromTime(this.value) 272 273 def getUTCDate(): 274 check_date(this) 275 if this.value is NaN: 276 return NaN 277 return DateFromTime(this.value) 278 279 def getDay(): 280 check_date(this) 281 if this.value is NaN: 282 return NaN 283 return WeekDay(UTCToLocal(this.value)) 284 285 def getUTCDay(): 286 check_date(this) 287 if this.value is NaN: 288 return NaN 289 return WeekDay(this.value) 290 291 def getHours(): 292 check_date(this) 293 if this.value is NaN: 294 return NaN 295 return HourFromTime(UTCToLocal(this.value)) 296 297 def getUTCHours(): 298 check_date(this) 299 if this.value is NaN: 300 return NaN 301 return HourFromTime(this.value) 302 303 def getMinutes(): 304 check_date(this) 305 if this.value is NaN: 306 return NaN 307 return MinFromTime(UTCToLocal(this.value)) 308 309 def getUTCMinutes(): 310 check_date(this) 311 if this.value is NaN: 312 return NaN 313 return MinFromTime(this.value) 314 315 def getSeconds(): 316 check_date(this) 317 if this.value is NaN: 318 return NaN 319 return SecFromTime(UTCToLocal(this.value)) 320 321 def getUTCSeconds(): 322 check_date(this) 323 if this.value is NaN: 324 return NaN 325 return SecFromTime(this.value) 326 327 def getMilliseconds(): 328 check_date(this) 329 if this.value is NaN: 330 return NaN 331 return msFromTime(UTCToLocal(this.value)) 332 333 def getUTCMilliseconds(): 334 check_date(this) 335 if this.value is NaN: 336 return NaN 337 return msFromTime(this.value) 338 339 def getTimezoneOffset(): 340 check_date(this) 341 if this.value is NaN: 342 return NaN 343 return (this.value - UTCToLocal(this.value)) // 60000 344 345 def setTime(time): 346 check_date(this) 347 this.value = TimeClip(time.to_number().to_int()) 348 return this.value 349 350 def setMilliseconds(ms): 351 check_date(this) 352 t = UTCToLocal(this.value) 353 tim = MakeTime( 354 Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms) 355 u = TimeClip(LocalToUTC(MakeDate(Day(t), tim))) 356 this.value = u 357 return u 358 359 def setUTCMilliseconds(ms): 360 check_date(this) 361 t = this.value 362 tim = MakeTime( 363 Js(HourFromTime(t)), Js(MinFromTime(t)), Js(SecFromTime(t)), ms) 364 u = TimeClip(MakeDate(Day(t), tim)) 365 this.value = u 366 return u 367 368 def setSeconds(sec, ms=None): 369 check_date(this) 370 t = UTCToLocal(this.value) 371 s = sec.to_number() 372 if not ms is None: milli = Js(msFromTime(t)) 373 else: milli = ms.to_number() 374 date = MakeDate( 375 Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli)) 376 u = TimeClip(LocalToUTC(date)) 377 this.value = u 378 return u 379 380 def setUTCSeconds(sec, ms=None): 381 check_date(this) 382 t = this.value 383 s = sec.to_number() 384 if not ms is None: milli = Js(msFromTime(t)) 385 else: milli = ms.to_number() 386 date = MakeDate( 387 Day(t), MakeTime(Js(HourFromTime(t)), Js(MinFromTime(t)), s, milli)) 388 v = TimeClip(date) 389 this.value = v 390 return v 391 392 def setMinutes(min, sec=None, ms=None): 393 check_date(this) 394 t = UTCToLocal(this.value) 395 m = min.to_number() 396 if not sec is None: s = Js(SecFromTime(t)) 397 else: s = sec.to_number() 398 if not ms is None: milli = Js(msFromTime(t)) 399 else: milli = ms.to_number() 400 date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli)) 401 u = TimeClip(LocalToUTC(date)) 402 this.value = u 403 return u 404 405 def setUTCMinutes(min, sec=None, ms=None): 406 check_date(this) 407 t = this.value 408 m = min.to_number() 409 if not sec is None: s = Js(SecFromTime(t)) 410 else: s = sec.to_number() 411 if not ms is None: milli = Js(msFromTime(t)) 412 else: milli = ms.to_number() 413 date = MakeDate(Day(t), MakeTime(Js(HourFromTime(t)), m, s, milli)) 414 v = TimeClip(date) 415 this.value = v 416 return v 417 418 def setHours(hour, min=None, sec=None, ms=None): 419 check_date(this) 420 t = UTCToLocal(this.value) 421 h = hour.to_number() 422 if not min is None: m = Js(MinFromTime(t)) 423 else: m = min.to_number() 424 if not sec is None: s = Js(SecFromTime(t)) 425 else: s = sec.to_number() 426 if not ms is None: milli = Js(msFromTime(t)) 427 else: milli = ms.to_number() 428 date = MakeDate(Day(t), MakeTime(h, m, s, milli)) 429 u = TimeClip(LocalToUTC(date)) 430 this.value = u 431 return u 432 433 def setUTCHours(hour, min=None, sec=None, ms=None): 434 check_date(this) 435 t = this.value 436 h = hour.to_number() 437 if not min is None: m = Js(MinFromTime(t)) 438 else: m = min.to_number() 439 if not sec is None: s = Js(SecFromTime(t)) 440 else: s = sec.to_number() 441 if not ms is None: milli = Js(msFromTime(t)) 442 else: milli = ms.to_number() 443 date = MakeDate(Day(t), MakeTime(h, m, s, milli)) 444 v = TimeClip(date) 445 this.value = v 446 return v 447 448 def setDate(date): 449 check_date(this) 450 t = UTCToLocal(this.value) 451 dt = date.to_number() 452 newDate = MakeDate( 453 MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t)) 454 u = TimeClip(LocalToUTC(newDate)) 455 this.value = u 456 return u 457 458 def setUTCDate(date): 459 check_date(this) 460 t = this.value 461 dt = date.to_number() 462 newDate = MakeDate( 463 MakeDay(Js(YearFromTime(t)), Js(MonthFromTime(t)), dt), TimeWithinDay(t)) 464 v = TimeClip(newDate) 465 this.value = v 466 return v 467 468 def setMonth(month, date=None): 469 check_date(this) 470 t = UTCToLocal(this.value) 471 m = month.to_number() 472 if not date is None: dt = Js(DateFromTime(t)) 473 else: dt = date.to_number() 474 newDate = MakeDate( 475 MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t)) 476 u = TimeClip(LocalToUTC(newDate)) 477 this.value = u 478 return u 479 480 def setUTCMonth(month, date=None): 481 check_date(this) 482 t = this.value 483 m = month.to_number() 484 if not date is None: dt = Js(DateFromTime(t)) 485 else: dt = date.to_number() 486 newDate = MakeDate( 487 MakeDay(Js(YearFromTime(t)), m, dt), TimeWithinDay(t)) 488 v = TimeClip(newDate) 489 this.value = v 490 return v 491 492 def setFullYear(year, month=None, date=None): 493 check_date(this) 494 if not this.value is NaN: t = UTCToLocal(this.value) 495 else: t = 0 496 y = year.to_number() 497 if not month is None: m = Js(MonthFromTime(t)) 498 else: m = month.to_number() 499 if not date is None: dt = Js(DateFromTime(t)) 500 else: dt = date.to_number() 501 newDate = MakeDate( 502 MakeDay(y, m, dt), TimeWithinDay(t)) 503 u = TimeClip(LocalToUTC(newDate)) 504 this.value = u 505 return u 506 507 def setUTCFullYear(year, month=None, date=None): 508 check_date(this) 509 if not this.value is NaN: t = UTCToLocal(this.value) 510 else: t = 0 511 y = year.to_number() 512 if not month is None: m = Js(MonthFromTime(t)) 513 else: m = month.to_number() 514 if not date is None: dt = Js(DateFromTime(t)) 515 else: dt = date.to_number() 516 newDate = MakeDate( 517 MakeDay(y, m, dt), TimeWithinDay(t)) 518 v = TimeClip(newDate) 519 this.value = v 520 return v 521 522 def toUTCString(): 523 check_date(this) 524 return this.utc_strftime('%d %B %Y %H:%M:%S') 525 526 def toISOString(): 527 check_date(this) 528 t = this.value 529 year = YearFromTime(t) 530 month, day, hour, minute, second, milli = pad( 531 MonthFromTime(t) + 1), pad(DateFromTime(t)), pad( 532 HourFromTime(t)), pad(MinFromTime(t)), pad( 533 SecFromTime(t)), pad(msFromTime(t)) 534 return ISO_FORMAT % (unicode(year) if 0 <= year <= 9999 else pad( 535 year, 6, True), month, day, hour, minute, second, milli) 536 537 def toJSON(key): 538 o = this.to_object() 539 tv = o.to_primitive('Number') 540 if tv.Class == 'Number' and not tv.is_finite(): 541 return this.null 542 toISO = o.get('toISOString') 543 if not toISO.is_callable(): 544 raise this.MakeError('TypeError', 'toISOString is not callable') 545 return toISO.call(o, ()) 546 547 548def pad(num, n=2, sign=False): 549 '''returns n digit string representation of the num''' 550 s = unicode(abs(num)) 551 if len(s) < n: 552 s = '0' * (n - len(s)) + s 553 if not sign: 554 return s 555 if num >= 0: 556 return '+' + s 557 else: 558 return '-' + s 559 560 561fill_prototype(DatePrototype, DateProto, default_attrs) 562 563Date.define_own_property( 564 'prototype', { 565 'value': DatePrototype, 566 'enumerable': False, 567 'writable': False, 568 'configurable': False 569 }) 570 571DatePrototype.define_own_property('constructor', { 572 'value': Date, 573 'enumerable': False, 574 'writable': True, 575 'configurable': True 576}) 577